Snap for 5234541 from 8829ced538f854607988056c67906568319bfe38 to sdk-release
Change-Id: Ibfe03d44534bc799dfdf43e2e9424312005711c7
diff --git a/BUILD b/BUILD
index aac392c..7aae4d5 100644
--- a/BUILD
+++ b/BUILD
@@ -17,11 +17,13 @@
"src/runtests.cc",
"src/weaver_tests.cc",
"src/avb_tests.cc",
+ "src/transport_tests.cc",
],
copts = COPTS,
deps = [
":dcrypto_test_data",
":km_test_lib",
+ ":reset_key_data_lib",
":util",
"@boringssl//:ssl",
"@com_github_gflags_gflags//:gflags",
@@ -81,7 +83,6 @@
"src/util.cc",
],
hdrs = [
- "src/blob.h",
"src/macros.h",
"src/util.h",
],
@@ -96,6 +97,16 @@
)
cc_library(
+ name = "reset_key_data_lib",
+ srcs = [
+ "src/test-data/test-keys/reset_key_data.cc",
+ ],
+ hdrs = [
+ "src/test-data/test-keys/reset_key_data.h",
+ ],
+)
+
+cc_library(
name = "km_test_lib",
srcs = [
"src/test-data/test-keys/rsa.cc",
diff --git a/OWNERS b/OWNERS
new file mode 100644
index 0000000..39b2298
--- /dev/null
+++ b/OWNERS
@@ -0,0 +1,6 @@
+# Default owners are top 3 or more active developers of the past 1 or 2 years
+# or people with more than 10 commits last year.
+# Please update this list if you find better owner candidates.
+ascull@google.com
+ngm@google.com
+wfrichar@google.com
diff --git a/scripts/release-tests.sh b/scripts/release-tests.sh
index b14ab75..155e9ac 100755
--- a/scripts/release-tests.sh
+++ b/scripts/release-tests.sh
@@ -1,13 +1,15 @@
#!/bin/bash
set -e
+source build/envsetup.sh
+
function integration_tests() {
m -j citadel_integration_tests || return 1
adb shell stop || return 1
adb sync || return 1
adb shell start || return 1
- adb exec-out \
- '/vendor/bin/hw/citadel_integration_tests --release-tests' || return 1
+ adb shell \
+ /vendor/bin/hw/citadel_integration_tests --release-tests || return 1
}
# TODO: add AVB / Weaver / Keymaster VTS / CTS tests with filters here.
@@ -21,7 +23,14 @@
}
function keymaster_vts_tests() {
- return 0
+ m -j VtsHalKeymasterV4_0TargetTest || return 1
+ adb sync data || return 1
+ # TODO(b/109771020): remove test filter below.
+ adb shell \
+ /data/nativetest64/VtsHalKeymasterV4_0TargetTest/VtsHalKeymasterV4_0TargetTest \
+ --verbose \
+ --hal_service_instance=android.hardware.keymaster@4.0::IKeymasterDevice/strongbox \
+ --gtest_filter=-EncryptionOperationsTest.RsaNoPaddingShortMessage || return 1
}
function weaver_cts_tests() {
@@ -40,10 +49,8 @@
}
function pay_cts_tests() {
- :
- # TODO(ngm): uncomment once these are working.
- # runtest --path \
- # cts/tests/tests/keystore/src/android/keystore/cts/ImportWrappedKeyTest.java || return 1
+ runtest --path \
+ cts/tests/tests/keystore/src/android/keystore/cts/ImportWrappedKeyTest.java || return 1
}
# TODO: add any other tests
@@ -53,18 +60,25 @@
exit 1
fi
-for t in integration_tests \
- oem_lock_vts_tests \
- keymaster_cts_tests \
- keymaster_vts_tests \
- weaver_cts_tests \
- weaver_vts_tests \
- auth_secret_vts_tests \
- pay_cts_tests; do
+adb root && adb remount
+
+# keymaster tests need to run before integration tests, which mess
+# with factory reset, and break keymaster on-boot info.
+for t in \
+ keymaster_vts_tests \
+ keymaster_cts_tests \
+ pay_cts_tests \
+ integration_tests \
+ oem_lock_vts_tests \
+ weaver_cts_tests \
+ weaver_vts_tests \
+ auth_secret_vts_tests; do
if eval "${t}"; then
- echo "PASS: ${t}"
+ echo "PASS: ${t}"
else
- echo "FAIL: ${t}"
- exit 1
+ echo "FAIL: ${t}"
+ exit 1
fi
done
+
+# TODO: factory reset the device to original state.
diff --git a/src/avb_tests.cc b/src/avb_tests.cc
index 32ff5ef..f6e3161 100644
--- a/src/avb_tests.cc
+++ b/src/avb_tests.cc
@@ -5,6 +5,7 @@
#include "nugget_tools.h"
#include "nugget/app/avb/avb.pb.h"
#include "Avb.client.h"
+#include "src/test-data/test-keys/reset_key_data.h"
#include <avb.h>
#include <application.h>
#include <nos/AppClient.h>
@@ -139,38 +140,10 @@
EXPECT_EQ(locks[OWNER], 0x00);
}
-static const uint8_t kResetKeyPem[] =
-"-----BEGIN RSA PRIVATE KEY-----\n\
-MIIEpAIBAAKCAQEAo0IoAa5cK7XyAj7u1jFStsfEcxkgAZVF9VWKzH1bofKxLioA\n\
-r5Lo4D33glKehxkOlDo6GkBj1PoI8WuvYYvEUyxJNUdlVpa1C2lbewEL0rfyBrZ9\n\
-4cp0ZeUknymYHn3ynW4Z8sYMlj7BNxGttV/jbxtgtT5WHJ+hg5/4/ifCPucN17Bt\n\
-heUKIBoAjy6DlB/pMg1NUQ82DaASMFe89mEzI9Zk4CRtkWjEhknY0bYm46U1ABJb\n\
-YmIsHlxdADskvWFDmq8CfJr/jXstTXxZeqaxPPdSP+WPwXN/ku5W7qkF2qimEKiy\n\
-DYHzY65JhfWmHOLLGNuz6iHkq93uzkKsGIIPGQIDAQABAoIBABGTvdrwetv56uRz\n\
-AiPti4pCV9RMkDWbbLzNSPRbStJU3t6phwlgN9Js2YkefBLvj7JF0pug8x6rDOtx\n\
-PKCz+5841Wj3FuILt9JStZa4th0p0NUIMOVudrnBwf+g6s/dn5FzmTeaOyCyAPt8\n\
-28b7W/FKcU8SNxM93JXfU1+JyFAdREqsXQfqLhCAXBb46fs5D8hg0c99RdWuJSuY\n\
-HKyVXDrjmYAHS5qUDeMx0OY/q1qM03FBvHekvJ78WPpUKF7B/gYH9lBHIHE0KLJY\n\
-JR6kKkzN/Ii6BsSubKKeuNntzlzd2ukvFdX4uc42dDpIXPdaQAn84KRYN7++KoGz\n\
-2LqtAAECgYEAzQt5kt9c+xDeKMPR92XQ4uMeLxTufBei1PFGZbJnJT8aEMkVhKT/\n\
-Pbh1Z8OnN9YvFprDNpEilUm7xyffrE7p0pI1/qiBXZExy6pIcGAo4ZcB8ayN0JV3\n\
-k+RilE73x+sKAyWOm82b273PiyHNsQI4flkO5Ev9rpZbPMKlvZYsmxkCgYEAy9RR\n\
-RwxwCpvFi3um0Rwz7CI2uvVXGaLVXyR2oNGLcJG7AhusYi4FX6XJQ3vAgiDmzu/c\n\
-SaEF9w7uqeueIUA7L7njYP1ojfJAUJEtQRfVJF2tDntN5YgYUTsx8n3IKTs4xFT4\n\
-dBthKo16zzLv92+8m4sWJhFW2zzFFLwk+G5jlAECgYEAln1piSZus8Y5h2nRXOZZ\n\
-XWyb5qpSLrmaRPegV1uM4IVjuBYduPDwdHhBkxrCS/TjMo/73ry+yRsIuq7FN03j\n\
-xyyQfItoByhdh8E+0VuCJbATOTEQFJre3KiuwXMD4LLc8lpKRIevcKPrA46XzOZ4\n\
-WCM9DsnHMrAf3oRt6KujqWECgYEAyu43fWUEp4suwg/5pXdOumnV040vinZzuKW0\n\
-9aeqDAkLBq5Gkfj/oJqOJoGux9+5640i5KtMJQzY0JOke7ZXNsz7dDTXQ3tMTOo9\n\
-A/GWYv5grWpVw5AbpcQpliNkhKhRfCactfwMYTE6c89i2haE0NdI1d2te9ik3l/y\n\
-7uP4gAECgYA3u2CumlkjHq+LbMK6Ry+Ajyy4ssM5PKJUqSogJDUkHsG/C7yaCdq/\n\
-Ljt2x2220H0pM9885C3PpKxoYwRih9dzOamnARJocAElp2b5AQB+tKddlMdwx1pQ\n\
-0IMGQ3fBYkDFLGYDk7hGYkLLlSJCZwi64xKmmfEwl83RL6JDSFupDg==\n\
------END RSA PRIVATE KEY-----";
-
-static RSA *GetResetKey()
+RSA *GetResetKey()
{
- BIO *bio = BIO_new_mem_buf((void*)kResetKeyPem, sizeof(kResetKeyPem) - 1);
+ BIO *bio = BIO_new_mem_buf((void*)test_data::kResetKeyPem,
+ test_data::kResetKeyPemSize - 1);
RSA *rsa = PEM_read_bio_RSAPrivateKey(bio, NULL, 0, NULL);
BIO_free(bio);
return rsa;
@@ -747,7 +720,7 @@
ASSERT_LE(sizeof(data), len);
ASSERT_NO_ERROR(code, "");
EXPECT_NE(0ULL, nonce);
- EXPECT_EQ((uint32_t)ResetToken::CURRENT, selector);
+ EXPECT_LE(selector, (uint32_t)ResetToken::CURRENT);
EXPECT_EQ(32UL, len);
// We didn't set a device id.
EXPECT_EQ(0, memcmp(data, empty, sizeof(empty)));
@@ -805,33 +778,6 @@
ASSERT_NO_ERROR(code, "");
}
-static const uint8_t kNullSig[] = {
- 0x95, 0x35, 0x5a, 0xb6, 0xe3, 0x8e, 0x43, 0x03, 0xd9, 0xd9, 0xd5, 0x6e,
- 0x99, 0x86, 0xff, 0x8e, 0x6a, 0xf1, 0x54, 0x6f, 0xa8, 0xff, 0x37, 0x38,
- 0xc6, 0x9b, 0x4d, 0xc6, 0x99, 0x1f, 0x37, 0x5c, 0xec, 0xf4, 0x32, 0xd8,
- 0xe6, 0x00, 0xcc, 0x74, 0xde, 0xa9, 0x68, 0x1a, 0xab, 0x6a, 0x6e, 0xe7,
- 0xa7, 0xa1, 0x59, 0xe0, 0x7c, 0x86, 0x95, 0x28, 0x94, 0x18, 0x3f, 0x0f,
- 0xb9, 0x0f, 0x05, 0x6c, 0x86, 0x5a, 0x6a, 0xe4, 0x6d, 0x36, 0x71, 0x86,
- 0x38, 0xab, 0x7a, 0x2d, 0x9c, 0xa5, 0xfa, 0xc8, 0x7c, 0x48, 0x02, 0x8c,
- 0x6b, 0x4d, 0xda, 0xa4, 0xb5, 0xa8, 0x17, 0x39, 0x5e, 0xe3, 0x1a, 0xd5,
- 0xf8, 0x87, 0x6e, 0xd9, 0xc0, 0x0c, 0x29, 0x4d, 0x93, 0xa2, 0x3b, 0xfc,
- 0x2d, 0x38, 0x8e, 0x2b, 0xc7, 0x49, 0x26, 0xd9, 0xcb, 0x47, 0x89, 0x4c,
- 0x79, 0xd3, 0x60, 0x62, 0xf9, 0x71, 0xa7, 0x73, 0x6a, 0x03, 0x65, 0x1f,
- 0x11, 0x0d, 0x9e, 0x27, 0x99, 0x6b, 0xa7, 0x46, 0x85, 0x75, 0xec, 0xff,
- 0x5b, 0x1d, 0x8d, 0x1b, 0x34, 0xd8, 0xb9, 0x4f, 0x63, 0x88, 0x08, 0xa8,
- 0x16, 0xba, 0xfc, 0xe7, 0x66, 0xa4, 0xe5, 0xde, 0x4e, 0x0b, 0x98, 0x80,
- 0xd5, 0x16, 0x55, 0xfb, 0xdb, 0xe8, 0xa2, 0x90, 0x85, 0x4e, 0xa9, 0xb6,
- 0x81, 0x55, 0xef, 0xbf, 0x12, 0xe3, 0xd2, 0xa9, 0xae, 0x2c, 0x43, 0x67,
- 0x4c, 0x09, 0x6d, 0x95, 0xaf, 0x44, 0xc2, 0xb9, 0x9d, 0x7c, 0xb1, 0x88,
- 0xf8, 0x6c, 0xa0, 0x13, 0x4c, 0xbf, 0x85, 0xa2, 0x8b, 0x9d, 0x06, 0xc8,
- 0x11, 0xdb, 0x1f, 0xfb, 0x05, 0x15, 0xd6, 0x1f, 0xe5, 0x52, 0x9c, 0xd5,
- 0xbd, 0xff, 0xb0, 0xce, 0x29, 0xec, 0xd8, 0x9e, 0xdb, 0x5b, 0xc9, 0x52,
- 0x24, 0xaf, 0x22, 0xeb, 0xce, 0x15, 0x0d, 0xfd, 0x6c, 0x76, 0x90, 0x3e,
- 0x4f, 0x63, 0xfd, 0xb1
-};
-
-const static unsigned int kNullSigLen = 256;
-
TEST_F(AvbTest, ProductionResetTestValid)
{
static const uint8_t kDeviceHash[] = {
@@ -876,7 +822,8 @@
message.nonce = 0;
memset(message.data, 0, sizeof(message.data));
code = ProductionResetTest(selector, message.nonce, message.data, len,
- kNullSig, kNullSigLen);
+ test_data::kResetSignatures[selector],
+ test_data::kResetSignatureLengths[selector]);
ASSERT_NO_ERROR(code, "");
}
@@ -889,4 +836,29 @@
EXPECT_EQ(locks[DEVICE], 0x00);
}
+TEST_F(AvbTest, ResetKeyNullTokenSignatureTest)
+{
+ struct ResetMessage message;
+ int code;
+
+ uint32_t selector;
+ uint64_t nonce;
+ uint8_t device_data[AVB_DEVICE_DATA_SIZE];
+ size_t len = sizeof(device_data);
+
+ // Get the selector
+ code = GetResetChallenge(client.get(), &selector, &nonce,
+ device_data, &len);
+ ASSERT_NO_ERROR(code, "");
+ ASSERT_LT(selector, test_data::kResetSignatureCount);
+
+ memset(&message, 0, sizeof(message));
+ // Now use a good one, but without getting a new nonce.
+ cout << "Testing key: " << selector << "\n";
+ code = ProductionResetTest(selector, message.nonce, message.data, 32,
+ test_data::kResetSignatures[selector],
+ test_data::kResetSignatureLengths[selector]);
+ ASSERT_NO_ERROR(code, "");
+}
+
} // namespace
diff --git a/src/blob.h b/src/blob.h
deleted file mode 100644
index 4a88b45..0000000
--- a/src/blob.h
+++ /dev/null
@@ -1,84 +0,0 @@
-#ifndef SRC_BLOB_H
-#define SRC_BLOB_H
-
-#include <stddef.h>
-#include <stdint.h>
-
-struct LITE_BIGNUM {
- uint32_t dmax; /* Size of d, in 32-bit words. */
- uint32_t d; /* Word array, little endian format ... */
-} __attribute__((packed));
-
-struct LITE_RSA {
- uint32_t e;
- struct LITE_BIGNUM N;
- struct LITE_BIGNUM d;
-} __attribute__((packed));
-
-/* TODO: maybe use protos? */
-struct blob_params {
- uint32_t tag;
- uint32_t integer;
- uint64_t long_integer;
- /* TODO: save space for opaque data (APP_DATA etc). */
-} __attribute__((packed));
-
-struct blob_enforcements {
- uint32_t params_count;
- /* TODO: sizeof(proto-params) instead of constant here. */
- struct blob_params params[20];
-} __attribute__((packed));
-
-/* TODO: refactor RSA_MAX_BYTES from dcrypto.h */
-struct blob_rsa {
- struct LITE_RSA rsa;
- uint8_t N_bytes[3072 >> 3];
- uint8_t d_bytes[3072 >> 3];
-} __attribute__((packed));
-
-struct blob_ec {
- uint32_t curve;
- uint8_t d[32];
- uint8_t x[32];
- uint8_t y[32];
-} __attribute__((packed));
-
-struct blob_sym {
- uint32_t key_bits;
- uint8_t bytes[512 >> 3];
-} __attribute__((packed));
-
-enum blob_alg {
- BLOB_RSA = 1,
- BLOB_EC = 2,
- BLOB_AES = 3,
- BLOB_DES = 4,
- BLOB_HMAC = 5,
-};
-
-#define KM_BLOB_MAGIC 0x474F4F47
-#define KM_BLOB_VERSION 1
-
-struct km_blob {
- struct {
- uint32_t magic;
- uint32_t version;
- uint32_t id;
- uint32_t iv[4];
- } h __attribute__((packed));
- struct {
- /* TODO: is sw_enforced expected to be managed by h/w? */
- struct blob_enforcements sw_enforced;
- struct blob_enforcements tee_enforced;
- uint32_t algorithm;
- union {
- struct blob_rsa rsa;
- struct blob_ec ec;
- struct blob_sym sym;
- } key;
- /* TODO: pad to block size. */
- } b __attribute__((packed));
- uint8_t hmac[32];
-} __attribute__((packed));
-
-#endif // SRC_BLOB_H
diff --git a/src/cavptests.cc b/src/cavptests.cc
index fc9c9b2..1bbc01f 100644
--- a/src/cavptests.cc
+++ b/src/cavptests.cc
@@ -22,6 +22,8 @@
using std::stringstream;
using std::unique_ptr;
+using test_harness::TestHarness;
+
DEFINE_bool(nos_test_dump_protos, false, "Dump binary protobufs to a file.");
DEFINE_int32(test_input_number, -1, "Run a specific test input.");
diff --git a/src/gtest_with_gflags_main.cc b/src/gtest_with_gflags_main.cc
index 3bf7958..fd92102 100644
--- a/src/gtest_with_gflags_main.cc
+++ b/src/gtest_with_gflags_main.cc
@@ -5,6 +5,8 @@
#include <iostream>
#include <sstream>
+#include "nugget_tools.h"
+
#ifdef ANDROID
#define FLAGS_list_slow_tests false
#define FLAGS_disable_slow_tests false
@@ -68,6 +70,10 @@
"ImportWrappedKeyTest.ImportSuccess",
};
+ const std::vector<std::string> disabled_for_non_direct_device_tests{
+ "TransportTest.*",
+ };
+
testing::InitGoogleMock(&argc, argv);
#ifndef ANDROID
google::ParseCommandLineFlags(&argc, &argv, true);
@@ -89,6 +95,9 @@
if (FLAGS_release_tests) {
generate_disabled_test_list(disabled_for_release_tests, &ss);
}
+ if (!nugget_tools::IsDirectDeviceClient()) {
+ generate_disabled_test_list(disabled_for_non_direct_device_tests, &ss);
+ }
if (FLAGS_disable_slow_tests || FLAGS_release_tests) {
::testing::GTEST_FLAG(filter) = ss.str();
diff --git a/src/keymaster-import-key-tests.cc b/src/keymaster-import-key-tests.cc
index 0392de7..4e2e531 100644
--- a/src/keymaster-import-key-tests.cc
+++ b/src/keymaster-import-key-tests.cc
@@ -8,7 +8,6 @@
#include "Keymaster.client.h"
#include "util.h"
-#include "src/blob.h"
#include "src/macros.h"
#include "src/test-data/test-keys/rsa.h"
@@ -94,6 +93,7 @@
// Do setup that is normally done by the bootloader.
keymaster_tools::SetRootOfTrust(client.get());
+ keymaster_tools::SetBootState(client.get());
}
void ImportKeyTest::TearDownTestCase() {
@@ -142,7 +142,7 @@
ImportKeyResponse response;
// Unsupported exponent
- initRSARequest(&request, Algorithm::RSA, 512, 2, 2,
+ initRSARequest(&request, Algorithm::RSA, 1024, 2, 2,
string(64, '\0'), string(64, '\0'));
ASSERT_NO_ERROR(service->ImportKey(request, &response), "");
@@ -155,7 +155,7 @@
ImportKeyResponse response;
// N does not match KEY_SIZE.
- initRSARequest(&request, Algorithm::RSA, 512, 3, 3,
+ initRSARequest(&request, Algorithm::RSA, 1024, 3, 3,
string(64, '\0'), string(63, '\0'));
ASSERT_NO_ERROR(service->ImportKey(request, &response), "");
EXPECT_EQ((ErrorCode)response.error_code(),
@@ -167,7 +167,7 @@
ImportKeyResponse response;
// D does not match KEY_SIZE.
- initRSARequest(&request, Algorithm::RSA, 512, 3, 3,
+ initRSARequest(&request, Algorithm::RSA, 1024, 3, 3,
string(63, '\0'), string(64, '\0'));
ASSERT_NO_ERROR(service->ImportKey(request, &response), "");
EXPECT_EQ((ErrorCode)response.error_code(),
@@ -179,7 +179,7 @@
ImportKeyResponse response;
// e does not match PUBLIC_EXPONENT tag.
- initRSARequest(&request, Algorithm::RSA, 512, 3, 2,
+ initRSARequest(&request, Algorithm::RSA, 1024, 3, 2,
string(64, '\0'), string(64, '\0'));
ASSERT_NO_ERROR(service->ImportKey(request, &response), "");
EXPECT_EQ((ErrorCode)response.error_code(),
@@ -246,14 +246,97 @@
EXPECT_EQ((ErrorCode)response.error_code(), ErrorCode::OK)
<< "Failed at TEST_RSA_KEYS[" << i << "]";
- /* TODO: add separate tests for blobs! */
- EXPECT_EQ(sizeof(struct km_blob), response.blob().blob().size());
- const struct km_blob *blob =
- (const struct km_blob *)response.blob().blob().data();
- EXPECT_EQ(memcmp(blob->b.key.rsa.N_bytes, TEST_RSA_KEYS[i].n,
- TEST_RSA_KEYS[i].size), 0);
- EXPECT_EQ(memcmp(blob->b.key.rsa.d_bytes,
- TEST_RSA_KEYS[i].d, TEST_RSA_KEYS[i].size), 0);
+ /* TODO: do something useful with the imported key */
+ }
+}
+
+TEST_F(ImportKeyTest, UpgradeSuccess) {
+ ImportKeyRequest request;
+ ImportKeyResponse response;
+
+ initRSARequest(&request, Algorithm::RSA);
+ KeyParameters *params = request.mutable_params();
+ KeyParameter *param = params->add_params();
+
+ param->set_tag(Tag::RSA_PUBLIC_EXPONENT);
+ param->set_long_integer(TEST_RSA_KEYS[0].e);
+
+ request.mutable_rsa()->set_e(TEST_RSA_KEYS[0].e);
+ request.mutable_rsa()->set_d(TEST_RSA_KEYS[0].d, TEST_RSA_KEYS[0].size);
+ request.mutable_rsa()->set_n(TEST_RSA_KEYS[0].n, TEST_RSA_KEYS[0].size);
+
+ {
+ EXPECT_TRUE(nugget_tools::RebootNugget(client.get()))
+ << "Failed to reboot nugget";
+
+ SetSystemVersionInfoRequest svRequest;
+ SetSystemVersionInfoResponse svResponse;
+
+ svRequest.set_system_version(1);
+ svRequest.set_system_security_level(1);
+ svRequest.set_vendor_security_level(1);
+
+ ASSERT_NO_ERROR(service->SetSystemVersionInfo(svRequest, &svResponse), "");
+ EXPECT_EQ((ErrorCode)svResponse.error_code(), ErrorCode::OK);
+
+ // Do setup that is normally done by the bootloader.
+ keymaster_tools::SetRootOfTrust(client.get());
+ keymaster_tools::SetBootState(client.get());
+ }
+
+ stringstream ss;
+ ASSERT_NO_ERROR(service->ImportKey(request, &response), "");
+ EXPECT_EQ((ErrorCode)response.error_code(), ErrorCode::OK)
+ << "Failed at TEST_RSA_KEYS[" << 0 << "]";
+
+ {
+ EXPECT_TRUE(nugget_tools::RebootNugget(client.get()))
+ << "Failed to reboot nugget";
+
+ SetSystemVersionInfoRequest svRequest;
+ SetSystemVersionInfoResponse svResponse;
+
+ /* Bump vendor version level, to force Upgrade. */
+ svRequest.set_system_version(1);
+ svRequest.set_system_security_level(1);
+ svRequest.set_vendor_security_level(2);
+
+ ASSERT_NO_ERROR(service->SetSystemVersionInfo(svRequest, &svResponse), "");
+ EXPECT_EQ((ErrorCode)svResponse.error_code(), ErrorCode::OK);
+
+ // Do setup that is normally done by the bootloader.
+ keymaster_tools::SetRootOfTrust(client.get());
+ keymaster_tools::SetBootState(client.get());
+ }
+
+ {
+ GetKeyCharacteristicsRequest gkRequest;
+ GetKeyCharacteristicsResponse gkResponse;
+
+ gkRequest.mutable_blob()->set_blob(response.blob().blob().data(),
+ response.blob().blob().size());
+ ASSERT_NO_ERROR(service->GetKeyCharacteristics(gkRequest, &gkResponse), "");
+ EXPECT_EQ((ErrorCode)gkResponse.error_code(),
+ ErrorCode::KEY_REQUIRES_UPGRADE);
+ }
+
+ {
+ UpgradeKeyRequest ukRequest;
+ UpgradeKeyResponse ukResponse;
+
+ ukRequest.mutable_blob()->set_blob(response.blob().blob().data(),
+ response.blob().blob().size());
+ ASSERT_NO_ERROR(service->UpgradeKey(ukRequest, &ukResponse), "");
+ EXPECT_EQ((ErrorCode)ukResponse.error_code(), ErrorCode::OK);
+
+ // GetKeyCharacteristics succeeds after the UpgradeKey().
+ GetKeyCharacteristicsRequest gkRequest;
+ GetKeyCharacteristicsResponse gkResponse;
+
+ gkRequest.mutable_blob()->set_blob(ukResponse.blob().blob().data(),
+ ukResponse.blob().blob().size());
+ ASSERT_NO_ERROR(service->GetKeyCharacteristics(gkRequest, &gkResponse), "");
+ EXPECT_EQ((ErrorCode)gkResponse.error_code(), ErrorCode::OK);
}
}
@@ -268,13 +351,7 @@
ASSERT_NO_ERROR(service->ImportKey(request, &response), "");
EXPECT_EQ((ErrorCode)response.error_code(), ErrorCode::OK);
- EXPECT_EQ(sizeof(struct km_blob), response.blob().blob().size());
- const struct km_blob *blob =
- (const struct km_blob *)response.blob().blob().data();
- EXPECT_EQ(memcmp(blob->b.key.rsa.N_bytes, RSA_1024_N,
- sizeof(RSA_1024_N)), 0);
- EXPECT_EQ(memcmp(blob->b.key.rsa.d_bytes,
- RSA_1024_D, sizeof(RSA_1024_D)), 0);
+ /* TODO: do something useful with the imported key */
}
// EC
diff --git a/src/keymaster-import-wrapped-key-tests.cc b/src/keymaster-import-wrapped-key-tests.cc
index 832a5c8..0b6fc4d 100644
--- a/src/keymaster-import-wrapped-key-tests.cc
+++ b/src/keymaster-import-wrapped-key-tests.cc
@@ -8,13 +8,13 @@
#include "Keymaster.client.h"
#include "util.h"
-#include "src/blob.h"
#include "src/macros.h"
#include "src/test-data/test-keys/rsa.h"
#include "openssl/bn.h"
#include "openssl/ec_key.h"
#include "openssl/nid.h"
+#include "openssl/sha.h"
using std::cout;
using std::string;
@@ -51,6 +51,7 @@
// Do setup that is normally done by the bootloader.
keymaster_tools::SetRootOfTrust(client.get());
+ keymaster_tools::SetBootState(client.get());
}
void ImportWrappedKeyTest::TearDownTestCase() {
@@ -192,38 +193,58 @@
0xb6, 0x47, 0x14, 0x43
};
+#if 0
+/* Left here for reference. */
const uint8_t IMPORTED_KEY[32] = {
0x8a, 0x28, 0xf1, 0xa8, 0xb8, 0x93, 0x8a, 0x2c, 0x1f, 0x35, 0x72, 0xb0,
0x4c, 0x48, 0xd5, 0xdf, 0x52, 0x28, 0x1e, 0xe2, 0x11, 0xad, 0x73, 0xf7,
0x7f, 0x97, 0x04, 0xe6, 0x79, 0x29, 0xff, 0xcf
};
+#endif
TEST_F(ImportWrappedKeyTest, ImportSuccess) {
+
+ ImportKeyRequest importRequest;
+ ImportKeyResponse importResponse;
+
+ KeyParameters *params = importRequest.mutable_params();
+
+ KeyParameter *param = params->add_params();
+ param->set_tag(Tag::ALGORITHM);
+ param->set_integer((uint32_t)Algorithm::RSA);
+
+ param = params->add_params();
+ param->set_tag(Tag::RSA_PUBLIC_EXPONENT);
+ param->set_long_integer(65537);
+
+ param = params->add_params();
+ param->set_tag(Tag::PURPOSE);
+ param->set_integer((uint32_t)KeyPurpose::WRAP_KEY);
+
+ param = params->add_params();
+ param->set_tag(Tag::PADDING);
+ param->set_integer((uint32_t)PaddingMode::PADDING_RSA_OAEP);
+
+ param = params->add_params();
+ param->set_tag(Tag::KEY_SIZE);
+ param->set_integer(2048);
+
+ importRequest.mutable_rsa()->set_e(65537);
+ importRequest.mutable_rsa()->set_d(
+ string((const char *)wrapping_key_D, sizeof(wrapping_key_D)));
+ importRequest.mutable_rsa()->set_n(
+ string((const char *)wrapping_key_N, sizeof(wrapping_key_N)));
+
+ ASSERT_NO_ERROR(service->ImportKey(importRequest, &importResponse), "");
+ ASSERT_EQ((ErrorCode)importResponse.error_code(), ErrorCode::OK);
+
ImportWrappedKeyRequest request;
ImportKeyResponse response;
const uint8_t masking_key[32] = {};
- struct km_blob blob;
-
- /* TODO: do key generation via rpc. */
- memset(&blob, 0, sizeof(blob));
- blob.b.algorithm = BLOB_RSA;
- blob.b.key.rsa.rsa.e = 65537;
- blob.b.key.rsa.rsa.N.dmax = sizeof(wrapping_key_N) / sizeof(uint32_t);
- blob.b.key.rsa.rsa.d.dmax = sizeof(wrapping_key_D) / sizeof(uint32_t);
-
- memcpy(&blob.b.key.rsa.N_bytes, wrapping_key_N, sizeof(wrapping_key_N));
- memcpy(&blob.b.key.rsa.d_bytes, wrapping_key_D, sizeof(wrapping_key_D));
-
- blob.b.tee_enforced.params[0].tag = Tag::PADDING;
- blob.b.tee_enforced.params[0].integer = PaddingMode::PADDING_RSA_OAEP;
- blob.b.tee_enforced.params_count++;
- blob.b.tee_enforced.params[1].tag = Tag::PURPOSE;
- blob.b.tee_enforced.params[1].integer = KeyPurpose::WRAP_KEY;
- blob.b.tee_enforced.params_count++;
request.set_key_format(KeyFormat::RAW);
- KeyParameters *params = request.mutable_params();
- KeyParameter *param = params->add_params();
+ params = request.mutable_params();
+ param = params->add_params();
param->set_tag(Tag::ALGORITHM);
param->set_integer((uint32_t)Algorithm::AES);
@@ -234,18 +255,13 @@
sizeof(ENCRYPTED_IMPORT_KEY));
request.set_aad(AAD, sizeof(AAD));
request.set_gcm_tag(GCM_TAG, sizeof(GCM_TAG));
- request.mutable_wrapping_key_blob()->set_blob(&blob, sizeof(blob));
+ request.mutable_wrapping_key_blob()->set_blob(importResponse.blob().blob());
request.set_masking_key(masking_key, sizeof(masking_key));
ASSERT_NO_ERROR(service->ImportWrappedKey(request, &response), "");
EXPECT_EQ((ErrorCode)response.error_code(), ErrorCode::OK);
- EXPECT_EQ(sizeof(struct km_blob), response.blob().blob().size());
- const struct km_blob *response_blob =
- (const struct km_blob *)response.blob().blob().data();
- EXPECT_EQ(response_blob->b.key.sym.key_bits >> 3, sizeof(IMPORTED_KEY));
- EXPECT_EQ(memcmp(response_blob->b.key.sym.bytes, IMPORTED_KEY,
- sizeof(IMPORTED_KEY)), 0);
+ /* TODO: use the imported key for something. */
}
} // namespace
diff --git a/src/keymaster-provision-tests.cc b/src/keymaster-provision-tests.cc
index 2edabad..b60339b 100644
--- a/src/keymaster-provision-tests.cc
+++ b/src/keymaster-provision-tests.cc
@@ -9,6 +9,7 @@
#include <application.h>
#include <keymaster.h>
#include <nos/AppClient.h>
+#include <nos/NuggetClient.h>
#include <nos/NuggetClientInterface.h>
#include "util.h"
@@ -143,7 +144,7 @@
PopulateDefaultRequest(&request);
- string max_serialno(KM_MNF_MAX_ENTRY_SIZE, '5');
+ string max_serialno(KM_MNF_MAX_ENTRY_SIZE, '5');
request.set_serialno(max_serialno);
Keymaster service(*client);
@@ -167,4 +168,657 @@
ASSERT_EQ((ErrorCode)response.error_code(), ErrorCode::OK);
}
+const static uint8_t ATTESTION_CERT_adacb483_0100b022[7 * 1024] = {
+ 0x29, 0x81, 0xb0, 0x4a, 0x4c, 0xcf, 0x9d, 0x8e, 0x80, 0xbc, 0xd9, 0xee,
+ 0x34, 0x23, 0x50, 0x55, 0x48, 0xb3, 0x7f, 0x79, 0xce, 0x66, 0x76, 0x91,
+ 0x7b, 0x98, 0x31, 0xfc, 0x9b, 0x30, 0x44, 0xbf, 0xcd, 0xa0, 0x1e, 0x04,
+ 0x51, 0x95, 0x86, 0x2d, 0xa6, 0x49, 0xce, 0x8a, 0x74, 0x0a, 0xf4, 0x96,
+ 0x71, 0xf3, 0x5b, 0xe7, 0xf9, 0xb7, 0x7d, 0xe4, 0x0c, 0x76, 0xc4, 0x63,
+ 0x7a, 0xba, 0x58, 0xde, 0x89, 0xab, 0xcd, 0xef, 0x01, 0x00, 0x02, 0x00,
+ 0x83, 0xb4, 0xac, 0xad, 0x22, 0xb0, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00,
+ 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x29, 0x7d, 0x4b, 0x89, 0x03, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x03, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x07, 0x83, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0x50, 0x50, 0x50, 0x50, 0x00, 0x08, 0x00, 0x00,
+ 0xa1, 0x04, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x57, 0x7c, 0xa0, 0xa6,
+ 0xac, 0xc2, 0xe3, 0x45, 0x3b, 0x4f, 0xe3, 0x9b, 0x79, 0x68, 0x37, 0x70,
+ 0xff, 0xf3, 0x0b, 0x4f, 0xf1, 0x80, 0x99, 0xc8, 0x37, 0xff, 0x3a, 0x8f,
+ 0x4a, 0x27, 0x3a, 0x58, 0xe5, 0x03, 0x4b, 0xfd, 0x49, 0x8b, 0x63, 0xc1,
+ 0xcb, 0xe6, 0xd9, 0xb0, 0xd3, 0x29, 0xc7, 0xd1, 0xee, 0x05, 0x4f, 0x3a,
+ 0x02, 0xd2, 0x69, 0x4f, 0xc0, 0x96, 0x41, 0x69, 0xc1, 0x9e, 0x7e, 0xcb,
+ 0xe5, 0xb9, 0x77, 0x2d, 0x73, 0x63, 0xaa, 0xb2, 0x7d, 0x5d, 0x82, 0x83,
+ 0xc9, 0x0e, 0x75, 0x25, 0x27, 0x50, 0x65, 0x0d, 0xe8, 0x9d, 0x98, 0xe3,
+ 0xd2, 0x5e, 0x7f, 0x4a, 0xca, 0x08, 0x2d, 0x99, 0x94, 0x69, 0xe9, 0x98,
+ 0x59, 0x75, 0x73, 0xd5, 0xb0, 0x23, 0x9e, 0xa3, 0x31, 0x3a, 0x24, 0x59,
+ 0xaa, 0xea, 0x5a, 0x79, 0x0d, 0xf2, 0x6f, 0xd9, 0x66, 0x4f, 0x1e, 0xd2,
+ 0x49, 0x7b, 0xb9, 0xb2, 0xbb, 0x6e, 0xe2, 0xc2, 0x58, 0x19, 0xaf, 0x53,
+ 0x22, 0x24, 0x32, 0x52, 0x1d, 0xbf, 0x9e, 0xf2, 0xfa, 0x65, 0xc0, 0x42,
+ 0x03, 0x2b, 0xfc, 0x77, 0x04, 0xb7, 0xe0, 0xb8, 0xfd, 0x79, 0xf5, 0xb8,
+ 0xee, 0x0e, 0x2d, 0x80, 0x52, 0x22, 0x60, 0x50, 0x60, 0x68, 0xbc, 0x5a,
+ 0x01, 0x71, 0x7a, 0x88, 0x6c, 0xe9, 0x55, 0xb1, 0xbb, 0xec, 0x45, 0x5f,
+ 0x03, 0x04, 0x19, 0x9b, 0xc0, 0xa0, 0x0b, 0xaa, 0x7b, 0x7a, 0xbf, 0xa7,
+ 0x8f, 0x7f, 0x78, 0x4a, 0x48, 0xc8, 0x1e, 0xd5, 0xb7, 0x5e, 0xc7, 0xe5,
+ 0x04, 0x6a, 0x9f, 0x8d, 0x6b, 0xb8, 0xf2, 0x0b, 0x30, 0x63, 0xe5, 0x87,
+ 0x9c, 0x72, 0xc3, 0x02, 0x81, 0x37, 0x3e, 0x0a, 0xf0, 0xe2, 0xbc, 0x1a,
+ 0xef, 0x82, 0x8f, 0x2c, 0xff, 0xd0, 0xe5, 0x70, 0x0a, 0x52, 0x97, 0x6f,
+ 0xbc, 0x2c, 0x97, 0x7c, 0x17, 0x61, 0xc1, 0x38, 0xbe, 0x34, 0xd4, 0x69,
+ 0xc4, 0x6a, 0xed, 0xed, 0xcc, 0x87, 0xcf, 0x11, 0x23, 0x13, 0x02, 0xeb,
+ 0xb0, 0x2c, 0xd0, 0x54, 0x95, 0x03, 0xd2, 0x6d, 0x3c, 0xc7, 0x4b, 0xd5,
+ 0xd8, 0x8e, 0xda, 0xef, 0x75, 0x8c, 0xe7, 0x60, 0x58, 0xcc, 0x93, 0x00,
+ 0x1d, 0xe6, 0xa2, 0x72, 0xf8, 0xf1, 0x12, 0xc1, 0x04, 0x98, 0xf5, 0x25,
+ 0xcd, 0x06, 0x7a, 0xb3, 0xc3, 0x11, 0xad, 0x1b, 0xa7, 0xc7, 0x0a, 0x1f,
+ 0x16, 0x2a, 0x1e, 0x62, 0xed, 0x20, 0xb1, 0x53, 0xe1, 0x04, 0x1b, 0xe8,
+ 0x98, 0x16, 0xce, 0xed, 0xf7, 0x24, 0xca, 0x8f, 0x25, 0xfa, 0x7c, 0xf8,
+ 0x20, 0x59, 0x4e, 0xea, 0xe6, 0x58, 0x9d, 0x2a, 0x7a, 0xfd, 0x65, 0xed,
+ 0x64, 0xdc, 0x66, 0x84, 0x08, 0xd3, 0xda, 0x6b, 0xcf, 0x50, 0x77, 0xed,
+ 0x42, 0x66, 0x6d, 0x8d, 0xb7, 0xdc, 0xc2, 0x22, 0xaa, 0xec, 0x61, 0x66,
+ 0xdb, 0xb5, 0xaf, 0x33, 0x0e, 0xe7, 0xb7, 0xca, 0x30, 0x82, 0x04, 0x9d,
+ 0x30, 0x82, 0x02, 0x85, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x0a, 0x17,
+ 0x10, 0x24, 0x68, 0x40, 0x71, 0x02, 0x97, 0x78, 0x50, 0x30, 0x0d, 0x06,
+ 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00,
+ 0x30, 0x2f, 0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x05, 0x13,
+ 0x10, 0x63, 0x63, 0x64, 0x31, 0x38, 0x62, 0x39, 0x62, 0x36, 0x30, 0x38,
+ 0x64, 0x36, 0x35, 0x38, 0x65, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55,
+ 0x04, 0x0c, 0x0c, 0x09, 0x53, 0x74, 0x72, 0x6f, 0x6e, 0x67, 0x42, 0x6f,
+ 0x78, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x38, 0x30, 0x35, 0x32, 0x35, 0x32,
+ 0x33, 0x32, 0x38, 0x34, 0x37, 0x5a, 0x17, 0x0d, 0x32, 0x38, 0x30, 0x35,
+ 0x32, 0x32, 0x32, 0x33, 0x32, 0x38, 0x34, 0x37, 0x5a, 0x30, 0x2f, 0x31,
+ 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x05, 0x13, 0x10, 0x39, 0x30,
+ 0x65, 0x38, 0x64, 0x61, 0x33, 0x63, 0x61, 0x64, 0x66, 0x63, 0x37, 0x38,
+ 0x32, 0x30, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x0c, 0x0c,
+ 0x09, 0x53, 0x74, 0x72, 0x6f, 0x6e, 0x67, 0x42, 0x6f, 0x78, 0x30, 0x82,
+ 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+ 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82,
+ 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xa5, 0x09, 0xd4, 0x09, 0xd2,
+ 0x30, 0x19, 0x36, 0x34, 0x71, 0xfd, 0x7d, 0x41, 0x89, 0xe6, 0x2c, 0xa5,
+ 0x9d, 0x10, 0x1b, 0x4f, 0x40, 0x6a, 0xb0, 0x5f, 0x56, 0x34, 0x16, 0xe6,
+ 0xeb, 0xd7, 0xf3, 0xe9, 0xc5, 0xdc, 0x20, 0xf3, 0x86, 0xd1, 0x77, 0x19,
+ 0xd7, 0x15, 0x1f, 0xe7, 0xec, 0x62, 0xdc, 0x0a, 0xbc, 0x64, 0xe9, 0x18,
+ 0x52, 0xb0, 0xaa, 0xb8, 0xff, 0x58, 0x6a, 0xe0, 0x0f, 0xb8, 0x56, 0xaf,
+ 0x77, 0xd3, 0xce, 0x3c, 0xdc, 0x48, 0x52, 0xdd, 0xb2, 0x86, 0x0d, 0x76,
+ 0x17, 0x7c, 0xfd, 0xee, 0xb4, 0xe6, 0x6e, 0x0a, 0x08, 0x9e, 0x06, 0xca,
+ 0x0f, 0xec, 0x4b, 0xb0, 0x7c, 0xaf, 0xea, 0x82, 0x27, 0xa8, 0xc9, 0xa7,
+ 0x63, 0xda, 0x89, 0xf6, 0x30, 0xba, 0x3c, 0x3a, 0xe5, 0xc6, 0xef, 0x11,
+ 0x06, 0x42, 0x8a, 0x2e, 0xfe, 0x19, 0xbe, 0xf2, 0xc7, 0x3b, 0x34, 0x16,
+ 0xb2, 0xe2, 0x64, 0xc7, 0xca, 0x66, 0x02, 0x85, 0xe3, 0x57, 0x6f, 0x11,
+ 0x13, 0x3a, 0xff, 0xd5, 0x30, 0x13, 0x7d, 0xea, 0xe0, 0x22, 0xa2, 0x91,
+ 0x0c, 0xaf, 0xf0, 0x5c, 0xd7, 0xc1, 0xb4, 0x85, 0x69, 0x7c, 0xc0, 0x39,
+ 0xdb, 0x4e, 0xc1, 0x5a, 0xd8, 0xcc, 0x42, 0x7c, 0x06, 0x74, 0x01, 0x93,
+ 0xa3, 0xa4, 0x10, 0x96, 0x29, 0xf2, 0x8e, 0x0a, 0xf7, 0x49, 0x4b, 0x87,
+ 0x49, 0x13, 0x89, 0xe5, 0x00, 0x10, 0x96, 0xea, 0x37, 0x0d, 0xd7, 0x5d,
+ 0x43, 0x41, 0x2b, 0x4e, 0x59, 0x9a, 0x51, 0xee, 0x73, 0xdb, 0x52, 0x95,
+ 0x08, 0xe2, 0x6b, 0xb2, 0x33, 0xf7, 0x04, 0xbe, 0x51, 0x1c, 0x23, 0x62,
+ 0x6e, 0xc2, 0x5f, 0x00, 0xc3, 0xa4, 0xc9, 0xbd, 0xe7, 0xc6, 0x65, 0x0d,
+ 0xb1, 0xc4, 0x5e, 0x62, 0xb9, 0x9c, 0x2a, 0x26, 0x05, 0x67, 0xd0, 0xa9,
+ 0x9a, 0x12, 0x1c, 0x49, 0x7b, 0x36, 0xbe, 0x6f, 0xf2, 0x68, 0x65, 0x02,
+ 0x03, 0x01, 0x00, 0x01, 0xa3, 0x81, 0xba, 0x30, 0x81, 0xb7, 0x30, 0x1d,
+ 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x77, 0xa4, 0xad,
+ 0xdf, 0x1d, 0x29, 0x89, 0xca, 0x92, 0xe3, 0xba, 0xde, 0x27, 0x3c, 0x70,
+ 0xdf, 0x36, 0x03, 0x7c, 0x0c, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23,
+ 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x1b, 0x17, 0x70, 0xc6, 0x97, 0xdc,
+ 0x84, 0x54, 0x75, 0x7c, 0x3c, 0x98, 0x5c, 0xe6, 0x1d, 0x1d, 0x08, 0x59,
+ 0x5d, 0x53, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff,
+ 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0e, 0x06, 0x03, 0x55,
+ 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x02, 0x04, 0x30,
+ 0x54, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x4d, 0x30, 0x4b, 0x30, 0x49,
+ 0xa0, 0x47, 0xa0, 0x45, 0x86, 0x43, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a,
+ 0x2f, 0x2f, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2e, 0x67, 0x6f,
+ 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d,
+ 0x2f, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e,
+ 0x2f, 0x63, 0x72, 0x6c, 0x2f, 0x31, 0x37, 0x31, 0x30, 0x32, 0x34, 0x36,
+ 0x38, 0x34, 0x30, 0x37, 0x31, 0x30, 0x32, 0x39, 0x37, 0x37, 0x38, 0x35,
+ 0x30, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
+ 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x02, 0x01, 0x00, 0x13, 0x22, 0xda,
+ 0xf2, 0x92, 0x93, 0xce, 0xc0, 0x9f, 0x70, 0x40, 0xc9, 0xda, 0x85, 0x6b,
+ 0x61, 0x6f, 0x8f, 0xbe, 0xe0, 0xa4, 0x04, 0x55, 0xc1, 0x63, 0x84, 0x61,
+ 0x37, 0xf5, 0x4b, 0x71, 0x6d, 0x62, 0xaa, 0x6f, 0xbf, 0x6c, 0xe8, 0x48,
+ 0x03, 0xad, 0x28, 0x85, 0x21, 0x9e, 0x3c, 0x1c, 0x91, 0x48, 0xee, 0x65,
+ 0x28, 0x65, 0x70, 0xd0, 0xbd, 0x5b, 0xcc, 0xdb, 0xce, 0xb1, 0xf5, 0xb5,
+ 0xc3, 0xca, 0x7a, 0xa9, 0xc8, 0x8a, 0x68, 0x12, 0x8a, 0xca, 0x6a, 0x85,
+ 0xa6, 0xbc, 0xda, 0x36, 0xe9, 0xb9, 0x94, 0x35, 0x82, 0x5b, 0xca, 0xbc,
+ 0xb6, 0x9f, 0x83, 0x03, 0x7f, 0x21, 0x6c, 0xee, 0x82, 0xc1, 0x3f, 0xbd,
+ 0xc1, 0x41, 0x4b, 0xdd, 0x1a, 0x6f, 0x6c, 0xaf, 0x4a, 0x52, 0xfc, 0x19,
+ 0x19, 0x17, 0xac, 0x29, 0x0c, 0x5e, 0xd7, 0x57, 0x90, 0xd5, 0xb1, 0x2b,
+ 0x36, 0x29, 0x1f, 0x45, 0x33, 0x17, 0xe0, 0x95, 0x50, 0x92, 0x08, 0x44,
+ 0xc2, 0x91, 0x11, 0xe8, 0x2e, 0x16, 0x50, 0x32, 0x98, 0xa5, 0x58, 0x82,
+ 0xd8, 0x78, 0x26, 0x27, 0xa5, 0x92, 0xa2, 0x47, 0xec, 0x74, 0x9f, 0xbc,
+ 0x0e, 0x87, 0x9b, 0xd0, 0x34, 0xce, 0x20, 0xb9, 0x6a, 0x89, 0x2b, 0x35,
+ 0xa8, 0xb7, 0x19, 0x18, 0x8d, 0x31, 0x81, 0xf3, 0x0f, 0xb6, 0x95, 0x64,
+ 0x4b, 0x79, 0x2e, 0xa1, 0xca, 0x69, 0xa6, 0x13, 0x10, 0x0a, 0x06, 0x1b,
+ 0x04, 0x8b, 0x46, 0xa3, 0x89, 0x5b, 0xee, 0xdc, 0xeb, 0x41, 0x7b, 0xbb,
+ 0x5c, 0x68, 0x6c, 0xd9, 0xb9, 0x8e, 0xe3, 0xd8, 0x87, 0x79, 0xe5, 0xf0,
+ 0x69, 0xe2, 0xe8, 0xb7, 0x98, 0x73, 0xab, 0xfb, 0xfd, 0xb6, 0xaf, 0x3e,
+ 0xc5, 0x04, 0xca, 0x9b, 0x70, 0x43, 0xe9, 0x27, 0xa7, 0x5b, 0x04, 0x90,
+ 0xc8, 0x6d, 0x5e, 0x94, 0x63, 0xa0, 0x80, 0x07, 0x0d, 0x46, 0xfb, 0x3b,
+ 0xd9, 0x9b, 0x5c, 0x6a, 0x6e, 0xb6, 0xf9, 0xa6, 0x82, 0xf4, 0x46, 0x9d,
+ 0x9e, 0x14, 0xa7, 0xa2, 0xb7, 0x0f, 0x2c, 0x5e, 0xbe, 0x78, 0xb1, 0x44,
+ 0x69, 0xf7, 0x83, 0x37, 0x6c, 0xa2, 0x52, 0xaf, 0x1a, 0x1d, 0xcd, 0x12,
+ 0x3f, 0x39, 0x98, 0x24, 0xac, 0xfc, 0x32, 0x8a, 0xba, 0xd7, 0xcf, 0x5e,
+ 0xf1, 0x10, 0x13, 0xcc, 0x58, 0x29, 0x26, 0x3f, 0x1d, 0xc1, 0xd4, 0x2a,
+ 0xec, 0xb4, 0xa1, 0xaf, 0xd9, 0xdd, 0x16, 0x7b, 0x54, 0x8f, 0xb2, 0x39,
+ 0xda, 0xdc, 0x26, 0x7d, 0x3a, 0x4f, 0x36, 0x72, 0x96, 0x12, 0x83, 0x7d,
+ 0x98, 0x98, 0xd2, 0x4a, 0x4e, 0xfb, 0x0e, 0xe6, 0x84, 0xee, 0xf4, 0x26,
+ 0xda, 0x01, 0x3b, 0xb3, 0x15, 0xda, 0x17, 0xc8, 0x78, 0x57, 0xfb, 0xd3,
+ 0x91, 0x17, 0x2d, 0x3c, 0x27, 0xab, 0x00, 0xda, 0xb0, 0x98, 0x95, 0xa4,
+ 0x84, 0x6b, 0xcd, 0xbf, 0xa7, 0xa7, 0x95, 0xef, 0xaa, 0xb0, 0x91, 0xf8,
+ 0x98, 0xa8, 0x33, 0x3d, 0x90, 0x93, 0x9d, 0x75, 0x11, 0xe9, 0xbd, 0x70,
+ 0x16, 0x6d, 0x22, 0xc9, 0x2f, 0x24, 0xb1, 0x55, 0x80, 0xcb, 0x6b, 0x19,
+ 0xc1, 0x78, 0xa0, 0xc5, 0x24, 0x86, 0xbd, 0xb8, 0x12, 0x64, 0x87, 0x89,
+ 0x91, 0x74, 0xd0, 0xf6, 0xa2, 0x4c, 0x44, 0xf8, 0x7d, 0xf5, 0x3d, 0x0b,
+ 0x1d, 0x69, 0xf6, 0xb3, 0xfb, 0x0b, 0x3d, 0x50, 0xd9, 0x5a, 0xe6, 0xbb,
+ 0x39, 0xd5, 0x9b, 0x6a, 0x16, 0xee, 0xce, 0xfe, 0x5c, 0x61, 0xc5, 0x2d,
+ 0x83, 0xf5, 0xe8, 0x0e, 0x21, 0xfc, 0x2e, 0xb7, 0xc8, 0xbc, 0xf6, 0x4d,
+ 0x6f, 0x9b, 0x1d, 0x69, 0x76, 0x6c, 0x89, 0x2c, 0x5f, 0x42, 0xde, 0xc5,
+ 0x2f, 0xe4, 0x30, 0x18, 0xcd, 0x47, 0xbc, 0x72, 0xa1, 0x50, 0x87, 0xd0,
+ 0x13, 0xc2, 0xe8, 0x2c, 0x55, 0xa1, 0xdc, 0x83, 0x3e, 0x66, 0x65, 0x88,
+ 0xc2, 0xa8, 0x2c, 0x81, 0x8d, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0x94, 0x02, 0x84, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0x50, 0x50, 0x50, 0x50, 0x34, 0x02, 0x00, 0x00, 0x60, 0xd1, 0x7e, 0x20,
+ 0x53, 0x4f, 0x4a, 0x8e, 0xcc, 0xdc, 0x7f, 0xae, 0x9e, 0x10, 0xfd, 0x62,
+ 0x05, 0xd5, 0xd5, 0xcc, 0x78, 0x63, 0x53, 0xfb, 0x61, 0x5c, 0xee, 0x28,
+ 0x92, 0x3f, 0x16, 0x88, 0x30, 0x82, 0x02, 0x30, 0x30, 0x82, 0x01, 0xb7,
+ 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x0a, 0x11, 0x23, 0x38, 0x24, 0x34,
+ 0x40, 0x08, 0x68, 0x01, 0x71, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48,
+ 0xce, 0x3d, 0x04, 0x03, 0x02, 0x30, 0x2f, 0x31, 0x19, 0x30, 0x17, 0x06,
+ 0x03, 0x55, 0x04, 0x05, 0x13, 0x10, 0x63, 0x63, 0x64, 0x31, 0x38, 0x62,
+ 0x39, 0x62, 0x36, 0x30, 0x38, 0x64, 0x36, 0x35, 0x38, 0x65, 0x31, 0x12,
+ 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x0c, 0x0c, 0x09, 0x53, 0x74, 0x72,
+ 0x6f, 0x6e, 0x67, 0x42, 0x6f, 0x78, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x38,
+ 0x30, 0x35, 0x32, 0x35, 0x32, 0x33, 0x32, 0x38, 0x35, 0x30, 0x5a, 0x17,
+ 0x0d, 0x32, 0x38, 0x30, 0x35, 0x32, 0x32, 0x32, 0x33, 0x32, 0x38, 0x35,
+ 0x30, 0x5a, 0x30, 0x2f, 0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, 0x04,
+ 0x05, 0x13, 0x10, 0x39, 0x30, 0x65, 0x38, 0x64, 0x61, 0x33, 0x63, 0x61,
+ 0x64, 0x66, 0x63, 0x37, 0x38, 0x32, 0x30, 0x31, 0x12, 0x30, 0x10, 0x06,
+ 0x03, 0x55, 0x04, 0x0c, 0x0c, 0x09, 0x53, 0x74, 0x72, 0x6f, 0x6e, 0x67,
+ 0x42, 0x6f, 0x78, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48,
+ 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03,
+ 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0xe4, 0x57, 0x44, 0xc2, 0xb1, 0x9f,
+ 0xaf, 0x70, 0x8a, 0x17, 0x2b, 0x40, 0x4b, 0x7b, 0x8a, 0xb8, 0xb1, 0x0d,
+ 0x6f, 0x78, 0x13, 0xc4, 0xdb, 0x6f, 0x0b, 0xaa, 0x57, 0x50, 0x09, 0x03,
+ 0xc2, 0x6f, 0xa2, 0x01, 0x0a, 0x93, 0x3b, 0xac, 0x70, 0xe0, 0x2a, 0x6b,
+ 0x1a, 0xbe, 0x25, 0xad, 0xb0, 0x0d, 0x1a, 0x9c, 0x9c, 0x94, 0xa5, 0x71,
+ 0xd3, 0x56, 0x2c, 0x74, 0x99, 0xd2, 0x32, 0xf5, 0x77, 0x27, 0xa3, 0x81,
+ 0xba, 0x30, 0x81, 0xb7, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04,
+ 0x16, 0x04, 0x14, 0x6f, 0xb1, 0xb5, 0x31, 0x9d, 0xb6, 0xb8, 0x85, 0x15,
+ 0xbe, 0xcf, 0xc0, 0x0c, 0x77, 0x1a, 0x8f, 0xe7, 0x54, 0xea, 0x96, 0x30,
+ 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14,
+ 0xbc, 0x5b, 0xcb, 0xd5, 0x79, 0xc6, 0x94, 0xdc, 0x19, 0x8f, 0x9b, 0x9f,
+ 0x67, 0x53, 0xcc, 0xeb, 0xe6, 0x62, 0xdf, 0xde, 0x30, 0x0f, 0x06, 0x03,
+ 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01,
+ 0xff, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04,
+ 0x04, 0x03, 0x02, 0x02, 0x04, 0x30, 0x54, 0x06, 0x03, 0x55, 0x1d, 0x1f,
+ 0x04, 0x4d, 0x30, 0x4b, 0x30, 0x49, 0xa0, 0x47, 0xa0, 0x45, 0x86, 0x43,
+ 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x61, 0x6e, 0x64, 0x72,
+ 0x6f, 0x69, 0x64, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70,
+ 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x74, 0x74, 0x65, 0x73,
+ 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x63, 0x72, 0x6c, 0x2f, 0x31,
+ 0x31, 0x32, 0x33, 0x33, 0x38, 0x32, 0x34, 0x33, 0x34, 0x34, 0x30, 0x30,
+ 0x38, 0x36, 0x38, 0x30, 0x31, 0x37, 0x31, 0x30, 0x0a, 0x06, 0x08, 0x2a,
+ 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x03, 0x67, 0x00, 0x30, 0x64,
+ 0x02, 0x30, 0x50, 0x73, 0xc6, 0x56, 0xeb, 0x18, 0x96, 0xab, 0x5f, 0xe7,
+ 0xbc, 0x77, 0xb5, 0x1f, 0x0f, 0x93, 0x36, 0x06, 0xbd, 0xd0, 0xc4, 0xa5,
+ 0x05, 0x01, 0x2d, 0x6d, 0x7c, 0x6c, 0x72, 0xf4, 0xbc, 0x3b, 0xdb, 0x27,
+ 0xc5, 0x9f, 0xcb, 0xf7, 0x8f, 0x13, 0x72, 0x09, 0xa9, 0xa0, 0x96, 0xaa,
+ 0x70, 0xf2, 0x02, 0x30, 0x62, 0x4c, 0xdb, 0x64, 0x3b, 0xf1, 0xfe, 0xe5,
+ 0x3a, 0xbd, 0x72, 0x1a, 0x07, 0x5c, 0xb4, 0x3d, 0x11, 0xaa, 0xe4, 0x9a,
+ 0x79, 0xc4, 0x88, 0x0a, 0xa9, 0x41, 0x09, 0xbe, 0xc0, 0x6e, 0xc8, 0xc3,
+ 0x7c, 0x25, 0xd2, 0x6c, 0x7f, 0x3b, 0xc7, 0x6e, 0x46, 0x32, 0x65, 0x4b,
+ 0xa3, 0x53, 0xf4, 0x95, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0x74, 0x02, 0x85, 0xee, 0xee, 0xee, 0xee, 0xee, 0x50, 0x50, 0x50, 0x50,
+ 0x4d, 0x01, 0x00, 0x00, 0x30, 0x82, 0x01, 0x49, 0x30, 0x81, 0xf0, 0xa0,
+ 0x03, 0x02, 0x01, 0x02, 0x02, 0x10, 0x3f, 0x2d, 0x32, 0x42, 0x04, 0x65,
+ 0x72, 0x08, 0x12, 0x82, 0x10, 0x2b, 0xaa, 0x66, 0x15, 0x0f, 0x30, 0x0a,
+ 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x30, 0x25,
+ 0x31, 0x23, 0x30, 0x21, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x1a, 0x53,
+ 0x74, 0x72, 0x6f, 0x6e, 0x67, 0x42, 0x6f, 0x78, 0x2d, 0x32, 0x42, 0x31,
+ 0x30, 0x38, 0x32, 0x31, 0x32, 0x30, 0x38, 0x37, 0x32, 0x36, 0x35, 0x30,
+ 0x34, 0x30, 0x22, 0x18, 0x0f, 0x32, 0x30, 0x31, 0x38, 0x30, 0x37, 0x30,
+ 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x5a, 0x18, 0x0f, 0x32, 0x30,
+ 0x32, 0x38, 0x30, 0x38, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
+ 0x5a, 0x30, 0x25, 0x31, 0x23, 0x30, 0x21, 0x06, 0x03, 0x55, 0x04, 0x03,
+ 0x13, 0x1a, 0x53, 0x74, 0x72, 0x6f, 0x6e, 0x67, 0x42, 0x6f, 0x78, 0x2d,
+ 0x32, 0x42, 0x31, 0x30, 0x38, 0x32, 0x31, 0x32, 0x30, 0x38, 0x37, 0x32,
+ 0x36, 0x35, 0x30, 0x34, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86,
+ 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d,
+ 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0x1c, 0xf7, 0x2d, 0xb6, 0xd3,
+ 0x52, 0x3e, 0x34, 0xf2, 0x42, 0x81, 0x1a, 0xf8, 0x04, 0x00, 0xe1, 0x68,
+ 0x5e, 0xba, 0x92, 0x4c, 0x07, 0x10, 0xc3, 0x26, 0xc7, 0xe7, 0xa6, 0x35,
+ 0x96, 0xaf, 0x31, 0xcc, 0x15, 0x6a, 0xc7, 0x8a, 0x2d, 0x06, 0xdc, 0x40,
+ 0xb9, 0xc4, 0x58, 0xd5, 0x77, 0xcd, 0xf7, 0x61, 0x7d, 0x70, 0x85, 0xca,
+ 0x32, 0x78, 0x7c, 0x8a, 0x7b, 0x8c, 0x8d, 0x29, 0x5a, 0xa3, 0xeb, 0x30,
+ 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x03,
+ 0x48, 0x00, 0x30, 0x45, 0x02, 0x21, 0x00, 0xf3, 0x9d, 0x47, 0x0b, 0x56,
+ 0xe0, 0x67, 0xaa, 0x0e, 0xa2, 0x35, 0xbd, 0xfe, 0xb3, 0x83, 0xb6, 0xc8,
+ 0x0b, 0x17, 0xee, 0x36, 0xa0, 0xe4, 0x89, 0xbc, 0x4f, 0xe6, 0x3e, 0x5a,
+ 0x38, 0x6f, 0x67, 0x02, 0x20, 0x6f, 0x01, 0xbe, 0x6a, 0xba, 0x84, 0x5d,
+ 0xe1, 0xbf, 0x6b, 0x65, 0x74, 0x37, 0xe5, 0xae, 0x5a, 0x56, 0x84, 0x73,
+ 0x10, 0xb9, 0xa4, 0x32, 0xa8, 0xd8, 0xde, 0x79, 0xba, 0x2f, 0xfb, 0x6b,
+ 0x06, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0x74, 0x02, 0x88, 0xee, 0xee, 0xee, 0xee, 0xee, 0x50, 0x50, 0x50, 0x50,
+ 0x4c, 0x01, 0x00, 0x00, 0x30, 0x82, 0x01, 0x48, 0x30, 0x81, 0xf0, 0xa0,
+ 0x03, 0x02, 0x01, 0x02, 0x02, 0x10, 0x3f, 0x2d, 0x32, 0x42, 0x04, 0x65,
+ 0x72, 0x08, 0x12, 0x82, 0x10, 0x2b, 0xaa, 0x66, 0x15, 0x0f, 0x30, 0x0a,
+ 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x30, 0x25,
+ 0x31, 0x23, 0x30, 0x21, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x1a, 0x55,
+ 0x32, 0x46, 0x47, 0x6e, 0x75, 0x62, 0x62, 0x79, 0x2d, 0x32, 0x42, 0x31,
+ 0x30, 0x38, 0x32, 0x31, 0x32, 0x30, 0x38, 0x37, 0x32, 0x36, 0x35, 0x30,
+ 0x34, 0x30, 0x22, 0x18, 0x0f, 0x32, 0x30, 0x31, 0x38, 0x30, 0x37, 0x30,
+ 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x5a, 0x18, 0x0f, 0x32, 0x30,
+ 0x32, 0x38, 0x30, 0x38, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
+ 0x5a, 0x30, 0x25, 0x31, 0x23, 0x30, 0x21, 0x06, 0x03, 0x55, 0x04, 0x03,
+ 0x13, 0x1a, 0x55, 0x32, 0x46, 0x47, 0x6e, 0x75, 0x62, 0x62, 0x79, 0x2d,
+ 0x32, 0x42, 0x31, 0x30, 0x38, 0x32, 0x31, 0x32, 0x30, 0x38, 0x37, 0x32,
+ 0x36, 0x35, 0x30, 0x34, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86,
+ 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d,
+ 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0xf5, 0x0e, 0x32, 0x2a, 0xbf,
+ 0x15, 0x7c, 0xf4, 0xe4, 0xf2, 0xe9, 0xdb, 0xf6, 0x89, 0xf6, 0x52, 0x6c,
+ 0x85, 0xf4, 0x47, 0xe0, 0x39, 0x6b, 0xa2, 0x68, 0x14, 0xf1, 0x9e, 0x84,
+ 0x57, 0x98, 0x58, 0xcb, 0xee, 0xf5, 0x81, 0x72, 0xef, 0x9c, 0xa9, 0x55,
+ 0x98, 0x67, 0x90, 0x8c, 0xdc, 0x74, 0xd5, 0xc5, 0xb3, 0x04, 0x14, 0xfc,
+ 0xe0, 0x72, 0x06, 0x84, 0x5e, 0x9f, 0xaf, 0x50, 0x3c, 0x05, 0x36, 0x30,
+ 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x03,
+ 0x47, 0x00, 0x30, 0x44, 0x02, 0x20, 0x4a, 0x6a, 0x68, 0x92, 0x28, 0x4c,
+ 0x8b, 0x36, 0x5e, 0x68, 0x9f, 0x2e, 0x8c, 0xbe, 0xb9, 0x6d, 0x75, 0x12,
+ 0x75, 0xf6, 0xd4, 0x56, 0x9a, 0x25, 0x14, 0xcd, 0xe0, 0xce, 0xb5, 0xd9,
+ 0x62, 0xcb, 0x02, 0x20, 0x61, 0xf6, 0xa4, 0x9a, 0x8a, 0x4c, 0x08, 0xaf,
+ 0x81, 0x16, 0xb4, 0x6e, 0x4f, 0x81, 0xb5, 0x03, 0x87, 0xe3, 0x72, 0xa7,
+ 0xbd, 0xfa, 0x94, 0x24, 0xc4, 0xc1, 0x43, 0x93, 0x11, 0x2d, 0x97, 0xfb,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0x08, 0x07, 0x86, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0x50, 0x50, 0x50, 0x50, 0x00, 0x0c, 0x00, 0x00, 0x15, 0x05, 0x00, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x42, 0xef, 0x49, 0x02, 0x82, 0x92, 0x65, 0xe5,
+ 0xd9, 0x18, 0x69, 0x4f, 0x69, 0x12, 0x15, 0x9b, 0x54, 0xf3, 0x62, 0xe4,
+ 0xcd, 0xd1, 0xb6, 0x00, 0x59, 0xca, 0xf0, 0xfb, 0x63, 0x33, 0xfa, 0x2c,
+ 0xd2, 0x25, 0x8a, 0xb6, 0x62, 0x56, 0xaa, 0x55, 0x5f, 0x26, 0xb8, 0x22,
+ 0x88, 0xfc, 0xc1, 0x5a, 0x50, 0xcd, 0xd0, 0xdc, 0x87, 0x5e, 0x43, 0xea,
+ 0x26, 0x0a, 0x17, 0xcb, 0x86, 0x0e, 0x15, 0xed, 0xec, 0xb4, 0xf9, 0x68,
+ 0x50, 0xcd, 0x26, 0x44, 0x78, 0x0e, 0x98, 0x5e, 0xc1, 0xa2, 0x4b, 0x5d,
+ 0xf5, 0xb2, 0x73, 0x55, 0xb9, 0xa5, 0xa2, 0x0e, 0x01, 0xe6, 0x16, 0x7f,
+ 0xef, 0xe3, 0xe9, 0x2d, 0x49, 0x00, 0x9d, 0x12, 0xe3, 0x09, 0x0c, 0x5d,
+ 0xcc, 0x26, 0xc1, 0x2b, 0xdb, 0xc3, 0xd8, 0x4d, 0x3d, 0x3f, 0x94, 0xdc,
+ 0xbf, 0x4b, 0x1b, 0x3e, 0x10, 0x28, 0xd9, 0xad, 0x5b, 0x9d, 0x15, 0xb9,
+ 0xc4, 0x48, 0x58, 0x57, 0x43, 0x84, 0xdc, 0x22, 0x18, 0x53, 0xc0, 0x00,
+ 0xcd, 0x36, 0x31, 0x99, 0x7b, 0xe0, 0xa8, 0x39, 0x8d, 0xfa, 0xc6, 0xbe,
+ 0x4b, 0x61, 0xb1, 0xd1, 0xae, 0x1e, 0xac, 0xa8, 0xae, 0x45, 0xaa, 0x6b,
+ 0x7c, 0x00, 0x8e, 0xc7, 0x18, 0xd0, 0x88, 0x95, 0xc9, 0x50, 0x44, 0x48,
+ 0xc0, 0xbb, 0x60, 0x02, 0x98, 0x51, 0xa1, 0x0c, 0xaa, 0x44, 0x84, 0x36,
+ 0x62, 0x71, 0x1f, 0x94, 0xcd, 0x39, 0x80, 0x6a, 0x82, 0x21, 0x15, 0x1f,
+ 0x17, 0xb2, 0x74, 0x1b, 0xc3, 0x99, 0x10, 0x29, 0x4a, 0x28, 0x51, 0x99,
+ 0x07, 0xf3, 0x5f, 0xbc, 0xbd, 0x35, 0x07, 0x41, 0x32, 0xd8, 0x59, 0x63,
+ 0xbe, 0x4a, 0x2d, 0xf0, 0x06, 0xd7, 0xe2, 0x88, 0x68, 0x72, 0x12, 0xe7,
+ 0x2a, 0xa0, 0x33, 0xfd, 0x04, 0xd5, 0xe9, 0xc4, 0x81, 0xeb, 0xe1, 0x97,
+ 0x04, 0xcf, 0x08, 0xb5, 0x67, 0x79, 0x39, 0x26, 0xc3, 0x6e, 0x7d, 0x24,
+ 0x2d, 0x0b, 0x75, 0x5f, 0x2d, 0x81, 0x63, 0xa9, 0x30, 0x0d, 0xe8, 0x79,
+ 0xf0, 0x8d, 0x9e, 0xab, 0x24, 0x79, 0x5c, 0xf6, 0x9c, 0x83, 0x53, 0x88,
+ 0x41, 0x92, 0x34, 0xb2, 0xec, 0xfa, 0x37, 0x5c, 0x9a, 0xea, 0x7a, 0xce,
+ 0x1f, 0xe3, 0x5f, 0x0e, 0x12, 0x5c, 0xac, 0x1a, 0x0f, 0x3c, 0xf1, 0x9b,
+ 0xda, 0xad, 0x06, 0xcc, 0x85, 0xd5, 0xaf, 0x51, 0xef, 0x97, 0x52, 0x4f,
+ 0x33, 0xef, 0x82, 0x24, 0x54, 0x19, 0xa2, 0x79, 0x62, 0x0b, 0xcc, 0x29,
+ 0xf9, 0xb0, 0xf6, 0xdc, 0xca, 0xae, 0xf9, 0xb3, 0x61, 0x69, 0x15, 0x19,
+ 0x36, 0x39, 0x3e, 0x57, 0x1f, 0x2b, 0x15, 0x74, 0x28, 0xb4, 0xb1, 0x13,
+ 0x2f, 0xc5, 0x78, 0x57, 0x76, 0x1e, 0xec, 0xa6, 0xfb, 0xa7, 0x72, 0xb7,
+ 0xcf, 0x38, 0x86, 0x78, 0x8a, 0x46, 0x97, 0x44, 0x05, 0xa8, 0x24, 0x89,
+ 0x9b, 0x6b, 0xcd, 0x56, 0x30, 0x82, 0x05, 0x11, 0x30, 0x82, 0x02, 0xf9,
+ 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x0a, 0x06, 0x97, 0x36, 0x83, 0x31,
+ 0x39, 0x58, 0x14, 0x16, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
+ 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x29, 0x31, 0x19,
+ 0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x05, 0x13, 0x10, 0x39, 0x35, 0x65,
+ 0x32, 0x33, 0x66, 0x66, 0x39, 0x62, 0x36, 0x65, 0x62, 0x30, 0x32, 0x35,
+ 0x61, 0x31, 0x0c, 0x30, 0x0a, 0x06, 0x03, 0x55, 0x04, 0x0c, 0x0c, 0x03,
+ 0x54, 0x45, 0x45, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x38, 0x30, 0x35, 0x32,
+ 0x35, 0x32, 0x33, 0x32, 0x38, 0x34, 0x30, 0x5a, 0x17, 0x0d, 0x32, 0x38,
+ 0x30, 0x35, 0x32, 0x32, 0x32, 0x33, 0x32, 0x38, 0x34, 0x30, 0x5a, 0x30,
+ 0x29, 0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x05, 0x13, 0x10,
+ 0x65, 0x65, 0x34, 0x62, 0x65, 0x65, 0x64, 0x33, 0x39, 0x33, 0x34, 0x37,
+ 0x32, 0x65, 0x64, 0x62, 0x31, 0x0c, 0x30, 0x0a, 0x06, 0x03, 0x55, 0x04,
+ 0x0c, 0x0c, 0x03, 0x54, 0x45, 0x45, 0x30, 0x82, 0x01, 0xa2, 0x30, 0x0d,
+ 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05,
+ 0x00, 0x03, 0x82, 0x01, 0x8f, 0x00, 0x30, 0x82, 0x01, 0x8a, 0x02, 0x82,
+ 0x01, 0x81, 0x00, 0xfc, 0x02, 0x98, 0x15, 0xa4, 0xd2, 0x71, 0xad, 0x26,
+ 0x19, 0xc0, 0x67, 0x90, 0x51, 0x8f, 0xa2, 0x99, 0x81, 0x8e, 0x29, 0xbb,
+ 0x3f, 0x01, 0x27, 0xee, 0x9a, 0x5a, 0x6a, 0xfc, 0xfc, 0x97, 0x52, 0xbb,
+ 0x6e, 0x9d, 0x25, 0xa4, 0x37, 0x4c, 0x90, 0xaf, 0x02, 0x83, 0xd3, 0xd7,
+ 0x8d, 0x02, 0x56, 0x3e, 0xad, 0x53, 0x99, 0x7e, 0xa3, 0x5b, 0x82, 0xfc,
+ 0xb0, 0x56, 0x49, 0x0f, 0x51, 0xd4, 0x90, 0xba, 0x95, 0xd9, 0x0f, 0xfa,
+ 0x39, 0x96, 0xbf, 0xc0, 0x04, 0x44, 0xf6, 0x4d, 0x10, 0xa5, 0x6c, 0x45,
+ 0x80, 0x4c, 0x2d, 0x88, 0x63, 0xa9, 0x96, 0x7e, 0x2c, 0x5f, 0xb9, 0x25,
+ 0x69, 0x4c, 0x06, 0x04, 0x5b, 0xc7, 0x0c, 0x1c, 0xfd, 0xf1, 0x3a, 0xdd,
+ 0x2e, 0xae, 0x10, 0x01, 0xe1, 0x2a, 0x4a, 0x87, 0x46, 0xb1, 0x76, 0xf3,
+ 0x0d, 0xd1, 0x23, 0x11, 0xf7, 0x55, 0x1d, 0x57, 0x2e, 0xa3, 0xfc, 0xb2,
+ 0x9a, 0xbb, 0x49, 0xd9, 0xd6, 0x20, 0x5c, 0xf7, 0x29, 0x1c, 0x2a, 0x82,
+ 0xf0, 0x7b, 0x7e, 0xcb, 0x5c, 0x71, 0x0c, 0x64, 0x67, 0xda, 0x70, 0x71,
+ 0xef, 0x0d, 0xb3, 0x39, 0x9b, 0x9e, 0xea, 0x23, 0x4e, 0xb2, 0x67, 0xd0,
+ 0xcb, 0x1b, 0x1c, 0x9a, 0xc0, 0x1c, 0x5a, 0x9a, 0xfe, 0x5a, 0x7a, 0x24,
+ 0xb1, 0x89, 0xdc, 0xcb, 0x59, 0xf2, 0xfe, 0xa8, 0x89, 0x90, 0x7e, 0x5e,
+ 0xbd, 0xaf, 0x8d, 0xc1, 0x96, 0x2e, 0x0d, 0xb9, 0xb9, 0x2b, 0xd6, 0x49,
+ 0xb8, 0x93, 0x70, 0x6e, 0x38, 0x7d, 0x56, 0x88, 0x79, 0xbb, 0xff, 0x21,
+ 0x08, 0x6d, 0xf5, 0xae, 0xb4, 0x60, 0x7b, 0xd5, 0xc4, 0x26, 0x12, 0xea,
+ 0x95, 0x71, 0x47, 0x3d, 0xf4, 0xee, 0x2e, 0x39, 0x24, 0x91, 0xf0, 0x6c,
+ 0x23, 0x4e, 0xb1, 0x02, 0x1a, 0x95, 0xf7, 0x8f, 0x95, 0x9d, 0xce, 0x73,
+ 0x13, 0x8b, 0xc9, 0xa7, 0x4f, 0xb2, 0x50, 0x9e, 0x19, 0xe6, 0xe5, 0xf7,
+ 0xb8, 0xe3, 0x75, 0xb5, 0x6a, 0x24, 0xdb, 0x5d, 0x91, 0x03, 0x34, 0xc0,
+ 0xe4, 0xa2, 0xc2, 0x0a, 0x9a, 0x74, 0x58, 0x7d, 0x3d, 0x3c, 0x40, 0x2a,
+ 0x33, 0x14, 0xe1, 0xce, 0xf3, 0x86, 0xbf, 0x68, 0x0f, 0xa8, 0xe2, 0xc0,
+ 0xa0, 0xa4, 0x37, 0x10, 0x91, 0x93, 0xee, 0x3f, 0x4c, 0xe9, 0x95, 0x9c,
+ 0x70, 0xa9, 0x12, 0xde, 0x3b, 0x92, 0xa6, 0x0b, 0xd7, 0xaf, 0x76, 0x86,
+ 0x24, 0x8a, 0x8a, 0xa5, 0x6d, 0x1b, 0x47, 0xe8, 0x21, 0xbe, 0x45, 0x9f,
+ 0xb0, 0x92, 0x6f, 0xd0, 0x09, 0x51, 0x4c, 0x6e, 0x8b, 0xfc, 0x83, 0xfb,
+ 0xb7, 0x80, 0xc7, 0xa1, 0x09, 0x14, 0x01, 0x63, 0x10, 0xc2, 0x9b, 0x20,
+ 0x10, 0xd2, 0x9a, 0xf4, 0x3c, 0x9f, 0x9a, 0xaf, 0xf0, 0xf1, 0xe1, 0xbc,
+ 0x85, 0x45, 0x68, 0x90, 0xaa, 0xf0, 0x7d, 0xf3, 0xf7, 0x0e, 0xba, 0x53,
+ 0x58, 0x56, 0xb1, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x81, 0xba, 0x30,
+ 0x81, 0xb7, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04,
+ 0x14, 0x96, 0x55, 0x9d, 0x9e, 0x4c, 0x02, 0x18, 0x85, 0xa7, 0x97, 0xe2,
+ 0x17, 0xab, 0x9b, 0x99, 0x4c, 0x36, 0x44, 0xd4, 0x54, 0x30, 0x1f, 0x06,
+ 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x81, 0xf6,
+ 0x73, 0x03, 0x40, 0x73, 0x83, 0x6d, 0x3e, 0x83, 0x38, 0x0a, 0x38, 0x3a,
+ 0x3d, 0x38, 0xcd, 0x28, 0x8a, 0xdd, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d,
+ 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30,
+ 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03,
+ 0x02, 0x02, 0x04, 0x30, 0x54, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x4d,
+ 0x30, 0x4b, 0x30, 0x49, 0xa0, 0x47, 0xa0, 0x45, 0x86, 0x43, 0x68, 0x74,
+ 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69,
+ 0x64, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73,
+ 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61,
+ 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x63, 0x72, 0x6c, 0x2f, 0x30, 0x36, 0x39,
+ 0x37, 0x33, 0x36, 0x38, 0x33, 0x33, 0x31, 0x33, 0x39, 0x35, 0x38, 0x31,
+ 0x34, 0x31, 0x36, 0x33, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
+ 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x02, 0x01,
+ 0x00, 0x6f, 0x92, 0x65, 0x9f, 0x8a, 0xe1, 0x7c, 0xff, 0x31, 0x9c, 0xed,
+ 0xfa, 0x1e, 0xb6, 0x66, 0xe3, 0x5e, 0xcc, 0xc2, 0x7c, 0xfe, 0x3b, 0xe1,
+ 0x61, 0x17, 0x91, 0x65, 0x4c, 0xfa, 0x5a, 0x7e, 0xbc, 0x59, 0x42, 0xda,
+ 0xb5, 0x45, 0x7a, 0x98, 0x0a, 0x2f, 0x55, 0x3e, 0x3b, 0x04, 0x95, 0xdd,
+ 0x3f, 0xf5, 0xae, 0x44, 0x1f, 0x32, 0x61, 0xa8, 0x7c, 0xca, 0xca, 0x72,
+ 0xbf, 0xbe, 0xc3, 0xe3, 0x2b, 0x49, 0x4c, 0x06, 0x03, 0x71, 0x69, 0xc9,
+ 0x15, 0xd3, 0xd6, 0xd6, 0x5c, 0xd7, 0xd5, 0x90, 0x31, 0xe6, 0x3c, 0xa0,
+ 0x4b, 0x8b, 0xf5, 0x15, 0xa4, 0x08, 0x7d, 0x53, 0x7f, 0xae, 0xb1, 0x95,
+ 0x3e, 0x03, 0xec, 0x1a, 0x2a, 0x6b, 0x80, 0x37, 0xe2, 0x78, 0x8d, 0x6d,
+ 0x82, 0xa9, 0x10, 0x79, 0x0f, 0x41, 0xc7, 0x25, 0x64, 0x40, 0xbd, 0x77,
+ 0x8d, 0x0f, 0x00, 0xe7, 0x2e, 0x1b, 0x0f, 0x33, 0xfa, 0xbc, 0xd0, 0xb6,
+ 0x25, 0x4a, 0xf6, 0xa0, 0xd0, 0x4b, 0xfb, 0x0b, 0x1f, 0x74, 0x7a, 0x51,
+ 0x3d, 0x94, 0xdb, 0x95, 0x4d, 0x34, 0x98, 0xb6, 0x41, 0x25, 0xc7, 0xb5,
+ 0x60, 0xaa, 0x08, 0x71, 0xc4, 0x12, 0xde, 0xa5, 0x5f, 0xc8, 0x59, 0x86,
+ 0x8d, 0x51, 0x05, 0x63, 0x20, 0x61, 0x45, 0x73, 0xbd, 0x74, 0xa9, 0xdc,
+ 0xae, 0x41, 0x63, 0x3c, 0xed, 0xe9, 0x87, 0xf6, 0xcb, 0xbb, 0xdc, 0x9a,
+ 0xbd, 0x14, 0x2f, 0xd4, 0x31, 0xc6, 0x9c, 0xa7, 0x97, 0xa6, 0x1b, 0xa0,
+ 0xde, 0xbf, 0xa2, 0xc2, 0x9b, 0x3f, 0xb3, 0x66, 0x64, 0xea, 0xa3, 0xad,
+ 0x46, 0x42, 0xf1, 0x6f, 0xe7, 0x31, 0xff, 0x6f, 0x7f, 0x92, 0xbe, 0xab,
+ 0x3a, 0x75, 0x2f, 0xfd, 0xa3, 0x48, 0x51, 0x4c, 0xe6, 0x6a, 0x81, 0x6a,
+ 0xfe, 0xd5, 0x88, 0x37, 0x32, 0xdb, 0xe8, 0xb6, 0x14, 0x68, 0xb5, 0x53,
+ 0xad, 0xb3, 0x4b, 0x06, 0x42, 0xbe, 0xd3, 0xc8, 0x66, 0x2a, 0xfd, 0x74,
+ 0xf2, 0xa0, 0xb7, 0xd6, 0xd0, 0xd3, 0xb7, 0xe6, 0xba, 0xb6, 0x00, 0xd9,
+ 0xab, 0x53, 0x70, 0x84, 0x35, 0xc4, 0x7e, 0x3d, 0x9b, 0x97, 0xd8, 0x86,
+ 0x7f, 0x33, 0x09, 0x83, 0x35, 0x8e, 0xc8, 0x9f, 0x43, 0x0b, 0x64, 0x0c,
+ 0xc1, 0xbb, 0xc9, 0x57, 0x2f, 0xb5, 0xe0, 0xfb, 0xea, 0x27, 0x02, 0x03,
+ 0xcd, 0xb5, 0x9d, 0x1e, 0xe9, 0xbb, 0x7f, 0x09, 0x7c, 0x28, 0xe4, 0x19,
+ 0xce, 0xe4, 0xa3, 0xd2, 0x52, 0xfa, 0x48, 0xa2, 0xdc, 0x50, 0xdb, 0x1a,
+ 0x1a, 0x61, 0x13, 0x02, 0x77, 0x28, 0xf1, 0xa2, 0x4a, 0xac, 0xf3, 0x29,
+ 0x00, 0x6b, 0x22, 0x37, 0x1a, 0x5c, 0x0c, 0x51, 0xf1, 0x11, 0xa0, 0xb7,
+ 0x55, 0x7f, 0x58, 0x19, 0x3c, 0x1b, 0x0c, 0xe8, 0x3f, 0x92, 0x4c, 0xa1,
+ 0x1e, 0xf0, 0xfe, 0x81, 0xb2, 0x8a, 0xf3, 0x3c, 0x70, 0xfa, 0x31, 0xec,
+ 0x32, 0x55, 0x2d, 0xac, 0x9f, 0x3e, 0x30, 0x01, 0xad, 0x54, 0x13, 0x53,
+ 0xf0, 0xd9, 0xb4, 0xa7, 0x14, 0xe7, 0x3c, 0xd2, 0x55, 0x54, 0xcf, 0x33,
+ 0x11, 0x81, 0x9c, 0xea, 0xeb, 0x5c, 0x93, 0xfb, 0x0d, 0x9c, 0x02, 0xc7,
+ 0x63, 0x64, 0x80, 0xfe, 0x23, 0x85, 0xbb, 0x0a, 0x97, 0x69, 0x84, 0xd4,
+ 0x85, 0x5d, 0xae, 0x1c, 0xc3, 0x4d, 0xa3, 0x3f, 0x8e, 0xa4, 0x68, 0xb7,
+ 0xf6, 0xc8, 0xef, 0x89, 0xa1, 0x0d, 0xab, 0x4e, 0xec, 0x31, 0xba, 0xca,
+ 0xab, 0x1c, 0x61, 0x5c, 0x39, 0xe1, 0x6c, 0xc4, 0xa2, 0xf1, 0x48, 0xba,
+ 0x13, 0x30, 0x62, 0x25, 0xb8, 0x81, 0xfd, 0xdc, 0x89, 0x1f, 0xfe, 0x2e,
+ 0x5c, 0xee, 0xf2, 0x22, 0xa0, 0x57, 0x2d, 0x71, 0x9e, 0x64, 0xd8, 0x7b,
+ 0x87, 0xd4, 0xe8, 0x7e, 0x82, 0x42, 0x66, 0x74, 0xd7, 0x68, 0xe0, 0xfd,
+ 0x91, 0x61, 0xa1, 0xff, 0x83, 0x98, 0x75, 0x29, 0xc5, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0x94, 0x02, 0x87, 0xee, 0xee, 0xee, 0xee, 0xee, 0x50, 0x50, 0x50, 0x50,
+ 0x29, 0x02, 0x00, 0x00, 0x97, 0xc2, 0xe5, 0x7f, 0x04, 0x8d, 0xab, 0x71,
+ 0x5f, 0xe7, 0xf6, 0x31, 0x88, 0xc6, 0x6b, 0xfc, 0x02, 0x65, 0x1b, 0x14,
+ 0x49, 0xaa, 0x7c, 0xa2, 0x12, 0x01, 0x08, 0x50, 0x31, 0xf0, 0x5e, 0xf8,
+ 0x30, 0x82, 0x02, 0x25, 0x30, 0x82, 0x01, 0xab, 0xa0, 0x03, 0x02, 0x01,
+ 0x02, 0x02, 0x0a, 0x15, 0x24, 0x41, 0x18, 0x76, 0x46, 0x31, 0x44, 0x50,
+ 0x41, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03,
+ 0x02, 0x30, 0x29, 0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x05,
+ 0x13, 0x10, 0x39, 0x35, 0x65, 0x32, 0x33, 0x66, 0x66, 0x39, 0x62, 0x36,
+ 0x65, 0x62, 0x30, 0x32, 0x35, 0x61, 0x31, 0x0c, 0x30, 0x0a, 0x06, 0x03,
+ 0x55, 0x04, 0x0c, 0x0c, 0x03, 0x54, 0x45, 0x45, 0x30, 0x1e, 0x17, 0x0d,
+ 0x31, 0x38, 0x30, 0x35, 0x32, 0x35, 0x32, 0x33, 0x32, 0x38, 0x34, 0x33,
+ 0x5a, 0x17, 0x0d, 0x32, 0x38, 0x30, 0x35, 0x32, 0x32, 0x32, 0x33, 0x32,
+ 0x38, 0x34, 0x33, 0x5a, 0x30, 0x29, 0x31, 0x19, 0x30, 0x17, 0x06, 0x03,
+ 0x55, 0x04, 0x05, 0x13, 0x10, 0x65, 0x65, 0x34, 0x62, 0x65, 0x65, 0x64,
+ 0x33, 0x39, 0x33, 0x34, 0x37, 0x32, 0x65, 0x64, 0x62, 0x31, 0x0c, 0x30,
+ 0x0a, 0x06, 0x03, 0x55, 0x04, 0x0c, 0x0c, 0x03, 0x54, 0x45, 0x45, 0x30,
+ 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01,
+ 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42,
+ 0x00, 0x04, 0x28, 0x3b, 0xf5, 0xc3, 0xb6, 0x12, 0xf2, 0xb7, 0x8d, 0x25,
+ 0x90, 0x2f, 0x1d, 0x5e, 0x91, 0x98, 0xd6, 0xad, 0xf7, 0xc9, 0x28, 0x25,
+ 0x62, 0xc1, 0xd5, 0x42, 0x7e, 0xd0, 0xa7, 0x0b, 0xd9, 0x9b, 0x25, 0x6a,
+ 0x2b, 0xbb, 0x7d, 0x62, 0x0d, 0x78, 0x42, 0xa3, 0x96, 0x42, 0x71, 0xf5,
+ 0xc5, 0x7a, 0xe4, 0xac, 0xe2, 0x17, 0xd3, 0x02, 0x33, 0x21, 0x55, 0x92,
+ 0x4d, 0x62, 0xd3, 0x3d, 0x9d, 0x3c, 0xa3, 0x81, 0xba, 0x30, 0x81, 0xb7,
+ 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x2d,
+ 0xab, 0x5f, 0x1a, 0x58, 0xc2, 0x0c, 0x11, 0x12, 0x44, 0x96, 0x91, 0x66,
+ 0x7c, 0xe1, 0xab, 0x47, 0x0d, 0x8a, 0xc4, 0x30, 0x1f, 0x06, 0x03, 0x55,
+ 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xc7, 0xbd, 0xe5, 0x13,
+ 0x91, 0x8c, 0x85, 0x2e, 0x04, 0x5c, 0x13, 0xb5, 0xa3, 0x28, 0x93, 0xb7,
+ 0x32, 0x63, 0xa3, 0x59, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01,
+ 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0e, 0x06,
+ 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x02,
+ 0x04, 0x30, 0x54, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x4d, 0x30, 0x4b,
+ 0x30, 0x49, 0xa0, 0x47, 0xa0, 0x45, 0x86, 0x43, 0x68, 0x74, 0x74, 0x70,
+ 0x73, 0x3a, 0x2f, 0x2f, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2e,
+ 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63,
+ 0x6f, 0x6d, 0x2f, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69,
+ 0x6f, 0x6e, 0x2f, 0x63, 0x72, 0x6c, 0x2f, 0x31, 0x35, 0x32, 0x34, 0x34,
+ 0x31, 0x31, 0x38, 0x37, 0x36, 0x34, 0x36, 0x33, 0x31, 0x34, 0x34, 0x35,
+ 0x30, 0x34, 0x31, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d,
+ 0x04, 0x03, 0x02, 0x03, 0x68, 0x00, 0x30, 0x65, 0x02, 0x30, 0x3c, 0x07,
+ 0x1f, 0xac, 0xc8, 0x38, 0x13, 0x81, 0xc5, 0xab, 0x00, 0x21, 0xea, 0xc9,
+ 0x26, 0x34, 0xb4, 0xb8, 0xce, 0x7c, 0x19, 0x16, 0xef, 0x12, 0x50, 0x61,
+ 0xc5, 0xce, 0x75, 0xec, 0x3b, 0x18, 0x73, 0x7f, 0x9b, 0x38, 0x74, 0xad,
+ 0xd4, 0x78, 0xe2, 0xf8, 0x94, 0xf6, 0x1f, 0xa2, 0xa2, 0x12, 0x02, 0x31,
+ 0x00, 0xee, 0x42, 0x9b, 0x75, 0x8e, 0x59, 0xe0, 0x9e, 0xfa, 0x93, 0xfd,
+ 0x44, 0x82, 0xa7, 0x11, 0x9c, 0x07, 0xfd, 0x07, 0x90, 0x71, 0x27, 0xb2,
+ 0x1e, 0x18, 0x58, 0x7e, 0xbe, 0xdf, 0xab, 0xfd, 0x2d, 0x26, 0xe8, 0x40,
+ 0xa4, 0x96, 0xbb, 0x08, 0xe8, 0x1b, 0xb5, 0x47, 0xa3, 0xe7, 0xb7, 0xb2,
+ 0xdc, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0x8e, 0xe5, 0xcc, 0x90,
+ 0xd5, 0xbe, 0xfc, 0x9a, 0x15, 0x3f, 0xce, 0x53, 0xfd, 0x9b, 0x13, 0x65,
+ 0x9c, 0x26, 0x48, 0xef, 0x0d, 0xa1, 0xa2, 0x9c, 0x29, 0x1a, 0x71, 0x84,
+ 0x7b, 0x61, 0xb4, 0xc0
+
+};
+
+#define CERT_BLOCK_SIZE 1024
+
+TEST_F(KeymasterProvisionTest, ProvisionCertificatesSuccess) {
+ // Fetch dev-id.
+ std::vector<uint8_t> dev_id;
+ nos::AppClient app(*client, APP_ID_NUGGET);
+
+ uint32_t retval;
+ dev_id.reserve(32);
+
+ retval = app.Call(NUGGET_PARAM_DEVICE_ID, dev_id, &dev_id);
+ ASSERT_EQ(retval, APP_SUCCESS);
+
+ // TODO: port this test over to Jenkins.
+ if (std::string(reinterpret_cast<const char *>(dev_id.data()),
+ dev_id.size() -1) != string("adacb483:0100b022")) {
+ return;
+ }
+
+ for (int i = 0; i < 7; i++) {
+ ProvisionCertificatesRequest request;
+ ProvisionCertificatesResponse response;
+
+ request.set_block_number(i);
+ request.set_cert_block(
+ &ATTESTION_CERT_adacb483_0100b022[i * CERT_BLOCK_SIZE],
+ CERT_BLOCK_SIZE);
+ uint8_t digest[SHA256_DIGEST_LENGTH];
+ request.set_digest(
+ SHA256(&ATTESTION_CERT_adacb483_0100b022[i * CERT_BLOCK_SIZE],
+ CERT_BLOCK_SIZE, &digest[0]), SHA256_DIGEST_LENGTH);
+
+ Keymaster service(*client);
+ ASSERT_NO_ERROR(service.ProvisionCertificates(request, &response), "");
+ ASSERT_EQ((ErrorCode)response.error_code(), ErrorCode::OK);
+
+ if (i == 0) {
+ // On a fresh spiflash, expect certs to be missing. On re-runs, certs
+ // will already be present.
+ EXPECT_TRUE(response.cert_status() == CertificateStatus::CERT_MISSING ||
+ response.cert_status() ==
+ CertificateStatus::CERT_PREVIOUSLY_PROVISIONED);
+ }
+ if (i == 6) {
+ // All done, cert status should indicate accordingly.
+ EXPECT_EQ(response.cert_status(),
+ CertificateStatus::CERT_PREVIOUSLY_PROVISIONED);
+ }
+ }
+}
+
} // namespace
diff --git a/src/test-data/test-keys/reset_key_data.cc b/src/test-data/test-keys/reset_key_data.cc
new file mode 100644
index 0000000..9f22c42
--- /dev/null
+++ b/src/test-data/test-keys/reset_key_data.cc
@@ -0,0 +1,124 @@
+
+#include "reset_key_data.h"
+
+namespace test_data {
+
+const uint8_t kResetKeyPem[] =
+"-----BEGIN RSA PRIVATE KEY-----\n\
+MIIEpAIBAAKCAQEAo0IoAa5cK7XyAj7u1jFStsfEcxkgAZVF9VWKzH1bofKxLioA\n\
+r5Lo4D33glKehxkOlDo6GkBj1PoI8WuvYYvEUyxJNUdlVpa1C2lbewEL0rfyBrZ9\n\
+4cp0ZeUknymYHn3ynW4Z8sYMlj7BNxGttV/jbxtgtT5WHJ+hg5/4/ifCPucN17Bt\n\
+heUKIBoAjy6DlB/pMg1NUQ82DaASMFe89mEzI9Zk4CRtkWjEhknY0bYm46U1ABJb\n\
+YmIsHlxdADskvWFDmq8CfJr/jXstTXxZeqaxPPdSP+WPwXN/ku5W7qkF2qimEKiy\n\
+DYHzY65JhfWmHOLLGNuz6iHkq93uzkKsGIIPGQIDAQABAoIBABGTvdrwetv56uRz\n\
+AiPti4pCV9RMkDWbbLzNSPRbStJU3t6phwlgN9Js2YkefBLvj7JF0pug8x6rDOtx\n\
+PKCz+5841Wj3FuILt9JStZa4th0p0NUIMOVudrnBwf+g6s/dn5FzmTeaOyCyAPt8\n\
+28b7W/FKcU8SNxM93JXfU1+JyFAdREqsXQfqLhCAXBb46fs5D8hg0c99RdWuJSuY\n\
+HKyVXDrjmYAHS5qUDeMx0OY/q1qM03FBvHekvJ78WPpUKF7B/gYH9lBHIHE0KLJY\n\
+JR6kKkzN/Ii6BsSubKKeuNntzlzd2ukvFdX4uc42dDpIXPdaQAn84KRYN7++KoGz\n\
+2LqtAAECgYEAzQt5kt9c+xDeKMPR92XQ4uMeLxTufBei1PFGZbJnJT8aEMkVhKT/\n\
+Pbh1Z8OnN9YvFprDNpEilUm7xyffrE7p0pI1/qiBXZExy6pIcGAo4ZcB8ayN0JV3\n\
+k+RilE73x+sKAyWOm82b273PiyHNsQI4flkO5Ev9rpZbPMKlvZYsmxkCgYEAy9RR\n\
+RwxwCpvFi3um0Rwz7CI2uvVXGaLVXyR2oNGLcJG7AhusYi4FX6XJQ3vAgiDmzu/c\n\
+SaEF9w7uqeueIUA7L7njYP1ojfJAUJEtQRfVJF2tDntN5YgYUTsx8n3IKTs4xFT4\n\
+dBthKo16zzLv92+8m4sWJhFW2zzFFLwk+G5jlAECgYEAln1piSZus8Y5h2nRXOZZ\n\
+XWyb5qpSLrmaRPegV1uM4IVjuBYduPDwdHhBkxrCS/TjMo/73ry+yRsIuq7FN03j\n\
+xyyQfItoByhdh8E+0VuCJbATOTEQFJre3KiuwXMD4LLc8lpKRIevcKPrA46XzOZ4\n\
+WCM9DsnHMrAf3oRt6KujqWECgYEAyu43fWUEp4suwg/5pXdOumnV040vinZzuKW0\n\
+9aeqDAkLBq5Gkfj/oJqOJoGux9+5640i5KtMJQzY0JOke7ZXNsz7dDTXQ3tMTOo9\n\
+A/GWYv5grWpVw5AbpcQpliNkhKhRfCactfwMYTE6c89i2haE0NdI1d2te9ik3l/y\n\
+7uP4gAECgYA3u2CumlkjHq+LbMK6Ry+Ajyy4ssM5PKJUqSogJDUkHsG/C7yaCdq/\n\
+Ljt2x2220H0pM9885C3PpKxoYwRih9dzOamnARJocAElp2b5AQB+tKddlMdwx1pQ\n\
+0IMGQ3fBYkDFLGYDk7hGYkLLlSJCZwi64xKmmfEwl83RL6JDSFupDg==\n\
+-----END RSA PRIVATE KEY-----";
+const size_t kResetKeyPemSize = sizeof(kResetKeyPem);
+
+// Dev-signed "null" message.
+static const uint8_t kNullDevSig[] = {
+ 0x9d, 0x16, 0x0c, 0x04, 0x64, 0xd6, 0x17, 0xbc, 0xf9, 0x81, 0x4d, 0x7b,
+ 0x15, 0x45, 0x2f, 0xa1, 0x66, 0xfa, 0x03, 0x45, 0x50, 0x9b, 0x60, 0x6e,
+ 0x77, 0x76, 0x4d, 0x09, 0x99, 0x98, 0xe5, 0x8e, 0x0a, 0xf3, 0x4e, 0x09,
+ 0x2c, 0xa0, 0xfd, 0x2e, 0xfa, 0x23, 0x16, 0x53, 0x61, 0x43, 0x6b, 0xba,
+ 0xb7, 0xf8, 0x6b, 0xb4, 0xbe, 0x55, 0x3d, 0x21, 0x63, 0x84, 0x64, 0x00,
+ 0x2d, 0xf0, 0x3c, 0x4d, 0x63, 0x4d, 0xe8, 0xf6, 0x26, 0xf7, 0x6b, 0x0e,
+ 0x08, 0xca, 0xda, 0xa0, 0x8d, 0x0a, 0x3f, 0x06, 0x9d, 0xf7, 0x4d, 0x97,
+ 0x86, 0xf4, 0xc2, 0x56, 0x94, 0x85, 0x46, 0xc0, 0x11, 0x0b, 0x9d, 0x12,
+ 0x39, 0x9e, 0x3d, 0xb7, 0xcb, 0xac, 0xe9, 0x63, 0x10, 0xd7, 0xeb, 0x1c,
+ 0x0b, 0xf7, 0x83, 0x06, 0xa8, 0xdd, 0x61, 0x38, 0xef, 0xe8, 0x13, 0x18,
+ 0xda, 0xd8, 0xdc, 0xd6, 0x12, 0x1c, 0xf3, 0x7c, 0x6e, 0x19, 0xd6, 0x94,
+ 0xe6, 0x3a, 0x6e, 0x8e, 0x5b, 0xcf, 0x3a, 0x69, 0x1c, 0xcf, 0xc2, 0x48,
+ 0xc2, 0xb2, 0x1b, 0xb8, 0x24, 0xc2, 0xc5, 0x7e, 0xdc, 0x5d, 0x01, 0xe6,
+ 0xfb, 0x14, 0xbf, 0x96, 0xc1, 0xd3, 0xdf, 0xe5, 0x14, 0x3f, 0xcb, 0xea,
+ 0xfa, 0xef, 0xa7, 0x5c, 0xc3, 0xcb, 0x62, 0x09, 0x0e, 0x1f, 0xd9, 0x56,
+ 0x35, 0xdb, 0x34, 0x23, 0x6a, 0xac, 0x43, 0x0d, 0x27, 0x90, 0x8e, 0x96,
+ 0xcc, 0x89, 0xb6, 0x74, 0x45, 0x1e, 0x8f, 0x48, 0x2a, 0x1d, 0x8f, 0xba,
+ 0xd0, 0x80, 0x7e, 0xf9, 0x1f, 0x21, 0x9b, 0x87, 0x80, 0x9b, 0x9e, 0x1a,
+ 0xb8, 0xc3, 0xe4, 0x55, 0xaa, 0x67, 0xa5, 0x2d, 0x1a, 0x85, 0xd8, 0x6a,
+ 0x9a, 0xc7, 0x5d, 0x1e, 0x1d, 0x51, 0x47, 0x09, 0x51, 0xf6, 0x7c, 0xe9,
+ 0xfc, 0x1f, 0x9e, 0xea, 0xc9, 0xce, 0x77, 0xf2, 0xb1, 0x79, 0x7e, 0x17,
+ 0xc2, 0x78, 0xab, 0xf7
+};
+
+static const uint8_t kNullProdSig[] = {
+ 0x41, 0xcf, 0x80, 0xa7, 0x43, 0xdb, 0xb1, 0x08, 0x36, 0x5f, 0xbb, 0x23,
+ 0xa4, 0x1c, 0xa9, 0x28, 0xdf, 0x64, 0x79, 0xeb, 0x41, 0x67, 0x5d, 0x35,
+ 0x09, 0x76, 0x4a, 0xca, 0x74, 0xe8, 0xf0, 0x5b, 0x7d, 0x53, 0x8f, 0x5f,
+ 0x49, 0xdb, 0x7c, 0x08, 0x70, 0xdb, 0xd3, 0xe2, 0x87, 0x51, 0x08, 0x6f,
+ 0x13, 0x40, 0x33, 0x56, 0xa9, 0x99, 0x07, 0xee, 0x18, 0x88, 0xe0, 0x63,
+ 0x15, 0x90, 0x4e, 0xd1, 0x4a, 0x51, 0x00, 0x91, 0x63, 0x3e, 0x55, 0x80,
+ 0xfc, 0xde, 0x18, 0x55, 0x52, 0x89, 0xa0, 0x05, 0xdc, 0x99, 0x80, 0x2c,
+ 0x90, 0xd1, 0x14, 0xea, 0xe0, 0xd7, 0xab, 0x26, 0x67, 0xe3, 0x75, 0xd0,
+ 0x06, 0xa9, 0x36, 0x11, 0x21, 0xc8, 0x21, 0x4c, 0x49, 0xe2, 0x81, 0x66,
+ 0x25, 0x2c, 0x41, 0xb6, 0x48, 0x65, 0x0b, 0x44, 0xc9, 0xcc, 0x0c, 0xad,
+ 0x88, 0x95, 0x9d, 0x9a, 0x25, 0x71, 0xb3, 0x85, 0x22, 0xbf, 0x28, 0x05,
+ 0x65, 0x62, 0x61, 0x54, 0x5d, 0xd9, 0xc8, 0x7c, 0x17, 0x5f, 0xec, 0xc7,
+ 0x40, 0xaf, 0x66, 0xd3, 0x0a, 0x1f, 0x6a, 0x56, 0xbc, 0x48, 0x84, 0xf6,
+ 0x61, 0xa3, 0xab, 0x3c, 0x81, 0x72, 0x75, 0x94, 0x5d, 0x03, 0xeb, 0xca,
+ 0x7f, 0xb3, 0x48, 0xbc, 0x8f, 0x4c, 0xb3, 0xc2, 0xae, 0xa9, 0x53, 0x91,
+ 0x17, 0x48, 0x48, 0x36, 0xb7, 0x7c, 0xd8, 0xe4, 0x99, 0x86, 0x1e, 0x57,
+ 0xaa, 0xaf, 0xab, 0xe4, 0x61, 0x32, 0x58, 0xdb, 0x45, 0x38, 0x26, 0x32,
+ 0x2c, 0xa0, 0x21, 0x34, 0xa3, 0xef, 0x6c, 0x2c, 0x8c, 0x74, 0x10, 0x3c,
+ 0x70, 0x3e, 0xe2, 0x80, 0x7a, 0xf5, 0x9f, 0xf1, 0x92, 0x43, 0x4f, 0x21,
+ 0xb8, 0x21, 0xd5, 0x7a, 0xa7, 0x36, 0xfc, 0x2e, 0x50, 0xd1, 0xa6, 0xbf,
+ 0xfc, 0xc7, 0x57, 0x75, 0x19, 0xb7, 0xcf, 0x8f, 0xdb, 0x3d, 0x1c, 0xa2,
+ 0xdc, 0x81, 0x71, 0x82
+};
+
+static const uint8_t kNullTestSig[] = {
+ 0x95, 0x35, 0x5a, 0xb6, 0xe3, 0x8e, 0x43, 0x03, 0xd9, 0xd9, 0xd5, 0x6e,
+ 0x99, 0x86, 0xff, 0x8e, 0x6a, 0xf1, 0x54, 0x6f, 0xa8, 0xff, 0x37, 0x38,
+ 0xc6, 0x9b, 0x4d, 0xc6, 0x99, 0x1f, 0x37, 0x5c, 0xec, 0xf4, 0x32, 0xd8,
+ 0xe6, 0x00, 0xcc, 0x74, 0xde, 0xa9, 0x68, 0x1a, 0xab, 0x6a, 0x6e, 0xe7,
+ 0xa7, 0xa1, 0x59, 0xe0, 0x7c, 0x86, 0x95, 0x28, 0x94, 0x18, 0x3f, 0x0f,
+ 0xb9, 0x0f, 0x05, 0x6c, 0x86, 0x5a, 0x6a, 0xe4, 0x6d, 0x36, 0x71, 0x86,
+ 0x38, 0xab, 0x7a, 0x2d, 0x9c, 0xa5, 0xfa, 0xc8, 0x7c, 0x48, 0x02, 0x8c,
+ 0x6b, 0x4d, 0xda, 0xa4, 0xb5, 0xa8, 0x17, 0x39, 0x5e, 0xe3, 0x1a, 0xd5,
+ 0xf8, 0x87, 0x6e, 0xd9, 0xc0, 0x0c, 0x29, 0x4d, 0x93, 0xa2, 0x3b, 0xfc,
+ 0x2d, 0x38, 0x8e, 0x2b, 0xc7, 0x49, 0x26, 0xd9, 0xcb, 0x47, 0x89, 0x4c,
+ 0x79, 0xd3, 0x60, 0x62, 0xf9, 0x71, 0xa7, 0x73, 0x6a, 0x03, 0x65, 0x1f,
+ 0x11, 0x0d, 0x9e, 0x27, 0x99, 0x6b, 0xa7, 0x46, 0x85, 0x75, 0xec, 0xff,
+ 0x5b, 0x1d, 0x8d, 0x1b, 0x34, 0xd8, 0xb9, 0x4f, 0x63, 0x88, 0x08, 0xa8,
+ 0x16, 0xba, 0xfc, 0xe7, 0x66, 0xa4, 0xe5, 0xde, 0x4e, 0x0b, 0x98, 0x80,
+ 0xd5, 0x16, 0x55, 0xfb, 0xdb, 0xe8, 0xa2, 0x90, 0x85, 0x4e, 0xa9, 0xb6,
+ 0x81, 0x55, 0xef, 0xbf, 0x12, 0xe3, 0xd2, 0xa9, 0xae, 0x2c, 0x43, 0x67,
+ 0x4c, 0x09, 0x6d, 0x95, 0xaf, 0x44, 0xc2, 0xb9, 0x9d, 0x7c, 0xb1, 0x88,
+ 0xf8, 0x6c, 0xa0, 0x13, 0x4c, 0xbf, 0x85, 0xa2, 0x8b, 0x9d, 0x06, 0xc8,
+ 0x11, 0xdb, 0x1f, 0xfb, 0x05, 0x15, 0xd6, 0x1f, 0xe5, 0x52, 0x9c, 0xd5,
+ 0xbd, 0xff, 0xb0, 0xce, 0x29, 0xec, 0xd8, 0x9e, 0xdb, 0x5b, 0xc9, 0x52,
+ 0x24, 0xaf, 0x22, 0xeb, 0xce, 0x15, 0x0d, 0xfd, 0x6c, 0x76, 0x90, 0x3e,
+ 0x4f, 0x63, 0xfd, 0xb1
+};
+
+const uint8_t *kResetSignatures[] = {
+ [0] = kNullTestSig,
+ [1] = kNullDevSig,
+ [2] = kNullProdSig,
+};
+
+const size_t kResetSignatureLengths[] = {
+ 256, 256, 256,
+};
+
+const size_t kResetSignatureCount = 3;
+
+} // namespace test_data
diff --git a/src/test-data/test-keys/reset_key_data.h b/src/test-data/test-keys/reset_key_data.h
new file mode 100644
index 0000000..0fb948f
--- /dev/null
+++ b/src/test-data/test-keys/reset_key_data.h
@@ -0,0 +1,17 @@
+#ifndef SRC_TEST_RESET_KEYS_H
+#define SRC_TEST_RESET_KEYS_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+namespace test_data {
+
+extern const uint8_t kResetKeyPem[];
+extern const size_t kResetKeyPemSize;
+extern const uint8_t *kResetSignatures[];
+extern const size_t kResetSignatureLengths[];
+extern const size_t kResetSignatureCount;
+} // namespace test_data
+
+
+#endif // SRC_TEST_RESET_KEYS_H
diff --git a/src/test-data/test-keys/rsa.h b/src/test-data/test-keys/rsa.h
index 07965e7..80a163b 100644
--- a/src/test-data/test-keys/rsa.h
+++ b/src/test-data/test-keys/rsa.h
@@ -27,14 +27,8 @@
const uint8_t *n;
const size_t size;
} TEST_RSA_KEYS[] = {
- {3, RSA_3_512_D, RSA_3_512_N, sizeof(RSA_3_512_N)},
- {65537, RSA_512_D, RSA_512_N, sizeof(RSA_512_N)},
- {65537, RSA_768_D, RSA_768_N, sizeof(RSA_768_N)},
{65537, RSA_1024_D, RSA_1024_N, sizeof(RSA_1024_N)},
{65537, RSA_2048_D, RSA_2048_N, sizeof(RSA_2048_N)},
- {65537, RSA_3072_D, RSA_3072_N, sizeof(RSA_3072_N)},
- // TODO: update transport to accept larger messages.
- // {RSA_4096_D, RSA_4096_N, sizeof(RSA_4096_N)},
};
diff --git a/src/transport_tests.cc b/src/transport_tests.cc
new file mode 100644
index 0000000..b57ccae
--- /dev/null
+++ b/src/transport_tests.cc
@@ -0,0 +1,798 @@
+#include <memory>
+
+#include "gmock/gmock.h"
+#include "nos/device.h"
+#include "nos/NuggetClient.h"
+#include "application.h"
+#include "app_transport_test.h"
+#include "util.h"
+
+using std::cout;
+using std::string;
+using std::unique_ptr;
+
+/*
+ * These test use the datagram protocol diretly to test that Citadel's transport
+ * implementation works as expected.
+ */
+namespace {
+
+static const uint16_t crc16_table[256] = {
+ 0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
+ 0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
+ 0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
+ 0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
+ 0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
+ 0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
+ 0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
+ 0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
+ 0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
+ 0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
+ 0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
+ 0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
+ 0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
+ 0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
+ 0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
+ 0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
+ 0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
+ 0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
+ 0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
+ 0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
+ 0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
+ 0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
+ 0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
+ 0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
+ 0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
+ 0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
+ 0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
+ 0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
+ 0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
+ 0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
+ 0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
+ 0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
+};
+
+uint16_t crc16_update(const void *buf, uint32_t len, uint16_t crc) {
+ uint32_t i;
+ const uint8_t *bytes = reinterpret_cast<const uint8_t *>(buf);
+ for (i = 0; i < len; ++i) {
+ crc = crc16_table[((crc >> 8) ^ *bytes++) & 0xFF] ^ (crc << 8);
+ }
+ return crc;
+}
+
+uint16_t crc16(const void *buf, uint32_t len) {
+ return crc16_update(buf, len, 0);
+}
+
+#define RETRY_COUNT 30
+#define RETRY_WAIT_TIME_US 5000
+
+/*
+ * Read a datagram from the device, correctly handling retries.
+ */
+static int nos_device_read(const struct nos_device *dev, uint32_t command,
+ void *buf, uint32_t len) {
+ int retries = RETRY_COUNT;
+ while (retries--) {
+ int err = dev->ops.read(dev->ctx, command, reinterpret_cast<uint8_t *>(buf), len);
+
+ if (err == -EAGAIN) {
+ /* Linux driver returns EAGAIN error if Citadel chip is asleep.
+ * Give to the chip a little bit of time to awake and retry reading
+ * status again. */
+ usleep(RETRY_WAIT_TIME_US);
+ continue;
+ }
+ return -err;
+ }
+
+ return ETIMEDOUT;
+}
+
+/*
+ * Write a datagram to the device, correctly handling retries.
+ */
+static int nos_device_write(const struct nos_device *dev, uint32_t command,
+ const void *buf, uint32_t len) {
+ int retries = RETRY_COUNT;
+ while (retries--) {
+ int err = dev->ops.write(dev->ctx, command, reinterpret_cast<const uint8_t *>(buf), len);
+
+ if (err == -EAGAIN) {
+ /* Linux driver returns EAGAIN error if Citadel chip is asleep.
+ * Give to the chip a little bit of time to awake and retry reading
+ * status again. */
+ usleep(RETRY_WAIT_TIME_US);
+ continue;
+ }
+ return -err;
+ }
+
+ return ETIMEDOUT;
+}
+
+/*
+ * The transport protocol has 4 stages:
+ * 1. Resetting the slave
+ * 2. Sending a command to the slave
+ * 3. Polling until the slave is done
+ * 4. Fetching the result from the slave
+ *
+ * There are CRCs used on the messages to ensure integrity. If the CRC fails,
+ * the the data transfer is retried. This can happen for the status message,
+ * arguments and command message or the reply data.
+ */
+class TransportTest: public testing::Test {
+ protected:
+ static nos_device* dev;
+ static unique_ptr<nos::NuggetClient> client;
+ static unique_ptr<test_harness::TestHarness> uart_printer;
+
+ static void SetUpTestCase();
+ static void TearDownTestCase();
+
+ virtual void SetUp();
+};
+
+nos_device* TransportTest::dev;
+unique_ptr<nos::NuggetClient> TransportTest::client;
+unique_ptr<test_harness::TestHarness> TransportTest::uart_printer;
+
+void TransportTest::SetUpTestCase() {
+ uart_printer = test_harness::TestHarness::MakeUnique();
+
+ client = nugget_tools::MakeDirectNuggetClient();
+ client->Open();
+ EXPECT_TRUE(client->IsOpen()) << "Unable to connect";
+ dev = client->Device();
+}
+
+void TransportTest::TearDownTestCase() {
+ dev = nullptr;
+ client->Close();
+ client.reset();
+
+ uart_printer = nullptr;
+}
+
+void TransportTest::SetUp() {
+ // Reset and give it a bit of time to settle
+ ASSERT_TRUE(nugget_tools::RebootNuggetUnchecked(client.get()));
+ // Give a bit of time for the reboot to take effect
+ usleep(30000);
+}
+
+bool StatusMatches(const transport_status& arg, uint32_t status, uint16_t flags,
+ uint8_t* reply, uint16_t reply_len) {
+ bool ok = true;
+
+ // v0 fields
+ ok &= arg.status == status;
+ ok &= arg.reply_len == reply_len;
+
+ // v1 fields
+ ok &= arg.length == sizeof(transport_status);
+ ok &= arg.version == TRANSPORT_V1;
+ ok &= arg.flags == flags;
+
+ // Check the status is a valid length
+ if (arg.length < STATUS_MIN_LENGTH || arg.length > STATUS_MAX_LENGTH) {
+ return false;
+ }
+
+ // As of v1, the length shouldn\t be greater than transport_status
+ if (arg.length > sizeof(transport_status)) {
+ return false;
+ }
+
+ // Check the CRCs are valid
+ transport_status st = arg;
+ st.crc = 0;
+ ok &= arg.crc == crc16(&st, st.length);
+ ok &= arg.reply_crc == crc16(reply, reply_len);
+
+ return ok;
+}
+
+MATCHER(IsIdle, "") {
+ return StatusMatches(arg,
+ APP_STATUS_IDLE, 0,
+ nullptr, 0);
+}
+
+MATCHER(IsWorking, "") {
+ return StatusMatches(arg,
+ APP_STATUS_IDLE, STATUS_FLAG_WORKING,
+ nullptr, 0);
+}
+
+MATCHER(IsTooMuch, "") {
+ return StatusMatches(arg,
+ APP_STATUS_DONE | APP_ERROR_TOO_MUCH, 0,
+ nullptr, 0);
+}
+
+MATCHER(IsBadCrc, "") {
+ return StatusMatches(arg,
+ APP_STATUS_DONE | APP_ERROR_CHECKSUM, 0,
+ nullptr, 0);
+}
+
+MATCHER(IsSuccess, "") {
+ return StatusMatches(arg,
+ APP_STATUS_DONE | APP_SUCCESS, 0,
+ nullptr, 0);
+}
+
+MATCHER_P2(IsSuccessWithData, data, len, "") {
+ return StatusMatches(arg,
+ APP_STATUS_DONE | APP_SUCCESS, 0,
+ data, len);
+}
+
+// Give the app time to complete rather than polling
+void WaitForApp() {
+ usleep(30000);
+}
+
+// Calculate and set the CRC for the command from data or the struct
+void SetCommandInfoCrc(const void* arg, uint16_t arg_len, uint32_t command,
+ void* command_info, uint16_t command_info_len) {
+ uint16_t crc = crc16(&arg_len, sizeof(arg_len));
+ crc = crc16_update(arg, arg_len, crc);
+ crc = crc16_update(&command, sizeof(command), crc);
+ uint16_t* const info_crc
+ = (uint16_t*)&((uint8_t*)command_info)[offsetof(transport_command_info, crc)];
+ *info_crc = 0;
+ *info_crc = crc16_update(command_info, command_info_len, crc);
+}
+void SetCommandInfoCrc(const void* arg, uint16_t arg_len, uint32_t command,
+ transport_command_info* info) {
+ SetCommandInfoCrc(arg, arg_len, command, info, sizeof(*info));
+}
+
+/* The initial state is to be idle. */
+TEST_F(TransportTest, ResetToIdle) {
+ transport_status status;
+ const uint32_t command = CMD_ID(APP_ID_TRANSPORT_TEST) | CMD_IS_READ | CMD_TRANSPORT;
+ ASSERT_EQ(nos_device_read(dev, command, &status, sizeof(transport_status)), 0);
+ ASSERT_THAT(status, IsIdle());
+}
+
+/* The master will be polling so need to confirm app is still working. */
+TEST_F(TransportTest, CommandImmediatelyTriggersWorking) {
+ { // Send "go" command
+ transport_command_info command_info = {};
+ const uint32_t command = CMD_ID(APP_ID_TRANSPORT_TEST) | CMD_PARAM(0);
+ ASSERT_EQ(nos_device_write(dev, command, &command_info, sizeof(command_info)), 0);
+ }
+ { // Check status
+ transport_status status;
+ const uint32_t command = CMD_ID(APP_ID_TRANSPORT_TEST) | CMD_IS_READ | CMD_TRANSPORT;
+ ASSERT_EQ(nos_device_read(dev, command, &status, sizeof(transport_status)), 0);
+ ASSERT_THAT(status, IsWorking());
+ }
+}
+
+TEST_F(TransportTest, CommandBadCrc) {
+ { // Send "go" command
+ transport_command_info command_info = {};
+ command_info.length = sizeof(transport_command_info);
+ command_info.version = TRANSPORT_V1;
+ const uint32_t command = CMD_ID(APP_ID_TRANSPORT_TEST) | CMD_PARAM(0);
+ ASSERT_EQ(nos_device_write(dev, command, &command_info, sizeof(command_info)), 0);
+ }
+ // Let app process command
+ WaitForApp();
+ { // Check status
+ transport_status status;
+ const uint32_t command = CMD_ID(APP_ID_TRANSPORT_TEST) | CMD_IS_READ | CMD_TRANSPORT;
+ ASSERT_EQ(nos_device_read(dev, command, &status, sizeof(transport_status)), 0);
+ ASSERT_THAT(status, IsBadCrc());
+ }
+}
+
+TEST_F(TransportTest, TooMuchData) {
+ { // Send data
+ uint8_t data[32] = {};
+ uint32_t command = CMD_ID(APP_ID_TRANSPORT_TEST) | CMD_IS_DATA | CMD_TRANSPORT;
+ CMD_SET_PARAM(command, sizeof(data));
+ ASSERT_EQ(nos_device_write(dev, command, data, sizeof(data)), 0);
+ }
+ { // Send "go" command
+ transport_command_info command_info = {};
+ command_info.version = TRANSPORT_V1;
+ const uint32_t command = CMD_ID(APP_ID_TRANSPORT_TEST) | CMD_PARAM(0);
+ ASSERT_EQ(nos_device_write(dev, command, &command_info, sizeof(command_info)), 0);
+ }
+ { // Check status
+ transport_status status;
+ const uint32_t command = CMD_ID(APP_ID_TRANSPORT_TEST) | CMD_IS_READ | CMD_TRANSPORT;
+ ASSERT_EQ(nos_device_read(dev, command, &status, sizeof(transport_status)), 0);
+ ASSERT_THAT(status, IsTooMuch());
+ }
+}
+
+/* Until the app says it is done, it is working. */
+TEST_F(TransportTest, HangKeepsWorking) {
+ { // Send "go" command
+ transport_command_info command_info = {};
+ command_info.length = sizeof(transport_command_info);
+ command_info.version = TRANSPORT_V1;
+ const uint32_t command = CMD_ID(APP_ID_TRANSPORT_TEST) | CMD_PARAM(TRANSPORT_TEST_HANG);
+ SetCommandInfoCrc(nullptr, 0, command, &command_info);
+ ASSERT_EQ(nos_device_write(dev, command, &command_info, sizeof(command_info)), 0);
+ }
+ { // Check status
+ transport_status status;
+ const uint32_t command = CMD_ID(APP_ID_TRANSPORT_TEST) | CMD_IS_READ | CMD_TRANSPORT;
+ ASSERT_EQ(nos_device_read(dev, command, &status, sizeof(transport_status)), 0);
+ ASSERT_THAT(status, IsWorking());
+ }
+ // Let app process command
+ WaitForApp();
+ { // Check status
+ transport_status status;
+ const uint32_t command = CMD_ID(APP_ID_TRANSPORT_TEST) | CMD_IS_READ | CMD_TRANSPORT;
+ ASSERT_EQ(nos_device_read(dev, command, &status, sizeof(transport_status)), 0);
+ ASSERT_THAT(status, IsWorking());
+ }
+ // Let app process command
+ WaitForApp();
+ { // Check status
+ transport_status status;
+ const uint32_t command = CMD_ID(APP_ID_TRANSPORT_TEST) | CMD_IS_READ | CMD_TRANSPORT;
+ ASSERT_EQ(nos_device_read(dev, command, &status, sizeof(transport_status)), 0);
+ ASSERT_THAT(status, IsWorking());
+ }
+}
+
+/* While the app is working, the master can only wait and can't modify memory. */
+TEST_F(TransportTest, CannotClearStatusWhileWorking) {
+ { // Send "go" command
+ transport_command_info command_info = {};
+ command_info.version = TRANSPORT_V1;
+ const uint32_t command = CMD_ID(APP_ID_TRANSPORT_TEST) | CMD_PARAM(TRANSPORT_TEST_HANG);
+ SetCommandInfoCrc(nullptr, 0, command, &command_info);
+ ASSERT_EQ(nos_device_write(dev, command, &command_info, sizeof(command_info)), 0);
+ }
+ { // Attempt to clear status
+ const uint32_t command = CMD_ID(APP_ID_TRANSPORT_TEST) | CMD_TRANSPORT;
+ ASSERT_EQ(nos_device_write(dev, command, nullptr, 0), 0);
+ }
+ { // Check status
+ transport_status status;
+ const uint32_t command = CMD_ID(APP_ID_TRANSPORT_TEST) | CMD_IS_READ | CMD_TRANSPORT;
+ ASSERT_EQ(nos_device_read(dev, command, &status, sizeof(transport_status)), 0);
+ ASSERT_THAT(status, IsWorking());
+ }
+}
+
+/* Protect from any race conditions that could arise. */
+TEST_F(TransportTest, CannotStartNewCommandWhileWorking) {
+ { // Send "go" command
+ transport_command_info command_info = {};
+ command_info.length = sizeof(transport_command_info);
+ command_info.version = TRANSPORT_V1;
+ const uint32_t command = CMD_ID(APP_ID_TRANSPORT_TEST) | CMD_PARAM(TRANSPORT_TEST_HANG);
+ SetCommandInfoCrc(nullptr, 0, command, &command_info);
+ ASSERT_EQ(nos_device_write(dev, command, &command_info, sizeof(command_info)), 0);
+ }
+ { // Send "go" command
+ transport_command_info command_info = {};
+ command_info.length = sizeof(transport_command_info);
+ command_info.version = TRANSPORT_V1;
+ const uint32_t command = CMD_ID(APP_ID_TRANSPORT_TEST) | CMD_PARAM(TRANSPORT_TEST_1234);
+ SetCommandInfoCrc(nullptr, 0, command, &command_info);
+ ASSERT_EQ(nos_device_write(dev, command, &command_info, sizeof(command_info)), 0);
+ }
+ // Let app process command
+ WaitForApp();
+ WaitForApp();
+ { // Check status
+ transport_status status;
+ const uint32_t command = CMD_ID(APP_ID_TRANSPORT_TEST) | CMD_IS_READ | CMD_TRANSPORT;
+ ASSERT_EQ(nos_device_read(dev, command, &status, sizeof(transport_status)), 0);
+ ASSERT_THAT(status, IsWorking());
+ }
+}
+
+TEST_F(TransportTest, CommandSuccess) {
+ { // Send "go" command
+ transport_command_info command_info = {};
+ command_info.length = sizeof(transport_command_info);
+ command_info.version = TRANSPORT_V1;
+ const uint32_t command = CMD_ID(APP_ID_TRANSPORT_TEST) | CMD_PARAM(TRANSPORT_TEST_NOP);
+ SetCommandInfoCrc(nullptr, 0, command, &command_info);
+ ASSERT_EQ(nos_device_write(dev, command, &command_info, sizeof(command_info)), 0);
+ }
+ // Let app process command
+ WaitForApp();
+ { // Check status
+ transport_status status;
+ const uint32_t command = CMD_ID(APP_ID_TRANSPORT_TEST) | CMD_IS_READ | CMD_TRANSPORT;
+ ASSERT_EQ(nos_device_read(dev, command, &status, sizeof(transport_status)), 0);
+ ASSERT_THAT(status, IsSuccess());
+ }
+}
+
+TEST_F(TransportTest, CommandSuccessWithData) {
+ uint8_t data[4];
+ { // Send "go" command
+ transport_command_info command_info = {};
+ command_info.length = sizeof(transport_command_info);
+ command_info.version = TRANSPORT_V1;
+ command_info.reply_len_hint = sizeof(data);
+ const uint32_t command = CMD_ID(APP_ID_TRANSPORT_TEST) | CMD_PARAM(TRANSPORT_TEST_1234);
+ SetCommandInfoCrc(nullptr, 0, command, &command_info);
+ ASSERT_EQ(nos_device_write(dev, command, &command_info, sizeof(command_info)), 0);
+ }
+ // Let app process command
+ WaitForApp();
+ { // Check status
+ transport_status status;
+ const uint32_t command = CMD_ID(APP_ID_TRANSPORT_TEST) | CMD_IS_READ | CMD_TRANSPORT;
+ ASSERT_EQ(nos_device_read(dev, command, &status, sizeof(transport_status)), 0);
+ ASSERT_EQ(status.reply_len, sizeof(data));
+
+ const uint32_t data_command = CMD_ID(APP_ID_TRANSPORT_TEST)
+ | CMD_IS_READ | CMD_IS_DATA | CMD_TRANSPORT;
+ ASSERT_EQ(nos_device_read(dev, data_command, data, sizeof(data)), 0);
+ ASSERT_THAT(status, IsSuccessWithData(data, sizeof(data)));
+ }
+}
+
+/* The crc is only calculated over the data the master will read. */
+TEST_F(TransportTest, CommandSuccessReplyLenHintRespected) {
+ constexpr uint16_t reply_len_hint = 2; // This is less than the actual response
+ { // Send "go" command
+ transport_command_info command_info = {};
+ command_info.length = sizeof(transport_command_info);
+ command_info.version = TRANSPORT_V1;
+ command_info.reply_len_hint = reply_len_hint;
+ const uint32_t command = CMD_ID(APP_ID_TRANSPORT_TEST) | CMD_PARAM(TRANSPORT_TEST_1234);
+ SetCommandInfoCrc(nullptr, 0, command, &command_info);
+ ASSERT_EQ(nos_device_write(dev, command, &command_info, sizeof(command_info)), 0);
+ }
+ // Let app process command
+ WaitForApp();
+ { // Check status
+ uint8_t data[4];
+ transport_status status;
+ const uint32_t command = CMD_ID(APP_ID_TRANSPORT_TEST) | CMD_IS_READ | CMD_TRANSPORT;
+ ASSERT_EQ(nos_device_read(dev, command, &status, sizeof(transport_status)), 0);
+ ASSERT_EQ(status.reply_len, reply_len_hint);
+
+ const uint32_t data_command = CMD_ID(APP_ID_TRANSPORT_TEST)
+ | CMD_IS_READ | CMD_IS_DATA | CMD_TRANSPORT;
+ ASSERT_EQ(nos_device_read(dev, data_command, data, reply_len_hint), 0);
+ // crc is only calculated over the data the master will read
+ ASSERT_THAT(status, IsSuccessWithData(data, reply_len_hint));
+ }
+}
+
+/* If there was a transmission error, need to be able to re-read data. */
+TEST_F(TransportTest, CommandSuccessRetryReadingData) {
+ uint8_t data[4];
+ { // Send "go" command
+ transport_command_info command_info = {};
+ command_info.length = sizeof(transport_command_info);
+ command_info.version = TRANSPORT_V1;
+ command_info.reply_len_hint = sizeof(data);
+ const uint32_t command = CMD_ID(APP_ID_TRANSPORT_TEST) | CMD_PARAM(TRANSPORT_TEST_1234);
+ SetCommandInfoCrc(nullptr, 0, command, &command_info);
+ ASSERT_EQ(nos_device_write(dev, command, &command_info, sizeof(command_info)), 0);
+ }
+ // Let app process command
+ WaitForApp();
+ { // Check status
+ transport_status status;
+ const uint32_t command = CMD_ID(APP_ID_TRANSPORT_TEST) | CMD_IS_READ | CMD_TRANSPORT;
+ ASSERT_EQ(nos_device_read(dev, command, &status, sizeof(transport_status)), 0);
+ ASSERT_EQ(status.reply_len, sizeof(data));
+
+ // This could happen if there was a crc error
+ for (int i = 0; i < 3; ++i) {
+ const uint32_t data_command = CMD_ID(APP_ID_TRANSPORT_TEST)
+ | CMD_IS_READ | CMD_IS_DATA | CMD_TRANSPORT;
+ ASSERT_EQ(nos_device_read(dev, data_command, data, sizeof(data)), 0);
+ ASSERT_THAT(status, IsSuccessWithData(data, sizeof(data)));
+ }
+ }
+}
+
+TEST_F(TransportTest, ClearStatusAfterSuccess) {
+ { // Send "go" command
+ transport_command_info command_info = {};
+ command_info.length = sizeof(transport_command_info);
+ command_info.version = TRANSPORT_V1;
+ const uint32_t command = CMD_ID(APP_ID_TRANSPORT_TEST) | CMD_PARAM(TRANSPORT_TEST_NOP);
+ SetCommandInfoCrc(nullptr, 0, command, &command_info);
+ ASSERT_EQ(nos_device_write(dev, command, &command_info, sizeof(command_info)), 0);
+ }
+ // Let app process command
+ WaitForApp();
+ { // Clear status
+ const uint32_t command = CMD_ID(APP_ID_TRANSPORT_TEST) | CMD_TRANSPORT;
+ ASSERT_EQ(nos_device_write(dev, command, nullptr, 0), 0);
+ }
+ { // Check status
+ transport_status status;
+ const uint32_t command = CMD_ID(APP_ID_TRANSPORT_TEST) | CMD_IS_READ | CMD_TRANSPORT;
+ ASSERT_EQ(nos_device_read(dev, command, &status, sizeof(transport_status)), 0);
+ ASSERT_THAT(status, IsIdle());
+ }
+}
+
+TEST_F(TransportTest, ClearStatusAfterError) {
+ { // Send "go" command
+ transport_command_info command_info = {};
+ command_info.length = sizeof(transport_command_info);
+ command_info.version = TRANSPORT_V1;
+ const uint32_t command = CMD_ID(APP_ID_TRANSPORT_TEST) | CMD_PARAM(0);
+ ASSERT_EQ(nos_device_write(dev, command, &command_info, sizeof(command_info)), 0);
+ }
+ // Let app process command
+ WaitForApp();
+ { // Clear status
+ const uint32_t command = CMD_ID(APP_ID_TRANSPORT_TEST) | CMD_TRANSPORT;
+ ASSERT_EQ(nos_device_write(dev, command, nullptr, 0), 0);
+ }
+ { // Check status
+ transport_status status;
+ const uint32_t command = CMD_ID(APP_ID_TRANSPORT_TEST) | CMD_IS_READ | CMD_TRANSPORT;
+ ASSERT_EQ(nos_device_read(dev, command, &status, sizeof(transport_status)), 0);
+ ASSERT_THAT(status, IsIdle());
+ }
+}
+
+TEST_F(TransportTest, SendArgumentData) {
+ const uint32_t data = 0x09080706;
+ { // Send data
+ uint32_t command = CMD_ID(APP_ID_TRANSPORT_TEST) | CMD_IS_DATA | CMD_TRANSPORT;
+ CMD_SET_PARAM(command, sizeof(data));
+ ASSERT_EQ(nos_device_write(dev, command, &data, sizeof(data)), 0);
+ }
+ { // Send "go" command
+ transport_command_info command_info = {};
+ command_info.length = sizeof(transport_command_info);
+ command_info.version = TRANSPORT_V1;
+ const uint32_t command = CMD_ID(APP_ID_TRANSPORT_TEST) | CMD_PARAM(TRANSPORT_TEST_9876);
+ SetCommandInfoCrc(&data, sizeof(data), command, &command_info);
+ ASSERT_EQ(nos_device_write(dev, command, &command_info, sizeof(command_info)), 0);
+ }
+ // Let app process command
+ WaitForApp();
+ { // Check status
+ transport_status status;
+ const uint32_t command = CMD_ID(APP_ID_TRANSPORT_TEST) | CMD_IS_READ | CMD_TRANSPORT;
+ ASSERT_EQ(nos_device_read(dev, command, &status, sizeof(transport_status)), 0);
+ ASSERT_THAT(status, IsSuccess());
+ }
+}
+
+/* Setting CMD_MORE_TO_COME appends new data. */
+TEST_F(TransportTest, SendArgumentDataInMultipleDatagrams) {
+ const uint32_t data = 0x09080706;
+ { // Send data1
+ const uint16_t data1 = 0x0706;
+ uint32_t command = CMD_ID(APP_ID_TRANSPORT_TEST) | CMD_IS_DATA | CMD_TRANSPORT;
+ CMD_SET_PARAM(command, sizeof(data1));
+ ASSERT_EQ(nos_device_write(dev, command, &data1, sizeof(data1)), 0);
+ }
+ { // Send data2
+ const uint16_t data2 = 0x0908;
+ uint32_t command = CMD_ID(APP_ID_TRANSPORT_TEST)
+ | CMD_IS_DATA | CMD_TRANSPORT | CMD_MORE_TO_COME;
+ CMD_SET_PARAM(command, sizeof(data2));
+ ASSERT_EQ(nos_device_write(dev, command, &data2, sizeof(data2)), 0);
+ }
+ { // Send "go" command
+ transport_command_info command_info = {};
+ command_info.length = sizeof(transport_command_info);
+ command_info.version = TRANSPORT_V1;
+ const uint32_t command = CMD_ID(APP_ID_TRANSPORT_TEST) | CMD_PARAM(TRANSPORT_TEST_9876);
+ SetCommandInfoCrc(&data, sizeof(data), command, &command_info);
+ ASSERT_EQ(nos_device_write(dev, command, &command_info, sizeof(command_info)), 0);
+ }
+ // Let app process command
+ WaitForApp();
+ { // Check status
+ transport_status status;
+ const uint32_t command = CMD_ID(APP_ID_TRANSPORT_TEST) | CMD_IS_READ | CMD_TRANSPORT;
+ ASSERT_EQ(nos_device_read(dev, command, &status, sizeof(transport_status)), 0);
+ ASSERT_THAT(status, IsSuccess());
+ }
+}
+
+/* Not setting the CMD_MORE_TO_COME flag overwrites rather than appends. */
+TEST_F(TransportTest, SendWrongArgumentDataByRestarting) {
+ const uint32_t data = 0x09080706;
+ { // Send data1
+ const uint16_t data1 = 0x0706;
+ uint32_t command = CMD_ID(APP_ID_TRANSPORT_TEST) | CMD_IS_DATA | CMD_TRANSPORT;
+ CMD_SET_PARAM(command, sizeof(data1));
+ ASSERT_EQ(nos_device_write(dev, command, &data1, sizeof(data1)), 0);
+ }
+ { // Send data2, restarting the args
+ const uint16_t data2 = 0x0908;
+ uint32_t command = CMD_ID(APP_ID_TRANSPORT_TEST) | CMD_IS_DATA | CMD_TRANSPORT;
+ CMD_SET_PARAM(command, sizeof(data2));
+ ASSERT_EQ(nos_device_write(dev, command, &data2, sizeof(data2)), 0);
+ }
+ { // Send "go" command
+ transport_command_info command_info = {};
+ command_info.length = sizeof(transport_command_info);
+ command_info.version = TRANSPORT_V1;
+ const uint32_t command = CMD_ID(APP_ID_TRANSPORT_TEST) | CMD_PARAM(TRANSPORT_TEST_9876);
+ SetCommandInfoCrc(&data, sizeof(data), command, &command_info);
+ ASSERT_EQ(nos_device_write(dev, command, &command_info, sizeof(command_info)), 0);
+ }
+ // Let app process command
+ WaitForApp();
+ { // Check status, bad crc as the args data is wrong
+ transport_status status;
+ const uint32_t command = CMD_ID(APP_ID_TRANSPORT_TEST) | CMD_IS_READ | CMD_TRANSPORT;
+ ASSERT_EQ(nos_device_read(dev, command, &status, sizeof(transport_status)), 0);
+ ASSERT_THAT(status, IsBadCrc());
+ }
+}
+
+/* Not setting the CMD_MORE_TO_COME flag clears previous data. */
+TEST_F(TransportTest, SendArgumentDataInMultipleDatagramsWithRestart) {
+ const uint32_t data = 0x09080706;
+ { // Send data1
+ const uint8_t spam[6] = {12, 46, 123, 63, 23, 75};
+ uint32_t command = CMD_ID(APP_ID_TRANSPORT_TEST) | CMD_IS_DATA | CMD_TRANSPORT;
+ CMD_SET_PARAM(command, sizeof(spam));
+ ASSERT_EQ(nos_device_write(dev, command, spam, sizeof(spam)), 0);
+ }
+ { // Send data1, restarting the args
+ const uint16_t data1 = 0x0706;
+ uint32_t command = CMD_ID(APP_ID_TRANSPORT_TEST) | CMD_IS_DATA | CMD_TRANSPORT;
+ CMD_SET_PARAM(command, sizeof(data1));
+ ASSERT_EQ(nos_device_write(dev, command, &data1, sizeof(data1)), 0);
+ }
+ { // Send data2
+ const uint16_t data2 = 0x0908;
+ uint32_t command = CMD_ID(APP_ID_TRANSPORT_TEST)
+ | CMD_IS_DATA | CMD_TRANSPORT | CMD_MORE_TO_COME;
+ CMD_SET_PARAM(command, sizeof(data2));
+ ASSERT_EQ(nos_device_write(dev, command, &data2, sizeof(data2)), 0);
+ }
+ { // Send "go" command
+ transport_command_info command_info = {};
+ command_info.length = sizeof(transport_command_info);
+ command_info.version = TRANSPORT_V1;
+ const uint32_t command = CMD_ID(APP_ID_TRANSPORT_TEST) | CMD_PARAM(TRANSPORT_TEST_9876);
+ SetCommandInfoCrc(&data, sizeof(data), command, &command_info);
+ ASSERT_EQ(nos_device_write(dev, command, &command_info, sizeof(command_info)), 0);
+ }
+ // Let app process command
+ WaitForApp();
+ { // Check status
+ transport_status status;
+ const uint32_t command = CMD_ID(APP_ID_TRANSPORT_TEST) | CMD_IS_READ | CMD_TRANSPORT;
+ ASSERT_EQ(nos_device_read(dev, command, &status, sizeof(transport_status)), 0);
+ ASSERT_THAT(status, IsSuccess());
+ }
+}
+
+// Forward compatibility
+
+/* New command info fields may be add in future versions. The crc is still
+ * calculated over them to ensure data integrity but, otherwise, the values are
+ * ignored. */
+TEST_F(TransportTest, NewCommandInfoIsIgnored) {
+ { // Send "go" command
+ union {
+ transport_command_info info;
+ uint8_t buffer[COMMAND_INFO_MAX_LENGTH];
+ } command_info = {};
+ memset(command_info.buffer, 0x48, COMMAND_INFO_MAX_LENGTH);
+ command_info.info.length = COMMAND_INFO_MAX_LENGTH;
+ command_info.info.version = TRANSPORT_V1;
+ const uint32_t command = CMD_ID(APP_ID_TRANSPORT_TEST) | CMD_PARAM(TRANSPORT_TEST_NOP);
+ // CRC is still calculated over all the data but new fields aren't used
+ SetCommandInfoCrc(nullptr, 0, command, &command_info, sizeof(command_info));
+ ASSERT_EQ(nos_device_write(dev, command, &command_info, sizeof(command_info)), 0);
+ }
+ // Let app process command
+ WaitForApp();
+ { // Check status
+ transport_status status;
+ const uint32_t command = CMD_ID(APP_ID_TRANSPORT_TEST) | CMD_IS_READ | CMD_TRANSPORT;
+ ASSERT_EQ(nos_device_read(dev, command, &status, sizeof(transport_status)), 0);
+ ASSERT_THAT(status, IsSuccess());
+ }
+}
+
+/* If the protocol adds more data to the command info datagram, it is not
+ * included in the crc. */
+TEST_F(TransportTest, CommandCrcOnlyCoversCommandInfoStruct) {
+ { // Send "go" command
+ union {
+ transport_command_info info;
+ /* The extra byte should not be included in the crc */
+ uint8_t buffer[COMMAND_INFO_MAX_LENGTH + 1];
+ } command_info = {};
+ command_info.info.length = COMMAND_INFO_MAX_LENGTH;
+ command_info.info.version = TRANSPORT_V1;
+ const uint32_t command = CMD_ID(APP_ID_TRANSPORT_TEST) | CMD_PARAM(0);
+ SetCommandInfoCrc(nullptr, 0, command, &command_info, sizeof(command_info));
+ ASSERT_EQ(nos_device_write(dev, command, &command_info, sizeof(command_info)), 0);
+ }
+ // Let app process command
+ WaitForApp();
+ { // Check status
+ transport_status status;
+ const uint32_t command = CMD_ID(APP_ID_TRANSPORT_TEST) | CMD_IS_READ | CMD_TRANSPORT;
+ ASSERT_EQ(nos_device_read(dev, command, &status, sizeof(transport_status)), 0);
+ ASSERT_THAT(status, IsBadCrc());
+ }
+}
+
+/* Future protocol updates may require more command info data which will be
+ * added after the COMMAND_INFO_MAX_LENGTH bytes currently reserved for the
+ * command info struct. The extra data should be ignored to allow for
+ * compatibility with such an upgrade. */
+TEST_F(TransportTest, NewCommandInfoStructIsIgnored) {
+ { // Send "go" command
+ union {
+ transport_command_info info;
+ struct {
+ uint8_t info[COMMAND_INFO_MAX_LENGTH];
+ uint8_t new_struct[48];
+ } buffer;
+ } command_info = {};
+ memset(command_info.buffer.info, 0xB6, COMMAND_INFO_MAX_LENGTH);
+ memset(command_info.buffer.new_struct, 0x19, sizeof(command_info.buffer.new_struct));
+ command_info.info.length = COMMAND_INFO_MAX_LENGTH;
+ command_info.info.version = TRANSPORT_V1;
+ const uint32_t command = CMD_ID(APP_ID_TRANSPORT_TEST) | CMD_PARAM(TRANSPORT_TEST_NOP);
+ // CRC is still calculated over all the data but new fields aren't used
+ SetCommandInfoCrc(nullptr, 0, command, &command_info, sizeof(command_info));
+ ASSERT_EQ(nos_device_write(dev, command, &command_info, sizeof(command_info)), 0);
+ }
+ // Let app process command
+ WaitForApp();
+ { // Check status
+ transport_status status;
+ const uint32_t command = CMD_ID(APP_ID_TRANSPORT_TEST) | CMD_IS_READ | CMD_TRANSPORT;
+ ASSERT_EQ(nos_device_read(dev, command, &status, sizeof(transport_status)), 0);
+ ASSERT_THAT(status, IsSuccess());
+ }
+}
+
+// Backward compatibility
+
+/* V0 does not send any checksums or command info */
+TEST_F(TransportTest, CompatibleWithV0) {
+ { // Send data
+ uint8_t data[4] = {23, 54, 133, 249};
+ uint32_t command = CMD_ID(APP_ID_TRANSPORT_TEST) | CMD_IS_DATA | CMD_TRANSPORT;
+ CMD_SET_PARAM(command, sizeof(data));
+ ASSERT_EQ(nos_device_write(dev, command, &data, sizeof(data)), 0);
+ }
+ { // Check status
+ transport_status status;
+ const uint32_t command = CMD_ID(APP_ID_TRANSPORT_TEST) | CMD_IS_READ | CMD_TRANSPORT;
+ ASSERT_EQ(nos_device_read(dev, command, &status, sizeof(transport_status)), 0);
+ ASSERT_THAT(status, IsIdle());
+ }
+ { // Send "go" command (without command info or crc)
+ const uint32_t command = CMD_ID(APP_ID_TRANSPORT_TEST) | CMD_PARAM(TRANSPORT_TEST_NOP);
+ ASSERT_EQ(nos_device_write(dev, command, nullptr, 0), 0);
+ }
+ // Let app process command
+ WaitForApp();
+ { // Check status
+ transport_status status;
+ const uint32_t command = CMD_ID(APP_ID_TRANSPORT_TEST) | CMD_IS_READ | CMD_TRANSPORT;
+ ASSERT_EQ(nos_device_read(dev, command, &status, sizeof(transport_status)), 0);
+ ASSERT_THAT(status, IsSuccess());
+ }
+}
+
+} // namespace
diff --git a/tools/keymaster_tools.cc b/tools/keymaster_tools.cc
index 68697c9..b91a52b 100644
--- a/tools/keymaster_tools.cc
+++ b/tools/keymaster_tools.cc
@@ -43,4 +43,21 @@
avb_tools::BootloaderDone(client);
}
+void SetBootState(nos::NuggetClientInterface *client)
+{
+
+ // Do keymaster setup that is normally executed by the bootloader.
+ avb_tools::SetBootloader(client);
+
+ SetBootStateRequest request;
+ SetBootStateResponse response;
+ Keymaster service(*client);
+ request.set_public_key(string(32, '\0'));
+ request.set_boot_hash(string(32, '\0'));
+ ASSERT_NO_ERROR(service.SetBootState(request, &response), "");
+ EXPECT_EQ((ErrorCode)response.error_code(), ErrorCode::OK);
+
+ avb_tools::BootloaderDone(client);
+}
+
} // namespace keymaster_tools
diff --git a/tools/keymaster_tools.h b/tools/keymaster_tools.h
index 2b659cd..39715b9 100644
--- a/tools/keymaster_tools.h
+++ b/tools/keymaster_tools.h
@@ -13,6 +13,7 @@
namespace keymaster_tools {
void SetRootOfTrust(nos::NuggetClientInterface *client);
+void SetBootState(nos::NuggetClientInterface *client);
} // namespace keymaster_tools
diff --git a/tools/nugget_tools.cc b/tools/nugget_tools.cc
index 3a692fc..36466d6 100644
--- a/tools/nugget_tools.cc
+++ b/tools/nugget_tools.cc
@@ -31,6 +31,16 @@
namespace nugget_tools {
+bool IsDirectDeviceClient() {
+#ifdef ANDROID
+ nos::NuggetClient client;
+ client.Open();
+ return client.IsOpen();
+#else
+ return true;
+#endif
+}
+
std::string GetCitadelUSBSerialNo() {
#ifdef ANDROID
return "";
@@ -62,6 +72,17 @@
#endif
}
+std::unique_ptr<nos::NuggetClient> MakeDirectNuggetClient() {
+#ifdef ANDROID
+ std::unique_ptr<nos::NuggetClient> client =
+ std::unique_ptr<nos::NuggetClient>(new nos::NuggetClient());
+ return client;
+#else
+ return std::unique_ptr<nos::NuggetClient>(
+ new nos::NuggetClient(GetCitadelUSBSerialNo()));
+#endif
+}
+
bool CyclesSinceBoot(nos::NuggetClientInterface *client, uint32_t *cycles) {
std::vector<uint8_t> buffer;
buffer.reserve(sizeof(uint32_t));
@@ -95,6 +116,16 @@
stats.time_spent_in_deep_sleep);
}
+bool RebootNuggetUnchecked(nos::NuggetClientInterface *client) {
+ std::vector<uint8_t> ignored;
+ if (client->CallApp(APP_ID_NUGGET, NUGGET_PARAM_REBOOT, ignored,
+ nullptr) != app_status::APP_SUCCESS) {
+ LOG(ERROR) << "CallApp(..., NUGGET_PARAM_REBOOT, ...) failed!\n";
+ return false;
+ }
+ return true;
+}
+
bool RebootNugget(nos::NuggetClientInterface *client) {
struct nugget_app_low_power_stats stats0;
struct nugget_app_low_power_stats stats1;
@@ -113,12 +144,7 @@
auto start = high_resolution_clock::now();
// Tell Nugget OS to reboot
- std::vector<uint8_t> ignored;
- if (client->CallApp(APP_ID_NUGGET, NUGGET_PARAM_REBOOT, ignored,
- nullptr) != app_status::APP_SUCCESS) {
- LOG(ERROR) << "CallApp(..., NUGGET_PARAM_REBOOT, ...) failed!\n";
- return false;
- }
+ if (!RebootNuggetUnchecked(client)) return false;
// Grab stats after sleeping
buffer.empty();
diff --git a/tools/nugget_tools.h b/tools/nugget_tools.h
index 1db4c0c..11c46e8 100644
--- a/tools/nugget_tools.h
+++ b/tools/nugget_tools.h
@@ -4,7 +4,7 @@
#include <app_nugget.h>
#include <application.h>
#include <nos/debug.h>
-#include <nos/NuggetClientInterface.h>
+#include <nos/NuggetClient.h>
#include <memory>
#include <string>
@@ -18,11 +18,17 @@
namespace nugget_tools {
+bool IsDirectDeviceClient();
+
std::string GetCitadelUSBSerialNo();
std::unique_ptr<nos::NuggetClientInterface> MakeNuggetClient();
+std::unique_ptr<nos::NuggetClient> MakeDirectNuggetClient();
+
// Always does a hard reboot. Use WaitForSleep() if you just want deep sleep.
+bool RebootNuggetUnchecked(nos::NuggetClientInterface *client);
+// Does a hard reboot and checks the stats to make sure it happened.
bool RebootNugget(nos::NuggetClientInterface *client);
// Returns true if Citadel entered deep sleep