Implemented tests for Certificate Provisioning Protocol.
-- Implemented unit level tests (TestCertProv).
-- Implemented Mock CA Service for testing purposes.
-- Implemented Certificate Provisioning Client to mimic
the client (certificate request initiator) behavior.
-- Implemented Certificate Provisioning Service to mimic
the CA Service (responder to the certificate request) behavior.
diff --git a/src/lib/profiles/security/WeaveCert.cpp b/src/lib/profiles/security/WeaveCert.cpp
index 26f84be..39edc62 100644
--- a/src/lib/profiles/security/WeaveCert.cpp
+++ b/src/lib/profiles/security/WeaveCert.cpp
@@ -49,8 +49,6 @@
using namespace nl::Weave::Profiles;
using namespace nl::Weave::Crypto;
-extern WEAVE_ERROR DecodeConvertTBSCert(TLVReader& reader, ASN1Writer& writer, WeaveCertificateData& certData);
-
#if HAVE_MALLOC && HAVE_FREE
static void *DefaultAlloc(size_t size)
{
diff --git a/src/lib/profiles/security/WeaveCert.h b/src/lib/profiles/security/WeaveCert.h
index 862b2fe..d12001e 100644
--- a/src/lib/profiles/security/WeaveCert.h
+++ b/src/lib/profiles/security/WeaveCert.h
@@ -42,6 +42,7 @@
using nl::Weave::TLV::TLVReader;
using nl::Weave::TLV::TLVWriter;
+using nl::Weave::ASN1::ASN1Writer;
using nl::Weave::ASN1::OID;
using nl::Weave::Crypto::EncodedECPublicKey;
using nl::Weave::Crypto::EncodedECPrivateKey;
@@ -295,6 +296,8 @@
extern WEAVE_ERROR DecodeWeaveDN(TLVReader& reader, WeaveDN& dn);
+extern WEAVE_ERROR DecodeConvertTBSCert(TLVReader& reader, ASN1Writer& writer, WeaveCertificateData& certData);
+
extern WEAVE_ERROR ConvertX509CertToWeaveCert(const uint8_t *x509Cert, uint32_t x509CertLen, uint8_t *weaveCertBuf, uint32_t weaveCertBufSize, uint32_t& weaveCertLen);
extern WEAVE_ERROR ConvertWeaveCertToX509Cert(const uint8_t *weaveCert, uint32_t weaveCertLen, uint8_t *x509CertBuf, uint32_t x509CertBufSize, uint32_t& x509CertLen);
diff --git a/src/lib/support/WeaveSupport.am b/src/lib/support/WeaveSupport.am
index a35366a..220839b 100644
--- a/src/lib/support/WeaveSupport.am
+++ b/src/lib/support/WeaveSupport.am
@@ -58,6 +58,7 @@
@top_builddir@/src/lib/support/crypto/HashAlgos-OpenSSL.cpp \
@top_builddir@/src/lib/support/crypto/HashAlgos-MinCrypt.cpp \
@top_builddir@/src/lib/support/crypto/HashAlgos-mbedTLS.cpp \
+ @top_builddir@/src/lib/support/crypto/RSA.cpp \
@top_builddir@/src/lib/support/crypto/WeaveCrypto.cpp \
@top_builddir@/src/lib/support/crypto/WeaveCrypto-OpenSSL.cpp \
@top_builddir@/src/lib/support/crypto/WeaveRNG-OpenSSL.cpp \
diff --git a/src/test-apps/.gitignore b/src/test-apps/.gitignore
index a77e898..b63bfba 100644
--- a/src/test-apps/.gitignore
+++ b/src/test-apps/.gitignore
@@ -15,6 +15,7 @@
TestASN1
TestBinding
TestCASE
+TestCertProv
TestCodeUtils
TestCrypto
TestDataManagement
@@ -87,6 +88,8 @@
weave-bdx-server
weave-bdx-server-development
weave-bdx-server-v0
+weave-cert-prov-client
+weave-cert-prov-server
weave-connection-tunnel
weave-dd-client
weave-device-descriptor
diff --git a/src/test-apps/CASEOptions.cpp b/src/test-apps/CASEOptions.cpp
index 90531b8..296c46c 100644
--- a/src/test-apps/CASEOptions.cpp
+++ b/src/test-apps/CASEOptions.cpp
@@ -270,66 +270,6 @@
return true;
}
-bool CASEOptions::ReadCertFile(const char *fileName, uint8_t *& certBuf, uint16_t& certLen)
-{
- uint32_t len;
-
- static const char *certB64Prefix = "1QAABAAB";
- static const size_t certB64PrefixLen = sizeof(certB64Prefix) - 1;
-
- // Read the specified file into a malloced buffer.
- certBuf = ReadFileArg(fileName, len, UINT16_MAX);
- if (certBuf == NULL)
- return false;
-
- // If the certificate is in base-64 format, convert it to raw TLV.
- if (len > certB64PrefixLen && memcmp(certBuf, certB64Prefix, certB64PrefixLen) == 0)
- {
- len = nl::Base64Decode((const char *)certBuf, len, (uint8_t *)certBuf);
- if (len == UINT16_MAX)
- {
- printf("Invalid certificate format: %s\n", fileName);
- free(certBuf);
- certBuf = NULL;
- return false;
- }
- }
-
- certLen = (uint16_t)len;
-
- return true;
-}
-
-bool CASEOptions::ReadPrivateKeyFile(const char *fileName, uint8_t *& keyBuf, uint16_t& keyLen)
-{
- uint32_t len;
-
- static const char *keyB64Prefix = "1QAABAAC";
- static const size_t keyB64PrefixLen = sizeof(keyB64Prefix) - 1;
-
- // Read the specified file into a malloced buffer.
- keyBuf = ReadFileArg(fileName, len, UINT16_MAX);
- if (keyBuf == NULL)
- return false;
-
- // If the private key is in base-64 format, convert it to raw TLV.
- if (len > keyB64PrefixLen && memcmp(keyBuf, keyB64Prefix, keyB64PrefixLen) == 0)
- {
- len = nl::Base64Decode((const char *)keyBuf, len, (uint8_t *)keyBuf);
- if (len == UINT16_MAX)
- {
- printf("Invalid private key format: %s\n", fileName);
- free(keyBuf);
- keyBuf = NULL;
- return false;
- }
- }
-
- keyLen = (uint16_t)len;
-
- return true;
-}
-
WEAVE_ERROR CASEOptions::GetNodeCert(const uint8_t *& nodeCert, uint16_t & nodeCertLen)
{
nodeCert = NodeCert;
@@ -355,8 +295,8 @@
{
if (!GetTestNodePrivateKey(FabricState.LocalNodeId, weavePrivKey, weavePrivKeyLen))
{
- printf("ERROR: Node private key not configured\n");
- return WEAVE_ERROR_KEY_NOT_FOUND;
+ printf("ERROR: Node private key not configured\n");
+ return WEAVE_ERROR_KEY_NOT_FOUND;
}
}
return WEAVE_NO_ERROR;
diff --git a/src/test-apps/CASEOptions.h b/src/test-apps/CASEOptions.h
index 4ea4169..0b21aa6 100644
--- a/src/test-apps/CASEOptions.h
+++ b/src/test-apps/CASEOptions.h
@@ -73,9 +73,6 @@
virtual bool HandleOption(const char *progName, OptionSet *optSet, int id, const char *name, const char *arg) __OVERRIDE;
- static bool ReadCertFile(const char *fileName, uint8_t *& certBuf, uint16_t& certLen);
- static bool ReadPrivateKeyFile(const char *fileName, uint8_t *& keyBuf, uint16_t& keyLen);
-
#if !WEAVE_CONFIG_LEGACY_CASE_AUTH_DELEGATE
// ===== Methods that implement the WeaveCASEAuthDelegate interface
diff --git a/src/test-apps/CertProvOptions.cpp b/src/test-apps/CertProvOptions.cpp
new file mode 100644
index 0000000..90424fd
--- /dev/null
+++ b/src/test-apps/CertProvOptions.cpp
@@ -0,0 +1,1543 @@
+/*
+ *
+ * Copyright (c) 2019-2020 Google LLC.
+ * All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file
+ * Implementation of CertProvOptions object, which provides an implementation of the
+ * WeaveNodeOpAuthDelegate and WeaveNodeMfrAttestDelegate interfaces for use
+ * in test applications.
+ *
+ */
+
+#include "stdio.h"
+
+#include "ToolCommon.h"
+#include "TestWeaveCertData.h"
+#include <Weave/Support/CodeUtils.h>
+#include <Weave/Core/WeaveTLV.h>
+#include <Weave/Profiles/WeaveProfiles.h>
+#include <Weave/Profiles/security/WeaveSig.h>
+#include <Weave/Profiles/security/WeaveSecurityDebug.h>
+#include <Weave/Profiles/security/WeavePrivateKey.h>
+#include <Weave/Profiles/security/WeaveCertProvisioning.h>
+#include <Weave/Profiles/service-provisioning/ServiceProvisioning.h>
+#include <Weave/Support/TimeUtils.h>
+#include <Weave/Support/NestCerts.h>
+#include <Weave/Support/ErrorStr.h>
+#include <Weave/Support/ASN1.h>
+#include <Weave/Support/crypto/HashAlgos.h>
+#include "CertProvOptions.h"
+
+using namespace nl::Weave;
+using namespace nl::Weave::TLV;
+using namespace nl::Weave::ASN1;
+using namespace nl::Weave::Profiles;
+using namespace nl::Weave::Profiles::Security;
+using namespace nl::Weave::Profiles::Security::CertProvisioning;
+
+const uint8_t TestPairingToken[] =
+{
+ /*
+ -----BEGIN PAIRING TOKEN-----
+ 1QAABAAJADUBMAEITi8yS0HXOtskAgQ3AyyBEERVTU1ZLUFDQ09VTlQtSUQYJgTLqPobJgVLNU9C
+ NwYsgRBEVU1NWS1BQ0NPVU5ULUlEGCQHAiYIJQBaIzAKOQQr2dtaYu+6sVMqD5ljt4owxYpBKaUZ
+ TksL837axemzNfB1GG1JXYbERCUHQbTTqe/utCrWCl2d4DWDKQEYNYIpASQCBRg1hCkBNgIEAgQB
+ GBg1gTACCEI8lV9GHlLbGDWAMAIIQjyVX0YeUtsYNQwwAR0AimGGYj0XstLP0m05PeQlaeCR6gVq
+ dc7dReuDzzACHHS0K6RtFGW3t3GaWq9k0ohgbrOxoDHKkm/K8kMYGDUCJgElAFojMAIcuvzjT4a/
+ fDgScCv5oxC/T5vz7zAPpURNQjpnajADOQQr2dtaYu+6sVMqD5ljt4owxYpBKaUZTksL837axemz
+ NfB1GG1JXYbERCUHQbTTqe/utCrWCl2d4BgY
+ -----END PAIRING TOKEN-----
+ */
+ 0xd5, 0x00, 0x00, 0x04, 0x00, 0x09, 0x00, 0x35, 0x01, 0x30, 0x01, 0x08, 0x4e, 0x2f, 0x32, 0x4b,
+ 0x41, 0xd7, 0x3a, 0xdb, 0x24, 0x02, 0x04, 0x37, 0x03, 0x2c, 0x81, 0x10, 0x44, 0x55, 0x4d, 0x4d,
+ 0x59, 0x2d, 0x41, 0x43, 0x43, 0x4f, 0x55, 0x4e, 0x54, 0x2d, 0x49, 0x44, 0x18, 0x26, 0x04, 0xcb,
+ 0xa8, 0xfa, 0x1b, 0x26, 0x05, 0x4b, 0x35, 0x4f, 0x42, 0x37, 0x06, 0x2c, 0x81, 0x10, 0x44, 0x55,
+ 0x4d, 0x4d, 0x59, 0x2d, 0x41, 0x43, 0x43, 0x4f, 0x55, 0x4e, 0x54, 0x2d, 0x49, 0x44, 0x18, 0x24,
+ 0x07, 0x02, 0x26, 0x08, 0x25, 0x00, 0x5a, 0x23, 0x30, 0x0a, 0x39, 0x04, 0x2b, 0xd9, 0xdb, 0x5a,
+ 0x62, 0xef, 0xba, 0xb1, 0x53, 0x2a, 0x0f, 0x99, 0x63, 0xb7, 0x8a, 0x30, 0xc5, 0x8a, 0x41, 0x29,
+ 0xa5, 0x19, 0x4e, 0x4b, 0x0b, 0xf3, 0x7e, 0xda, 0xc5, 0xe9, 0xb3, 0x35, 0xf0, 0x75, 0x18, 0x6d,
+ 0x49, 0x5d, 0x86, 0xc4, 0x44, 0x25, 0x07, 0x41, 0xb4, 0xd3, 0xa9, 0xef, 0xee, 0xb4, 0x2a, 0xd6,
+ 0x0a, 0x5d, 0x9d, 0xe0, 0x35, 0x83, 0x29, 0x01, 0x18, 0x35, 0x82, 0x29, 0x01, 0x24, 0x02, 0x05,
+ 0x18, 0x35, 0x84, 0x29, 0x01, 0x36, 0x02, 0x04, 0x02, 0x04, 0x01, 0x18, 0x18, 0x35, 0x81, 0x30,
+ 0x02, 0x08, 0x42, 0x3c, 0x95, 0x5f, 0x46, 0x1e, 0x52, 0xdb, 0x18, 0x35, 0x80, 0x30, 0x02, 0x08,
+ 0x42, 0x3c, 0x95, 0x5f, 0x46, 0x1e, 0x52, 0xdb, 0x18, 0x35, 0x0c, 0x30, 0x01, 0x1d, 0x00, 0x8a,
+ 0x61, 0x86, 0x62, 0x3d, 0x17, 0xb2, 0xd2, 0xcf, 0xd2, 0x6d, 0x39, 0x3d, 0xe4, 0x25, 0x69, 0xe0,
+ 0x91, 0xea, 0x05, 0x6a, 0x75, 0xce, 0xdd, 0x45, 0xeb, 0x83, 0xcf, 0x30, 0x02, 0x1c, 0x74, 0xb4,
+ 0x2b, 0xa4, 0x6d, 0x14, 0x65, 0xb7, 0xb7, 0x71, 0x9a, 0x5a, 0xaf, 0x64, 0xd2, 0x88, 0x60, 0x6e,
+ 0xb3, 0xb1, 0xa0, 0x31, 0xca, 0x92, 0x6f, 0xca, 0xf2, 0x43, 0x18, 0x18, 0x35, 0x02, 0x26, 0x01,
+ 0x25, 0x00, 0x5a, 0x23, 0x30, 0x02, 0x1c, 0xba, 0xfc, 0xe3, 0x4f, 0x86, 0xbf, 0x7c, 0x38, 0x12,
+ 0x70, 0x2b, 0xf9, 0xa3, 0x10, 0xbf, 0x4f, 0x9b, 0xf3, 0xef, 0x30, 0x0f, 0xa5, 0x44, 0x4d, 0x42,
+ 0x3a, 0x67, 0x6a, 0x30, 0x03, 0x39, 0x04, 0x2b, 0xd9, 0xdb, 0x5a, 0x62, 0xef, 0xba, 0xb1, 0x53,
+ 0x2a, 0x0f, 0x99, 0x63, 0xb7, 0x8a, 0x30, 0xc5, 0x8a, 0x41, 0x29, 0xa5, 0x19, 0x4e, 0x4b, 0x0b,
+ 0xf3, 0x7e, 0xda, 0xc5, 0xe9, 0xb3, 0x35, 0xf0, 0x75, 0x18, 0x6d, 0x49, 0x5d, 0x86, 0xc4, 0x44,
+ 0x25, 0x07, 0x41, 0xb4, 0xd3, 0xa9, 0xef, 0xee, 0xb4, 0x2a, 0xd6, 0x0a, 0x5d, 0x9d, 0xe0, 0x18,
+ 0x18,
+};
+
+const uint16_t TestPairingTokenLength = sizeof(TestPairingToken);
+
+const uint8_t TestPairingInitData[] =
+{
+ 0x6E, 0x3C, 0x71, 0x5B, 0xE0, 0x19, 0xD4, 0x35, 0x83, 0x29, 0x01, 0x18, 0x35, 0x82, 0x29, 0x01,
+ 0x24, 0x02, 0x05, 0x18, 0x35, 0x84, 0x29, 0x01, 0x36, 0x02, 0x04, 0x02, 0x04, 0x01,
+};
+
+const uint16_t TestPairingInitDataLength = sizeof(TestPairingInitData);
+
+const uint32_t TestDevice1_MfrAttest_HMACKeyId = 0xCAFECAFE;
+
+const uint8_t TestDevice1_MfrAttest_HMACMetaData[] =
+{
+ 0x2a, 0xd6, 0x0a, 0x29, 0x01, 0x6E, 0x71, 0x29, 0x01, 0x18, 0x35
+};
+
+const uint16_t TestDevice1_MfrAttest_HMACMetaDataLength = sizeof(TestDevice1_MfrAttest_HMACMetaData);
+
+const uint8_t TestDevice1_MfrAttest_HMACKey[] =
+{
+ 0xd9, 0xdb, 0x5a, 0x62, 0xE0, 0x19, 0xD4, 0x35, 0x83, 0x29, 0x01, 0x18, 0x35, 0x82, 0x29, 0x01,
+ 0x24, 0x02, 0x05, 0x18, 0x36, 0x02, 0x04, 0x02, 0x04, 0x01, 0x29, 0x01, 0x0b, 0xf3, 0xa0, 0x31
+};
+
+const uint16_t TestDevice1_MfrAttest_HMACKeyLength = sizeof(TestDevice1_MfrAttest_HMACKey);
+
+DeviceCredentialsStore gDeviceCredsStore;
+
+CertProvOptions gCertProvOptions;
+
+DeviceCredentialsStore::DeviceCredentialsStore()
+{
+ mDeviceId = kNodeIdNotSpecified;
+ mDevicePrivateKeyLen = 0;
+ mDeviceCertLen = 0;
+ mDeviceICACertsLen = 0;
+}
+
+WEAVE_ERROR DeviceCredentialsStore::StoreDeviceCert(const uint8_t * cert, uint16_t certLen)
+{
+ WEAVE_ERROR err = WEAVE_NO_ERROR;
+
+ VerifyOrExit(cert != NULL, err = WEAVE_ERROR_INVALID_ARGUMENT);
+ VerifyOrExit(certLen <= sizeof(mDeviceCert), err = WEAVE_ERROR_BUFFER_TOO_SMALL);
+
+ memcpy(mDeviceCert, cert, certLen);
+ mDeviceCertLen = certLen;
+
+exit:
+ return err;
+}
+
+WEAVE_ERROR DeviceCredentialsStore::StoreDeviceICACerts(const uint8_t * certs, uint16_t certsLen)
+{
+ WEAVE_ERROR err = WEAVE_NO_ERROR;
+
+ VerifyOrExit(certs != NULL, err = WEAVE_ERROR_INVALID_ARGUMENT);
+ VerifyOrExit(certsLen <= sizeof(mDeviceICACerts), err = WEAVE_ERROR_BUFFER_TOO_SMALL);
+
+ memcpy(mDeviceICACerts, certs, certsLen);
+ mDeviceICACertsLen = certsLen;
+
+exit:
+ return err;
+}
+
+WEAVE_ERROR DeviceCredentialsStore::StoreDevicePrivateKey(const uint8_t * key, uint16_t keyLen)
+{
+ WEAVE_ERROR err = WEAVE_NO_ERROR;
+
+ VerifyOrExit(key != NULL, err = WEAVE_ERROR_INVALID_ARGUMENT);
+ VerifyOrExit(keyLen <= sizeof(mDevicePrivateKey), err = WEAVE_ERROR_BUFFER_TOO_SMALL);
+
+ memcpy(mDevicePrivateKey, key, keyLen);
+ mDevicePrivateKeyLen = keyLen;
+
+exit:
+ return err;
+}
+
+WEAVE_ERROR DeviceCredentialsStore::GetDeviceId(uint64_t & deviceId)
+{
+ WEAVE_ERROR err = WEAVE_NO_ERROR;
+
+ VerifyOrExit(mDeviceId != kNodeIdNotSpecified, err = WEAVE_ERROR_WRONG_NODE_ID);
+
+ deviceId = mDeviceId;
+
+exit:
+ return err;
+}
+
+WEAVE_ERROR DeviceCredentialsStore::GetDeviceCert(const uint8_t *& cert, uint16_t & certLen)
+{
+ WEAVE_ERROR err = WEAVE_NO_ERROR;
+
+ VerifyOrExit(mDeviceCertLen > 0, err = WEAVE_ERROR_CERT_NOT_FOUND);
+
+ cert = mDeviceCert;
+ certLen = mDeviceCertLen;
+
+exit:
+ return err;
+}
+
+WEAVE_ERROR DeviceCredentialsStore::GetDeviceICACerts(const uint8_t *& cert, uint16_t & certLen)
+{
+ WEAVE_ERROR err = WEAVE_NO_ERROR;
+
+ VerifyOrExit(mDeviceICACertsLen > 0, err = WEAVE_ERROR_CERT_NOT_FOUND);
+
+ cert = mDeviceICACerts;
+ certLen = mDeviceICACertsLen;
+
+exit:
+ return err;
+}
+
+WEAVE_ERROR DeviceCredentialsStore::GetDevicePrivateKey(const uint8_t *& key, uint16_t & keyLen)
+{
+ WEAVE_ERROR err = WEAVE_NO_ERROR;
+
+ VerifyOrExit(mDevicePrivateKeyLen > 0, err = WEAVE_ERROR_KEY_NOT_FOUND);
+
+ key = mDevicePrivateKey;
+ keyLen = mDevicePrivateKeyLen;
+
+exit:
+ return err;
+}
+
+void DeviceCredentialsStore::ClearDeviceId(void)
+{
+ mDeviceId = kNodeIdNotSpecified;
+}
+
+void DeviceCredentialsStore::ClearDeviceCert(void)
+{
+ ClearSecretData(mDeviceCert, sizeof(mDeviceCert));
+ mDeviceCertLen = 0;
+}
+
+void DeviceCredentialsStore::ClearDeviceICACerts(void)
+{
+ ClearSecretData(mDeviceICACerts, sizeof(mDeviceICACerts));
+ mDeviceICACertsLen = 0;
+}
+
+void DeviceCredentialsStore::ClearDevicePrivateKey(void)
+{
+ ClearSecretData(mDevicePrivateKey, sizeof(mDevicePrivateKey));
+ mDevicePrivateKeyLen = 0;
+}
+
+void DeviceCredentialsStore::ClearDeviceCredentials(void)
+{
+ ClearDeviceId();
+ ClearDeviceCert();
+ ClearDeviceICACerts();
+ ClearDevicePrivateKey();
+}
+
+bool DeviceCredentialsStore::DeviceIdExists(void)
+{
+ return (mDeviceId != kNodeIdNotSpecified);
+}
+
+bool DeviceCredentialsStore::DeviceCertExists(void)
+{
+ return (mDeviceCertLen > 0);
+}
+
+bool DeviceCredentialsStore::DeviceICACertsExists(void)
+{
+ return (mDeviceICACertsLen > 0);
+}
+
+bool DeviceCredentialsStore::DevicePrivateKeyExists(void)
+{
+ return (mDevicePrivateKeyLen > 0);
+}
+
+bool DeviceCredentialsStore::DeviceCredentialsExist(void)
+{
+ return (DeviceIdExists() && DeviceCertExists() && DevicePrivateKeyExists());
+}
+
+static WEAVE_ERROR GenerateDeviceECDSASignature(const uint8_t *hash, uint8_t hashLen, EncodedECDSASignature& ecdsaSig)
+{
+ WEAVE_ERROR err;
+ const uint8_t * key = NULL;
+ uint16_t keyLen;
+ uint32_t weaveCurveId;
+ EncodedECPrivateKey devicePrivKey;
+ EncodedECPublicKey devicePubKey;
+
+ err = gDeviceCredsStore.GetDevicePrivateKey(key, keyLen);
+ SuccessOrExit(err);
+
+ err = DecodeWeaveECPrivateKey(key, keyLen, weaveCurveId, devicePubKey, devicePrivKey);
+ SuccessOrExit(err);
+
+ err = nl::Weave::Crypto::GenerateECDSASignature(WeaveCurveIdToOID(weaveCurveId),
+ hash, hashLen, devicePrivKey, ecdsaSig);
+ SuccessOrExit(err);
+
+exit:
+ return err;
+}
+
+WEAVE_ERROR DeviceCredentialsStore::GenerateAndStoreDeviceCredentials(uint64_t deviceId)
+{
+ WEAVE_ERROR err;
+ uint8_t weaveKey[kWeaveDevicePrivateKeyBufSize];
+ uint32_t weaveKeyLen;
+ uint8_t weaveCert[kWeaveDeviceCertBufSize];
+ uint16_t weaveCertLen;
+ uint8_t privKey[EncodedECPrivateKey::kMaxValueLength];
+ uint8_t pubKey[EncodedECPublicKey::kMaxValueLength];
+ EncodedECPublicKey devicePubKey;
+ EncodedECPrivateKey devicePrivKey;
+
+ // If not specified, generate random device Id.
+ if (deviceId == kNodeIdNotSpecified)
+ {
+ err = GenerateWeaveNodeId(deviceId);
+ SuccessOrExit(err);
+ }
+
+ // Store generated device Id.
+ err = StoreDeviceId(deviceId);
+ SuccessOrExit(err);
+
+ devicePrivKey.PrivKey = privKey;
+ devicePrivKey.PrivKeyLen = sizeof(privKey);
+
+ devicePubKey.ECPoint = pubKey;
+ devicePubKey.ECPointLen = sizeof(pubKey);
+
+ // Generate random EC private/public key pair.
+ err = GenerateECDHKey(WeaveCurveIdToOID(WEAVE_CONFIG_OPERATIONAL_DEVICE_CERT_CURVE_ID), devicePubKey, devicePrivKey);
+ SuccessOrExit(err);
+
+ // Encode Weave device EC private/public key pair into EllipticCurvePrivateKey TLV structure.
+ err = EncodeWeaveECPrivateKey(WEAVE_CONFIG_OPERATIONAL_DEVICE_CERT_CURVE_ID, &devicePubKey, devicePrivKey,
+ weaveKey, sizeof(weaveKey), weaveKeyLen);
+ SuccessOrExit(err);
+
+ // Store generated device private key.
+ err = StoreDevicePrivateKey(weaveKey, weaveKeyLen);
+ SuccessOrExit(err);
+
+ // Generate self-signed operational device certificate.
+ err = GenerateOperationalDeviceCert(deviceId, devicePubKey, weaveCert, sizeof(weaveCert), weaveCertLen, GenerateDeviceECDSASignature);
+ SuccessOrExit(err);
+
+ // Store generated device certificate.
+ err = StoreDeviceCert(weaveCert, weaveCertLen);
+ SuccessOrExit(err);
+
+exit:
+ if (err != WEAVE_NO_ERROR)
+ {
+ ClearDeviceCredentials();
+ }
+ return err;
+}
+
+WEAVE_ERROR DeviceCredentialsStore::GenerateAndReplaceCurrentDeviceCert(void)
+{
+ WEAVE_ERROR err;
+ const uint8_t * currentCert;
+ uint16_t currentCertLen;
+ uint8_t cert[kWeaveDeviceCertBufSize];
+ uint16_t certLen;
+ uint8_t icaCert[kWeaveDeviceCertBufSize];
+ uint16_t icaCertLen;
+ WeaveCertificateSet certSet;
+ bool certSetInitialized = false;
+ WeaveCertificateData *certData = NULL;
+
+ // Get current certificate data.
+ {
+ err = GetDeviceCert(currentCert, currentCertLen);
+ SuccessOrExit(err);
+
+ err = certSet.Init(1, nl::TestCerts::kTestCertBufSize);
+ SuccessOrExit(err);
+
+ certSetInitialized = true;
+
+ // Load Weave operational device certificate.
+ err = certSet.LoadCert(currentCert, currentCertLen, kDecodeFlag_GenerateTBSHash, certData);
+ SuccessOrExit(err);
+ }
+
+ // Generate service assigned test device certificate.
+ err = GenerateTestDeviceCert(certData->SubjectDN.AttrValue.WeaveId, certData->PublicKey.EC,
+ cert, sizeof(cert), certLen);
+ SuccessOrExit(err);
+
+ err = StoreDeviceCert(cert, certLen);
+ SuccessOrExit(err);
+
+ // Write test intermediate CA certificate in a Weave TLV array form.
+ {
+ TLVWriter writer;
+ TLVType containerType;
+
+ writer.Init(icaCert, sizeof(icaCert));
+
+ err = writer.StartContainer(ProfileTag(kWeaveProfile_Security, kTag_WeaveCertificateList), kTLVType_Array, containerType);
+ SuccessOrExit(err);
+
+ err = writer.CopyContainer(AnonymousTag, nl::NestCerts::Development::DeviceCA::Cert, nl::NestCerts::Development::DeviceCA::CertLength);
+ SuccessOrExit(err);
+
+ err = writer.EndContainer(containerType);
+ SuccessOrExit(err);
+
+ err = writer.Finalize();
+ SuccessOrExit(err);
+
+ icaCertLen = writer.GetLengthWritten();
+ }
+
+ err = StoreDeviceICACerts(icaCert, icaCertLen);
+ SuccessOrExit(err);
+
+exit:
+ if (certSetInitialized)
+ certSet.Release();
+
+ return err;
+}
+
+NL_DLL_EXPORT WEAVE_ERROR GenerateTestDeviceCert(uint64_t deviceId, EncodedECPublicKey& devicePubKey,
+ uint8_t *cert, uint16_t certBufSize, uint16_t& certLen)
+{
+ return GenerateTestDeviceCert(deviceId, devicePubKey,
+ nl::TestCerts::sTestCert_CA_Weave, nl::TestCerts::sTestCertLength_CA_Weave,
+ nl::TestCerts::sTestCert_CA_PrivateKey_Weave, nl::TestCerts::sTestCertLength_CA_PrivateKey_Weave,
+ cert, certBufSize, certLen);
+}
+
+NL_DLL_EXPORT WEAVE_ERROR GenerateTestDeviceCert(uint64_t deviceId, EncodedECPublicKey& devicePubKey,
+ const uint8_t *caCert, uint16_t caCertLen,
+ const uint8_t *caKey, uint16_t caKeyLen,
+ uint8_t *cert, uint16_t certBufSize, uint16_t& certLen)
+{
+ WEAVE_ERROR err;
+ TLVWriter writer;
+ TLVType containerType;
+ TLVType containerType2;
+ TLVType containerType3;
+ uint8_t *certDecodeBuf = NULL;
+ WeaveCertificateSet certSet;
+ bool certSetInitialized = false;
+ WeaveCertificateData *caCertData = NULL;
+ WeaveCertificateData *certData = NULL;
+
+ VerifyOrExit(devicePubKey.ECPoint != NULL, err = WEAVE_ERROR_INVALID_ARGUMENT);
+ VerifyOrExit(caCert != NULL, err = WEAVE_ERROR_INVALID_ARGUMENT);
+ VerifyOrExit(caKey != NULL, err = WEAVE_ERROR_INVALID_ARGUMENT);
+ VerifyOrExit(cert != NULL, err = WEAVE_ERROR_INVALID_ARGUMENT);
+
+ // Get CA certificate data.
+ {
+ err = certSet.Init(1, nl::TestCerts::kTestCertBufSize);
+ SuccessOrExit(err);
+
+ certSetInitialized = true;
+
+ // Load Weave operational device certificate.
+ err = certSet.LoadCert(caCert, caCertLen, kDecodeFlag_GenerateTBSHash, caCertData);
+ SuccessOrExit(err);
+ }
+
+ writer.Init(cert, certBufSize);
+
+ err = writer.StartContainer(ProfileTag(kWeaveProfile_Security, kTag_WeaveCertificate), kTLVType_Structure, containerType);
+ SuccessOrExit(err);
+
+ // Certificate serial number.
+ {
+ enum
+ {
+ kCertSerialNumber_Length = 8, // Length of the certificate serial number.
+ kCertSerialNumber_FirstByteMask = 0x7F, // Mask applied on the first byte of the key Id value.
+ kCertSerialNumber_FirstBytePrefix = 0x40, // 4-bit Type value (0100) added at the beginning of the key Id value.
+ };
+ uint8_t certSerialNumber[kCertSerialNumber_Length];
+
+ // Generate a random value to be used as the serial number.
+ err = nl::Weave::Platform::Security::GetSecureRandomData(certSerialNumber, kCertSerialNumber_Length);
+ SuccessOrExit(err);
+
+ // Apply mask to avoid negative numbers.
+ certSerialNumber[0] &= kCertSerialNumber_FirstByteMask;
+
+ // Apply mask to guarantee the first byte is not zero.
+ certSerialNumber[0] |= kCertSerialNumber_FirstBytePrefix;
+
+ err = writer.PutBytes(ContextTag(kTag_SerialNumber), certSerialNumber, sizeof(certSerialNumber));
+ SuccessOrExit(err);
+ }
+
+ // Weave signature algorithm.
+ err = writer.Put(ContextTag(kTag_SignatureAlgorithm), static_cast<uint8_t>(kOID_SigAlgo_ECDSAWithSHA256 & ~kOIDCategory_Mask));
+ SuccessOrExit(err);
+
+ // Certificate issuer Id.
+ {
+ err = writer.StartContainer(ContextTag(kTag_Issuer), kTLVType_Path, containerType2);
+ SuccessOrExit(err);
+
+ err = writer.Put(ContextTag(kOID_AttributeType_WeaveDeviceId & kOID_Mask), caCertData->SubjectDN.AttrValue.WeaveId);
+ SuccessOrExit(err);
+
+ err = writer.EndContainer(containerType2);
+ SuccessOrExit(err);
+ }
+
+ // Certificate validity times.
+ err = writer.Put(ContextTag(kTag_NotBefore), PackedCertDateToTime(WEAVE_CONFIG_OP_DEVICE_CERT_VALID_DATE_NOT_BEFORE));
+ SuccessOrExit(err);
+
+ // Certificate validity period is 10 year.
+ err = writer.Put(ContextTag(kTag_NotAfter), PackedCertDateToTime(WEAVE_CONFIG_OP_DEVICE_CERT_VALID_DATE_NOT_BEFORE + (10 * 12 * 31)));
+ SuccessOrExit(err);
+
+ // Certificate subject Id.
+ {
+ err = writer.StartContainer(ContextTag(kTag_Subject), kTLVType_Path, containerType2);
+ SuccessOrExit(err);
+
+ err = writer.Put(ContextTag(kOID_AttributeType_WeaveDeviceId & kOID_Mask), deviceId);
+ SuccessOrExit(err);
+
+ err = writer.EndContainer(containerType2);
+ SuccessOrExit(err);
+ }
+
+ // EC public key algorithm.
+ err = writer.Put(ContextTag(kTag_PublicKeyAlgorithm), static_cast<uint8_t>(kOID_PubKeyAlgo_ECPublicKey & kOID_Mask));
+ SuccessOrExit(err);
+
+ // EC public key curve Id.
+ err = writer.Put(ContextTag(kTag_EllipticCurveIdentifier), static_cast<uint32_t>(WEAVE_CONFIG_OPERATIONAL_DEVICE_CERT_CURVE_ID));
+ SuccessOrExit(err);
+
+ // EC public key.
+ err = writer.PutBytes(ContextTag(kTag_EllipticCurvePublicKey), devicePubKey.ECPoint, devicePubKey.ECPointLen);
+ SuccessOrExit(err);
+
+ // Certificate extension: basic constraints.
+ {
+ err = writer.StartContainer(ContextTag(kTag_BasicConstraints), kTLVType_Structure, containerType2);
+ SuccessOrExit(err);
+
+ // This extension is critical.
+ err = writer.PutBoolean(ContextTag(kTag_BasicConstraints_Critical), true);
+ SuccessOrExit(err);
+
+ err = writer.EndContainer(containerType2);
+ SuccessOrExit(err);
+ }
+
+ // Certificate extension: key usage.
+ {
+ err = writer.StartContainer(ContextTag(kTag_KeyUsage), kTLVType_Structure, containerType2);
+ SuccessOrExit(err);
+
+ // This extension is critical.
+ err = writer.PutBoolean(ContextTag(kTag_KeyUsage_Critical), true);
+ SuccessOrExit(err);
+
+ err = writer.Put(ContextTag(kTag_KeyUsage_KeyUsage), static_cast<uint16_t>(kKeyUsageFlag_DigitalSignature | kKeyUsageFlag_KeyEncipherment));
+ SuccessOrExit(err);
+
+ err = writer.EndContainer(containerType2);
+ SuccessOrExit(err);
+ }
+
+ // Certificate extension: extended key usage.
+ {
+ err = writer.StartContainer(ContextTag(kTag_ExtendedKeyUsage), kTLVType_Structure, containerType2);
+ SuccessOrExit(err);
+
+ // This extension is critical.
+ err = writer.PutBoolean(ContextTag(kTag_ExtendedKeyUsage_Critical), true);
+ SuccessOrExit(err);
+
+ err = writer.StartContainer(ContextTag(kTag_ExtendedKeyUsage_KeyPurposes), kTLVType_Array, containerType3);
+ SuccessOrExit(err);
+
+ // Key purpose is client authentication.
+ err = writer.Put(AnonymousTag, static_cast<uint8_t>(kOID_KeyPurpose_ClientAuth & kOID_Mask));
+ SuccessOrExit(err);
+
+ // Key purpose is server authentication.
+ err = writer.Put(AnonymousTag, static_cast<uint8_t>(kOID_KeyPurpose_ServerAuth & kOID_Mask));
+ SuccessOrExit(err);
+
+ err = writer.EndContainer(containerType3);
+ SuccessOrExit(err);
+
+ err = writer.EndContainer(containerType2);
+ SuccessOrExit(err);
+ }
+
+ // Certificate extension: subject key identifier.
+ {
+ /* Use "truncated" SHA-1 hash. Per RFC5280:
+ *
+ * "(2) The keyIdentifier is composed of a four-bit type field with the value 0100 followed
+ * by the least significant 60 bits of the SHA-1 hash of the value of the BIT STRING
+ * subjectPublicKey (excluding the tag, length, and number of unused bits)."
+ */
+ enum
+ {
+ kCertKeyId_Length = 8, // Length of the certificate key identifier.
+ kCertKeyId_FirstByte = nl::Weave::Platform::Security::SHA1::kHashLength - kCertKeyId_Length,
+ // First byte of the SHA1 hash that used to generate certificate keyId.
+ kCertKeyId_FirstByteMask = 0x0F, // Mask applied on the first byte of the key Id value.
+ kCertKeyId_FirstBytePrefix = 0x40, // 4-bit Type value (0100) added at the beginning of the key Id value.
+ };
+ nl::Weave::Platform::Security::SHA1 sha1;
+ uint8_t hash[nl::Weave::Platform::Security::SHA1::kHashLength];
+ uint8_t *certKeyId = &hash[kCertKeyId_FirstByte];
+
+ sha1.Begin();
+ sha1.AddData(devicePubKey.ECPoint, devicePubKey.ECPointLen);
+ sha1.Finish(hash);
+
+ certKeyId[0] &= kCertKeyId_FirstByteMask;
+ certKeyId[0] |= kCertKeyId_FirstBytePrefix;
+
+ err = writer.StartContainer(ContextTag(kTag_SubjectKeyIdentifier), kTLVType_Structure, containerType2);
+ SuccessOrExit(err);
+
+ err = writer.PutBytes(ContextTag(kTag_SubjectKeyIdentifier_KeyIdentifier), certKeyId, kCertKeyId_Length);
+ SuccessOrExit(err);
+
+ err = writer.EndContainer(containerType2);
+ SuccessOrExit(err);
+ }
+
+ // Certificate extension: authority key identifier.
+ {
+ err = writer.StartContainer(ContextTag(kTag_AuthorityKeyIdentifier), kTLVType_Structure, containerType2);
+ SuccessOrExit(err);
+
+ err = writer.PutBytes(ContextTag(kTag_AuthorityKeyIdentifier_KeyIdentifier), caCertData->SubjectKeyId.Id, caCertData->SubjectKeyId.Len);
+ SuccessOrExit(err);
+
+ err = writer.EndContainer(containerType2);
+ SuccessOrExit(err);
+ }
+
+ // Start the ECDSASignature structure.
+ // Note that the ECDSASignature tag is added here but the actual certificate data (S and R values)
+ // will be written later. This is needed to prevent DecodeConvertTBSCert() function from failing.
+ // This function expects to read new non-hashable element after all TBS data is converted.
+ err = writer.StartContainer(ContextTag(kTag_ECDSASignature), kTLVType_Structure, containerType2);
+ SuccessOrExit(err);
+
+ {
+ enum
+ {
+ kCertDecodeBufferSize = 1024, // Maximum ASN1 encoded size of the operational device certificate.
+ };
+ TLVReader reader;
+ ASN1Writer tbsWriter;
+ TLVType readContainerType;
+
+ reader.Init(cert, certBufSize);
+
+ // Parse the beginning of the WeaveSignature structure.
+ err = reader.Next(kTLVType_Structure, ProfileTag(kWeaveProfile_Security, kTag_WeaveCertificate));
+ SuccessOrExit(err);
+
+ // Enter the certificate structure.
+ err = reader.EnterContainer(readContainerType);
+ SuccessOrExit(err);
+
+ // Allocate decode memory buffer.
+ certDecodeBuf = static_cast<uint8_t *>(nl::Weave::Platform::Security::MemoryAlloc(kCertDecodeBufferSize));
+ VerifyOrExit(certDecodeBuf != NULL, err = WEAVE_ERROR_NO_MEMORY);
+
+ // Allocate certificate data structure.
+ certData = static_cast<WeaveCertificateData *>(nl::Weave::Platform::Security::MemoryAlloc(sizeof(WeaveCertificateData)));
+ VerifyOrExit(certData != NULL, err = WEAVE_ERROR_NO_MEMORY);
+
+ // Initialize an ASN1Writer and convert the TBS (to-be-signed) portion of
+ // the certificate to ASN.1 DER encoding.
+ tbsWriter.Init(certDecodeBuf, kCertDecodeBufferSize);
+ err = DecodeConvertTBSCert(reader, tbsWriter, *certData);
+ SuccessOrExit(err);
+
+ // Finish writing the ASN.1 DER encoding of the TBS certificate.
+ err = tbsWriter.Finalize();
+ SuccessOrExit(err);
+
+ // Generate a SHA hash of the encoded TBS certificate.
+ nl::Weave::Platform::Security::SHA256 sha256;
+ sha256.Begin();
+ sha256.AddData(certDecodeBuf, tbsWriter.GetLengthWritten());
+ sha256.Finish(certData->TBSHash);
+
+ uint32_t caCurveId;
+ EncodedECPublicKey caPubKey;
+ EncodedECPrivateKey caPrivKey;
+
+ // Decode the CA private key.
+ err = DecodeWeaveECPrivateKey(caKey, caKeyLen, caCurveId, caPubKey, caPrivKey);
+ SuccessOrExit(err);
+
+ // Reuse already allocated decode buffer to hold the generated signature value.
+ EncodedECDSASignature ecdsaSig;
+ ecdsaSig.R = certDecodeBuf;
+ ecdsaSig.RLen = EncodedECDSASignature::kMaxValueLength;
+ ecdsaSig.S = certDecodeBuf + EncodedECDSASignature::kMaxValueLength;
+ ecdsaSig.SLen = EncodedECDSASignature::kMaxValueLength;
+
+ // Generate an ECDSA signature for the given message hash.
+ err = nl::Weave::Crypto::GenerateECDSASignature(WeaveCurveIdToOID(caCurveId), certData->TBSHash, nl::Weave::Platform::Security::SHA256::kHashLength, caPrivKey, ecdsaSig);
+ SuccessOrExit(err);
+
+ // Write the R value.
+ err = writer.PutBytes(ContextTag(kTag_ECDSASignature_r), ecdsaSig.R, ecdsaSig.RLen);
+ SuccessOrExit(err);
+
+ // Write the S value.
+ err = writer.PutBytes(ContextTag(kTag_ECDSASignature_s), ecdsaSig.S, ecdsaSig.SLen);
+ SuccessOrExit(err);
+ }
+
+ err = writer.EndContainer(containerType2);
+ SuccessOrExit(err);
+
+ err = writer.EndContainer(containerType);
+ SuccessOrExit(err);
+
+ err = writer.Finalize();
+ SuccessOrExit(err);
+
+ certLen = static_cast<uint16_t>(writer.GetLengthWritten());
+
+exit:
+ if (certDecodeBuf != NULL)
+ nl::Weave::Platform::Security::MemoryFree(certDecodeBuf);
+
+ if (certSetInitialized)
+ certSet.Release();
+
+ return err;
+}
+
+WEAVE_ERROR ValidateWeaveDeviceCert(WeaveCertificateSet & certSet)
+{
+ WEAVE_ERROR err;
+ WeaveCertificateData * cert = certSet.Certs;
+ bool isSelfSigned = cert->IssuerDN.IsEqual(cert->SubjectDN);
+ enum { kLastSecondOfDay = nl::kSecondsPerDay - 1 };
+
+ // Verify that the certificate of device type.
+ VerifyOrExit(cert->CertType == kCertType_Device, err = WEAVE_ERROR_WRONG_CERT_TYPE);
+
+ // Verify correct subject attribute.
+ VerifyOrExit(cert->SubjectDN.AttrOID == ASN1::kOID_AttributeType_WeaveDeviceId, err = WEAVE_ERROR_WRONG_CERT_SUBJECT);
+
+ // Verify that the key usage extension exists in the certificate and that the corresponding usages are supported.
+ VerifyOrExit((cert->CertFlags & kCertFlag_ExtPresent_KeyUsage) != 0 &&
+ (cert->KeyUsageFlags == (kKeyUsageFlag_DigitalSignature | kKeyUsageFlag_KeyEncipherment)),
+ err = WEAVE_ERROR_CERT_USAGE_NOT_ALLOWED);
+
+ // Verify the validity time of the certificate.
+ {
+ uint32_t effectiveTime;
+ ASN1UniversalTime effectiveTimeASN1 = {
+ .Year = 2020,
+ .Month = 01,
+ .Day = 01,
+ .Hour = 00,
+ .Minute = 00,
+ .Second = 00
+ };
+ err = PackCertTime(effectiveTimeASN1, effectiveTime);
+ SuccessOrExit(err);
+
+ VerifyOrExit(effectiveTime >= PackedCertDateToTime(cert->NotBeforeDate), err = WEAVE_ERROR_CERT_NOT_VALID_YET);
+
+ VerifyOrExit(effectiveTime <= PackedCertDateToTime(cert->NotAfterDate) + kLastSecondOfDay, err = WEAVE_ERROR_CERT_EXPIRED);
+ }
+
+ // Verify that a hash of the 'to-be-signed' portion of the certificate has been computed. We will need this to
+ // verify the cert's signature below.
+ VerifyOrExit((cert->CertFlags & kCertFlag_TBSHashPresent) != 0, err = WEAVE_ERROR_INVALID_ARGUMENT);
+
+ // Verify correct public key algorithm.
+ VerifyOrExit(cert->PubKeyAlgoOID == kOID_PubKeyAlgo_ECPublicKey, err = WEAVE_ERROR_INVALID_ARGUMENT);
+
+ // Verify correct key purpose.
+ VerifyOrExit(cert->KeyPurposeFlags == (kKeyPurposeFlag_ServerAuth | kKeyPurposeFlag_ClientAuth), err = WEAVE_ERROR_INVALID_ARGUMENT);
+
+ // Verify correct EC curve.
+ VerifyOrExit((cert->PubKeyCurveId == kWeaveCurveId_prime256v1) ||
+ (cert->PubKeyCurveId == kWeaveCurveId_secp224r1), err = WEAVE_ERROR_UNSUPPORTED_ELLIPTIC_CURVE);
+
+ if (isSelfSigned)
+ {
+ // Verify that the certificate is self-signed.
+ VerifyOrExit(cert->AuthKeyId.IsEqual(cert->SubjectKeyId), err = WEAVE_ERROR_WRONG_CERT_SUBJECT);
+
+ // Verify the signature algorithm.
+ VerifyOrExit(cert->SigAlgoOID == kOID_SigAlgo_ECDSAWithSHA256, err = WEAVE_ERROR_WRONG_CERT_SIGNATURE_ALGORITHM);
+
+ // Verify certificate signature.
+ err = VerifyECDSASignature(WeaveCurveIdToOID(cert->PubKeyCurveId),
+ cert->TBSHash, SHA256::kHashLength,
+ cert->Signature.EC, cert->PublicKey.EC);
+ SuccessOrExit(err);
+ }
+ else
+ {
+ CertificateKeyId caKeyId;
+ EncodedECPublicKey caPublicKey;
+ OID caCurveOID;
+ uint8_t tbsHashLen;
+
+ if (cert->IssuerDN.AttrValue.WeaveId == nl::NestCerts::Development::DeviceCA::CAId)
+ {
+ caKeyId.Id = nl::NestCerts::Development::DeviceCA::SubjectKeyId;
+ caKeyId.Len = static_cast<uint8_t>(nl::NestCerts::Development::DeviceCA::SubjectKeyIdLength);
+
+ caPublicKey.ECPoint = const_cast<uint8_t *>(nl::NestCerts::Development::DeviceCA::PublicKey);
+ caPublicKey.ECPointLen = static_cast<uint16_t>(nl::NestCerts::Development::DeviceCA::PublicKeyLength);
+
+ caCurveOID = WeaveCurveIdToOID(nl::NestCerts::Development::DeviceCA::CurveOID);
+ }
+ else if (cert->IssuerDN.AttrValue.WeaveId == nl::TestCerts::sTestCert_CA_Id)
+ {
+ caKeyId.Id = nl::TestCerts::sTestCert_CA_SubjectKeyId;
+ caKeyId.Len = nl::TestCerts::sTestCertLength_CA_SubjectKeyId;
+
+ caPublicKey.ECPoint = const_cast<uint8_t *>(nl::TestCerts::sTestCert_CA_PublicKey);
+ caPublicKey.ECPointLen = static_cast<uint16_t>(nl::TestCerts::sTestCertLength_CA_PublicKey);
+
+ caCurveOID = WeaveCurveIdToOID(nl::TestCerts::sTestCert_CA_CurveId);
+ }
+ else
+ {
+ ExitNow(err = WEAVE_ERROR_WRONG_CERT_SUBJECT);
+ }
+
+ // Verify that the certificate is signed by the device CA.
+ VerifyOrExit(cert->AuthKeyId.IsEqual(caKeyId), err = WEAVE_ERROR_WRONG_CERT_SUBJECT);
+
+ // Verify the signature algorithm.
+ VerifyOrExit((cert->SigAlgoOID == kOID_SigAlgo_ECDSAWithSHA256) ||
+ (cert->SigAlgoOID == kOID_SigAlgo_ECDSAWithSHA1), err = WEAVE_ERROR_WRONG_CERT_SIGNATURE_ALGORITHM);
+
+ tbsHashLen = ((cert->SigAlgoOID == kOID_SigAlgo_ECDSAWithSHA256) ? static_cast<uint8_t>(SHA256::kHashLength) : static_cast<uint8_t>(SHA1::kHashLength));
+
+ // Verify certificate signature.
+ err = VerifyECDSASignature(caCurveOID, cert->TBSHash, tbsHashLen, cert->Signature.EC, caPublicKey);
+ SuccessOrExit(err);
+ }
+
+exit:
+ return err;
+}
+
+/**
+ * Handler for Certificate Provisioning Client API events.
+ *
+ * @param[in] appState A pointer to application-defined state information associated with the client object.
+ * @param[in] eventType Event ID passed by the event callback.
+ * @param[in] inParam Reference of input event parameters passed by the event callback.
+ * @param[in] outParam Reference of output event parameters passed by the event callback.
+ *
+ */
+void CertProvOptions::CertProvClientEventHandler(void * appState, WeaveCertProvEngine::EventType eventType,
+ const WeaveCertProvEngine::InEventParam & inParam, WeaveCertProvEngine::OutEventParam & outParam)
+{
+ WEAVE_ERROR err = WEAVE_NO_ERROR;
+ WeaveCertificateSet certSet;
+ bool certSetInitialized = false;
+ CertProvOptions * certProvOptions = static_cast<CertProvOptions *>(appState);
+ WeaveCertProvEngine * certProvEngine = inParam.Source;
+ Binding *binding = certProvEngine->GetBinding();
+ uint64_t peerNodeId;
+ IPAddress peerAddr;
+ uint16_t peerPort;
+ InterfaceId peerInterfaceId;
+
+ if (binding != NULL)
+ {
+ peerNodeId = binding->GetPeerNodeId();
+ binding->GetPeerIPAddress(peerAddr, peerPort, peerInterfaceId);
+ }
+
+ switch (eventType)
+ {
+ case WeaveCertProvEngine::kEvent_PrepareAuthorizeInfo:
+ {
+ if (binding != NULL)
+ WeaveLogDetail(SecurityManager, "WeaveCertProvEngine::kEvent_PrepareAuthorizeInfo; to node %" PRIX64 " (%s)", peerNodeId, peerAddr);
+ else
+ WeaveLogDetail(SecurityManager, "WeaveCertProvEngine::kEvent_PrepareAuthorizeInfo");
+
+ if (certProvOptions->IncludeAuthorizeInfo)
+ {
+ TLVWriter * writer = inParam.PrepareAuthorizeInfo.Writer;
+
+ // Pairing Token.
+ err = writer->PutBytes(ContextTag(kTag_GetCertReqMsg_Authorize_PairingToken), certProvOptions->PairingToken, certProvOptions->PairingTokenLen);
+ SuccessOrExit(err);
+
+ // Pairing Initialization Data.
+ err = writer->PutBytes(ContextTag(kTag_GetCertReqMsg_Authorize_PairingInitData), certProvOptions->PairingInitData, certProvOptions->PairingInitDataLen);
+ SuccessOrExit(err);
+ }
+ break;
+ }
+
+ case WeaveCertProvEngine::kEvent_ResponseReceived:
+ {
+ if (inParam.ResponseReceived.ReplaceCert)
+ {
+ enum
+ {
+ kMaxCerts = 4, // Maximum number of certificates in the certificate verification chain.
+ kCertDecodeBufSize = 1024, // Size of buffer needed to hold any of the test certificates
+ // (in either Weave or DER form), or to decode the certificates.
+ };
+ WeaveCertificateData *certData;
+ const uint8_t * cert = inParam.ResponseReceived.Cert;
+ uint16_t certLen = inParam.ResponseReceived.CertLen;
+ const uint8_t * relatedCerts = inParam.ResponseReceived.RelatedCerts;
+ uint16_t relatedCertsLen = inParam.ResponseReceived.RelatedCertsLen;
+
+ if (binding != NULL)
+ WeaveLogDetail(SecurityManager, "WeaveCertProvEngine::kEvent_ResponseReceived; from node %" PRIX64 " (%s)", peerNodeId, peerAddr);
+ else
+ WeaveLogDetail(SecurityManager, "WeaveCertProvEngine::kEvent_ResponseReceived");
+
+ // This certificate validation step is added for testing purposes only.
+ // In reality, device doesn't have to validate certificate issued by the CA service.
+ {
+ err = certSet.Init(kMaxCerts, kCertDecodeBufSize);
+ SuccessOrExit(err);
+
+ certSetInitialized = true;
+
+ err = certSet.LoadCert(cert, certLen, kDecodeFlag_GenerateTBSHash, certData);
+ SuccessOrExit(err);
+
+ if (relatedCerts != NULL)
+ {
+ err = certSet.LoadCerts(relatedCerts, relatedCertsLen, kDecodeFlag_GenerateTBSHash);
+ SuccessOrExit(err);
+ }
+
+ err = ValidateWeaveDeviceCert(certSet);
+ SuccessOrExit(err);
+ }
+
+ // Store service assigned operational device certificate.
+ err = gDeviceCredsStore.StoreDeviceCert(cert, certLen);
+ SuccessOrExit(err);
+
+ // Store service assigned device intermediate CA certificates.
+ if (relatedCerts != NULL)
+ {
+ err = gDeviceCredsStore.StoreDeviceICACerts(relatedCerts, relatedCertsLen);
+ SuccessOrExit(err);
+ }
+ }
+ else
+ {
+ if (binding != NULL)
+ WeaveLogDetail(SecurityManager, "WeaveCertProvEngine::kEvent_ResponseReceived; received status report from node %" PRIX64 " (%s): "
+ "No Need to Replace Operational Device Certificate", peerNodeId, peerAddr);
+ else
+ WeaveLogDetail(SecurityManager, "WeaveCertProvEngine::kEvent_ResponseReceived; received status report: No Need to Replace Operational Device Certificate");
+ }
+
+ certProvEngine->AbortCertificateProvisioning();
+
+ break;
+ }
+
+ case WeaveCertProvEngine::kEvent_CommunicationError:
+ {
+ if (inParam.CommunicationError.Reason == WEAVE_ERROR_STATUS_REPORT_RECEIVED)
+ {
+ if (binding != NULL)
+ WeaveLogError(SecurityManager, "WeaveCertProvEngine::kEvent_CommunicationError; received status report from node %" PRIX64 " (%s): %s", peerNodeId, peerAddr,
+ nl::StatusReportStr(inParam.CommunicationError.RcvdStatusReport->mProfileId, inParam.CommunicationError.RcvdStatusReport->mStatusCode));
+ else
+ WeaveLogError(SecurityManager, "WeaveCertProvEngine::kEvent_CommunicationError; received status report: %s",
+ nl::StatusReportStr(inParam.CommunicationError.RcvdStatusReport->mProfileId, inParam.CommunicationError.RcvdStatusReport->mStatusCode));
+ }
+ else
+ {
+ if (binding != NULL)
+ WeaveLogError(SecurityManager, "WeaveCertProvEngine::kEvent_CommunicationError with node %" PRIX64 " (%s): %s",
+ peerNodeId, peerAddr, ErrorStr(inParam.CommunicationError.Reason));
+ else
+ WeaveLogError(SecurityManager, "WeaveCertProvEngine::kEvent_CommunicationError: %s",
+ ErrorStr(inParam.CommunicationError.Reason));
+ }
+
+ certProvEngine->AbortCertificateProvisioning();
+
+ break;
+ }
+
+ default:
+ if (binding != NULL)
+ WeaveLogError(SecurityManager, "WeaveCertProvEngine: unrecognized API event with node %" PRIX64 " (%s)", peerNodeId, peerAddr);
+ else
+ WeaveLogError(SecurityManager, "WeaveCertProvEngine: unrecognized API event");
+ break;
+ }
+
+exit:
+ if (eventType == WeaveCertProvEngine::kEvent_PrepareAuthorizeInfo)
+ outParam.PrepareAuthorizeInfo.Error = err;
+ else if (eventType == WeaveCertProvEngine::kEvent_ResponseReceived)
+ outParam.ResponseReceived.Error = err;
+
+ if (certSetInitialized)
+ certSet.Release();
+}
+
+bool ParseGetCertReqType(const char *str, uint8_t& output)
+{
+ int reqType;
+
+ if (!ParseInt(str, reqType))
+ return false;
+
+ switch (reqType)
+ {
+ case 1:
+ output = WeaveCertProvEngine::kReqType_GetInitialOpDeviceCert;
+ return true;
+ case 2:
+ output = WeaveCertProvEngine::kReqType_RotateOpDeviceCert;
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool ParseMfrAttestType(const char *str, uint8_t& output)
+{
+ int maType;
+
+ if (!ParseInt(str, maType))
+ return false;
+
+ switch (maType)
+ {
+ case 1:
+ output = kMfrAttestType_WeaveCert;
+ return true;
+ case 2:
+ output = kMfrAttestType_X509Cert;
+ return true;
+ case 3:
+ output = kMfrAttestType_HMAC;
+ return true;
+ default:
+ return false;
+ }
+}
+
+CertProvOptions::CertProvOptions()
+{
+ static OptionDef optionDefs[] =
+ {
+ { "get-cert-req-type", kArgumentRequired, kToolCommonOpt_GetCertReqType },
+ { "pairing-token", kArgumentRequired, kToolCommonOpt_PairingToken },
+ { "send-auth-info", kNoArgument, kToolCommonOpt_SendAuthorizeInfo },
+ { "op-cert", kArgumentRequired, kToolCommonOpt_OpCert },
+ { "op-key", kArgumentRequired, kToolCommonOpt_OpKey },
+ { "op-ca-cert", kArgumentRequired, kToolCommonOpt_OpICACerts },
+ { "send-op-ca-cert", kNoArgument, kToolCommonOpt_SendOpICACerts },
+ { "ma-type", kArgumentRequired, kToolCommonOpt_MfrAttestType },
+ { "ma-node-id", kArgumentRequired, kToolCommonOpt_MfrAttestNodeId },
+ { "ma-cert", kArgumentRequired, kToolCommonOpt_MfrAttestCert },
+ { "ma-key", kArgumentRequired, kToolCommonOpt_MfrAttestKey },
+ { "ma-ca-cert", kArgumentRequired, kToolCommonOpt_MfrAttestICACert1 },
+ { "ma-ca-cert2", kArgumentRequired, kToolCommonOpt_MfrAttestICACert2 },
+ { "send-ma-ca-cert", kNoArgument, kToolCommonOpt_SendMfrAttestICACerts },
+ { NULL }
+ };
+ OptionDefs = optionDefs;
+
+ HelpGroupName = "CERTIFICATE PROVISIONING OPTIONS";
+
+ OptionHelp =
+ " --get-cert-req-type <int>\n"
+ " Get Certificate Request type. If not specified the default value is used.\n"
+ " Valid values are:\n"
+ " 1 - get initial operational certificate (default).\n"
+ " 2 - rotate operational certificate.\n"
+ "\n"
+ " --pairing-token <pairing-token-file>\n"
+ " File containing a Weave Pairing Token to be used to authorize the certificate\n"
+ " provisioning request. If not specified the default test pairing token is used.\n"
+ "\n"
+ " --send-auth-info\n"
+ " Include an authorization information in the Get Certificate Request message.\n"
+ "\n"
+ " --op-cert <cert-file>\n"
+ " File containing a Weave Operational certificate to be used to authenticate the node\n"
+ " when establishing a CASE session. The file can contain either raw TLV or\n"
+ " base-64. If not specified the default test certificate is used.\n"
+ "\n"
+ " --op-key <key-file>\n"
+ " File containing an Operational private key to be used to authenticate the node's\n"
+ " when establishing a CASE session. The file can contain either raw TLV or\n"
+ " base-64. If not specified the default test key is used.\n"
+ "\n"
+ " --op-ca-cert <cert-file>\n"
+ " File containing a Weave Operational CA certificate to be included along with the\n"
+ " node's Operational certificate in the Get Certificat Request message. The file can contain\n"
+ " either raw TLV or base-64. If not specified the default test CA certificate is used.\n"
+ "\n"
+ " --send-op-ca-cert\n"
+ " Include a Weave Operational CA certificate in the Get Certificat Request message.\n"
+ " This option is set automatically when op-ca-cert is specified.\n"
+ "\n"
+ " --ma-type <int>\n"
+ " Device Manufacturer Attestation type. If not specified the default value is used.\n"
+ " Supported options are:\n"
+ " 1 - Weave certificate (default).\n"
+ " 2 - X509 RSA certificate.\n"
+ " 3 - HMAC Attestation.\n"
+ "\n"
+ " --ma-node-id <int>\n"
+ " Device Manufacturer Attestation node id. If not specified the default test device #1\n"
+ " node id is used.\n"
+ "\n"
+ " --ma-cert <cert-file>\n"
+ " File containing a Weave Manufacturer Attestation certificate to be used to authenticate\n"
+ " the node's manufacturer. The file can contain either raw TLV or base-64. If not\n"
+ " specified the default test certificate is used.\n"
+ "\n"
+ " --ma-key <key-file>\n"
+ " File containing a Manufacturer Attestation private key to be used to authenticate\n"
+ " the node's manufacturer. The file can contain either raw TLV orbase-64. If not\n"
+ " specified the default test key is used.\n"
+ "\n"
+ " --ma-ca-cert <cert-file>\n"
+ " File containing a Weave Manufacturer Attestation CA certificate to be included along\n"
+ " with the node's Manufacturer Attestation certificate in the Get Certificat Request\n"
+ " message. The file can contain either raw TLV or base-64. If not specified the default\n"
+ " test CA certificate is used.\n"
+ "\n"
+ " --ma-ca-cert2 <cert-file>\n"
+ " File containing a Weave Manufacturer Attestation second CA certificate to be included along\n"
+ " with the node's Manufacturer Attestation certificate in the Get Certificat Request\n"
+ " message. The file can contain either raw TLV or base-64. If not specified the default\n"
+ " test CA certificate is used.\n"
+ "\n"
+ " --send-ma-ca-cert\n"
+ " Include a Weave Manufacturer Attestation CA certificate in the Get Certificat Request message.\n"
+ " This option is set automatically when ma-ca-cert is specified.\n"
+ "";
+
+ // Defaults
+ DeviceId = kNodeIdNotSpecified;
+ RequestType = WeaveCertProvEngine::kReqType_GetInitialOpDeviceCert;
+ IncludeAuthorizeInfo = false;
+ PairingToken = TestPairingToken;
+ PairingTokenLen = TestPairingTokenLength;
+ PairingInitData = TestPairingInitData;
+ PairingInitDataLen = TestPairingInitDataLength;
+ OperationalCert = NULL;
+ OperationalCertLen = 0;
+ OperationalPrivateKey = NULL;
+ OperationalPrivateKeyLen = 0;
+ IncludeOperationalICACerts = false;
+ OperationalICACerts = NULL;
+ OperationalICACertsLen = 0;
+ MfrAttestType = kMfrAttestType_WeaveCert;
+ MfrAttestDeviceId = TestDevice1_NodeId;
+ MfrAttestCert = NULL;
+ MfrAttestCertLen = 0;
+ MfrAttestPrivateKey = NULL;
+ MfrAttestPrivateKeyLen = 0;
+ IncludeMfrAttestICACerts = false;
+ MfrAttestICACert1 = NULL;
+ MfrAttestICACert1Len = 0;
+ MfrAttestICACert2 = NULL;
+ MfrAttestICACert2Len = 0;
+}
+
+bool CertProvOptions::HandleOption(const char *progName, OptionSet *optSet, int id, const char *name, const char *arg)
+{
+ uint32_t len;
+
+ switch (id)
+ {
+ case kToolCommonOpt_GetCertReqType:
+ if (!ParseGetCertReqType(arg, RequestType))
+ {
+ PrintArgError("%s: Invalid value specified for GetCertificate request type: %s\n", progName, arg);
+ return false;
+ }
+ break;
+
+ case kToolCommonOpt_PairingToken:
+ PairingToken = ReadFileArg(arg, len);
+ if (PairingToken == NULL)
+ return false;
+ PairingTokenLen = len;
+ break;
+
+ case kToolCommonOpt_PairingInitData:
+ PairingInitData = ReadFileArg(arg, len);
+ if (PairingInitData == NULL)
+ return false;
+ PairingInitDataLen = len;
+ break;
+
+ case kToolCommonOpt_SendAuthorizeInfo:
+ IncludeAuthorizeInfo = true;
+ break;
+
+ case kToolCommonOpt_OpCert:
+ if (!ReadCertFile(arg, (uint8_t *&)OperationalCert, OperationalCertLen))
+ return false;
+ break;
+
+ case kToolCommonOpt_OpKey:
+ if (!ReadPrivateKeyFile(arg, (uint8_t *&)OperationalPrivateKey, OperationalPrivateKeyLen))
+ return false;
+ break;
+
+ case kToolCommonOpt_OpICACerts:
+ if (!ReadCertFile(arg, (uint8_t *&)OperationalICACerts, OperationalICACertsLen))
+ return false;
+ break;
+
+ case kToolCommonOpt_SendOpICACerts:
+ IncludeOperationalICACerts = true;
+ break;
+
+ case kToolCommonOpt_MfrAttestType:
+ if (!ParseMfrAttestType(arg, MfrAttestType))
+ {
+ PrintArgError("%s: Invalid value specified for manufacturer attestation type: %s\n", progName, arg);
+ return false;
+ }
+ break;
+
+ case kToolCommonOpt_MfrAttestNodeId:
+ if (!ParseNodeId(arg, MfrAttestDeviceId))
+ {
+ PrintArgError("%s: Invalid value specified for manufacturer attestation node id: %s\n", progName, arg);
+ return false;
+ }
+ break;
+
+ case kToolCommonOpt_MfrAttestCert:
+ if (!ReadCertFile(arg, (uint8_t *&)MfrAttestCert, MfrAttestCertLen))
+ return false;
+ break;
+
+ case kToolCommonOpt_MfrAttestKey:
+ if (!ReadPrivateKeyFile(arg, (uint8_t *&)MfrAttestPrivateKey, MfrAttestPrivateKeyLen))
+ return false;
+ break;
+
+ case kToolCommonOpt_MfrAttestICACert1:
+ if (!ReadCertFile(arg, (uint8_t *&)MfrAttestICACert1, MfrAttestICACert1Len))
+ return false;
+ break;
+
+ case kToolCommonOpt_MfrAttestICACert2:
+ if (!ReadCertFile(arg, (uint8_t *&)MfrAttestICACert2, MfrAttestICACert2Len))
+ return false;
+ break;
+
+ case kToolCommonOpt_SendMfrAttestICACerts:
+ IncludeMfrAttestICACerts = true;
+ break;
+
+ default:
+ PrintArgError("%s: INTERNAL ERROR: Unhandled option: %s\n", progName, name);
+ return false;
+ }
+
+ return true;
+}
+
+// ===== Methods that implement the WeaveNodeOpAuthDelegate interface
+
+WEAVE_ERROR CertProvOptions::EncodeOpCert(TLVWriter & writer, uint64_t tag)
+{
+ WEAVE_ERROR err;
+ const uint8_t * cert = OperationalCert;
+ uint16_t certLen = OperationalCertLen;
+
+ if (cert == NULL || certLen == 0)
+ {
+ err = gDeviceCredsStore.GetDeviceCert(cert, certLen);
+ SuccessOrExit(err);
+ }
+
+ err = writer.CopyContainer(tag, cert, certLen);
+ SuccessOrExit(err);
+
+exit:
+ return err;
+}
+
+WEAVE_ERROR CertProvOptions::EncodeOpRelatedCerts(TLVWriter & writer, uint64_t tag)
+{
+ WEAVE_ERROR err = WEAVE_NO_ERROR;
+ TLVType containerType;
+ const uint8_t * cert = OperationalICACerts;
+ uint16_t certLen = OperationalICACertsLen;
+
+ if (IncludeOperationalICACerts)
+ {
+ if (cert == NULL || certLen == 0)
+ {
+ err = gDeviceCredsStore.GetDeviceICACerts(cert, certLen);
+ SuccessOrExit(err);
+ }
+
+ err = writer.CopyContainer(tag, cert, certLen);
+ SuccessOrExit(err);
+ }
+
+exit:
+ return err;
+}
+
+WEAVE_ERROR CertProvOptions::GenerateAndEncodeOpSig(const uint8_t * hash, uint8_t hashLen, TLVWriter & writer, uint64_t tag)
+{
+ WEAVE_ERROR err;
+ const uint8_t * key = OperationalPrivateKey;
+ uint16_t keyLen = OperationalPrivateKeyLen;
+
+ if (key == NULL || keyLen == 0)
+ {
+ err = gDeviceCredsStore.GetDevicePrivateKey(key, keyLen);
+ SuccessOrExit(err);
+ }
+
+ err = GenerateAndEncodeWeaveECDSASignature(writer, tag, hash, hashLen, key, keyLen);
+ SuccessOrExit(err);
+
+exit:
+ return err;
+}
+
+// ===== Methods that implement the WeaveNodeMfrAttestDelegate interface
+
+WEAVE_ERROR CertProvOptions::EncodeMAInfo(TLVWriter & writer)
+{
+ WEAVE_ERROR err;
+ TLVType containerType;
+ const uint8_t * cert = MfrAttestCert;
+ uint16_t certLen = MfrAttestCertLen;
+ const uint8_t * caCert = MfrAttestICACert1;
+ uint16_t caCertLen = MfrAttestICACert1Len;
+ const uint8_t * caCert2 = MfrAttestICACert2;
+ uint16_t caCert2Len = MfrAttestICACert2Len;
+
+ if (MfrAttestType == kMfrAttestType_WeaveCert)
+ {
+ if (cert == NULL || certLen == 0)
+ {
+ if (!GetTestNodeCert(MfrAttestDeviceId, cert, certLen))
+ {
+ printf("ERROR: Node manufacturer attestation certificate not configured\n");
+ ExitNow(err = WEAVE_ERROR_CERT_NOT_FOUND);
+ }
+ }
+
+ err = writer.CopyContainer(ContextTag(kTag_GetCertReqMsg_MfrAttest_WeaveCert), cert, certLen);
+ SuccessOrExit(err);
+
+ if (IncludeMfrAttestICACerts)
+ {
+ if (caCert == NULL || caCertLen == 0)
+ {
+ caCert = nl::NestCerts::Development::DeviceCA::Cert;
+ caCertLen = nl::NestCerts::Development::DeviceCA::CertLength;
+ }
+
+ err = writer.StartContainer(ContextTag(kTag_GetCertReqMsg_MfrAttest_WeaveRelCerts), kTLVType_Array, containerType);
+ SuccessOrExit(err);
+
+ err = writer.CopyContainer(AnonymousTag, caCert, caCertLen);
+ SuccessOrExit(err);
+
+ err = writer.EndContainer(containerType);
+ SuccessOrExit(err);
+ }
+ }
+ else if (MfrAttestType == kMfrAttestType_X509Cert)
+ {
+ if (cert == NULL || certLen == 0)
+ {
+ cert = TestDevice1_X509_RSA_Cert;
+ certLen = TestDevice1_X509_RSA_CertLength;
+ }
+
+ // Copy the test device manufacturer attestation X509 RSA certificate into supplied TLV writer.
+ err = writer.PutBytes(ContextTag(kTag_GetCertReqMsg_MfrAttest_X509Cert), cert, certLen);
+ SuccessOrExit(err);
+
+ if (IncludeMfrAttestICACerts)
+ {
+ if (caCert == NULL || caCertLen == 0)
+ {
+ caCert = TestDevice1_X509_RSA_ICACert1;
+ caCertLen = TestDevice1_X509_RSA_ICACert1Length;
+
+ caCert2 = TestDevice1_X509_RSA_ICACert2;
+ caCert2Len = TestDevice1_X509_RSA_ICACert2Length;
+ }
+
+ // Start the RelatedCertificates array. This contains the list of certificates the signature verifier
+ // will need to verify the signature.
+ err = writer.StartContainer(ContextTag(kTag_GetCertReqMsg_MfrAttest_X509RelCerts), kTLVType_Array, containerType);
+ SuccessOrExit(err);
+
+ // Copy first Intermidiate CA (ICA) certificate.
+ err = writer.PutBytes(AnonymousTag, caCert, caCertLen);
+ SuccessOrExit(err);
+
+ // Copy second Intermidiate CA (ICA) certificate.
+ if (caCert2 != NULL && caCert2Len > 0)
+ {
+ err = writer.PutBytes(AnonymousTag, caCert2, caCert2Len);
+ SuccessOrExit(err);
+ }
+
+ err = writer.EndContainer(containerType);
+ SuccessOrExit(err);
+ }
+ }
+ else if (MfrAttestType == kMfrAttestType_HMAC)
+ {
+ err = writer.Put(ContextTag(kTag_GetCertReqMsg_MfrAttest_HMACKeyId), TestDevice1_MfrAttest_HMACKeyId);
+ SuccessOrExit(err);
+
+ if (IncludeMfrAttestICACerts)
+ {
+ err = writer.PutBytes(ContextTag(kTag_GetCertReqMsg_MfrAttest_HMACMetaData), TestDevice1_MfrAttest_HMACMetaData, TestDevice1_MfrAttest_HMACMetaDataLength);
+ SuccessOrExit(err);
+ }
+ }
+ else
+ {
+ ExitNow(err = WEAVE_ERROR_INVALID_ARGUMENT);
+ }
+
+exit:
+ return err;
+}
+
+WEAVE_ERROR CertProvOptions::GenerateAndEncodeMASig(const uint8_t * data, uint16_t dataLen, TLVWriter & writer)
+{
+ WEAVE_ERROR err;
+ const uint8_t * key = MfrAttestPrivateKey;
+ uint16_t keyLen = MfrAttestPrivateKeyLen;
+ nl::Weave::Platform::Security::SHA256 sha256;
+ uint8_t hash[SHA256::kHashLength];
+
+ // Calculate data hash.
+ if (MfrAttestType == kMfrAttestType_WeaveCert || MfrAttestType == kMfrAttestType_X509Cert)
+ {
+ sha256.Begin();
+ sha256.AddData(data, dataLen);
+ sha256.Finish(hash);
+ }
+
+ if (MfrAttestType == kMfrAttestType_WeaveCert)
+ {
+ if (key == NULL || keyLen == 0)
+ {
+ if (!GetTestNodePrivateKey(MfrAttestDeviceId, key, keyLen))
+ {
+ printf("ERROR: Node manufacturer attestation private key not configured\n");
+ ExitNow(err = WEAVE_ERROR_KEY_NOT_FOUND);
+ }
+ }
+
+ err = writer.Put(ContextTag(kTag_GetCertReqMsg_MfrAttestSigAlgo), static_cast<uint16_t>(ASN1::kOID_SigAlgo_ECDSAWithSHA256));
+ SuccessOrExit(err);
+
+ err = GenerateAndEncodeWeaveECDSASignature(writer, ContextTag(kTag_GetCertReqMsg_MfrAttestSig_ECDSA), hash, SHA256::kHashLength, key, keyLen);
+ SuccessOrExit(err);
+ }
+ else if (MfrAttestType == kMfrAttestType_X509Cert)
+ {
+#if WEAVE_WITH_OPENSSL
+ if (key == NULL || keyLen == 0)
+ {
+ key = TestDevice1_X509_RSA_PrivateKey;
+ keyLen = TestDevice1_X509_RSA_PrivateKeyLength;
+ }
+
+ err = writer.Put(ContextTag(kTag_GetCertReqMsg_MfrAttestSigAlgo), static_cast<uint16_t>(ASN1::kOID_SigAlgo_SHA256WithRSAEncryption));
+ SuccessOrExit(err);
+
+ err = nl::Weave::Crypto::GenerateAndEncodeWeaveRSASignature(ASN1::kOID_SigAlgo_SHA256WithRSAEncryption,
+ writer, ContextTag(kTag_GetCertReqMsg_MfrAttestSig_RSA),
+ hash, SHA256::kHashLength, key, keyLen);
+ SuccessOrExit(err);
+#else
+ printf("ERROR: Manufacturer Attestation X509 encoded certificates not supported.\n");
+ ExitNow(err = WEAVE_ERROR_NOT_IMPLEMENTED);
+#endif
+ }
+ else if (MfrAttestType == kMfrAttestType_HMAC)
+ {
+ if (key == NULL || keyLen == 0)
+ {
+ key = TestDevice1_MfrAttest_HMACKey;
+ keyLen = TestDevice1_MfrAttest_HMACKeyLength;
+ }
+
+ err = writer.Put(ContextTag(kTag_GetCertReqMsg_MfrAttestSigAlgo), static_cast<uint16_t>(ASN1::kOID_SigAlgo_HMACWithSHA256));
+ SuccessOrExit(err);
+
+ err = GenerateAndEncodeWeaveHMACSignature(ASN1::kOID_SigAlgo_HMACWithSHA256, writer, ContextTag(kTag_GetCertReqMsg_MfrAttestSig_HMAC),
+ data, dataLen, key, keyLen);
+ SuccessOrExit(err);
+ }
+ else
+ {
+ ExitNow(err = WEAVE_ERROR_INVALID_ARGUMENT);
+ }
+
+exit:
+ return err;
+}
diff --git a/src/test-apps/CertProvOptions.h b/src/test-apps/CertProvOptions.h
new file mode 100644
index 0000000..f2423e7
--- /dev/null
+++ b/src/test-apps/CertProvOptions.h
@@ -0,0 +1,168 @@
+/*
+ *
+ * Copyright (c) 2019-2020 Google LLC.
+ * All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file
+ * Definition of CertProvOptions class, which handles Certificate Provisioning specific
+ * command line options and provides an implementation of the WeaveNodeOpAuthDelegate and
+ * WeaveNodeMfrAttestDelegate interfaces for use in test applications.
+ *
+ */
+
+#ifndef CERTPROVOPTIONS_H_
+#define CERTPROVOPTIONS_H_
+
+#include <Weave/Core/WeaveCore.h>
+#include <Weave/Profiles/security/WeaveSecurity.h>
+#include <Weave/Profiles/security/WeaveCertProvisioning.h>
+#include "ToolCommonOptions.h"
+
+using namespace nl::Weave::Profiles::Security::CertProvisioning;
+
+
+extern WEAVE_ERROR GenerateTestDeviceCert(uint64_t deviceId, EncodedECPublicKey& devicePubKey,
+ uint8_t *cert, uint16_t certBufSize, uint16_t& certLen);
+
+extern WEAVE_ERROR GenerateTestDeviceCert(uint64_t deviceId, EncodedECPublicKey& devicePubKey,
+ const uint8_t *caCert, uint16_t caCertLen,
+ const uint8_t *caKey, uint16_t caKeyLen,
+ uint8_t *cert, uint16_t certBufSize, uint16_t& certLen);
+
+class DeviceCredentialsStore
+{
+public:
+
+ enum
+ {
+ kWeaveDeviceCertBufSize = 300, // Size of buffer needed to hold Weave device certificate.
+ kWeaveDevicePrivateKeyBufSize = 128, // Size of buffer needed to hold Weave device private key.
+ };
+
+ DeviceCredentialsStore();
+
+ WEAVE_ERROR StoreDeviceId(uint64_t deviceId) { mDeviceId = deviceId; return WEAVE_NO_ERROR; };
+ WEAVE_ERROR StoreDeviceCert(const uint8_t * cert, uint16_t certLen);
+ WEAVE_ERROR StoreDeviceICACerts(const uint8_t * certs, uint16_t certsLen);
+ WEAVE_ERROR StoreDevicePrivateKey(const uint8_t * key, uint16_t keyLen);
+
+ WEAVE_ERROR GetDeviceId(uint64_t & deviceId);
+ WEAVE_ERROR GetDeviceCert(const uint8_t *& cert, uint16_t & certLen);
+ WEAVE_ERROR GetDeviceICACerts(const uint8_t *& cert, uint16_t & certLen);
+ WEAVE_ERROR GetDevicePrivateKey(const uint8_t *& key, uint16_t & keyLen);
+
+ void ClearDeviceId(void);
+ void ClearDeviceCert(void);
+ void ClearDeviceICACerts(void);
+ void ClearDevicePrivateKey(void);
+ void ClearDeviceCredentials(void);
+
+ bool DeviceIdExists(void);
+ bool DeviceCertExists(void);
+ bool DeviceICACertsExists(void);
+ bool DevicePrivateKeyExists(void);
+ bool DeviceCredentialsExist(void);
+
+ WEAVE_ERROR GenerateAndStoreDeviceCredentials(uint64_t deviceId = kNodeIdNotSpecified);
+ WEAVE_ERROR GenerateAndReplaceCurrentDeviceCert(void);
+
+private:
+
+ uint64_t mDeviceId;
+ uint8_t mDevicePrivateKey[kWeaveDevicePrivateKeyBufSize];
+ uint16_t mDevicePrivateKeyLen;
+ uint8_t mDeviceCert[kWeaveDeviceCertBufSize];
+ uint16_t mDeviceCertLen;
+ uint8_t mDeviceICACerts[kWeaveDeviceCertBufSize];
+ uint16_t mDeviceICACertsLen;
+};
+
+enum
+{
+ kMfrAttestType_Undefined = 0,
+ kMfrAttestType_WeaveCert = 1,
+ kMfrAttestType_X509Cert = 2,
+ kMfrAttestType_HMAC = 3,
+};
+
+extern void CertProvClientEventHandler(void * appState, WeaveCertProvEngine::EventType eventType, const WeaveCertProvEngine::InEventParam & inParam, WeaveCertProvEngine::OutEventParam & outParam);
+
+class CertProvOptions : public WeaveNodeOpAuthDelegate, public WeaveNodeMfrAttestDelegate, public OptionSetBase
+{
+public:
+ uint64_t DeviceId;
+
+ uint8_t RequestType;
+
+ bool IncludeAuthorizeInfo;
+ const uint8_t *PairingToken;
+ uint16_t PairingTokenLen;
+ const uint8_t *PairingInitData;
+ uint16_t PairingInitDataLen;
+
+ const uint8_t *OperationalCert;
+ uint16_t OperationalCertLen;
+
+ const uint8_t *OperationalPrivateKey;
+ uint16_t OperationalPrivateKeyLen;
+
+ bool IncludeOperationalICACerts;
+ const uint8_t *OperationalICACerts;
+ uint16_t OperationalICACertsLen;
+
+ uint64_t MfrAttestDeviceId;
+
+ uint8_t MfrAttestType;
+
+ const uint8_t *MfrAttestCert;
+ uint16_t MfrAttestCertLen;
+
+ const uint8_t *MfrAttestPrivateKey;
+ uint16_t MfrAttestPrivateKeyLen;
+
+ bool IncludeMfrAttestICACerts;
+ const uint8_t *MfrAttestICACert1;
+ uint16_t MfrAttestICACert1Len;
+ const uint8_t *MfrAttestICACert2;
+ uint16_t MfrAttestICACert2Len;
+
+ CertProvOptions();
+
+ static void CertProvClientEventHandler(void * appState, WeaveCertProvEngine::EventType eventType,
+ const WeaveCertProvEngine::InEventParam & inParam, WeaveCertProvEngine::OutEventParam & outParam);
+
+private:
+
+ virtual bool HandleOption(const char *progName, OptionSet *optSet, int id, const char *name, const char *arg) __OVERRIDE;
+
+ // ===== Methods that implement the WeaveNodeOpAuthDelegate interface
+
+ WEAVE_ERROR EncodeOpCert(TLVWriter & writer, uint64_t tag) __OVERRIDE;
+ WEAVE_ERROR EncodeOpRelatedCerts(TLVWriter & writer, uint64_t tag) __OVERRIDE;
+ WEAVE_ERROR GenerateAndEncodeOpSig(const uint8_t * hash, uint8_t hashLen, TLVWriter & writer, uint64_t tag) __OVERRIDE;
+
+ // ===== Methods that implement the WeaveNodeMfrAttestDelegate interface
+
+ WEAVE_ERROR EncodeMAInfo(TLVWriter & writer) __OVERRIDE;
+ WEAVE_ERROR GenerateAndEncodeMASig(const uint8_t * data, uint16_t dataLen, TLVWriter & writer) __OVERRIDE;
+};
+
+extern DeviceCredentialsStore gDeviceCredsStore;
+
+extern CertProvOptions gCertProvOptions;
+
+#endif /* CERTPROVOPTIONS_H_ */
diff --git a/src/test-apps/Certs.cpp b/src/test-apps/Certs.cpp
index 68918cd..0a70e9e 100644
--- a/src/test-apps/Certs.cpp
+++ b/src/test-apps/Certs.cpp
@@ -1,5 +1,6 @@
/*
*
+ * Copyright (c) 2019 Google LLC.
* Copyright (c) 2013-2017 Nest Labs, Inc.
* All rights reserved.
*
@@ -1171,7 +1172,6 @@
{ 0, NULL, 0, NULL, 0 }
};
-
TestCACert TestCACerts[] =
{
{ TestMockRoot_CAId, TestMockRoot_Cert, TestMockRoot_CertLength },
@@ -1215,3 +1215,498 @@
}
return false;
}
+
+extern const uint8_t TestDevice1_X509_RSA_PrivateKey[] =
+{
+
+ /*
+ -----BEGIN RSA PRIVATE KEY-----
+ MIIEogIBAAKCAQEAsvcl5D4YDk1TaYefzdQcoQTfDLQJ1DE/LLfBd3djeiPhVtvq
+ gdmc1s3/w6sj2cCRnf85VURnt5dlsbaCYOSYRBJKqX5aoU6KCzSqD5l8OO/OG+c9
+ s7hrDZVpJ8PLC8iQRSXYmkmHpmDWHZyLZcesUddgNKeqe1qVjGY97q9oRbMGzsT7
+ LqLhaR8ve0+esrRnZwOWYTFoHmncCrABYkCs8dapRnhRWGTTOyhwZJbgI+vMuveg
+ AM4C4vjG/Bt5IhwjXF2R88oZ1ybpvPIytB+TT1PypxuuxYjO84c/9isZBP29G5Ui
+ 7LoFOI6D0QBc91dLyF/ZBtfCrZrR73fRY9yX3QIDAQABAoIBAFFz8ycCq+g2gXRS
+ agVAOReAJBSgDKkrENnFeKRrDjeVBQaHaSBYbu3FLFdeGR8OajhC5VFNpPcGTR6p
+ NoXrBPJWcOzbuVwZZvLasVwQO12ep2xDvu2BThgMnKOglVVzn1YZd5AhT0AGau1n
+ Rnq4elF1eS/977Xc8JvKHP35j7fIlHych8uiDTKJxu8mzxzpCIdLb5S1WzpjQQcK
+ zc7HhZvPtcqfYY5QTeuiyM4mQuLRNVvovq6X9VIswly6cgtZRpX3KKe5AY1fEjfa
+ SMwM+069SVhW6ubXvPB2wl0uSSg3/DjyC7DCPpiu4g38kFlS0Hz2EkMYHFHYMwCW
+ 6K236nECgYEA4e8kgbFC/QztgMAm561LkjN6hEkaPkC+Yon6zs+TIjtcCl5leKrj
+ cMG75OxopB1exz3YC4Uz9kMp9AtF9I1dILbrl2EWEjF7yzFsoGKwnZSuzIu3VbtZ
+ iTHlz6cMiB0tTR8mser6f+dqD8uXCo7FeTv+CPskpsTdXpuubcQHG7cCgYEAysfu
+ KQS4+L9Hm1xkkTndXxGDuY4tnbKzlODnANlrww3oFfpTw2DmG3rk5w3nBlu5IlnQ
+ W6wNo8L6fMJg3+JE+/4jrvzWfIVbwGL5OWrSjqNUcBvez1xZMQTrmhbhipE5RyjV
+ zdiJC1niRoa17UFwvzjwFWHzcuKOYGeUKqGC0QsCgYA3nu3317HMJlCZ77QkOO9v
+ 0KiKxIxnYvz7uUg7fbKVLNPd4ZtNd5SCf89H7kNck7ZvinQTcfl22NYNNHFGYT7Z
+ /O5G2Cnc1L3LKiG54lHkmWPnC0ZZHsROGDChTFizcatjXxXhmx2MO2ZK+S339Wn8
+ DJ7fiyRcwf5VejIY57dwRQKBgEjkUWIBRpRz/cOFFMl3aXHxE86xowga4p7TsXYG
+ scvtxc2QrGeA/3ZFWN8Nikwo0IXejx1E3apOPkh2fug7p9yFYEJYtKkSLwcbDMds
+ 9L89Su75tcAITC9ou2AqdWygA1zm+uQBwFGKP+JmLiNY8LRsPTESgrZ7Zf6VfRdN
+ 8349AoGAZlHOiirU6UDSN7ShW56ETQLoQ4ZtCpEWDhT8sRrYFG+formzskTcO7zq
+ wpbTRzmgnBtZT+lpiPuQEUBWaDs8bql48DNfyu51IGVJfrzUxa0q44955pWFgP7A
+ bX1ZbTUztvwM18GL+tomtBDwFVCyJZDekpX34yD8IC0gjaDtXPo=
+ -----END RSA PRIVATE KEY-----
+ */
+
+ 0x30, 0x82, 0x04, 0xA2, 0x02, 0x01, 0x00, 0x02, 0x82, 0x01, 0x01, 0x00, 0xB2, 0xF7, 0x25, 0xE4,
+ 0x3E, 0x18, 0x0E, 0x4D, 0x53, 0x69, 0x87, 0x9F, 0xCD, 0xD4, 0x1C, 0xA1, 0x04, 0xDF, 0x0C, 0xB4,
+ 0x09, 0xD4, 0x31, 0x3F, 0x2C, 0xB7, 0xC1, 0x77, 0x77, 0x63, 0x7A, 0x23, 0xE1, 0x56, 0xDB, 0xEA,
+ 0x81, 0xD9, 0x9C, 0xD6, 0xCD, 0xFF, 0xC3, 0xAB, 0x23, 0xD9, 0xC0, 0x91, 0x9D, 0xFF, 0x39, 0x55,
+ 0x44, 0x67, 0xB7, 0x97, 0x65, 0xB1, 0xB6, 0x82, 0x60, 0xE4, 0x98, 0x44, 0x12, 0x4A, 0xA9, 0x7E,
+ 0x5A, 0xA1, 0x4E, 0x8A, 0x0B, 0x34, 0xAA, 0x0F, 0x99, 0x7C, 0x38, 0xEF, 0xCE, 0x1B, 0xE7, 0x3D,
+ 0xB3, 0xB8, 0x6B, 0x0D, 0x95, 0x69, 0x27, 0xC3, 0xCB, 0x0B, 0xC8, 0x90, 0x45, 0x25, 0xD8, 0x9A,
+ 0x49, 0x87, 0xA6, 0x60, 0xD6, 0x1D, 0x9C, 0x8B, 0x65, 0xC7, 0xAC, 0x51, 0xD7, 0x60, 0x34, 0xA7,
+ 0xAA, 0x7B, 0x5A, 0x95, 0x8C, 0x66, 0x3D, 0xEE, 0xAF, 0x68, 0x45, 0xB3, 0x06, 0xCE, 0xC4, 0xFB,
+ 0x2E, 0xA2, 0xE1, 0x69, 0x1F, 0x2F, 0x7B, 0x4F, 0x9E, 0xB2, 0xB4, 0x67, 0x67, 0x03, 0x96, 0x61,
+ 0x31, 0x68, 0x1E, 0x69, 0xDC, 0x0A, 0xB0, 0x01, 0x62, 0x40, 0xAC, 0xF1, 0xD6, 0xA9, 0x46, 0x78,
+ 0x51, 0x58, 0x64, 0xD3, 0x3B, 0x28, 0x70, 0x64, 0x96, 0xE0, 0x23, 0xEB, 0xCC, 0xBA, 0xF7, 0xA0,
+ 0x00, 0xCE, 0x02, 0xE2, 0xF8, 0xC6, 0xFC, 0x1B, 0x79, 0x22, 0x1C, 0x23, 0x5C, 0x5D, 0x91, 0xF3,
+ 0xCA, 0x19, 0xD7, 0x26, 0xE9, 0xBC, 0xF2, 0x32, 0xB4, 0x1F, 0x93, 0x4F, 0x53, 0xF2, 0xA7, 0x1B,
+ 0xAE, 0xC5, 0x88, 0xCE, 0xF3, 0x87, 0x3F, 0xF6, 0x2B, 0x19, 0x04, 0xFD, 0xBD, 0x1B, 0x95, 0x22,
+ 0xEC, 0xBA, 0x05, 0x38, 0x8E, 0x83, 0xD1, 0x00, 0x5C, 0xF7, 0x57, 0x4B, 0xC8, 0x5F, 0xD9, 0x06,
+ 0xD7, 0xC2, 0xAD, 0x9A, 0xD1, 0xEF, 0x77, 0xD1, 0x63, 0xDC, 0x97, 0xDD, 0x02, 0x03, 0x01, 0x00,
+ 0x01, 0x02, 0x82, 0x01, 0x00, 0x51, 0x73, 0xF3, 0x27, 0x02, 0xAB, 0xE8, 0x36, 0x81, 0x74, 0x52,
+ 0x6A, 0x05, 0x40, 0x39, 0x17, 0x80, 0x24, 0x14, 0xA0, 0x0C, 0xA9, 0x2B, 0x10, 0xD9, 0xC5, 0x78,
+ 0xA4, 0x6B, 0x0E, 0x37, 0x95, 0x05, 0x06, 0x87, 0x69, 0x20, 0x58, 0x6E, 0xED, 0xC5, 0x2C, 0x57,
+ 0x5E, 0x19, 0x1F, 0x0E, 0x6A, 0x38, 0x42, 0xE5, 0x51, 0x4D, 0xA4, 0xF7, 0x06, 0x4D, 0x1E, 0xA9,
+ 0x36, 0x85, 0xEB, 0x04, 0xF2, 0x56, 0x70, 0xEC, 0xDB, 0xB9, 0x5C, 0x19, 0x66, 0xF2, 0xDA, 0xB1,
+ 0x5C, 0x10, 0x3B, 0x5D, 0x9E, 0xA7, 0x6C, 0x43, 0xBE, 0xED, 0x81, 0x4E, 0x18, 0x0C, 0x9C, 0xA3,
+ 0xA0, 0x95, 0x55, 0x73, 0x9F, 0x56, 0x19, 0x77, 0x90, 0x21, 0x4F, 0x40, 0x06, 0x6A, 0xED, 0x67,
+ 0x46, 0x7A, 0xB8, 0x7A, 0x51, 0x75, 0x79, 0x2F, 0xFD, 0xEF, 0xB5, 0xDC, 0xF0, 0x9B, 0xCA, 0x1C,
+ 0xFD, 0xF9, 0x8F, 0xB7, 0xC8, 0x94, 0x7C, 0x9C, 0x87, 0xCB, 0xA2, 0x0D, 0x32, 0x89, 0xC6, 0xEF,
+ 0x26, 0xCF, 0x1C, 0xE9, 0x08, 0x87, 0x4B, 0x6F, 0x94, 0xB5, 0x5B, 0x3A, 0x63, 0x41, 0x07, 0x0A,
+ 0xCD, 0xCE, 0xC7, 0x85, 0x9B, 0xCF, 0xB5, 0xCA, 0x9F, 0x61, 0x8E, 0x50, 0x4D, 0xEB, 0xA2, 0xC8,
+ 0xCE, 0x26, 0x42, 0xE2, 0xD1, 0x35, 0x5B, 0xE8, 0xBE, 0xAE, 0x97, 0xF5, 0x52, 0x2C, 0xC2, 0x5C,
+ 0xBA, 0x72, 0x0B, 0x59, 0x46, 0x95, 0xF7, 0x28, 0xA7, 0xB9, 0x01, 0x8D, 0x5F, 0x12, 0x37, 0xDA,
+ 0x48, 0xCC, 0x0C, 0xFB, 0x4E, 0xBD, 0x49, 0x58, 0x56, 0xEA, 0xE6, 0xD7, 0xBC, 0xF0, 0x76, 0xC2,
+ 0x5D, 0x2E, 0x49, 0x28, 0x37, 0xFC, 0x38, 0xF2, 0x0B, 0xB0, 0xC2, 0x3E, 0x98, 0xAE, 0xE2, 0x0D,
+ 0xFC, 0x90, 0x59, 0x52, 0xD0, 0x7C, 0xF6, 0x12, 0x43, 0x18, 0x1C, 0x51, 0xD8, 0x33, 0x00, 0x96,
+ 0xE8, 0xAD, 0xB7, 0xEA, 0x71, 0x02, 0x81, 0x81, 0x00, 0xE1, 0xEF, 0x24, 0x81, 0xB1, 0x42, 0xFD,
+ 0x0C, 0xED, 0x80, 0xC0, 0x26, 0xE7, 0xAD, 0x4B, 0x92, 0x33, 0x7A, 0x84, 0x49, 0x1A, 0x3E, 0x40,
+ 0xBE, 0x62, 0x89, 0xFA, 0xCE, 0xCF, 0x93, 0x22, 0x3B, 0x5C, 0x0A, 0x5E, 0x65, 0x78, 0xAA, 0xE3,
+ 0x70, 0xC1, 0xBB, 0xE4, 0xEC, 0x68, 0xA4, 0x1D, 0x5E, 0xC7, 0x3D, 0xD8, 0x0B, 0x85, 0x33, 0xF6,
+ 0x43, 0x29, 0xF4, 0x0B, 0x45, 0xF4, 0x8D, 0x5D, 0x20, 0xB6, 0xEB, 0x97, 0x61, 0x16, 0x12, 0x31,
+ 0x7B, 0xCB, 0x31, 0x6C, 0xA0, 0x62, 0xB0, 0x9D, 0x94, 0xAE, 0xCC, 0x8B, 0xB7, 0x55, 0xBB, 0x59,
+ 0x89, 0x31, 0xE5, 0xCF, 0xA7, 0x0C, 0x88, 0x1D, 0x2D, 0x4D, 0x1F, 0x26, 0xB1, 0xEA, 0xFA, 0x7F,
+ 0xE7, 0x6A, 0x0F, 0xCB, 0x97, 0x0A, 0x8E, 0xC5, 0x79, 0x3B, 0xFE, 0x08, 0xFB, 0x24, 0xA6, 0xC4,
+ 0xDD, 0x5E, 0x9B, 0xAE, 0x6D, 0xC4, 0x07, 0x1B, 0xB7, 0x02, 0x81, 0x81, 0x00, 0xCA, 0xC7, 0xEE,
+ 0x29, 0x04, 0xB8, 0xF8, 0xBF, 0x47, 0x9B, 0x5C, 0x64, 0x91, 0x39, 0xDD, 0x5F, 0x11, 0x83, 0xB9,
+ 0x8E, 0x2D, 0x9D, 0xB2, 0xB3, 0x94, 0xE0, 0xE7, 0x00, 0xD9, 0x6B, 0xC3, 0x0D, 0xE8, 0x15, 0xFA,
+ 0x53, 0xC3, 0x60, 0xE6, 0x1B, 0x7A, 0xE4, 0xE7, 0x0D, 0xE7, 0x06, 0x5B, 0xB9, 0x22, 0x59, 0xD0,
+ 0x5B, 0xAC, 0x0D, 0xA3, 0xC2, 0xFA, 0x7C, 0xC2, 0x60, 0xDF, 0xE2, 0x44, 0xFB, 0xFE, 0x23, 0xAE,
+ 0xFC, 0xD6, 0x7C, 0x85, 0x5B, 0xC0, 0x62, 0xF9, 0x39, 0x6A, 0xD2, 0x8E, 0xA3, 0x54, 0x70, 0x1B,
+ 0xDE, 0xCF, 0x5C, 0x59, 0x31, 0x04, 0xEB, 0x9A, 0x16, 0xE1, 0x8A, 0x91, 0x39, 0x47, 0x28, 0xD5,
+ 0xCD, 0xD8, 0x89, 0x0B, 0x59, 0xE2, 0x46, 0x86, 0xB5, 0xED, 0x41, 0x70, 0xBF, 0x38, 0xF0, 0x15,
+ 0x61, 0xF3, 0x72, 0xE2, 0x8E, 0x60, 0x67, 0x94, 0x2A, 0xA1, 0x82, 0xD1, 0x0B, 0x02, 0x81, 0x80,
+ 0x37, 0x9E, 0xED, 0xF7, 0xD7, 0xB1, 0xCC, 0x26, 0x50, 0x99, 0xEF, 0xB4, 0x24, 0x38, 0xEF, 0x6F,
+ 0xD0, 0xA8, 0x8A, 0xC4, 0x8C, 0x67, 0x62, 0xFC, 0xFB, 0xB9, 0x48, 0x3B, 0x7D, 0xB2, 0x95, 0x2C,
+ 0xD3, 0xDD, 0xE1, 0x9B, 0x4D, 0x77, 0x94, 0x82, 0x7F, 0xCF, 0x47, 0xEE, 0x43, 0x5C, 0x93, 0xB6,
+ 0x6F, 0x8A, 0x74, 0x13, 0x71, 0xF9, 0x76, 0xD8, 0xD6, 0x0D, 0x34, 0x71, 0x46, 0x61, 0x3E, 0xD9,
+ 0xFC, 0xEE, 0x46, 0xD8, 0x29, 0xDC, 0xD4, 0xBD, 0xCB, 0x2A, 0x21, 0xB9, 0xE2, 0x51, 0xE4, 0x99,
+ 0x63, 0xE7, 0x0B, 0x46, 0x59, 0x1E, 0xC4, 0x4E, 0x18, 0x30, 0xA1, 0x4C, 0x58, 0xB3, 0x71, 0xAB,
+ 0x63, 0x5F, 0x15, 0xE1, 0x9B, 0x1D, 0x8C, 0x3B, 0x66, 0x4A, 0xF9, 0x2D, 0xF7, 0xF5, 0x69, 0xFC,
+ 0x0C, 0x9E, 0xDF, 0x8B, 0x24, 0x5C, 0xC1, 0xFE, 0x55, 0x7A, 0x32, 0x18, 0xE7, 0xB7, 0x70, 0x45,
+ 0x02, 0x81, 0x80, 0x48, 0xE4, 0x51, 0x62, 0x01, 0x46, 0x94, 0x73, 0xFD, 0xC3, 0x85, 0x14, 0xC9,
+ 0x77, 0x69, 0x71, 0xF1, 0x13, 0xCE, 0xB1, 0xA3, 0x08, 0x1A, 0xE2, 0x9E, 0xD3, 0xB1, 0x76, 0x06,
+ 0xB1, 0xCB, 0xED, 0xC5, 0xCD, 0x90, 0xAC, 0x67, 0x80, 0xFF, 0x76, 0x45, 0x58, 0xDF, 0x0D, 0x8A,
+ 0x4C, 0x28, 0xD0, 0x85, 0xDE, 0x8F, 0x1D, 0x44, 0xDD, 0xAA, 0x4E, 0x3E, 0x48, 0x76, 0x7E, 0xE8,
+ 0x3B, 0xA7, 0xDC, 0x85, 0x60, 0x42, 0x58, 0xB4, 0xA9, 0x12, 0x2F, 0x07, 0x1B, 0x0C, 0xC7, 0x6C,
+ 0xF4, 0xBF, 0x3D, 0x4A, 0xEE, 0xF9, 0xB5, 0xC0, 0x08, 0x4C, 0x2F, 0x68, 0xBB, 0x60, 0x2A, 0x75,
+ 0x6C, 0xA0, 0x03, 0x5C, 0xE6, 0xFA, 0xE4, 0x01, 0xC0, 0x51, 0x8A, 0x3F, 0xE2, 0x66, 0x2E, 0x23,
+ 0x58, 0xF0, 0xB4, 0x6C, 0x3D, 0x31, 0x12, 0x82, 0xB6, 0x7B, 0x65, 0xFE, 0x95, 0x7D, 0x17, 0x4D,
+ 0xF3, 0x7E, 0x3D, 0x02, 0x81, 0x80, 0x66, 0x51, 0xCE, 0x8A, 0x2A, 0xD4, 0xE9, 0x40, 0xD2, 0x37,
+ 0xB4, 0xA1, 0x5B, 0x9E, 0x84, 0x4D, 0x02, 0xE8, 0x43, 0x86, 0x6D, 0x0A, 0x91, 0x16, 0x0E, 0x14,
+ 0xFC, 0xB1, 0x1A, 0xD8, 0x14, 0x6F, 0x9F, 0xA2, 0xB9, 0xB3, 0xB2, 0x44, 0xDC, 0x3B, 0xBC, 0xEA,
+ 0xC2, 0x96, 0xD3, 0x47, 0x39, 0xA0, 0x9C, 0x1B, 0x59, 0x4F, 0xE9, 0x69, 0x88, 0xFB, 0x90, 0x11,
+ 0x40, 0x56, 0x68, 0x3B, 0x3C, 0x6E, 0xA9, 0x78, 0xF0, 0x33, 0x5F, 0xCA, 0xEE, 0x75, 0x20, 0x65,
+ 0x49, 0x7E, 0xBC, 0xD4, 0xC5, 0xAD, 0x2A, 0xE3, 0x8F, 0x79, 0xE6, 0x95, 0x85, 0x80, 0xFE, 0xC0,
+ 0x6D, 0x7D, 0x59, 0x6D, 0x35, 0x33, 0xB6, 0xFC, 0x0C, 0xD7, 0xC1, 0x8B, 0xFA, 0xDA, 0x26, 0xB4,
+ 0x10, 0xF0, 0x15, 0x50, 0xB2, 0x25, 0x90, 0xDE, 0x92, 0x95, 0xF7, 0xE3, 0x20, 0xFC, 0x20, 0x2D,
+ 0x20, 0x8D, 0xA0, 0xED, 0x5C, 0xFA,
+};
+
+extern const uint16_t TestDevice1_X509_RSA_PrivateKeyLength = sizeof(TestDevice1_X509_RSA_PrivateKey);
+
+extern const uint8_t TestDevice1_X509_RSA_Cert[] =
+{
+
+ /*
+ -----BEGIN CERTIFICATE-----
+ MIIEATCCAumgAwIBAgICAVwwDQYJKoZIhvcNAQELBQAwfDELMAkGA1UEBhMCVVMx
+ EzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDU1vdW50YWluIFZpZXcxEzAR
+ BgNVBAoMCkdvb2dsZSBJbmMxDTALBgNVBAsMBENhc3QxHDAaBgNVBAMME0Nhc3Qg
+ VGVzdCBBdWRpbyBJQ0EwHhcNMTgwODI0MjIxODM0WhcNMTkwMTMxMjIxODM0WjB/
+ MQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91
+ bnRhaW4gVmlldzETMBEGA1UECgwKR29vZ2xlIEluYzENMAsGA1UECwwEQ2FzdDEf
+ MB0GA1UEAwwWQ2FzdCBUZXN0IEF1ZGlvIERldmljZTCCASIwDQYJKoZIhvcNAQEB
+ BQADggEPADCCAQoCggEBALL3JeQ+GA5NU2mHn83UHKEE3wy0CdQxPyy3wXd3Y3oj
+ 4Vbb6oHZnNbN/8OrI9nAkZ3/OVVEZ7eXZbG2gmDkmEQSSql+WqFOigs0qg+ZfDjv
+ zhvnPbO4aw2VaSfDywvIkEUl2JpJh6Zg1h2ci2XHrFHXYDSnqntalYxmPe6vaEWz
+ Bs7E+y6i4WkfL3tPnrK0Z2cDlmExaB5p3AqwAWJArPHWqUZ4UVhk0zsocGSW4CPr
+ zLr3oADOAuL4xvwbeSIcI1xdkfPKGdcm6bzyMrQfk09T8qcbrsWIzvOHP/YrGQT9
+ vRuVIuy6BTiOg9EAXPdXS8hf2QbXwq2a0e930WPcl90CAwEAAaOBiTCBhjAJBgNV
+ HRMEAjAAMB0GA1UdDgQWBBSWrc2xhFX96LoUFpfjbOto/N8EaTAfBgNVHSMEGDAW
+ gBSO2zh0skDMPeznfas3b3eUKvaqbzALBgNVHQ8EBAMCB4AwEwYDVR0lBAwwCgYI
+ KwYBBQUHAwIwFwYDVR0gBBAwDjAMBgorBgEEAdZ5AgUCMA0GCSqGSIb3DQEBCwUA
+ A4IBAQArQuSfmrxO9uZTNPVmHy5+AT2Tv+Tie1gAs8i/5dy5gBDJ2RNfhOPyj7A+
+ OtpA+AhuZQJB9d1qacpGNWhQF2f/DW5gYqSnz8ZD55rzG5nkGV937rNogEY2e2O7
+ dUtipcvfEhpMIvCsEJpIs/6ulGvb74/62Buf3wUFn24Nkf16J7JSX4h79P1mc87L
+ Q0Z57LLrc7l6QFhO5Aoy5/khtz9iTPqJfob4LL//x/DIdf9ZPcSY/kIh5afq9A2K
+ 9ERWH06TtkEiA2wSICP78GVJJOf9/87H6GdYmWDzRI3dCoV05nECF9dnXYnDSs+R
+ 1nSRbjURlnWJRj7jOcx5QnUUEmOV
+ -----END CERTIFICATE-----
+ */
+
+ 0x30, 0x82, 0x04, 0x01, 0x30, 0x82, 0x02, 0xE9, 0xA0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x02, 0x01,
+ 0x5C, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0B, 0x05, 0x00,
+ 0x30, 0x7C, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31,
+ 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0C, 0x0A, 0x43, 0x61, 0x6C, 0x69, 0x66, 0x6F,
+ 0x72, 0x6E, 0x69, 0x61, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0C, 0x0D, 0x4D,
+ 0x6F, 0x75, 0x6E, 0x74, 0x61, 0x69, 0x6E, 0x20, 0x56, 0x69, 0x65, 0x77, 0x31, 0x13, 0x30, 0x11,
+ 0x06, 0x03, 0x55, 0x04, 0x0A, 0x0C, 0x0A, 0x47, 0x6F, 0x6F, 0x67, 0x6C, 0x65, 0x20, 0x49, 0x6E,
+ 0x63, 0x31, 0x0D, 0x30, 0x0B, 0x06, 0x03, 0x55, 0x04, 0x0B, 0x0C, 0x04, 0x43, 0x61, 0x73, 0x74,
+ 0x31, 0x1C, 0x30, 0x1A, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0C, 0x13, 0x43, 0x61, 0x73, 0x74, 0x20,
+ 0x54, 0x65, 0x73, 0x74, 0x20, 0x41, 0x75, 0x64, 0x69, 0x6F, 0x20, 0x49, 0x43, 0x41, 0x30, 0x1E,
+ 0x17, 0x0D, 0x31, 0x38, 0x30, 0x38, 0x32, 0x34, 0x32, 0x32, 0x31, 0x38, 0x33, 0x34, 0x5A, 0x17,
+ 0x0D, 0x31, 0x39, 0x30, 0x31, 0x33, 0x31, 0x32, 0x32, 0x31, 0x38, 0x33, 0x34, 0x5A, 0x30, 0x7F,
+ 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30,
+ 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0C, 0x0A, 0x43, 0x61, 0x6C, 0x69, 0x66, 0x6F, 0x72, 0x6E,
+ 0x69, 0x61, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0C, 0x0D, 0x4D, 0x6F, 0x75,
+ 0x6E, 0x74, 0x61, 0x69, 0x6E, 0x20, 0x56, 0x69, 0x65, 0x77, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03,
+ 0x55, 0x04, 0x0A, 0x0C, 0x0A, 0x47, 0x6F, 0x6F, 0x67, 0x6C, 0x65, 0x20, 0x49, 0x6E, 0x63, 0x31,
+ 0x0D, 0x30, 0x0B, 0x06, 0x03, 0x55, 0x04, 0x0B, 0x0C, 0x04, 0x43, 0x61, 0x73, 0x74, 0x31, 0x1F,
+ 0x30, 0x1D, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0C, 0x16, 0x43, 0x61, 0x73, 0x74, 0x20, 0x54, 0x65,
+ 0x73, 0x74, 0x20, 0x41, 0x75, 0x64, 0x69, 0x6F, 0x20, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 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,
+ 0xB2, 0xF7, 0x25, 0xE4, 0x3E, 0x18, 0x0E, 0x4D, 0x53, 0x69, 0x87, 0x9F, 0xCD, 0xD4, 0x1C, 0xA1,
+ 0x04, 0xDF, 0x0C, 0xB4, 0x09, 0xD4, 0x31, 0x3F, 0x2C, 0xB7, 0xC1, 0x77, 0x77, 0x63, 0x7A, 0x23,
+ 0xE1, 0x56, 0xDB, 0xEA, 0x81, 0xD9, 0x9C, 0xD6, 0xCD, 0xFF, 0xC3, 0xAB, 0x23, 0xD9, 0xC0, 0x91,
+ 0x9D, 0xFF, 0x39, 0x55, 0x44, 0x67, 0xB7, 0x97, 0x65, 0xB1, 0xB6, 0x82, 0x60, 0xE4, 0x98, 0x44,
+ 0x12, 0x4A, 0xA9, 0x7E, 0x5A, 0xA1, 0x4E, 0x8A, 0x0B, 0x34, 0xAA, 0x0F, 0x99, 0x7C, 0x38, 0xEF,
+ 0xCE, 0x1B, 0xE7, 0x3D, 0xB3, 0xB8, 0x6B, 0x0D, 0x95, 0x69, 0x27, 0xC3, 0xCB, 0x0B, 0xC8, 0x90,
+ 0x45, 0x25, 0xD8, 0x9A, 0x49, 0x87, 0xA6, 0x60, 0xD6, 0x1D, 0x9C, 0x8B, 0x65, 0xC7, 0xAC, 0x51,
+ 0xD7, 0x60, 0x34, 0xA7, 0xAA, 0x7B, 0x5A, 0x95, 0x8C, 0x66, 0x3D, 0xEE, 0xAF, 0x68, 0x45, 0xB3,
+ 0x06, 0xCE, 0xC4, 0xFB, 0x2E, 0xA2, 0xE1, 0x69, 0x1F, 0x2F, 0x7B, 0x4F, 0x9E, 0xB2, 0xB4, 0x67,
+ 0x67, 0x03, 0x96, 0x61, 0x31, 0x68, 0x1E, 0x69, 0xDC, 0x0A, 0xB0, 0x01, 0x62, 0x40, 0xAC, 0xF1,
+ 0xD6, 0xA9, 0x46, 0x78, 0x51, 0x58, 0x64, 0xD3, 0x3B, 0x28, 0x70, 0x64, 0x96, 0xE0, 0x23, 0xEB,
+ 0xCC, 0xBA, 0xF7, 0xA0, 0x00, 0xCE, 0x02, 0xE2, 0xF8, 0xC6, 0xFC, 0x1B, 0x79, 0x22, 0x1C, 0x23,
+ 0x5C, 0x5D, 0x91, 0xF3, 0xCA, 0x19, 0xD7, 0x26, 0xE9, 0xBC, 0xF2, 0x32, 0xB4, 0x1F, 0x93, 0x4F,
+ 0x53, 0xF2, 0xA7, 0x1B, 0xAE, 0xC5, 0x88, 0xCE, 0xF3, 0x87, 0x3F, 0xF6, 0x2B, 0x19, 0x04, 0xFD,
+ 0xBD, 0x1B, 0x95, 0x22, 0xEC, 0xBA, 0x05, 0x38, 0x8E, 0x83, 0xD1, 0x00, 0x5C, 0xF7, 0x57, 0x4B,
+ 0xC8, 0x5F, 0xD9, 0x06, 0xD7, 0xC2, 0xAD, 0x9A, 0xD1, 0xEF, 0x77, 0xD1, 0x63, 0xDC, 0x97, 0xDD,
+ 0x02, 0x03, 0x01, 0x00, 0x01, 0xA3, 0x81, 0x89, 0x30, 0x81, 0x86, 0x30, 0x09, 0x06, 0x03, 0x55,
+ 0x1D, 0x13, 0x04, 0x02, 0x30, 0x00, 0x30, 0x1D, 0x06, 0x03, 0x55, 0x1D, 0x0E, 0x04, 0x16, 0x04,
+ 0x14, 0x96, 0xAD, 0xCD, 0xB1, 0x84, 0x55, 0xFD, 0xE8, 0xBA, 0x14, 0x16, 0x97, 0xE3, 0x6C, 0xEB,
+ 0x68, 0xFC, 0xDF, 0x04, 0x69, 0x30, 0x1F, 0x06, 0x03, 0x55, 0x1D, 0x23, 0x04, 0x18, 0x30, 0x16,
+ 0x80, 0x14, 0x8E, 0xDB, 0x38, 0x74, 0xB2, 0x40, 0xCC, 0x3D, 0xEC, 0xE7, 0x7D, 0xAB, 0x37, 0x6F,
+ 0x77, 0x94, 0x2A, 0xF6, 0xAA, 0x6F, 0x30, 0x0B, 0x06, 0x03, 0x55, 0x1D, 0x0F, 0x04, 0x04, 0x03,
+ 0x02, 0x07, 0x80, 0x30, 0x13, 0x06, 0x03, 0x55, 0x1D, 0x25, 0x04, 0x0C, 0x30, 0x0A, 0x06, 0x08,
+ 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x02, 0x30, 0x17, 0x06, 0x03, 0x55, 0x1D, 0x20, 0x04,
+ 0x10, 0x30, 0x0E, 0x30, 0x0C, 0x06, 0x0A, 0x2B, 0x06, 0x01, 0x04, 0x01, 0xD6, 0x79, 0x02, 0x05,
+ 0x02, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0B, 0x05, 0x00,
+ 0x03, 0x82, 0x01, 0x01, 0x00, 0x2B, 0x42, 0xE4, 0x9F, 0x9A, 0xBC, 0x4E, 0xF6, 0xE6, 0x53, 0x34,
+ 0xF5, 0x66, 0x1F, 0x2E, 0x7E, 0x01, 0x3D, 0x93, 0xBF, 0xE4, 0xE2, 0x7B, 0x58, 0x00, 0xB3, 0xC8,
+ 0xBF, 0xE5, 0xDC, 0xB9, 0x80, 0x10, 0xC9, 0xD9, 0x13, 0x5F, 0x84, 0xE3, 0xF2, 0x8F, 0xB0, 0x3E,
+ 0x3A, 0xDA, 0x40, 0xF8, 0x08, 0x6E, 0x65, 0x02, 0x41, 0xF5, 0xDD, 0x6A, 0x69, 0xCA, 0x46, 0x35,
+ 0x68, 0x50, 0x17, 0x67, 0xFF, 0x0D, 0x6E, 0x60, 0x62, 0xA4, 0xA7, 0xCF, 0xC6, 0x43, 0xE7, 0x9A,
+ 0xF3, 0x1B, 0x99, 0xE4, 0x19, 0x5F, 0x77, 0xEE, 0xB3, 0x68, 0x80, 0x46, 0x36, 0x7B, 0x63, 0xBB,
+ 0x75, 0x4B, 0x62, 0xA5, 0xCB, 0xDF, 0x12, 0x1A, 0x4C, 0x22, 0xF0, 0xAC, 0x10, 0x9A, 0x48, 0xB3,
+ 0xFE, 0xAE, 0x94, 0x6B, 0xDB, 0xEF, 0x8F, 0xFA, 0xD8, 0x1B, 0x9F, 0xDF, 0x05, 0x05, 0x9F, 0x6E,
+ 0x0D, 0x91, 0xFD, 0x7A, 0x27, 0xB2, 0x52, 0x5F, 0x88, 0x7B, 0xF4, 0xFD, 0x66, 0x73, 0xCE, 0xCB,
+ 0x43, 0x46, 0x79, 0xEC, 0xB2, 0xEB, 0x73, 0xB9, 0x7A, 0x40, 0x58, 0x4E, 0xE4, 0x0A, 0x32, 0xE7,
+ 0xF9, 0x21, 0xB7, 0x3F, 0x62, 0x4C, 0xFA, 0x89, 0x7E, 0x86, 0xF8, 0x2C, 0xBF, 0xFF, 0xC7, 0xF0,
+ 0xC8, 0x75, 0xFF, 0x59, 0x3D, 0xC4, 0x98, 0xFE, 0x42, 0x21, 0xE5, 0xA7, 0xEA, 0xF4, 0x0D, 0x8A,
+ 0xF4, 0x44, 0x56, 0x1F, 0x4E, 0x93, 0xB6, 0x41, 0x22, 0x03, 0x6C, 0x12, 0x20, 0x23, 0xFB, 0xF0,
+ 0x65, 0x49, 0x24, 0xE7, 0xFD, 0xFF, 0xCE, 0xC7, 0xE8, 0x67, 0x58, 0x99, 0x60, 0xF3, 0x44, 0x8D,
+ 0xDD, 0x0A, 0x85, 0x74, 0xE6, 0x71, 0x02, 0x17, 0xD7, 0x67, 0x5D, 0x89, 0xC3, 0x4A, 0xCF, 0x91,
+ 0xD6, 0x74, 0x91, 0x6E, 0x35, 0x11, 0x96, 0x75, 0x89, 0x46, 0x3E, 0xE3, 0x39, 0xCC, 0x79, 0x42,
+ 0x75, 0x14, 0x12, 0x63, 0x95,
+};
+
+extern const uint16_t TestDevice1_X509_RSA_CertLength = sizeof(TestDevice1_X509_RSA_Cert);
+
+extern const uint8_t TestDevice1_X509_RSA_ICACert1[] =
+{
+
+ /*
+ -----BEGIN CERTIFICATE-----
+ MIID7DCCAtSgAwIBAgICATgwDQYJKoZIhvcNAQELBQAwezELMAkGA1UEBhMCVVMx
+ EzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDU1vdW50YWluIFZpZXcxEzAR
+ BgNVBAoMCkdvb2dsZSBJbmMxDTALBgNVBAsMBENhc3QxGzAZBgNVBAMMEkNhc3Qg
+ VGVzdCBSb290IElDQTAeFw0xODAzMTIyMzU1MDFaFw0zODAzMDcyMzU1MDFaMHwx
+ CzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1Nb3Vu
+ dGFpbiBWaWV3MRMwEQYDVQQKDApHb29nbGUgSW5jMQ0wCwYDVQQLDARDYXN0MRww
+ GgYDVQQDDBNDYXN0IFRlc3QgQXVkaW8gSUNBMIIBIjANBgkqhkiG9w0BAQEFAAOC
+ AQ8AMIIBCgKCAQEA1Y2yj6kw5fykMoTW7j9T1w5VScQeWSVnPgFWz5obQRZ7VrYP
+ Oi/ZHvb0ycN+s6j1g2xyDMFghlecODA9k0AYZR6Sw7EpkpoGvDA/5mbVlN7D6/tl
+ LnLBka5kU1qhZfzVd6xRFY4gq3LYgz3qZ8mt9ApeqiXw2hZk24IGd8WVusvOWRir
+ +c3ynUboLSfJ5SEVwO265tbrp0cTlWSA6TxF40d0ClrgrrGTkoXQ2VnR5xAJ7Q7F
+ nFes/QLQvX05JJEOEF0l0eCSsqmyyDYVDoNBCyTPsSHl7FFAzpukrKr2fB/ONt7F
+ RrkvRsifb0U8x7g2FjM6tJy9MmdAeDUQlyDzWwIDAQABo3kwdzAPBgNVHRMECDAG
+ AQH/AgEAMB0GA1UdDgQWBBSO2zh0skDMPeznfas3b3eUKvaqbzAfBgNVHSMEGDAW
+ gBQa+LZlKyhYfOWkFt2l8Tk0jkS11jALBgNVHQ8EBAMCAQYwFwYDVR0gBBAwDjAM
+ BgorBgEEAdZ5AgUCMA0GCSqGSIb3DQEBCwUAA4IBAQANr3/keM6aq1H3SC1uluw4
+ Po8NkY+ksmrV6tjYKPGMlU12vAVzDazuIsTOxl1OfUhFQwjYpNYUibK61aFPvDcj
+ JGqfzap5m7qzcxl9KwiqMCuBrbZv/IUjQnOWqQrlB+vjQo9Sju1WOEpmyytnWzkl
+ 670xoNxlw5ik99+Qh4sG19Ts1E9ck26YvRAc3oXKk3wh+QIU9IKDXOqeZ/2DpVix
+ mSv8s/phC/Q9NWlcDWWJmf8/8RM1OhhaqGUkcqSEW0zWz1nRQUs/iPcpKm+eO4Cj
+ o+p5Udp1wo7j/Kv+CcluBPnaeqO9guplGUiiKlFsfgXFOUdGwY8x96ltRqdbmy1H
+ -----END CERTIFICATE-----
+ */
+
+ 0x30, 0x82, 0x03, 0xEC, 0x30, 0x82, 0x02, 0xD4, 0xA0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x02, 0x01,
+ 0x38, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0B, 0x05, 0x00,
+ 0x30, 0x7B, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31,
+ 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0C, 0x0A, 0x43, 0x61, 0x6C, 0x69, 0x66, 0x6F,
+ 0x72, 0x6E, 0x69, 0x61, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0C, 0x0D, 0x4D,
+ 0x6F, 0x75, 0x6E, 0x74, 0x61, 0x69, 0x6E, 0x20, 0x56, 0x69, 0x65, 0x77, 0x31, 0x13, 0x30, 0x11,
+ 0x06, 0x03, 0x55, 0x04, 0x0A, 0x0C, 0x0A, 0x47, 0x6F, 0x6F, 0x67, 0x6C, 0x65, 0x20, 0x49, 0x6E,
+ 0x63, 0x31, 0x0D, 0x30, 0x0B, 0x06, 0x03, 0x55, 0x04, 0x0B, 0x0C, 0x04, 0x43, 0x61, 0x73, 0x74,
+ 0x31, 0x1B, 0x30, 0x19, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0C, 0x12, 0x43, 0x61, 0x73, 0x74, 0x20,
+ 0x54, 0x65, 0x73, 0x74, 0x20, 0x52, 0x6F, 0x6F, 0x74, 0x20, 0x49, 0x43, 0x41, 0x30, 0x1E, 0x17,
+ 0x0D, 0x31, 0x38, 0x30, 0x33, 0x31, 0x32, 0x32, 0x33, 0x35, 0x35, 0x30, 0x31, 0x5A, 0x17, 0x0D,
+ 0x33, 0x38, 0x30, 0x33, 0x30, 0x37, 0x32, 0x33, 0x35, 0x35, 0x30, 0x31, 0x5A, 0x30, 0x7C, 0x31,
+ 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11,
+ 0x06, 0x03, 0x55, 0x04, 0x08, 0x0C, 0x0A, 0x43, 0x61, 0x6C, 0x69, 0x66, 0x6F, 0x72, 0x6E, 0x69,
+ 0x61, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0C, 0x0D, 0x4D, 0x6F, 0x75, 0x6E,
+ 0x74, 0x61, 0x69, 0x6E, 0x20, 0x56, 0x69, 0x65, 0x77, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55,
+ 0x04, 0x0A, 0x0C, 0x0A, 0x47, 0x6F, 0x6F, 0x67, 0x6C, 0x65, 0x20, 0x49, 0x6E, 0x63, 0x31, 0x0D,
+ 0x30, 0x0B, 0x06, 0x03, 0x55, 0x04, 0x0B, 0x0C, 0x04, 0x43, 0x61, 0x73, 0x74, 0x31, 0x1C, 0x30,
+ 0x1A, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0C, 0x13, 0x43, 0x61, 0x73, 0x74, 0x20, 0x54, 0x65, 0x73,
+ 0x74, 0x20, 0x41, 0x75, 0x64, 0x69, 0x6F, 0x20, 0x49, 0x43, 0x41, 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, 0xD5, 0x8D, 0xB2, 0x8F,
+ 0xA9, 0x30, 0xE5, 0xFC, 0xA4, 0x32, 0x84, 0xD6, 0xEE, 0x3F, 0x53, 0xD7, 0x0E, 0x55, 0x49, 0xC4,
+ 0x1E, 0x59, 0x25, 0x67, 0x3E, 0x01, 0x56, 0xCF, 0x9A, 0x1B, 0x41, 0x16, 0x7B, 0x56, 0xB6, 0x0F,
+ 0x3A, 0x2F, 0xD9, 0x1E, 0xF6, 0xF4, 0xC9, 0xC3, 0x7E, 0xB3, 0xA8, 0xF5, 0x83, 0x6C, 0x72, 0x0C,
+ 0xC1, 0x60, 0x86, 0x57, 0x9C, 0x38, 0x30, 0x3D, 0x93, 0x40, 0x18, 0x65, 0x1E, 0x92, 0xC3, 0xB1,
+ 0x29, 0x92, 0x9A, 0x06, 0xBC, 0x30, 0x3F, 0xE6, 0x66, 0xD5, 0x94, 0xDE, 0xC3, 0xEB, 0xFB, 0x65,
+ 0x2E, 0x72, 0xC1, 0x91, 0xAE, 0x64, 0x53, 0x5A, 0xA1, 0x65, 0xFC, 0xD5, 0x77, 0xAC, 0x51, 0x15,
+ 0x8E, 0x20, 0xAB, 0x72, 0xD8, 0x83, 0x3D, 0xEA, 0x67, 0xC9, 0xAD, 0xF4, 0x0A, 0x5E, 0xAA, 0x25,
+ 0xF0, 0xDA, 0x16, 0x64, 0xDB, 0x82, 0x06, 0x77, 0xC5, 0x95, 0xBA, 0xCB, 0xCE, 0x59, 0x18, 0xAB,
+ 0xF9, 0xCD, 0xF2, 0x9D, 0x46, 0xE8, 0x2D, 0x27, 0xC9, 0xE5, 0x21, 0x15, 0xC0, 0xED, 0xBA, 0xE6,
+ 0xD6, 0xEB, 0xA7, 0x47, 0x13, 0x95, 0x64, 0x80, 0xE9, 0x3C, 0x45, 0xE3, 0x47, 0x74, 0x0A, 0x5A,
+ 0xE0, 0xAE, 0xB1, 0x93, 0x92, 0x85, 0xD0, 0xD9, 0x59, 0xD1, 0xE7, 0x10, 0x09, 0xED, 0x0E, 0xC5,
+ 0x9C, 0x57, 0xAC, 0xFD, 0x02, 0xD0, 0xBD, 0x7D, 0x39, 0x24, 0x91, 0x0E, 0x10, 0x5D, 0x25, 0xD1,
+ 0xE0, 0x92, 0xB2, 0xA9, 0xB2, 0xC8, 0x36, 0x15, 0x0E, 0x83, 0x41, 0x0B, 0x24, 0xCF, 0xB1, 0x21,
+ 0xE5, 0xEC, 0x51, 0x40, 0xCE, 0x9B, 0xA4, 0xAC, 0xAA, 0xF6, 0x7C, 0x1F, 0xCE, 0x36, 0xDE, 0xC5,
+ 0x46, 0xB9, 0x2F, 0x46, 0xC8, 0x9F, 0x6F, 0x45, 0x3C, 0xC7, 0xB8, 0x36, 0x16, 0x33, 0x3A, 0xB4,
+ 0x9C, 0xBD, 0x32, 0x67, 0x40, 0x78, 0x35, 0x10, 0x97, 0x20, 0xF3, 0x5B, 0x02, 0x03, 0x01, 0x00,
+ 0x01, 0xA3, 0x79, 0x30, 0x77, 0x30, 0x0F, 0x06, 0x03, 0x55, 0x1D, 0x13, 0x04, 0x08, 0x30, 0x06,
+ 0x01, 0x01, 0xFF, 0x02, 0x01, 0x00, 0x30, 0x1D, 0x06, 0x03, 0x55, 0x1D, 0x0E, 0x04, 0x16, 0x04,
+ 0x14, 0x8E, 0xDB, 0x38, 0x74, 0xB2, 0x40, 0xCC, 0x3D, 0xEC, 0xE7, 0x7D, 0xAB, 0x37, 0x6F, 0x77,
+ 0x94, 0x2A, 0xF6, 0xAA, 0x6F, 0x30, 0x1F, 0x06, 0x03, 0x55, 0x1D, 0x23, 0x04, 0x18, 0x30, 0x16,
+ 0x80, 0x14, 0x1A, 0xF8, 0xB6, 0x65, 0x2B, 0x28, 0x58, 0x7C, 0xE5, 0xA4, 0x16, 0xDD, 0xA5, 0xF1,
+ 0x39, 0x34, 0x8E, 0x44, 0xB5, 0xD6, 0x30, 0x0B, 0x06, 0x03, 0x55, 0x1D, 0x0F, 0x04, 0x04, 0x03,
+ 0x02, 0x01, 0x06, 0x30, 0x17, 0x06, 0x03, 0x55, 0x1D, 0x20, 0x04, 0x10, 0x30, 0x0E, 0x30, 0x0C,
+ 0x06, 0x0A, 0x2B, 0x06, 0x01, 0x04, 0x01, 0xD6, 0x79, 0x02, 0x05, 0x02, 0x30, 0x0D, 0x06, 0x09,
+ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0B, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00,
+ 0x0D, 0xAF, 0x7F, 0xE4, 0x78, 0xCE, 0x9A, 0xAB, 0x51, 0xF7, 0x48, 0x2D, 0x6E, 0x96, 0xEC, 0x38,
+ 0x3E, 0x8F, 0x0D, 0x91, 0x8F, 0xA4, 0xB2, 0x6A, 0xD5, 0xEA, 0xD8, 0xD8, 0x28, 0xF1, 0x8C, 0x95,
+ 0x4D, 0x76, 0xBC, 0x05, 0x73, 0x0D, 0xAC, 0xEE, 0x22, 0xC4, 0xCE, 0xC6, 0x5D, 0x4E, 0x7D, 0x48,
+ 0x45, 0x43, 0x08, 0xD8, 0xA4, 0xD6, 0x14, 0x89, 0xB2, 0xBA, 0xD5, 0xA1, 0x4F, 0xBC, 0x37, 0x23,
+ 0x24, 0x6A, 0x9F, 0xCD, 0xAA, 0x79, 0x9B, 0xBA, 0xB3, 0x73, 0x19, 0x7D, 0x2B, 0x08, 0xAA, 0x30,
+ 0x2B, 0x81, 0xAD, 0xB6, 0x6F, 0xFC, 0x85, 0x23, 0x42, 0x73, 0x96, 0xA9, 0x0A, 0xE5, 0x07, 0xEB,
+ 0xE3, 0x42, 0x8F, 0x52, 0x8E, 0xED, 0x56, 0x38, 0x4A, 0x66, 0xCB, 0x2B, 0x67, 0x5B, 0x39, 0x25,
+ 0xEB, 0xBD, 0x31, 0xA0, 0xDC, 0x65, 0xC3, 0x98, 0xA4, 0xF7, 0xDF, 0x90, 0x87, 0x8B, 0x06, 0xD7,
+ 0xD4, 0xEC, 0xD4, 0x4F, 0x5C, 0x93, 0x6E, 0x98, 0xBD, 0x10, 0x1C, 0xDE, 0x85, 0xCA, 0x93, 0x7C,
+ 0x21, 0xF9, 0x02, 0x14, 0xF4, 0x82, 0x83, 0x5C, 0xEA, 0x9E, 0x67, 0xFD, 0x83, 0xA5, 0x58, 0xB1,
+ 0x99, 0x2B, 0xFC, 0xB3, 0xFA, 0x61, 0x0B, 0xF4, 0x3D, 0x35, 0x69, 0x5C, 0x0D, 0x65, 0x89, 0x99,
+ 0xFF, 0x3F, 0xF1, 0x13, 0x35, 0x3A, 0x18, 0x5A, 0xA8, 0x65, 0x24, 0x72, 0xA4, 0x84, 0x5B, 0x4C,
+ 0xD6, 0xCF, 0x59, 0xD1, 0x41, 0x4B, 0x3F, 0x88, 0xF7, 0x29, 0x2A, 0x6F, 0x9E, 0x3B, 0x80, 0xA3,
+ 0xA3, 0xEA, 0x79, 0x51, 0xDA, 0x75, 0xC2, 0x8E, 0xE3, 0xFC, 0xAB, 0xFE, 0x09, 0xC9, 0x6E, 0x04,
+ 0xF9, 0xDA, 0x7A, 0xA3, 0xBD, 0x82, 0xEA, 0x65, 0x19, 0x48, 0xA2, 0x2A, 0x51, 0x6C, 0x7E, 0x05,
+ 0xC5, 0x39, 0x47, 0x46, 0xC1, 0x8F, 0x31, 0xF7, 0xA9, 0x6D, 0x46, 0xA7, 0x5B, 0x9B, 0x2D, 0x47,
+};
+
+extern const uint16_t TestDevice1_X509_RSA_ICACert1Length = sizeof(TestDevice1_X509_RSA_ICACert1);
+
+extern const uint8_t TestDevice1_X509_RSA_ICACert2[] =
+{
+
+ /*
+ -----BEGIN CERTIFICATE-----
+ MIIDzDCCArSgAwIBAgICATYwDQYJKoZIhvcNAQELBQAwdTELMAkGA1UEBhMCVVMx
+ EzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDU1vdW50YWluIFZpZXcxEzAR
+ BgNVBAoMCkdvb2dsZSBJbmMxDTALBgNVBAsMBENhc3QxFTATBgNVBAMMDENhc3Qg
+ Um9vdCBDQTAeFw0xODAzMTIyMzQ4MzVaFw0zODAzMDcyMzQ4MzVaMHsxCzAJBgNV
+ BAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1Nb3VudGFpbiBW
+ aWV3MRMwEQYDVQQKDApHb29nbGUgSW5jMQ0wCwYDVQQLDARDYXN0MRswGQYDVQQD
+ DBJDYXN0IFRlc3QgUm9vdCBJQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
+ AoIBAQDrqU17a/iZxhBMMiKBj7nj8QFJmbJU131Xyw9p5VzwaJm/5Y7kGArxJHiR
+ +1qURs0/1Vnijv6jhOCLLj+KUdPyUvtXKVFPkQ7IXOrGnuV2gS5M8I6GDu/pKp0z
+ X8+94MBQbX+vODiLXtahzXwjEsHkqwjwy2tuo/qGna8n83fWGLavedmtlVCVIRdw
+ y2VOr5xXJ2IL0+U1Qh275Lp56iYdOCWLFjpjgJJVrmfI90+iqo3syEFKknm6JsoR
+ R1smAgR8yEZwNN2SdipFWun59OthNGS3+oB5v7N4oCc7NttpPotbOOR1FHucF/SJ
+ HEVKqMpJyjowOEXfHYfA1Tj2oUkTAgMBAAGjYDBeMA8GA1UdEwQIMAYBAf8CAQEw
+ HQYDVR0OBBYEFBr4tmUrKFh85aQW3aXxOTSORLXWMB8GA1UdIwQYMBaAFHyaHn3f
+ eVS818xeypmGRXlldCgZMAsGA1UdDwQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAQEA
+ d5GrKh+V1uDMeU1UdLP8OxwOg4DXqBna6qK3pZBEcnLaZv7/KydTTUzGSrdSVCEx
+ P8rn7XB5mxhyItHQSIuPNwKLTN4UjiaaSebl+HFBJwM9uTIqMIy32IswZEv2ULIU
+ tztmFqpKf1Mfm67u0jcxtZM3KpCGIhcVsCS2eiGsBEfXds6dXalO6t7aCRNvRaDm
+ eA09ePKateEemtaTDWEJKYNfNGZNW8OyRaHcTXwE8HMrO2s4wFFW0k3oRmiddxBC
+ YCel+gXvw1UiD3pINLrlH36NNFxyfBfgLhZ7Idyi4LPBvrouQ2qcC76N0l1rbloT
+ /9mT+6JUYu/LVFGfwtTtWQ==
+ -----END CERTIFICATE-----
+ */
+
+ 0x30, 0x82, 0x03, 0xCC, 0x30, 0x82, 0x02, 0xB4, 0xA0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x02, 0x01,
+ 0x36, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0B, 0x05, 0x00,
+ 0x30, 0x75, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31,
+ 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0C, 0x0A, 0x43, 0x61, 0x6C, 0x69, 0x66, 0x6F,
+ 0x72, 0x6E, 0x69, 0x61, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0C, 0x0D, 0x4D,
+ 0x6F, 0x75, 0x6E, 0x74, 0x61, 0x69, 0x6E, 0x20, 0x56, 0x69, 0x65, 0x77, 0x31, 0x13, 0x30, 0x11,
+ 0x06, 0x03, 0x55, 0x04, 0x0A, 0x0C, 0x0A, 0x47, 0x6F, 0x6F, 0x67, 0x6C, 0x65, 0x20, 0x49, 0x6E,
+ 0x63, 0x31, 0x0D, 0x30, 0x0B, 0x06, 0x03, 0x55, 0x04, 0x0B, 0x0C, 0x04, 0x43, 0x61, 0x73, 0x74,
+ 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0C, 0x0C, 0x43, 0x61, 0x73, 0x74, 0x20,
+ 0x52, 0x6F, 0x6F, 0x74, 0x20, 0x43, 0x41, 0x30, 0x1E, 0x17, 0x0D, 0x31, 0x38, 0x30, 0x33, 0x31,
+ 0x32, 0x32, 0x33, 0x34, 0x38, 0x33, 0x35, 0x5A, 0x17, 0x0D, 0x33, 0x38, 0x30, 0x33, 0x30, 0x37,
+ 0x32, 0x33, 0x34, 0x38, 0x33, 0x35, 0x5A, 0x30, 0x7B, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55,
+ 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0C,
+ 0x0A, 0x43, 0x61, 0x6C, 0x69, 0x66, 0x6F, 0x72, 0x6E, 0x69, 0x61, 0x31, 0x16, 0x30, 0x14, 0x06,
+ 0x03, 0x55, 0x04, 0x07, 0x0C, 0x0D, 0x4D, 0x6F, 0x75, 0x6E, 0x74, 0x61, 0x69, 0x6E, 0x20, 0x56,
+ 0x69, 0x65, 0x77, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x0A, 0x0C, 0x0A, 0x47, 0x6F,
+ 0x6F, 0x67, 0x6C, 0x65, 0x20, 0x49, 0x6E, 0x63, 0x31, 0x0D, 0x30, 0x0B, 0x06, 0x03, 0x55, 0x04,
+ 0x0B, 0x0C, 0x04, 0x43, 0x61, 0x73, 0x74, 0x31, 0x1B, 0x30, 0x19, 0x06, 0x03, 0x55, 0x04, 0x03,
+ 0x0C, 0x12, 0x43, 0x61, 0x73, 0x74, 0x20, 0x54, 0x65, 0x73, 0x74, 0x20, 0x52, 0x6F, 0x6F, 0x74,
+ 0x20, 0x49, 0x43, 0x41, 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, 0xEB, 0xA9, 0x4D, 0x7B, 0x6B, 0xF8, 0x99, 0xC6, 0x10, 0x4C, 0x32,
+ 0x22, 0x81, 0x8F, 0xB9, 0xE3, 0xF1, 0x01, 0x49, 0x99, 0xB2, 0x54, 0xD7, 0x7D, 0x57, 0xCB, 0x0F,
+ 0x69, 0xE5, 0x5C, 0xF0, 0x68, 0x99, 0xBF, 0xE5, 0x8E, 0xE4, 0x18, 0x0A, 0xF1, 0x24, 0x78, 0x91,
+ 0xFB, 0x5A, 0x94, 0x46, 0xCD, 0x3F, 0xD5, 0x59, 0xE2, 0x8E, 0xFE, 0xA3, 0x84, 0xE0, 0x8B, 0x2E,
+ 0x3F, 0x8A, 0x51, 0xD3, 0xF2, 0x52, 0xFB, 0x57, 0x29, 0x51, 0x4F, 0x91, 0x0E, 0xC8, 0x5C, 0xEA,
+ 0xC6, 0x9E, 0xE5, 0x76, 0x81, 0x2E, 0x4C, 0xF0, 0x8E, 0x86, 0x0E, 0xEF, 0xE9, 0x2A, 0x9D, 0x33,
+ 0x5F, 0xCF, 0xBD, 0xE0, 0xC0, 0x50, 0x6D, 0x7F, 0xAF, 0x38, 0x38, 0x8B, 0x5E, 0xD6, 0xA1, 0xCD,
+ 0x7C, 0x23, 0x12, 0xC1, 0xE4, 0xAB, 0x08, 0xF0, 0xCB, 0x6B, 0x6E, 0xA3, 0xFA, 0x86, 0x9D, 0xAF,
+ 0x27, 0xF3, 0x77, 0xD6, 0x18, 0xB6, 0xAF, 0x79, 0xD9, 0xAD, 0x95, 0x50, 0x95, 0x21, 0x17, 0x70,
+ 0xCB, 0x65, 0x4E, 0xAF, 0x9C, 0x57, 0x27, 0x62, 0x0B, 0xD3, 0xE5, 0x35, 0x42, 0x1D, 0xBB, 0xE4,
+ 0xBA, 0x79, 0xEA, 0x26, 0x1D, 0x38, 0x25, 0x8B, 0x16, 0x3A, 0x63, 0x80, 0x92, 0x55, 0xAE, 0x67,
+ 0xC8, 0xF7, 0x4F, 0xA2, 0xAA, 0x8D, 0xEC, 0xC8, 0x41, 0x4A, 0x92, 0x79, 0xBA, 0x26, 0xCA, 0x11,
+ 0x47, 0x5B, 0x26, 0x02, 0x04, 0x7C, 0xC8, 0x46, 0x70, 0x34, 0xDD, 0x92, 0x76, 0x2A, 0x45, 0x5A,
+ 0xE9, 0xF9, 0xF4, 0xEB, 0x61, 0x34, 0x64, 0xB7, 0xFA, 0x80, 0x79, 0xBF, 0xB3, 0x78, 0xA0, 0x27,
+ 0x3B, 0x36, 0xDB, 0x69, 0x3E, 0x8B, 0x5B, 0x38, 0xE4, 0x75, 0x14, 0x7B, 0x9C, 0x17, 0xF4, 0x89,
+ 0x1C, 0x45, 0x4A, 0xA8, 0xCA, 0x49, 0xCA, 0x3A, 0x30, 0x38, 0x45, 0xDF, 0x1D, 0x87, 0xC0, 0xD5,
+ 0x38, 0xF6, 0xA1, 0x49, 0x13, 0x02, 0x03, 0x01, 0x00, 0x01, 0xA3, 0x60, 0x30, 0x5E, 0x30, 0x0F,
+ 0x06, 0x03, 0x55, 0x1D, 0x13, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xFF, 0x02, 0x01, 0x01, 0x30,
+ 0x1D, 0x06, 0x03, 0x55, 0x1D, 0x0E, 0x04, 0x16, 0x04, 0x14, 0x1A, 0xF8, 0xB6, 0x65, 0x2B, 0x28,
+ 0x58, 0x7C, 0xE5, 0xA4, 0x16, 0xDD, 0xA5, 0xF1, 0x39, 0x34, 0x8E, 0x44, 0xB5, 0xD6, 0x30, 0x1F,
+ 0x06, 0x03, 0x55, 0x1D, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x7C, 0x9A, 0x1E, 0x7D, 0xDF,
+ 0x79, 0x54, 0xBC, 0xD7, 0xCC, 0x5E, 0xCA, 0x99, 0x86, 0x45, 0x79, 0x65, 0x74, 0x28, 0x19, 0x30,
+ 0x0B, 0x06, 0x03, 0x55, 0x1D, 0x0F, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x0D, 0x06, 0x09,
+ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0B, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00,
+ 0x77, 0x91, 0xAB, 0x2A, 0x1F, 0x95, 0xD6, 0xE0, 0xCC, 0x79, 0x4D, 0x54, 0x74, 0xB3, 0xFC, 0x3B,
+ 0x1C, 0x0E, 0x83, 0x80, 0xD7, 0xA8, 0x19, 0xDA, 0xEA, 0xA2, 0xB7, 0xA5, 0x90, 0x44, 0x72, 0x72,
+ 0xDA, 0x66, 0xFE, 0xFF, 0x2B, 0x27, 0x53, 0x4D, 0x4C, 0xC6, 0x4A, 0xB7, 0x52, 0x54, 0x21, 0x31,
+ 0x3F, 0xCA, 0xE7, 0xED, 0x70, 0x79, 0x9B, 0x18, 0x72, 0x22, 0xD1, 0xD0, 0x48, 0x8B, 0x8F, 0x37,
+ 0x02, 0x8B, 0x4C, 0xDE, 0x14, 0x8E, 0x26, 0x9A, 0x49, 0xE6, 0xE5, 0xF8, 0x71, 0x41, 0x27, 0x03,
+ 0x3D, 0xB9, 0x32, 0x2A, 0x30, 0x8C, 0xB7, 0xD8, 0x8B, 0x30, 0x64, 0x4B, 0xF6, 0x50, 0xB2, 0x14,
+ 0xB7, 0x3B, 0x66, 0x16, 0xAA, 0x4A, 0x7F, 0x53, 0x1F, 0x9B, 0xAE, 0xEE, 0xD2, 0x37, 0x31, 0xB5,
+ 0x93, 0x37, 0x2A, 0x90, 0x86, 0x22, 0x17, 0x15, 0xB0, 0x24, 0xB6, 0x7A, 0x21, 0xAC, 0x04, 0x47,
+ 0xD7, 0x76, 0xCE, 0x9D, 0x5D, 0xA9, 0x4E, 0xEA, 0xDE, 0xDA, 0x09, 0x13, 0x6F, 0x45, 0xA0, 0xE6,
+ 0x78, 0x0D, 0x3D, 0x78, 0xF2, 0x9A, 0xB5, 0xE1, 0x1E, 0x9A, 0xD6, 0x93, 0x0D, 0x61, 0x09, 0x29,
+ 0x83, 0x5F, 0x34, 0x66, 0x4D, 0x5B, 0xC3, 0xB2, 0x45, 0xA1, 0xDC, 0x4D, 0x7C, 0x04, 0xF0, 0x73,
+ 0x2B, 0x3B, 0x6B, 0x38, 0xC0, 0x51, 0x56, 0xD2, 0x4D, 0xE8, 0x46, 0x68, 0x9D, 0x77, 0x10, 0x42,
+ 0x60, 0x27, 0xA5, 0xFA, 0x05, 0xEF, 0xC3, 0x55, 0x22, 0x0F, 0x7A, 0x48, 0x34, 0xBA, 0xE5, 0x1F,
+ 0x7E, 0x8D, 0x34, 0x5C, 0x72, 0x7C, 0x17, 0xE0, 0x2E, 0x16, 0x7B, 0x21, 0xDC, 0xA2, 0xE0, 0xB3,
+ 0xC1, 0xBE, 0xBA, 0x2E, 0x43, 0x6A, 0x9C, 0x0B, 0xBE, 0x8D, 0xD2, 0x5D, 0x6B, 0x6E, 0x5A, 0x13,
+ 0xFF, 0xD9, 0x93, 0xFB, 0xA2, 0x54, 0x62, 0xEF, 0xCB, 0x54, 0x51, 0x9F, 0xC2, 0xD4, 0xED, 0x59,
+};
+
+extern const uint16_t TestDevice1_X509_RSA_ICACert2Length = sizeof(TestDevice1_X509_RSA_ICACert2);
+
+extern const uint8_t TestDevice_X509_RSA_RootCert[] =
+{
+
+ /*
+ -----BEGIN CERTIFICATE-----
+ MIIDxTCCAq2gAwIBAgIBAjANBgkqhkiG9w0BAQUFADB1MQswCQYDVQQGEwJVUzET
+ MBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzETMBEG
+ A1UECgwKR29vZ2xlIEluYzENMAsGA1UECwwEQ2FzdDEVMBMGA1UEAwwMQ2FzdCBS
+ b290IENBMB4XDTE0MDQwMjE3MzQyNloXDTM0MDMyODE3MzQyNlowdTELMAkGA1UE
+ BhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDU1vdW50YWluIFZp
+ ZXcxEzARBgNVBAoMCkdvb2dsZSBJbmMxDTALBgNVBAsMBENhc3QxFTATBgNVBAMM
+ DENhc3QgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALrZ
+ ZZ3aOdPBd/bU0K6PWAhoOUqV7XDP/XkIqarl6binLaBnR4qeyc9wswWHaRHscJiX
+ w+bDw+u9xrA9/E/BXjif2s9zMAZbeTfBXoyHR5SaQZIq1pXEcVwnXQixgMaSvRvj
+ QZeh7HWfVZ4+n48cx2VkB9OzlqEEn5HE3gp7bNnIwHgxoBlCqeiD48788c7CLiRG
+ lQkZysBGsuUButdP87/2aa2ZBPqgBzkO5t9RRwfA5KlcS5TFL7OgMH/nlWuyrzIN
+ 8YzVbct7R6cIq8sno03PSlrxBdH4YsUQKnRpquZLlvub2GPkWGbTrYpu/3te+aVW
+ Hi2CMVvw4iTmQUofrhMCAwEAAaNgMF4wDwYDVR0TBAgwBgEB/wIBAjAdBgNVHQ4E
+ FgQUfJoefd95VLzXzF7KmYZFeWV0KBkwHwYDVR0jBBgwFoAUfJoefd95VLzXzF7K
+ mYZFeWV0KBkwCwYDVR0PBAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQCA9Fr7PSgZ
+ USDX1PsSl0pl8lg1kncwavHXtlEaf5rNx3sDQq1VagCv8OEGwr1reHXb/kERU0o5
+ u5o6xlk0Lywz47LWXH/deOtxWznag5DFMeI/I+/a6ystd17ew0PSyWtZgsrV7fqh
+ ZFvL8Q0aYuGc6KcYcPBfF5b47Ybbrh3gzz5dLu4WbZUrPP2X8wVaJGhNObb45Fi6
+ 9eAmeFHFW11OCeVsR4t6Wi6JU+bMNlsmPPhyQwKC0ivN8NOj7BM+UtWDPQfcHUNl
+ ejMCAaPOt9ZgUTsJwiOKMv6YGWBik4XNNEbb1SMPedp3ACoCbYNYzgN3NeGjIJPC
+ SqKkRhx1LB9N
+ -----END CERTIFICATE-----
+ */
+
+ 0x30, 0x82, 0x03, 0xC5, 0x30, 0x82, 0x02, 0xAD, 0xA0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x01, 0x02,
+ 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30,
+ 0x75, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13,
+ 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0C, 0x0A, 0x43, 0x61, 0x6C, 0x69, 0x66, 0x6F, 0x72,
+ 0x6E, 0x69, 0x61, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0C, 0x0D, 0x4D, 0x6F,
+ 0x75, 0x6E, 0x74, 0x61, 0x69, 0x6E, 0x20, 0x56, 0x69, 0x65, 0x77, 0x31, 0x13, 0x30, 0x11, 0x06,
+ 0x03, 0x55, 0x04, 0x0A, 0x0C, 0x0A, 0x47, 0x6F, 0x6F, 0x67, 0x6C, 0x65, 0x20, 0x49, 0x6E, 0x63,
+ 0x31, 0x0D, 0x30, 0x0B, 0x06, 0x03, 0x55, 0x04, 0x0B, 0x0C, 0x04, 0x43, 0x61, 0x73, 0x74, 0x31,
+ 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0C, 0x0C, 0x43, 0x61, 0x73, 0x74, 0x20, 0x52,
+ 0x6F, 0x6F, 0x74, 0x20, 0x43, 0x41, 0x30, 0x1E, 0x17, 0x0D, 0x31, 0x34, 0x30, 0x34, 0x30, 0x32,
+ 0x31, 0x37, 0x33, 0x34, 0x32, 0x36, 0x5A, 0x17, 0x0D, 0x33, 0x34, 0x30, 0x33, 0x32, 0x38, 0x31,
+ 0x37, 0x33, 0x34, 0x32, 0x36, 0x5A, 0x30, 0x75, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04,
+ 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0C, 0x0A,
+ 0x43, 0x61, 0x6C, 0x69, 0x66, 0x6F, 0x72, 0x6E, 0x69, 0x61, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03,
+ 0x55, 0x04, 0x07, 0x0C, 0x0D, 0x4D, 0x6F, 0x75, 0x6E, 0x74, 0x61, 0x69, 0x6E, 0x20, 0x56, 0x69,
+ 0x65, 0x77, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x0A, 0x0C, 0x0A, 0x47, 0x6F, 0x6F,
+ 0x67, 0x6C, 0x65, 0x20, 0x49, 0x6E, 0x63, 0x31, 0x0D, 0x30, 0x0B, 0x06, 0x03, 0x55, 0x04, 0x0B,
+ 0x0C, 0x04, 0x43, 0x61, 0x73, 0x74, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0C,
+ 0x0C, 0x43, 0x61, 0x73, 0x74, 0x20, 0x52, 0x6F, 0x6F, 0x74, 0x20, 0x43, 0x41, 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, 0xBA, 0xD9,
+ 0x65, 0x9D, 0xDA, 0x39, 0xD3, 0xC1, 0x77, 0xF6, 0xD4, 0xD0, 0xAE, 0x8F, 0x58, 0x08, 0x68, 0x39,
+ 0x4A, 0x95, 0xED, 0x70, 0xCF, 0xFD, 0x79, 0x08, 0xA9, 0xAA, 0xE5, 0xE9, 0xB8, 0xA7, 0x2D, 0xA0,
+ 0x67, 0x47, 0x8A, 0x9E, 0xC9, 0xCF, 0x70, 0xB3, 0x05, 0x87, 0x69, 0x11, 0xEC, 0x70, 0x98, 0x97,
+ 0xC3, 0xE6, 0xC3, 0xC3, 0xEB, 0xBD, 0xC6, 0xB0, 0x3D, 0xFC, 0x4F, 0xC1, 0x5E, 0x38, 0x9F, 0xDA,
+ 0xCF, 0x73, 0x30, 0x06, 0x5B, 0x79, 0x37, 0xC1, 0x5E, 0x8C, 0x87, 0x47, 0x94, 0x9A, 0x41, 0x92,
+ 0x2A, 0xD6, 0x95, 0xC4, 0x71, 0x5C, 0x27, 0x5D, 0x08, 0xB1, 0x80, 0xC6, 0x92, 0xBD, 0x1B, 0xE3,
+ 0x41, 0x97, 0xA1, 0xEC, 0x75, 0x9F, 0x55, 0x9E, 0x3E, 0x9F, 0x8F, 0x1C, 0xC7, 0x65, 0x64, 0x07,
+ 0xD3, 0xB3, 0x96, 0xA1, 0x04, 0x9F, 0x91, 0xC4, 0xDE, 0x0A, 0x7B, 0x6C, 0xD9, 0xC8, 0xC0, 0x78,
+ 0x31, 0xA0, 0x19, 0x42, 0xA9, 0xE8, 0x83, 0xE3, 0xCE, 0xFC, 0xF1, 0xCE, 0xC2, 0x2E, 0x24, 0x46,
+ 0x95, 0x09, 0x19, 0xCA, 0xC0, 0x46, 0xB2, 0xE5, 0x01, 0xBA, 0xD7, 0x4F, 0xF3, 0xBF, 0xF6, 0x69,
+ 0xAD, 0x99, 0x04, 0xFA, 0xA0, 0x07, 0x39, 0x0E, 0xE6, 0xDF, 0x51, 0x47, 0x07, 0xC0, 0xE4, 0xA9,
+ 0x5C, 0x4B, 0x94, 0xC5, 0x2F, 0xB3, 0xA0, 0x30, 0x7F, 0xE7, 0x95, 0x6B, 0xB2, 0xAF, 0x32, 0x0D,
+ 0xF1, 0x8C, 0xD5, 0x6D, 0xCB, 0x7B, 0x47, 0xA7, 0x08, 0xAB, 0xCB, 0x27, 0xA3, 0x4D, 0xCF, 0x4A,
+ 0x5A, 0xF1, 0x05, 0xD1, 0xF8, 0x62, 0xC5, 0x10, 0x2A, 0x74, 0x69, 0xAA, 0xE6, 0x4B, 0x96, 0xFB,
+ 0x9B, 0xD8, 0x63, 0xE4, 0x58, 0x66, 0xD3, 0xAD, 0x8A, 0x6E, 0xFF, 0x7B, 0x5E, 0xF9, 0xA5, 0x56,
+ 0x1E, 0x2D, 0x82, 0x31, 0x5B, 0xF0, 0xE2, 0x24, 0xE6, 0x41, 0x4A, 0x1F, 0xAE, 0x13, 0x02, 0x03,
+ 0x01, 0x00, 0x01, 0xA3, 0x60, 0x30, 0x5E, 0x30, 0x0F, 0x06, 0x03, 0x55, 0x1D, 0x13, 0x04, 0x08,
+ 0x30, 0x06, 0x01, 0x01, 0xFF, 0x02, 0x01, 0x02, 0x30, 0x1D, 0x06, 0x03, 0x55, 0x1D, 0x0E, 0x04,
+ 0x16, 0x04, 0x14, 0x7C, 0x9A, 0x1E, 0x7D, 0xDF, 0x79, 0x54, 0xBC, 0xD7, 0xCC, 0x5E, 0xCA, 0x99,
+ 0x86, 0x45, 0x79, 0x65, 0x74, 0x28, 0x19, 0x30, 0x1F, 0x06, 0x03, 0x55, 0x1D, 0x23, 0x04, 0x18,
+ 0x30, 0x16, 0x80, 0x14, 0x7C, 0x9A, 0x1E, 0x7D, 0xDF, 0x79, 0x54, 0xBC, 0xD7, 0xCC, 0x5E, 0xCA,
+ 0x99, 0x86, 0x45, 0x79, 0x65, 0x74, 0x28, 0x19, 0x30, 0x0B, 0x06, 0x03, 0x55, 0x1D, 0x0F, 0x04,
+ 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01,
+ 0x01, 0x05, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x80, 0xF4, 0x5A, 0xFB, 0x3D, 0x28, 0x19,
+ 0x51, 0x20, 0xD7, 0xD4, 0xFB, 0x12, 0x97, 0x4A, 0x65, 0xF2, 0x58, 0x35, 0x92, 0x77, 0x30, 0x6A,
+ 0xF1, 0xD7, 0xB6, 0x51, 0x1A, 0x7F, 0x9A, 0xCD, 0xC7, 0x7B, 0x03, 0x42, 0xAD, 0x55, 0x6A, 0x00,
+ 0xAF, 0xF0, 0xE1, 0x06, 0xC2, 0xBD, 0x6B, 0x78, 0x75, 0xDB, 0xFE, 0x41, 0x11, 0x53, 0x4A, 0x39,
+ 0xBB, 0x9A, 0x3A, 0xC6, 0x59, 0x34, 0x2F, 0x2C, 0x33, 0xE3, 0xB2, 0xD6, 0x5C, 0x7F, 0xDD, 0x78,
+ 0xEB, 0x71, 0x5B, 0x39, 0xDA, 0x83, 0x90, 0xC5, 0x31, 0xE2, 0x3F, 0x23, 0xEF, 0xDA, 0xEB, 0x2B,
+ 0x2D, 0x77, 0x5E, 0xDE, 0xC3, 0x43, 0xD2, 0xC9, 0x6B, 0x59, 0x82, 0xCA, 0xD5, 0xED, 0xFA, 0xA1,
+ 0x64, 0x5B, 0xCB, 0xF1, 0x0D, 0x1A, 0x62, 0xE1, 0x9C, 0xE8, 0xA7, 0x18, 0x70, 0xF0, 0x5F, 0x17,
+ 0x96, 0xF8, 0xED, 0x86, 0xDB, 0xAE, 0x1D, 0xE0, 0xCF, 0x3E, 0x5D, 0x2E, 0xEE, 0x16, 0x6D, 0x95,
+ 0x2B, 0x3C, 0xFD, 0x97, 0xF3, 0x05, 0x5A, 0x24, 0x68, 0x4D, 0x39, 0xB6, 0xF8, 0xE4, 0x58, 0xBA,
+ 0xF5, 0xE0, 0x26, 0x78, 0x51, 0xC5, 0x5B, 0x5D, 0x4E, 0x09, 0xE5, 0x6C, 0x47, 0x8B, 0x7A, 0x5A,
+ 0x2E, 0x89, 0x53, 0xE6, 0xCC, 0x36, 0x5B, 0x26, 0x3C, 0xF8, 0x72, 0x43, 0x02, 0x82, 0xD2, 0x2B,
+ 0xCD, 0xF0, 0xD3, 0xA3, 0xEC, 0x13, 0x3E, 0x52, 0xD5, 0x83, 0x3D, 0x07, 0xDC, 0x1D, 0x43, 0x65,
+ 0x7A, 0x33, 0x02, 0x01, 0xA3, 0xCE, 0xB7, 0xD6, 0x60, 0x51, 0x3B, 0x09, 0xC2, 0x23, 0x8A, 0x32,
+ 0xFE, 0x98, 0x19, 0x60, 0x62, 0x93, 0x85, 0xCD, 0x34, 0x46, 0xDB, 0xD5, 0x23, 0x0F, 0x79, 0xDA,
+ 0x77, 0x00, 0x2A, 0x02, 0x6D, 0x83, 0x58, 0xCE, 0x03, 0x77, 0x35, 0xE1, 0xA3, 0x20, 0x93, 0xC2,
+ 0x4A, 0xA2, 0xA4, 0x46, 0x1C, 0x75, 0x2C, 0x1F, 0x4D,
+};
+
+extern const uint16_t TestDevice_X509_RSA_RootCertLength = sizeof(TestDevice_X509_RSA_RootCert);
diff --git a/src/test-apps/Makefile.am b/src/test-apps/Makefile.am
index 9d35c48..c46a09a 100644
--- a/src/test-apps/Makefile.am
+++ b/src/test-apps/Makefile.am
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2018-2019 Google LLC
+# Copyright (c) 2018-2020 Google LLC
# Copyright (c) 2014-2018 Nest Labs, Inc.
# All rights reserved.
#
@@ -81,9 +81,11 @@
#
noinst_HEADERS = \
CASEOptions.h \
+ CertProvOptions.h \
DMTestClient.h \
DeviceDescOptions.h \
KeyExportOptions.h \
+ MockCAService.h \
MockDCLPServer.h \
MockDCServer.h \
MockDDServer.h \
@@ -117,7 +119,7 @@
MockWdmViewServer.h \
PASEEngineTest.h \
TAKEOptions.h \
- TapAddrAutoconf.h \
+ TapAddrAutoconf.h \
TestDRBG.h \
TestEventLoggingSchemaExamples.h \
TestGroupKeyStore.h \
@@ -197,11 +199,13 @@
libWeaveTestCommon_a_SOURCES = \
CASEOptions.cpp \
+ CertProvOptions.cpp \
KeyExportOptions.cpp \
TAKEOptions.cpp \
DeviceDescOptions.cpp \
Certs.cpp \
TestGroupKeyStore.cpp \
+ TestWeaveCertData.cpp \
ToolCommon.cpp \
ToolCommonOptions.cpp \
TapAddrAutoconf.cpp \
@@ -293,6 +297,8 @@
endif
libexec_PROGRAMS += \
+ weave-cert-prov-client \
+ weave-cert-prov-server \
weave-device-descriptor \
weave-key-export \
weave-ping \
@@ -308,6 +314,7 @@
TestAppKeys \
TestArgParser \
TestCASE \
+ TestCertProv \
TestCodeUtils \
TestCrypto \
TestDRBG \
@@ -423,6 +430,7 @@
TestAppKeys \
TestArgParser \
TestCASE \
+ TestCertProv \
TestCodeUtils \
TestCrypto \
TestDRBG \
@@ -1169,6 +1177,10 @@
TestCASE_LDFLAGS = $(AM_CPPFLAGS)
TestCASE_LDADD = libWeaveTestCommon.a $(COMMON_LDADD)
+TestCertProv_SOURCES = TestCertProv.cpp MockCAService.cpp
+TestCertProv_LDFLAGS = $(AM_CPPFLAGS)
+TestCertProv_LDADD = libWeaveTestCommon.a $(COMMON_LDADD)
+
TestCodeUtils_SOURCES = TestCodeUtils.cpp
TestCodeUtils_LDADD =
@@ -1417,7 +1429,7 @@
schema/weave/trait/locale/LocaleCapabilitiesTrait.cpp \
schema/weave/trait/security/BoltLockSettingsTrait.cpp \
schema/weave/trait/telemetry/NetworkWiFiTelemetryTrait.cpp \
- MockWdmNodeOptions.cpp \
+ MockWdmNodeOptions.cpp \
MockWdmViewServer.cpp \
MockWdmViewClient.cpp \
MockWdmSubscriptionInitiator.cpp \
@@ -1485,7 +1497,7 @@
MockWdmSubscriptionInitiator.cpp \
MockWdmTestVerifier.cpp \
MockWdmSubscriptionResponder.cpp \
- MockWdmNodeOptions.cpp \
+ MockWdmNodeOptions.cpp \
MockLoggingManager.cpp \
MockEvents.cpp
@@ -1567,6 +1579,15 @@
weave_dd_client_LDFLAGS = ${AM_CPPFLAGS}
weave_dd_client_LDADD = libWeaveTestCommon.a $(COMMON_LDADD)
+weave_cert_prov_client_SOURCES = weave-cert-prov-client.cpp
+weave_cert_prov_client_LDFLAGS = ${AM_CPPFLAGS}
+weave_cert_prov_client_LDADD = libWeaveTestCommon.a $(COMMON_LDADD)
+
+weave_cert_prov_server_SOURCES = weave-cert-prov-server.cpp \
+ MockCAService.cpp
+weave_cert_prov_server_LDFLAGS = ${AM_CPPFLAGS}
+weave_cert_prov_server_LDADD = libWeaveTestCommon.a $(COMMON_LDADD)
+
weave_device_descriptor_SOURCES = weave-device-descriptor.cpp
weave_device_descriptor_LDFLAGS = ${AM_CPPFLAGS}
weave_device_descriptor_LDADD = libWeaveTestCommon.a $(COMMON_LDADD)
diff --git a/src/test-apps/MockCAService.cpp b/src/test-apps/MockCAService.cpp
new file mode 100644
index 0000000..4588f99
--- /dev/null
+++ b/src/test-apps/MockCAService.cpp
@@ -0,0 +1,696 @@
+/*
+ *
+ * Copyright (c) 2019-2020 Google LLC.
+ * All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file
+ * This file implements a derived unsolicited responder
+ * (i.e., server) for the Certificate Provisioned protocol of the
+ * Weave Security profile used for the Weave mock
+ * device command line functional testing tool.
+ *
+ */
+
+#define __STDC_FORMAT_MACROS
+
+#include <inttypes.h>
+
+#include "ToolCommon.h"
+#include "MockCAService.h"
+#include <Weave/Support/CodeUtils.h>
+#include <Weave/Support/NestCerts.h>
+#include <Weave/Support/crypto/HashAlgos.h>
+#include <Weave/Support/crypto/RSA.h>
+#include <Weave/Profiles/WeaveProfiles.h>
+#include <Weave/Profiles/common/CommonProfile.h>
+#include <Weave/Profiles/security/WeaveSig.h>
+#include <Weave/Profiles/security/WeaveCert.h>
+#include <Weave/Profiles/security/WeavePrivateKey.h>
+#include <Weave/Profiles/status-report/StatusReportProfile.h>
+
+#if WEAVE_WITH_OPENSSL
+#include <openssl/x509.h>
+#endif
+
+using namespace nl::Weave::Profiles;
+using namespace nl::Weave::Profiles::Security;
+using namespace nl::Weave::Profiles::Security::CertProvisioning;
+using namespace nl::Weave::Encoding;
+using namespace nl::Weave::TLV;
+using namespace nl::Weave::ASN1;
+
+#if WEAVE_WITH_OPENSSL
+
+static WEAVE_ERROR ValidateX509DeviceCert(X509Cert *certSet, uint8_t certCount)
+{
+ WEAVE_ERROR err = WEAVE_NO_ERROR;
+ BIO *certBuf[kMaxCertCount] = { NULL };
+ X509 *cert[kMaxCertCount] = { NULL };
+ X509_STORE *store = NULL;
+ X509_STORE_CTX *ctx = NULL;
+ X509_VERIFY_PARAM *param = NULL;
+ int res;
+
+ VerifyOrExit(certSet != NULL && certCount > 0 && certCount <= kMaxCertCount, err = WEAVE_ERROR_INVALID_ARGUMENT);
+
+ store = X509_STORE_new();
+ VerifyOrExit(store != NULL, err = WEAVE_ERROR_NO_MEMORY);
+
+ for (int i = 0; i < certCount; i++)
+ {
+ VerifyOrExit(certSet[i].Cert != NULL && certSet[i].Len > 0, err = WEAVE_ERROR_INVALID_ARGUMENT);
+
+ certBuf[i] = BIO_new_mem_buf(certSet[i].Cert, certSet[i].Len);
+ VerifyOrExit(certBuf[i] != NULL, err = WEAVE_ERROR_NO_MEMORY);
+
+ cert[i] = d2i_X509_bio(certBuf[i], NULL);
+ VerifyOrExit(cert[i] != NULL, err = WEAVE_ERROR_NO_MEMORY);
+
+ if (i > 0)
+ {
+ res = X509_STORE_add_cert(store, cert[i]);
+ VerifyOrExit(res == 1, err = WEAVE_ERROR_NO_MEMORY);
+ }
+ }
+
+ ctx = X509_STORE_CTX_new();
+ VerifyOrExit(ctx != NULL, err = WEAVE_ERROR_NO_MEMORY);
+
+ param = X509_VERIFY_PARAM_new();
+ VerifyOrExit(param != NULL, err = WEAVE_ERROR_NO_MEMORY);
+
+ X509_VERIFY_PARAM_clear_flags(param, X509_V_FLAG_USE_CHECK_TIME);
+ X509_STORE_CTX_set0_param(ctx, param);
+
+ res = X509_STORE_CTX_init(ctx, store, cert[0], NULL);
+ VerifyOrExit(res == 1, err = WEAVE_ERROR_INVALID_ARGUMENT);
+
+ res = X509_verify_cert(ctx);
+ VerifyOrExit(res == 1, err = WEAVE_ERROR_INVALID_SIGNATURE);
+
+exit:
+ if (NULL != param) X509_VERIFY_PARAM_free(param);
+ if (NULL != ctx) X509_STORE_CTX_free(ctx);
+ if (NULL != store) X509_STORE_free(store);
+ for (int i = 0; i < certCount; i++)
+ {
+ if (NULL != cert[i]) X509_free(cert[i]);
+ if (NULL != certBuf[i]) BIO_free(certBuf[i]);
+ }
+
+ return err;
+}
+
+#endif // WEAVE_WITH_OPENSSL
+
+GetCertificateRequestMessage::GetCertificateRequestMessage()
+{
+ mReqType = WeaveCertProvEngine::kReqType_NotSpecified;
+ mMfrAttestType = kMfrAttestType_Undefined;
+
+ AuthorizeInfoPairingToken = NULL;
+ AuthorizeInfoPairingTokenLen = 0;
+ AuthorizeInfoPairingInitData = NULL;
+ AuthorizeInfoPairingInitDataLen = 0;
+
+ memset(MfrAttestX509CertSet, 0, sizeof(MfrAttestX509CertSet));
+ MfrAttestX509CertCount = 0;
+
+ OperationalSigAlgo = kOID_NotSpecified;
+ memset(&OperationalSig, 0, sizeof(OperationalSig));
+ MfrAttestSigAlgo = kOID_NotSpecified;
+ memset(&MfrAttestSig, 0, sizeof(MfrAttestSig));
+
+ mOperationalCertSetInitialized = false;
+ mMfrAttestCertSetInitialized = false;
+
+ mTBSDataStart = NULL;
+ mTBSDataLen = 0;
+}
+
+WEAVE_ERROR GetCertificateRequestMessage::Decode(PacketBuffer *msgBuf)
+{
+ WEAVE_ERROR err;
+ TLVReader reader;
+ TLVType outerContainer;
+ WeaveCertificateData * certData;
+
+ reader.Init(msgBuf);
+
+ // Advance the reader to the start of the GetCertificateRequest message structure.
+ err = reader.Next(kTLVType_Structure, AnonymousTag);
+ SuccessOrExit(err);
+
+ err = reader.EnterContainer(outerContainer);
+ SuccessOrExit(err);
+
+ // Request Type.
+ {
+ mTBSDataStart = reader.GetReadPoint();
+
+ err = reader.Next(kTLVType_UnsignedInteger, ContextTag(kTag_GetCertReqMsg_ReqType));
+ SuccessOrExit(err);
+
+ err = reader.Get(mReqType);
+ SuccessOrExit(err);
+
+ VerifyOrExit(RequestType() == WeaveCertProvEngine::kReqType_GetInitialOpDeviceCert ||
+ RequestType() == WeaveCertProvEngine::kReqType_RotateOpDeviceCert, err = WEAVE_ERROR_INVALID_ARGUMENT);
+
+ err = reader.Next();
+ SuccessOrExit(err);
+ }
+
+ // Request authorization information - pairing token (optional).
+ if (reader.GetType() == kTLVType_ByteString && reader.GetTag() == ContextTag(kTag_GetCertReqMsg_Authorize_PairingToken))
+ {
+ err = reader.GetDataPtr(AuthorizeInfoPairingToken);
+ SuccessOrExit(err);
+
+ AuthorizeInfoPairingTokenLen = reader.GetLength();
+
+ err = reader.Next();
+ SuccessOrExit(err);
+
+ // Request authorization information - pairing init data (optional).
+ if (reader.GetType() == kTLVType_ByteString && reader.GetTag() == ContextTag(kTag_GetCertReqMsg_Authorize_PairingInitData))
+ {
+ err = reader.GetDataPtr(AuthorizeInfoPairingInitData);
+ SuccessOrExit(err);
+
+ AuthorizeInfoPairingInitDataLen = reader.GetLength();
+
+ err = reader.Next();
+ SuccessOrExit(err);
+ }
+ }
+
+ // Operational Device Certificate.
+ {
+ VerifyOrExit(reader.GetType() == kTLVType_Structure, err = WEAVE_ERROR_WRONG_TLV_TYPE);
+ VerifyOrExit(reader.GetTag() == ContextTag(kTag_GetCertReqMsg_OpDeviceCert), err = WEAVE_ERROR_UNEXPECTED_TLV_ELEMENT);
+
+ err = OperationalCertSet.Init(kMaxCertCount, nl::TestCerts::kTestCertBufSize);
+ SuccessOrExit(err);
+
+ mOperationalCertSetInitialized = true;
+
+ // Load Weave operational device certificate.
+ err = OperationalCertSet.LoadCert(reader, kDecodeFlag_GenerateTBSHash, certData);
+ SuccessOrExit(err);
+
+ mTBSDataLen = reader.GetReadPoint() - mTBSDataStart;
+
+ err = reader.Next();
+ SuccessOrExit(err);
+ }
+
+ // Load intermediate certificates (optional).
+ if (reader.GetType() == kTLVType_Array && reader.GetTag() == ContextTag(kTag_GetCertReqMsg_OpRelatedCerts))
+ {
+ // Intermediate certificates are not expected when self-signed certificate is used
+ // in the Get Initial Operational Device Certificate Request.
+ VerifyOrExit(RequestType() != WeaveCertProvEngine::kReqType_GetInitialOpDeviceCert, err = WEAVE_ERROR_UNEXPECTED_TLV_ELEMENT);
+
+ err = OperationalCertSet.LoadCerts(reader, kDecodeFlag_GenerateTBSHash);
+ SuccessOrExit(err);
+
+ mTBSDataLen = reader.GetReadPoint() - mTBSDataStart;
+
+ err = reader.Next();
+ SuccessOrExit(err);
+ }
+
+ // Manufacturer Attestation Information (optional).
+ if (reader.GetType() == kTLVType_Structure && reader.GetTag() == ContextTag(kTag_GetCertReqMsg_MfrAttest_WeaveCert))
+ {
+ err = MfrAttestWeaveCertSet.Init(kMaxCertCount, nl::TestCerts::kTestCertBufSize);
+ SuccessOrExit(err);
+
+ mMfrAttestCertSetInitialized = true;
+
+ // Load manufacturer attestation Weave certificate.
+ err = MfrAttestWeaveCertSet.LoadCert(reader, kDecodeFlag_GenerateTBSHash, certData);
+ SuccessOrExit(err);
+
+ mTBSDataLen = reader.GetReadPoint() - mTBSDataStart;
+
+ err = reader.Next(kTLVType_Array, ContextTag(kTag_GetCertReqMsg_MfrAttest_WeaveRelCerts));
+
+ if (err == WEAVE_NO_ERROR)
+ {
+ // Load intermediate certificate.
+ err = MfrAttestWeaveCertSet.LoadCerts(reader, kDecodeFlag_GenerateTBSHash);
+ SuccessOrExit(err);
+
+ mTBSDataLen = reader.GetReadPoint() - mTBSDataStart;
+
+ err = reader.Next();
+ SuccessOrExit(err);
+ }
+
+ MfrAttestType(kMfrAttestType_WeaveCert);
+ }
+ else if (reader.GetType() == kTLVType_ByteString && reader.GetTag() == ContextTag(kTag_GetCertReqMsg_MfrAttest_X509Cert))
+ {
+ err = reader.GetDataPtr(const_cast<const uint8_t *&>(MfrAttestX509CertSet[MfrAttestX509CertCount].Cert));
+ SuccessOrExit(err);
+
+ MfrAttestX509CertSet[MfrAttestX509CertCount++].Len = reader.GetLength();
+
+ mTBSDataLen = MfrAttestX509CertSet[0].Cert + reader.GetLength() - mTBSDataStart;
+
+ err = reader.Next(kTLVType_Array, ContextTag(kTag_GetCertReqMsg_MfrAttest_X509RelCerts));
+
+ // Intermediate certificates (optional).
+ if (err == WEAVE_NO_ERROR)
+ {
+ TLVType outerContainer2;
+
+ err = reader.EnterContainer(outerContainer2);
+ SuccessOrExit(err);
+
+ err = reader.Next();
+
+ while (err != WEAVE_END_OF_TLV)
+ {
+ SuccessOrExit(err);
+
+ VerifyOrExit(MfrAttestX509CertCount < kMaxCertCount, err = WEAVE_ERROR_BUFFER_TOO_SMALL);
+
+ err = reader.GetDataPtr(const_cast<const uint8_t *&>(MfrAttestX509CertSet[MfrAttestX509CertCount].Cert));
+ SuccessOrExit(err);
+
+ MfrAttestX509CertSet[MfrAttestX509CertCount++].Len = reader.GetLength();
+
+ err = reader.Next();
+ }
+
+ err = reader.ExitContainer(outerContainer2);
+ SuccessOrExit(err);
+
+ mTBSDataLen = reader.GetReadPoint() - mTBSDataStart;
+
+ err = reader.Next();
+ SuccessOrExit(err);
+ }
+
+ MfrAttestType(kMfrAttestType_X509Cert);
+ }
+ else if (reader.GetType() == kTLVType_UnsignedInteger && reader.GetTag() == ContextTag(kTag_GetCertReqMsg_MfrAttest_HMACKeyId))
+ {
+ err = reader.Get(MfrAttestHMACKeyId);
+ SuccessOrExit(err);
+
+ mTBSDataLen = reader.GetReadPoint() - mTBSDataStart;
+
+ err = reader.Next();
+ SuccessOrExit(err);
+
+ // Request authorization information - pairing init data (optional).
+ if (reader.GetType() == kTLVType_ByteString && reader.GetTag() == ContextTag(kTag_GetCertReqMsg_MfrAttest_HMACMetaData))
+ {
+ err = reader.GetDataPtr(MfrAttestHMACMetaData);
+ SuccessOrExit(err);
+
+ MfrAttestHMACMetaDataLen = reader.GetLength();
+
+ mTBSDataLen = MfrAttestHMACMetaData + MfrAttestHMACMetaDataLen - mTBSDataStart;
+
+ err = reader.Next();
+ SuccessOrExit(err);
+ }
+
+ MfrAttestType(kMfrAttestType_HMAC);
+ }
+ else
+ {
+ VerifyOrExit(!MfrAttestRequired(), err = WEAVE_ERROR_INVALID_ARGUMENT);
+ }
+
+ // Operational Device Signature.
+ {
+ VerifyOrExit(reader.GetType() == kTLVType_UnsignedInteger, err = WEAVE_ERROR_WRONG_TLV_TYPE);
+ VerifyOrExit(reader.GetTag() == ContextTag(kTag_GetCertReqMsg_OpDeviceSigAlgo), err = WEAVE_ERROR_UNEXPECTED_TLV_ELEMENT);
+
+ err = reader.Get(OperationalSigAlgo);
+ SuccessOrExit(err);
+
+ err = reader.Next(kTLVType_Structure, ContextTag(kTag_GetCertReqMsg_OpDeviceSig_ECDSA));
+ SuccessOrExit(err);
+
+ err = DecodeWeaveECDSASignature(reader, OperationalSig);
+ SuccessOrExit(err);
+
+ err = reader.Next();
+ }
+
+ // Manufacturer Attestation Signature (optional).
+ if (MfrAttestPresent())
+ {
+ VerifyOrExit(reader.GetType() == kTLVType_UnsignedInteger, err = WEAVE_ERROR_WRONG_TLV_TYPE);
+ VerifyOrExit(reader.GetTag() == ContextTag(kTag_GetCertReqMsg_MfrAttestSigAlgo), err = WEAVE_ERROR_UNEXPECTED_TLV_ELEMENT);
+
+ err = reader.Get(MfrAttestSigAlgo);
+ SuccessOrExit(err);
+
+ err = reader.Next();
+ SuccessOrExit(err);
+
+ if (reader.GetType() == kTLVType_Structure && reader.GetTag() == ContextTag(kTag_GetCertReqMsg_MfrAttestSig_ECDSA))
+ {
+ VerifyOrExit(MfrAttestType() == kMfrAttestType_WeaveCert, err = WEAVE_ERROR_UNEXPECTED_TLV_ELEMENT);
+
+ err = DecodeWeaveECDSASignature(reader, MfrAttestSig.EC);
+ SuccessOrExit(err);
+ }
+ else if (reader.GetType() == kTLVType_ByteString && reader.GetTag() == ContextTag(kTag_GetCertReqMsg_MfrAttestSig_RSA))
+ {
+ VerifyOrExit(MfrAttestType() == kMfrAttestType_X509Cert, err = WEAVE_ERROR_UNEXPECTED_TLV_ELEMENT);
+
+ err = MfrAttestSig.RSA.ReadSignature(reader);
+ SuccessOrExit(err);
+ }
+ else if (reader.GetType() == kTLVType_ByteString && reader.GetTag() == ContextTag(kTag_GetCertReqMsg_MfrAttestSig_HMAC))
+ {
+ VerifyOrExit(MfrAttestType() == kMfrAttestType_HMAC, err = WEAVE_ERROR_UNEXPECTED_TLV_ELEMENT);
+
+ err = MfrAttestSig.HMAC.ReadSignature(reader);
+ SuccessOrExit(err);
+
+ err = reader.Next();
+ }
+ else
+ {
+ // Any other manufacturer attestation types are not currently supported.
+ ExitNow(err = WEAVE_ERROR_UNEXPECTED_TLV_ELEMENT);
+ }
+ }
+
+ err = reader.VerifyEndOfContainer();
+ SuccessOrExit(err);
+
+ err = reader.ExitContainer(outerContainer);
+ SuccessOrExit(err);
+
+exit:
+ return err;
+}
+
+WEAVE_ERROR GetCertificateRequestMessage::GenerateTBSHash(uint8_t *tbsHash)
+{
+ nl::Weave::Platform::Security::SHA256 sha256;
+
+ sha256.Begin();
+ sha256.AddData(mTBSDataStart, mTBSDataLen);
+ sha256.Finish(tbsHash);
+
+ return WEAVE_NO_ERROR;
+}
+
+MockCAService::MockCAService()
+{
+ mExchangeMgr = NULL;
+ mLogMessageData = false;
+ mIncludeRelatedCerts = false;
+ mDoNotRotateCert = false;
+
+ mCACert = nl::TestCerts::sTestCert_CA_Weave;
+ mCACertLen = nl::TestCerts::sTestCertLength_CA_Weave;
+
+ mCAPrivateKey = nl::TestCerts::sTestCert_CA_PrivateKey_Weave;
+ mCAPrivateKeyLen = nl::TestCerts::sTestCertLength_CA_PrivateKey_Weave;
+}
+
+WEAVE_ERROR MockCAService::Init(nl::Weave::WeaveExchangeManager *exchangeMgr)
+{
+ WEAVE_ERROR err;
+
+ mExchangeMgr = exchangeMgr;
+
+ // Register to receive unsolicited GetCertificateRequest messages from the exchange manager.
+ err = mExchangeMgr->RegisterUnsolicitedMessageHandler(kWeaveProfile_Security, kMsgType_GetCertificateRequest, HandleClientRequest, this);
+ SuccessOrExit(err);
+
+exit:
+ return err;
+}
+
+WEAVE_ERROR MockCAService::Shutdown()
+{
+ if (mExchangeMgr != NULL)
+ mExchangeMgr->UnregisterUnsolicitedMessageHandler(kWeaveProfile_Security, kMsgType_GetCertificateRequest);
+ return WEAVE_NO_ERROR;
+}
+
+void MockCAService::HandleClientRequest(nl::Weave::ExchangeContext *ec, const nl::Inet::IPPacketInfo *pktInfo,
+ const nl::Weave::WeaveMessageInfo *msgInfo, uint32_t profileId,
+ uint8_t msgType, PacketBuffer *reqMsg)
+{
+ WEAVE_ERROR err = WEAVE_NO_ERROR;
+ MockCAService *server = static_cast<MockCAService *>(ec->AppState);
+ GetCertificateRequestMessage getCertMsg;
+ PacketBuffer *respMsg = NULL;
+ char ipAddrStr[64];
+ ec->PeerAddr.ToString(ipAddrStr, sizeof(ipAddrStr));
+
+ VerifyOrExit(profileId == kWeaveProfile_Security &&
+ msgType == kMsgType_GetCertificateRequest, err = WEAVE_ERROR_NO_MEMORY);
+
+ printf("GetCertificate request received from node %" PRIX64 " (%s)\n", ec->PeerNodeId, ipAddrStr);
+
+ err = server->ProcessGetCertificateRequest(reqMsg, getCertMsg);
+ SuccessOrExit(err);
+
+ if ((getCertMsg.RequestType() == WeaveCertProvEngine::kReqType_RotateOpDeviceCert) && server->mDoNotRotateCert)
+ {
+ err = server->SendStatusReport(ec, Security::kStatusCode_NoNewCertRequired);
+ SuccessOrExit(err);
+ }
+ else
+ {
+ respMsg = PacketBuffer::New();
+ VerifyOrExit(respMsg != NULL, err = WEAVE_ERROR_NO_MEMORY);
+
+ err = server->GenerateGetCertificateResponse(respMsg, *getCertMsg.OperationalCertSet.Certs);
+ SuccessOrExit(err);
+
+ err = ec->SendMessage(kWeaveProfile_Security, kMsgType_GetCertificateResponse, respMsg, 0);
+ respMsg = NULL;
+ SuccessOrExit(err);
+ }
+
+exit:
+ if (err != WEAVE_NO_ERROR)
+ server->SendStatusReport(ec, Security::kStatusCode_UnathorizedGetCertRequest);
+
+ if (reqMsg != NULL)
+ PacketBuffer::Free(reqMsg);
+
+ if (respMsg != NULL)
+ PacketBuffer::Free(respMsg);
+}
+
+WEAVE_ERROR MockCAService::SendStatusReport(nl::Weave::ExchangeContext *ec, uint16_t statusCode)
+{
+ WEAVE_ERROR err;
+ PacketBuffer *statusMsg;
+ StatusReporting::StatusReport statusReport;
+
+ statusMsg = PacketBuffer::New();
+ VerifyOrExit(statusMsg != NULL, err = WEAVE_ERROR_NO_MEMORY);
+
+ statusReport.mProfileId = kWeaveProfile_Security;
+ statusReport.mStatusCode = statusCode;
+
+ err = statusReport.pack(statusMsg);
+ SuccessOrExit(err);
+
+ err = ec->SendMessage(kWeaveProfile_Common, Common::kMsgType_StatusReport, statusMsg, 0);
+ statusMsg = NULL;
+ SuccessOrExit(err);
+
+exit:
+ if (statusMsg != NULL)
+ PacketBuffer::Free(statusMsg);
+
+ return err;
+}
+
+WEAVE_ERROR MockCAService::ProcessGetCertificateRequest(PacketBuffer *msgBuf, GetCertificateRequestMessage & msg)
+{
+ WEAVE_ERROR err;
+ uint8_t tbsHash[SHA256::kHashLength];
+
+ err = msg.Decode(msgBuf);
+ SuccessOrExit(err);
+
+ // Validate Manufacturer Attestation Information if present.
+ if (msg.AuthorizeInfoPresent())
+ {
+ int res;
+
+ VerifyOrExit(msg.AuthorizeInfoPairingTokenLen == TestPairingTokenLength, err = WEAVE_ERROR_INVALID_ARGUMENT);
+
+ res = memcmp(msg.AuthorizeInfoPairingToken, TestPairingToken, TestPairingTokenLength);
+ VerifyOrExit(res == 0, err = WEAVE_ERROR_INVALID_ARGUMENT);
+
+ VerifyOrExit(msg.AuthorizeInfoPairingInitDataLen == TestPairingInitDataLength, err = WEAVE_ERROR_INVALID_ARGUMENT);
+
+ res = memcmp(msg.AuthorizeInfoPairingInitData, TestPairingInitData, TestPairingInitDataLength);
+ VerifyOrExit(res == 0, err = WEAVE_ERROR_INVALID_ARGUMENT);
+ }
+
+ err = ValidateWeaveDeviceCert(msg.OperationalCertSet);
+ SuccessOrExit(err);
+
+ if (msg.MfrAttestRequired())
+ {
+ VerifyOrExit(msg.MfrAttestPresent(), err = WEAVE_ERROR_INVALID_ARGUMENT);
+ }
+
+ // Validate Manufacturer Attestation Information if present.
+ if (msg.MfrAttestPresent())
+ {
+ if (msg.MfrAttestType() == kMfrAttestType_WeaveCert)
+ {
+ err = ValidateWeaveDeviceCert(msg.MfrAttestWeaveCertSet);
+ SuccessOrExit(err);
+ }
+ else if (msg.MfrAttestType() == kMfrAttestType_X509Cert)
+ {
+ // Add Trusted X509 Root Certificate.
+ msg.MfrAttestX509CertSet[msg.MfrAttestX509CertCount].Cert = TestDevice_X509_RSA_RootCert;
+ msg.MfrAttestX509CertSet[msg.MfrAttestX509CertCount++].Len = TestDevice_X509_RSA_RootCertLength;
+
+ err = ValidateX509DeviceCert(msg.MfrAttestX509CertSet, msg.MfrAttestX509CertCount);
+ SuccessOrExit(err);
+ }
+ else if (msg.MfrAttestType() == kMfrAttestType_HMAC)
+ {
+ VerifyOrExit(msg.MfrAttestHMACKeyId == TestDevice1_MfrAttest_HMACKeyId, err = WEAVE_ERROR_INVALID_ARGUMENT);
+
+ if (msg.MfrAttestHMACMetaData != NULL)
+ {
+ int res;
+
+ VerifyOrExit(msg.MfrAttestHMACMetaDataLen == TestDevice1_MfrAttest_HMACMetaDataLength, err = WEAVE_ERROR_INVALID_ARGUMENT);
+
+ res = memcmp(msg.MfrAttestHMACMetaData, TestDevice1_MfrAttest_HMACMetaData, TestDevice1_MfrAttest_HMACMetaDataLength);
+ VerifyOrExit(res == 0, err = WEAVE_ERROR_INVALID_ARGUMENT);
+ }
+ }
+ else
+ {
+ ExitNow(WEAVE_ERROR_INVALID_ARGUMENT);
+ }
+ }
+
+ err = msg.GenerateTBSHash(tbsHash);
+ SuccessOrExit(err);
+
+ // Only ECDSAWithSHA256 algorithm is allowed for operational signature.
+ VerifyOrExit(msg.OperationalSigAlgo == kOID_SigAlgo_ECDSAWithSHA256, err = WEAVE_ERROR_INVALID_ARGUMENT);
+
+ // Verify operational signature.
+ err = VerifyECDSASignature(WeaveCurveIdToOID(msg.OperationalCertSet.Certs->PubKeyCurveId),
+ tbsHash, SHA256::kHashLength, msg.OperationalSig, msg.OperationalCertSet.Certs->PublicKey.EC);
+ SuccessOrExit(err);
+
+ // Verify Manufacturer Attestation Signature if present.
+ if (msg.MfrAttestPresent())
+ {
+ if (msg.MfrAttestSigAlgo == kOID_SigAlgo_ECDSAWithSHA256)
+ {
+ err = VerifyECDSASignature(WeaveCurveIdToOID(msg.MfrAttestWeaveCertSet.Certs->PubKeyCurveId),
+ tbsHash, SHA256::kHashLength, msg.MfrAttestSig.EC, msg.MfrAttestWeaveCertSet.Certs->PublicKey.EC);
+ SuccessOrExit(err);
+ }
+ else if (msg.MfrAttestSigAlgo == kOID_SigAlgo_SHA256WithRSAEncryption)
+ {
+#if WEAVE_WITH_OPENSSL
+ err = VerifyRSASignature(kOID_SigAlgo_SHA256WithRSAEncryption, tbsHash, SHA256::kHashLength, msg.MfrAttestSig.RSA,
+ msg.MfrAttestX509CertSet[0].Cert, msg.MfrAttestX509CertSet[0].Len);
+ SuccessOrExit(err);
+#else
+ ExitNow(err = WEAVE_ERROR_NOT_IMPLEMENTED);
+#endif
+ }
+ else if (msg.MfrAttestSigAlgo == kOID_SigAlgo_HMACWithSHA256)
+ {
+ err = VerifyHMACSignature(kOID_SigAlgo_HMACWithSHA256, msg.mTBSDataStart, msg.mTBSDataLen, msg.MfrAttestSig.HMAC,
+ TestDevice1_MfrAttest_HMACKey, TestDevice1_MfrAttest_HMACKeyLength);
+ SuccessOrExit(err);
+ }
+ else
+ {
+ ExitNow(err = WEAVE_ERROR_UNSUPPORTED_SIGNATURE_TYPE);
+ }
+ }
+
+exit:
+ return err;
+}
+
+WEAVE_ERROR MockCAService::GenerateGetCertificateResponse(PacketBuffer * msgBuf, WeaveCertificateData & receivedDeviceCertData)
+{
+ WEAVE_ERROR err = WEAVE_NO_ERROR;
+ TLVWriter writer;
+ TLVType containerType;
+ uint8_t cert[nl::TestCerts::kTestCertBufSize];
+ uint16_t certLen;
+
+ err = GenerateTestDeviceCert(receivedDeviceCertData.SubjectDN.AttrValue.WeaveId, receivedDeviceCertData.PublicKey.EC,
+ mCACert, mCACertLen,
+ mCAPrivateKey, mCAPrivateKeyLen,
+ cert, sizeof(cert), certLen);
+ SuccessOrExit(err);
+
+ writer.Init(msgBuf);
+
+ err = writer.StartContainer(AnonymousTag, kTLVType_Structure, containerType);
+ SuccessOrExit(err);
+
+ err = writer.CopyContainer(ContextTag(kTag_GetCertRespMsg_OpDeviceCert), cert, certLen);
+ SuccessOrExit(err);
+
+ if (mIncludeRelatedCerts)
+ {
+ TLVType containerType2;
+
+ // Start the RelatedCertificates array. This contains the list of certificates the signature verifier
+ // will need to verify the signature.
+ err = writer.StartContainer(ContextTag(kTag_GetCertRespMsg_OpRelatedCerts), kTLVType_Array, containerType2);
+ SuccessOrExit(err);
+
+ // Copy the intermediate test device CA certificate.
+ err = writer.CopyContainer(AnonymousTag, mCACert, mCACertLen);
+ SuccessOrExit(err);
+
+ err = writer.EndContainer(containerType2);
+ SuccessOrExit(err);
+ }
+
+ err = writer.EndContainer(containerType);
+ SuccessOrExit(err);
+
+ err = writer.Finalize();
+ SuccessOrExit(err);
+
+exit:
+ return err;
+}
diff --git a/src/test-apps/MockCAService.h b/src/test-apps/MockCAService.h
new file mode 100644
index 0000000..c1f2614
--- /dev/null
+++ b/src/test-apps/MockCAService.h
@@ -0,0 +1,143 @@
+/*
+ *
+ * Copyright (c) 2019-2020 Google LLC.
+ * All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file
+ * This file defines a derived unsolicited responder
+ * (i.e., server) for the Certificate Provisioned protocol of the
+ * Weave Security profile used for the Weave mock
+ * device command line functional testing tool.
+ *
+ */
+
+#ifndef MOCKCASERVICE_H_
+#define MOCKCASERVICE_H_
+
+#include "CertProvOptions.h"
+#include <Weave/Core/WeaveCore.h>
+#include <Weave/Profiles/security/WeaveCertProvisioning.h>
+
+using ::nl::Weave::System::PacketBuffer;
+
+enum {
+ kMaxCertCount = 4,
+};
+
+struct X509Cert
+{
+ const uint8_t *Cert;
+ uint16_t Len;
+};
+
+class GetCertificateRequestMessage
+{
+public:
+ GetCertificateRequestMessage();
+
+ WeaveCertificateSet OperationalCertSet;
+
+ const uint8_t *mTBSDataStart;
+ uint16_t mTBSDataLen;
+
+ const uint8_t *AuthorizeInfoPairingToken;
+ uint16_t AuthorizeInfoPairingTokenLen;
+ const uint8_t *AuthorizeInfoPairingInitData;
+ uint16_t AuthorizeInfoPairingInitDataLen;
+
+ WeaveCertificateSet MfrAttestWeaveCertSet;
+ X509Cert MfrAttestX509CertSet[kMaxCertCount];
+ uint8_t MfrAttestX509CertCount;
+ uint32_t MfrAttestHMACKeyId;
+ const uint8_t * MfrAttestHMACMetaData;
+ uint16_t MfrAttestHMACMetaDataLen;
+
+ OID OperationalSigAlgo;
+ EncodedECDSASignature OperationalSig;
+
+ OID MfrAttestSigAlgo;
+ union
+ {
+ EncodedECDSASignature EC;
+ EncodedRSASignature RSA;
+ EncodedHMACSignature HMAC;
+ } MfrAttestSig;
+
+ uint8_t RequestType() const { return mReqType; }
+ GetCertificateRequestMessage& RequestType (uint8_t val) { mReqType = val; return *this; }
+
+ uint8_t MfrAttestType() const { return mMfrAttestType; }
+ GetCertificateRequestMessage& MfrAttestType (uint8_t val) { mMfrAttestType = val; return *this; }
+
+ bool AuthorizeInfoPresent() const { return (AuthorizeInfoPairingToken != NULL); }
+ bool MfrAttestPresent() const { return (mMfrAttestType != kMfrAttestType_Undefined); }
+ bool MfrAttestRequired() const { return (mReqType == nl::Weave::Profiles::Security::CertProvisioning::WeaveCertProvEngine::kReqType_GetInitialOpDeviceCert); }
+
+ WEAVE_ERROR Decode(PacketBuffer *msgBuf);
+ WEAVE_ERROR GenerateTBSHash(uint8_t *tbsHash);
+
+private:
+ uint8_t mReqType;
+ uint8_t mMfrAttestType;
+
+ bool mOperationalCertSetInitialized;
+ bool mMfrAttestCertSetInitialized;
+};
+
+class MockCAService
+{
+public:
+ MockCAService();
+
+ WEAVE_ERROR Init(nl::Weave::WeaveExchangeManager *exchangeMgr);
+ WEAVE_ERROR Shutdown();
+
+ WEAVE_ERROR ProcessGetCertificateRequest(PacketBuffer *msgBuf, GetCertificateRequestMessage & msg);
+ WEAVE_ERROR GenerateGetCertificateResponse(PacketBuffer * msgBuf, WeaveCertificateData & receivedDeviceCertData);
+
+ bool LogMessageData() const { return mLogMessageData; }
+ MockCAService& LogMessageData(bool val) { mLogMessageData = val; return *this; }
+
+ bool IncludeRelatedCerts() const { return mIncludeRelatedCerts; }
+ MockCAService& IncludeRelatedCerts(bool val) { mIncludeRelatedCerts = val; return *this; }
+
+ bool DoNotRotateCert() const { return mDoNotRotateCert; }
+ MockCAService& DoNotRotateCert(bool val) { mDoNotRotateCert = val; return *this; }
+
+ void SetCACert(const uint8_t * cert, uint16_t certLen) { mCACert = cert; mCACertLen = certLen; }
+ void SetCAPrivateKey(const uint8_t * privateKey, uint16_t privateKeyLen) { mCAPrivateKey = privateKey; mCAPrivateKeyLen = privateKeyLen; }
+
+private:
+ nl::Weave::WeaveExchangeManager *mExchangeMgr;
+ bool mLogMessageData;
+ bool mIncludeRelatedCerts;
+ bool mDoNotRotateCert;
+
+ const uint8_t * mCACert;
+ uint16_t mCACertLen;
+
+ const uint8_t * mCAPrivateKey;
+ uint16_t mCAPrivateKeyLen;
+
+ WEAVE_ERROR SendStatusReport(nl::Weave::ExchangeContext *ec, uint16_t statusCode);
+
+ static void HandleClientRequest(nl::Weave::ExchangeContext *ec, const nl::Inet::IPPacketInfo *addrInfo,
+ const nl::Weave::WeaveMessageInfo *msgInfo, uint32_t profileId,
+ uint8_t msgType, PacketBuffer *payload);
+};
+
+#endif /* MOCKCASERVICE_H_ */
diff --git a/src/test-apps/TestCertProv.cpp b/src/test-apps/TestCertProv.cpp
new file mode 100644
index 0000000..bf86f48
--- /dev/null
+++ b/src/test-apps/TestCertProv.cpp
@@ -0,0 +1,795 @@
+/*
+ *
+ * Copyright (c) 2019-2020 Google LLC.
+ * All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file
+ * Unit tests for the WeaveCertProvClient class.
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "ToolCommon.h"
+#include "CertProvOptions.h"
+#include "MockCAService.h"
+#include <Weave/Support/ErrorStr.h>
+#include <Weave/Core/WeaveTLV.h>
+#include <Weave/Profiles/security/WeaveSecurity.h>
+#include <Weave/Profiles/security/WeaveCertProvisioning.h>
+#include <Weave/Profiles/security/WeavePrivateKey.h>
+#include <Weave/Profiles/security/WeaveSig.h>
+#include <Weave/Support/crypto/EllipticCurve.h>
+#include <Weave/Support/NestCerts.h>
+#include <Weave/Support/RandUtils.h>
+
+#if WEAVE_WITH_OPENSSL
+#include <openssl/rsa.h>
+#include <openssl/pem.h>
+#endif
+
+#if WEAVE_SYSTEM_CONFIG_USE_LWIP
+#include "lwip/tcpip.h"
+#endif // WEAVE_SYSTEM_CONFIG_USE_LWIP
+
+using namespace nl::Weave::TLV;
+using namespace nl::Weave::Profiles::Security;
+using namespace nl::Weave::Profiles::Security::CertProvisioning;
+using namespace nl::Weave::ASN1;
+
+using nl::Weave::Crypto::EncodedECPublicKey;
+using nl::Weave::Crypto::EncodedECPrivateKey;
+using nl::Weave::Profiles::Security::CertProvisioning::WeaveCertProvEngine;
+
+#define DEBUG_PRINT_ENABLE 0
+
+uint32_t debugPrintCount = 0;
+
+#define TOOL_NAME "TestCertProv"
+
+static bool HandleOption(const char *progName, OptionSet *optSet, int id, const char *name, const char *arg);
+
+const char *gCurTest = NULL;
+
+#define VerifyOrQuit(TST, MSG) \
+do { \
+ if (!(TST)) \
+ { \
+ fprintf(stdout, "%s FAILED: ", (gCurTest != NULL) ? gCurTest : __FUNCTION__); \
+ fputs(MSG, stdout); \
+ fputs("\n", stdout); \
+ exit(-1); \
+ } \
+} while (0)
+
+#define SuccessOrQuit(ERR, MSG) \
+do { \
+ if ((ERR) != WEAVE_NO_ERROR) \
+ { \
+ fprintf(stdout, "%s FAILED: ", (gCurTest != NULL) ? gCurTest : __FUNCTION__); \
+ fputs(MSG, stdout); \
+ fputs(": ", stdout); \
+ fputs(ErrorStr(ERR), stdout); \
+ fputs("\n", stdout); \
+ exit(-1); \
+ } \
+} while (0)
+
+extern WEAVE_ERROR MakeCertInfo(uint8_t *buf, uint16_t bufSize, uint16_t& certInfoLen,
+ const uint8_t *entityCert, uint16_t entityCertLen,
+ const uint8_t *intermediateCert, uint16_t intermediateCertLen);
+
+class MessageMutator
+{
+public:
+ virtual ~MessageMutator() { }
+ virtual void Reset() = 0;
+ virtual void MutateMessage(const char *msgType, PacketBuffer *msgBuf, WeaveCertProvEngine& clientEng, MockCAService& serviceEng) = 0;
+ virtual bool IsComplete() = 0;
+};
+
+class NullMutator : public MessageMutator
+{
+public:
+ virtual void Reset() { }
+ virtual void MutateMessage(const char *msgType, PacketBuffer *msgBuf, WeaveCertProvEngine& clientEng, MockCAService& serviceEng) { };
+ virtual bool IsComplete() { return true; }
+};
+
+static NullMutator gNullMutator;
+
+class MessageFuzzer : public MessageMutator
+{
+public:
+ MessageFuzzer(const char *msgType)
+ {
+ mMsgType = msgType;
+ mIndex = 0;
+ mSkipStart = 0;
+ mSkipLen = 0;
+ mComplete = false;
+ mTimeLimit = 0;
+ }
+
+ virtual void Reset() { mIndex = 0; mComplete = false; }
+
+ virtual void MutateMessage(const char *msgType, PacketBuffer *msgBuf, WeaveCertProvEngine& clientEng, MockCAService& serviceEng)
+ {
+ if (strcmp(msgType, mMsgType) == 0)
+ {
+ uint8_t *msgStart = msgBuf->Start();
+ uint16_t msgLen = msgBuf->DataLength();
+ uint8_t fuzzMask;
+
+ VerifyOrQuit(msgLen > 0, "Unexpected packet length");
+
+ if (mIndex == mSkipStart)
+ mIndex += mSkipLen;
+
+ if (mIndex >= msgLen)
+ mIndex = msgLen - 1;
+
+ do
+ fuzzMask = GetRandU8();
+ while (fuzzMask == 0 ||
+ // Make sure the EndOfContainer element modifies its Type field - otherwize it might still be interpreted as EndOfContainer element.
+ ((msgStart[mIndex] == kTLVElementType_EndOfContainer) && ((fuzzMask & kTLVTypeMask) == 0)));
+
+ printf("MessageFuzzer: %s message mutated (offset %u, fuzz mask 0x%02X, orig value 0x%02X)\n", msgType, mIndex, fuzzMask, msgStart[mIndex]);
+
+ msgStart[mIndex] ^= fuzzMask;
+
+ mIndex++;
+
+ mComplete = (mIndex >= msgLen);
+ }
+ }
+
+ virtual bool IsComplete()
+ {
+ if (mComplete)
+ return true;
+
+ if (mTimeLimit != 0)
+ {
+ time_t now;
+ time(&now);
+ if (now >= mTimeLimit)
+ return true;
+ }
+
+ return false;
+ }
+
+ MessageFuzzer& Skip(uint16_t start, uint16_t len) { mSkipStart = start; mSkipLen = len; return *this; }
+
+ MessageFuzzer& TimeLimit(time_t timeLimit) { mTimeLimit = timeLimit; return *this; }
+
+private:
+ const char *mMsgType;
+ uint16_t mIndex;
+ uint16_t mSkipStart;
+ uint16_t mSkipLen;
+ bool mComplete;
+ time_t mTimeLimit;
+};
+
+class CertProvEngineTest
+{
+public:
+ CertProvEngineTest(const char *testName)
+ {
+ mTestName = testName;
+ memset(mExpectedErrors, 0, sizeof(mExpectedErrors));
+ mMutator = &gNullMutator;
+ mMfrAttestType = kMfrAttestType_WeaveCert;
+ mReqType = WeaveCertProvEngine::kReqType_GetInitialOpDeviceCert;
+ mLogMessageData = false;
+ mClientIncludeAuthorizeInfo = false;
+ mClientIncludeOperationalRelatedCerts = false;
+ mClientIncludeMfrAttestInfo = true;
+ mClientIncludeMfrAttestRelatedCerts = false;
+ mServerIncludeDeviceCACert = false;
+ }
+
+ const char *TestName() const { return mTestName; }
+
+ uint8_t RequestType() const { return mReqType; }
+ CertProvEngineTest& RequestType (uint8_t val) { mReqType = val; return *this; }
+
+ uint8_t MfrAttestType() const { return mMfrAttestType; }
+ CertProvEngineTest& MfrAttestType (uint8_t val) { mMfrAttestType = val; return *this; }
+
+ bool LogMessageData() const { return mLogMessageData; }
+ CertProvEngineTest& LogMessageData(bool val) { mLogMessageData = val; return *this; }
+
+ bool ClientIncludeAuthorizeInfo() const { return mClientIncludeAuthorizeInfo; }
+ CertProvEngineTest& ClientIncludeAuthorizeInfo(bool val) { mClientIncludeAuthorizeInfo = val; return *this; }
+
+ bool ClientIncludeOperationalRelatedCerts() const { return mClientIncludeOperationalRelatedCerts; }
+ CertProvEngineTest& ClientIncludeOperationalRelatedCerts(bool val) { mClientIncludeOperationalRelatedCerts = val; return *this; }
+
+ bool ClientIncludeMfrAttestInfo() const { return mClientIncludeMfrAttestInfo; }
+ CertProvEngineTest& ClientIncludeMfrAttestInfo(bool val) { mClientIncludeMfrAttestInfo = val; return *this; }
+
+ bool ClientIncludeMfrAttestRelatedCerts() const { return mClientIncludeMfrAttestRelatedCerts; }
+ CertProvEngineTest& ClientIncludeMfrAttestRelatedCerts(bool val) { mClientIncludeMfrAttestRelatedCerts = val; return *this; }
+
+ bool ServerIncludeRelatedCerts() const { return mServerIncludeDeviceCACert; }
+ CertProvEngineTest& ServerIncludeRelatedCerts(bool val) { mServerIncludeDeviceCACert = val; return *this; }
+
+ CertProvEngineTest& ExpectError(WEAVE_ERROR err)
+ {
+ return ExpectError(NULL, err);
+ }
+
+ CertProvEngineTest& ExpectError(const char *opName, WEAVE_ERROR err)
+ {
+ for (size_t i = 0; i < kMaxExpectedErrors; i++)
+ {
+ if (mExpectedErrors[i].Error == WEAVE_NO_ERROR)
+ {
+ mExpectedErrors[i].Error = err;
+ mExpectedErrors[i].OpName = opName;
+ break;
+ }
+ }
+
+ return *this;
+ }
+
+ bool IsExpectedError(const char *opName, WEAVE_ERROR err) const
+ {
+ for (size_t i = 0; i < kMaxExpectedErrors && mExpectedErrors[i].Error != WEAVE_NO_ERROR; i++)
+ {
+ if (mExpectedErrors[i].Error == err &&
+ (mExpectedErrors[i].OpName == NULL || strcmp(mExpectedErrors[i].OpName, opName) == 0))
+ return true;
+ }
+ return false;
+ }
+
+ bool IsSuccessExpected() const { return mExpectedErrors[0].Error == WEAVE_NO_ERROR; }
+
+ CertProvEngineTest& Mutator(MessageMutator *mutator) { mMutator = mutator; return *this; }
+
+ void Run() const;
+
+private:
+ enum
+ {
+ kMaxExpectedErrors = 32
+ };
+
+ struct ExpectedError
+ {
+ const char *OpName;
+ WEAVE_ERROR Error;
+ };
+
+ const char *mTestName;
+ uint8_t mReqType;
+ uint8_t mMfrAttestType;
+ bool mLogMessageData;
+ bool mClientIncludeAuthorizeInfo;
+ bool mClientIncludeOperationalRelatedCerts;
+ bool mClientIncludeMfrAttestInfo;
+ bool mClientIncludeMfrAttestRelatedCerts;
+ bool mServerIncludeDeviceCACert;
+ ExpectedError mExpectedErrors[kMaxExpectedErrors];
+ MessageMutator *mMutator;
+
+ void PrintGetCertificateRequestMessage(PacketBuffer *msgBuf) const;
+};
+
+void CertProvEngineTest::PrintGetCertificateRequestMessage(PacketBuffer *msgBuf) const
+{
+ debugPrintCount++;
+ printf("// ------------------- GET CERTIFICATE REQUEST MESSAGE EXAMPLE %02d --------------------------\n", debugPrintCount);
+ printf("// Operational Device Id : 0x%" PRIX64 "\n", gCertProvOptions.DeviceId);
+ printf("// GetCertReqMsg_ReqType : %s\n", (RequestType() == WeaveCertProvEngine::kReqType_GetInitialOpDeviceCert) ?
+ "Get Initial Operational Device Certificate" : "Rotate Operational Device Certificate");
+ printf("// GetCertAuthorizeInfo : %s\n", ClientIncludeAuthorizeInfo() ? "Yes" : "-----");
+ printf("// GetCertReqMsg_OpDeviceCert : %s\n", (RequestType() == WeaveCertProvEngine::kReqType_GetInitialOpDeviceCert) ?
+ "TestDevice1_OperationalSelfSignedCert" : "TestDevice1_OperationalServiceAssignedCert");
+ printf("// GetCertReqMsg_OpRelatedCerts : %s\n", ClientIncludeOperationalRelatedCerts() ? "nl::NestCerts::Development::DeviceCA::Cert" : "-----");
+ if (ClientIncludeMfrAttestInfo())
+ {
+ if ((MfrAttestType() == kMfrAttestType_WeaveCert))
+ {
+ printf("// GetCertReqMsg_MfrAttest_WeaveCert : %s\n", "TestDevice1_Cert");
+ printf("// GetCertReqMsg_MfrAttest_WeaveRelCerts : %s\n", ClientIncludeMfrAttestRelatedCerts() ? "nl::NestCerts::Development::DeviceCA::Cert" : "-----");
+ }
+ else if ((MfrAttestType() == kMfrAttestType_X509Cert))
+ {
+ printf("// GetCertReqMsg_MfrAttest_X509Cert : %s\n", "TestDevice1_X509_RSA_Cert");
+ printf("// GetCertReqMsg_MfrAttest_X509RelCerts : %s\n", ClientIncludeMfrAttestRelatedCerts() ? "TestDevice1_X509_RSA_ICACert1 (_ICACert2)" : "-----");
+ }
+ else if ((MfrAttestType() == kMfrAttestType_HMAC))
+ {
+ printf("// GetCertReqMsg_MfrAttest_HMACKeyId : 0x%" PRIX32 "\n", TestDevice1_MfrAttest_HMACKeyId);
+ }
+ }
+ else
+ {
+ printf("// GetCertReqMsg_MfrAttestInfo : -----\n");
+ }
+ printf("// GetCertReqMsg_OpDeviceSigAlgo : ECDSAWithSHA256\n");
+ printf("// GetCertReqMsg_OpDeviceSig_ECDSA : ECDSASignature\n");
+ if (ClientIncludeMfrAttestInfo())
+ {
+ if ((MfrAttestType() == kMfrAttestType_WeaveCert))
+ {
+ printf("// GetCertReqMsg_MfrAttestSigAlgo : ECDSAWithSHA256\n");
+ printf("// GetCertReqMsg_MfrAttestSig_ECDSA : ECDSASignature\n");
+ }
+ else if ((MfrAttestType() == kMfrAttestType_X509Cert))
+ {
+ printf("// GetCertReqMsg_MfrAttestSigAlgo : SHA256WithRSAEncryption\n");
+ printf("// GetCertReqMsg_MfrAttestSig_RSA : RSASignature\n");
+ }
+ else if ((MfrAttestType() == kMfrAttestType_HMAC))
+ {
+ printf("// GetCertReqMsg_MfrAttestSigAlgo : HMACWithSHA256\n");
+ printf("// GetCertReqMsg_MfrAttestSig_HMAC : HMACSignature\n");
+ }
+ }
+ else
+ {
+ printf("// GetCertReqMsg_MfrAttestSig : -----\n");
+ }
+ printf("// EXPECTED RESULT : %s\n", IsSuccessExpected() ? "SUCCESS" : "ERROR");
+ printf("// -----------------------------------------------------------------------------------------\n");
+
+ uint8_t * data = msgBuf->Start();
+ uint16_t dataLen = msgBuf->DataLength();
+
+ printf("\nextern const uint8_t sGetCertRequestMsg_Example%02d[] =\n{", debugPrintCount);
+
+ for (uint32_t i = 0; i < dataLen; i++)
+ {
+ if (i % 16 == 0)
+ printf("\n ");
+ printf("0x%02X, ", data[i]);
+ }
+
+ printf("\n};\n\n");
+}
+
+void CertProvEngineTest::Run() const
+{
+ WEAVE_ERROR err;
+ WeaveCertProvEngine clientEng;
+ MockCAService serviceEng;
+ PacketBuffer *msgBuf = NULL;
+ PacketBuffer *msgBuf2 = NULL;
+ WeaveExchangeManager exchangeMgr;
+
+ printf("========== Starting Test: %s\n", TestName());
+ printf(" Manufacturer Attestation Type : %s\n", (MfrAttestType() == kMfrAttestType_WeaveCert) ? "Weave Certificate" : "X509 Certificate");
+ printf(" Request Type : %s\n", (RequestType() == WeaveCertProvEngine::kReqType_GetInitialOpDeviceCert) ? "GetInitialOpDeviceCert" : "RotateCert");
+ printf(" Client Include Authorization Info : %s\n", ClientIncludeAuthorizeInfo() ? "Yes" : "No");
+ printf(" Client Include Op Related Certs : %s\n", ClientIncludeOperationalRelatedCerts() ? "Yes" : "No");
+ printf(" Client Include Manufacturer Attest Info : %s\n", ClientIncludeMfrAttestInfo() ? "Yes" : "No");
+ printf(" Client Include Manuf Attest Related Certs : %s\n", ClientIncludeMfrAttestRelatedCerts() ? "Yes" : "No");
+ printf(" Server Include Op Related Certs : %s\n", ServerIncludeRelatedCerts() ? "Yes" : "No");
+ printf(" Expected Error : %s\n", IsSuccessExpected() ? "No" : "Yes");
+ printf("==========\n");
+
+ gCurTest = TestName();
+
+ mMutator->Reset();
+
+ gCertProvOptions.MfrAttestDeviceId = TestDevice1_NodeId;
+ gCertProvOptions.RequestType = RequestType();
+ gCertProvOptions.IncludeAuthorizeInfo = ClientIncludeAuthorizeInfo();
+ gCertProvOptions.IncludeOperationalICACerts = ClientIncludeOperationalRelatedCerts();
+ gCertProvOptions.MfrAttestType = MfrAttestType();
+ gCertProvOptions.IncludeMfrAttestICACerts = ClientIncludeMfrAttestRelatedCerts();
+
+ gDeviceCredsStore.GenerateAndStoreDeviceCredentials();
+ if (RequestType() == WeaveCertProvEngine::kReqType_RotateOpDeviceCert)
+ gDeviceCredsStore.GenerateAndReplaceCurrentDeviceCert();
+
+ err = gDeviceCredsStore.GetDeviceId(gCertProvOptions.DeviceId);
+ SuccessOrQuit(err, "gDeviceCredsStore.GetDeviceId() failed");
+
+ do
+ {
+ clientEng.Init(NULL, &gCertProvOptions, &gCertProvOptions, gCertProvOptions.CertProvClientEventHandler, &gCertProvOptions);
+ serviceEng.Init(&exchangeMgr);
+ serviceEng.LogMessageData(LogMessageData());
+ serviceEng.IncludeRelatedCerts(ServerIncludeRelatedCerts());
+
+ // ========== Client Forms GetCertificateRequest ==========
+
+ {
+ msgBuf = PacketBuffer::New();
+ VerifyOrQuit(msgBuf != NULL, "PacketBuffer::New() failed");
+ printf("\nCalling WeaveCertProvEngine::GenerateGetCertificateRequest\n");
+
+ err = clientEng.GenerateGetCertificateRequest(msgBuf, RequestType(), ClientIncludeMfrAttestInfo());
+
+#if DEBUG_PRINT_ENABLE
+ PrintGetCertificateRequestMessage(msgBuf);
+#endif
+
+ if (IsExpectedError("WeaveCertProvEngine::GenerateGetCertificateRequest", err))
+ goto onExpectedError;
+
+ SuccessOrQuit(err, "WeaveCertProvEngine::GenerateGetCertificateRequest() failed");
+ }
+
+ // ========== Client Sends GetCertificateRequest to the CA Service ==========
+
+ mMutator->MutateMessage("GetCertificateRequest", msgBuf, clientEng, serviceEng);
+
+ printf("Client->Service: GetCertificateRequest Message (%d bytes)\n", msgBuf->DataLength());
+ if (LogMessageData())
+ DumpMemory(msgBuf->Start(), msgBuf->DataLength(), " ", 16);
+
+ // ========== CA Service Processes GetCertificateRequest ==========
+
+ {
+ printf("Service: Calling ProcessGetCertificateRequest\n");
+
+ GetCertificateRequestMessage msg;
+
+ err = serviceEng.ProcessGetCertificateRequest(msgBuf, msg);
+
+ if (IsExpectedError("Service:ProcessGetCertificateRequest", err))
+ goto onExpectedError;
+
+ SuccessOrQuit(err, "MockCAService::ProcessGetCertificateRequest() failed");
+
+ // ========== CA Service Forms GetCertificateResponse ==========
+
+ msgBuf2 = PacketBuffer::New();
+ VerifyOrQuit(msgBuf2 != NULL, "PacketBuffer::New() failed");
+
+ printf("Service: Calling GenerateGetCertificateResponse\n");
+
+ err = serviceEng.GenerateGetCertificateResponse(msgBuf2, *msg.OperationalCertSet.Certs);
+
+ PacketBuffer::Free(msgBuf);
+ msgBuf = NULL;
+
+ if (IsExpectedError("Service:GenerateGetCertificateResponse", err))
+ goto onExpectedError;
+
+ SuccessOrQuit(err, "MockCAService::GenerateGetCertificateResponse() failed");
+ }
+
+ // ========== CA Service Sends GetCertificateResponse to Client ==========
+
+ mMutator->MutateMessage("GetCertificateResponse", msgBuf2, clientEng, serviceEng);
+
+ printf("Service->Client: GetCertificateResponse Message (%d bytes)\n", msgBuf2->DataLength());
+ if (LogMessageData())
+ DumpMemory(msgBuf2->Start(), msgBuf2->DataLength(), " ", 16);
+
+ // ========== Client Processes GetCertificateResponse ==========
+
+ {
+ printf("Client: Calling ProcessGetCertificateResponse\n");
+
+ err = clientEng.ProcessGetCertificateResponse(msgBuf2);
+
+ PacketBuffer::Free(msgBuf2);
+ msgBuf2 = NULL;
+
+ if (IsExpectedError("Client:ProcessGetCertificateResponse", err))
+ goto onExpectedError;
+
+ SuccessOrQuit(err, "CertProvisioningClient::ProcessGetCertificateResponse() failed");
+ }
+
+ VerifyOrQuit(clientEng.GetState() == WeaveCertProvEngine::kState_Idle, "Client not in Idle state");
+
+ VerifyOrQuit(IsSuccessExpected(), "Test succeeded unexpectedly");
+
+ onExpectedError:
+
+ if (msgBuf != NULL)
+ {
+ PacketBuffer::Free(msgBuf);
+ msgBuf = NULL;
+ }
+
+ if (msgBuf2 != NULL)
+ {
+ PacketBuffer::Free(msgBuf2);
+ msgBuf2 = NULL;
+ }
+
+ clientEng.Shutdown();
+ serviceEng.Shutdown();
+
+ } while (!mMutator->IsComplete());
+
+ printf("Test Complete: %s\n\n", TestName());
+
+ gCurTest = NULL;
+}
+
+void CertProvEngineTests_GetInitialCertTests()
+{
+ bool logData = false;
+
+ struct TestCase
+ {
+ uint8_t maType; // Manufacturer Attestation Type.
+ uint8_t reqType; // Request Type.
+ bool cIncludeAI; // Client Includes Request Authorization Information.
+ bool cIncludeOpRC; // Client Includes Operational Device Related Certificates.
+ bool cIncludeMA; // Client Includes Manufacturer Attestation Information.
+ bool cIncludeMARC; // Client Includes Manufacturer Attestation Related Certificates.
+ bool sIncludeSOpRC; // Server Includes Operational Device Related Certificates.
+ struct
+ {
+ WEAVE_ERROR err; // Expected error.
+ const char * opName; // Function name.
+ } ExpectedResult;
+ };
+
+ enum
+ {
+ // Short-hand names to make the test cases table more concise.
+ WeaveCert = kMfrAttestType_WeaveCert,
+ X509Cert = kMfrAttestType_X509Cert,
+ HMAC = kMfrAttestType_HMAC,
+ InitReq = WeaveCertProvEngine::kReqType_GetInitialOpDeviceCert,
+ RotateReq = WeaveCertProvEngine::kReqType_RotateOpDeviceCert,
+ };
+
+ static const TestCase sTestCases[] =
+ {
+ // Manuf Client Client Client Client Server
+ // Attest Req Includes Includes Includes Includes Includes
+ // Type Type AuthInfo OpRCerts ManufAtt MARCerts OpRCerts Expected Result
+ // ==============================================================================================================
+
+ // Basic testing of certificate provisioning protocol with different load orders.
+ { WeaveCert, InitReq, false, false, false, false, false, { WEAVE_ERROR_INVALID_ARGUMENT, "Service:ProcessGetCertificateRequest" } },
+ { WeaveCert, InitReq, false, false, true, false, false, { WEAVE_NO_ERROR, NULL } },
+ { WeaveCert, InitReq, false, false, true, true, true, { WEAVE_NO_ERROR, NULL } },
+ { WeaveCert, InitReq, false, true, true, true, false, { WEAVE_ERROR_UNEXPECTED_TLV_ELEMENT, "Service:ProcessGetCertificateRequest" } },
+
+ { WeaveCert, InitReq, true, false, false, false, false, { WEAVE_ERROR_INVALID_ARGUMENT, "Service:ProcessGetCertificateRequest" } },
+ { WeaveCert, InitReq, true, false, true, false, false, { WEAVE_NO_ERROR, NULL } },
+ { WeaveCert, InitReq, true, false, true, true, true, { WEAVE_NO_ERROR, NULL } },
+ { WeaveCert, InitReq, true, true, true, true, false, { WEAVE_ERROR_UNEXPECTED_TLV_ELEMENT, "Service:ProcessGetCertificateRequest" } },
+
+ { WeaveCert, RotateReq, false, false, false, false, false, { WEAVE_NO_ERROR, NULL } },
+ { WeaveCert, RotateReq, false, false, true, false, false, { WEAVE_NO_ERROR, NULL } },
+ { WeaveCert, RotateReq, false, false, true, true, true, { WEAVE_NO_ERROR, NULL } },
+ { WeaveCert, RotateReq, false, true, true, true, false, { WEAVE_NO_ERROR, NULL } },
+
+ { WeaveCert, RotateReq, true, false, false, false, false, { WEAVE_NO_ERROR, NULL } },
+ { WeaveCert, RotateReq, true, false, true, false, false, { WEAVE_NO_ERROR, NULL } },
+ { WeaveCert, RotateReq, true, false, true, true, true, { WEAVE_NO_ERROR, NULL } },
+ { WeaveCert, RotateReq, true, true, true, true, false, { WEAVE_NO_ERROR, NULL } },
+
+#if WEAVE_SYSTEM_CONFIG_PACKETBUFFER_CAPACITY_MAX > 4400
+ { X509Cert, InitReq, false, false, true, false, false, { WEAVE_ERROR_INVALID_SIGNATURE, "Service:ProcessGetCertificateRequest" } },
+ { X509Cert, InitReq, false, false, true, true, true, { WEAVE_NO_ERROR, NULL } },
+ { X509Cert, InitReq, false, true, true, true, false, { WEAVE_ERROR_UNEXPECTED_TLV_ELEMENT, "Service:ProcessGetCertificateRequest" } },
+
+ { X509Cert, InitReq, true, false, true, false, false, { WEAVE_ERROR_INVALID_SIGNATURE, "Service:ProcessGetCertificateRequest" } },
+ { X509Cert, InitReq, true, false, true, true, true, { WEAVE_NO_ERROR, NULL } },
+ { X509Cert, InitReq, true, true, true, true, false, { WEAVE_ERROR_UNEXPECTED_TLV_ELEMENT, "Service:ProcessGetCertificateRequest" } },
+
+ { X509Cert, RotateReq, false, false, true, false, false, { WEAVE_ERROR_INVALID_SIGNATURE, "Service:ProcessGetCertificateRequest" } },
+ { X509Cert, RotateReq, false, false, true, true, true, { WEAVE_NO_ERROR, NULL } },
+ { X509Cert, RotateReq, false, true, true, true, false, { WEAVE_NO_ERROR, NULL } },
+
+ { X509Cert, RotateReq, true, false, true, false, false, { WEAVE_ERROR_INVALID_SIGNATURE, "Service:ProcessGetCertificateRequest" } },
+ { X509Cert, RotateReq, true, false, true, true, true, { WEAVE_NO_ERROR, NULL } },
+ { X509Cert, RotateReq, true, true, true, true, false, { WEAVE_NO_ERROR, NULL } },
+#endif // WEAVE_SYSTEM_CONFIG_PACKETBUFFER_CAPACITY_MAX > 4000
+
+ { HMAC, InitReq, false, false, true, false, false, { WEAVE_NO_ERROR, NULL } },
+ { HMAC, InitReq, false, false, true, false, false, { WEAVE_NO_ERROR, NULL } },
+ { HMAC, InitReq, true, false, true, false, true, { WEAVE_NO_ERROR, NULL } },
+ { HMAC, InitReq, true, true, true, false, true, { WEAVE_ERROR_UNEXPECTED_TLV_ELEMENT, "Service:ProcessGetCertificateRequest" } },
+
+ { HMAC, RotateReq, true, false, true, false, false, { WEAVE_NO_ERROR, NULL } },
+ { HMAC, RotateReq, false, true, true, false, true, { WEAVE_NO_ERROR, NULL } },
+ };
+
+ static const size_t sNumTestCases = sizeof(sTestCases) / sizeof(sTestCases[0]);
+
+ for (unsigned i = 0; i < sNumTestCases; i++)
+ {
+ const TestCase& testCase = sTestCases[i];
+
+ // Basic sanity test
+ CertProvEngineTest("Basic")
+ .MfrAttestType(testCase.maType)
+ .RequestType(testCase.reqType)
+ .ClientIncludeAuthorizeInfo(testCase.cIncludeAI)
+ .ClientIncludeOperationalRelatedCerts(testCase.cIncludeOpRC)
+ .ClientIncludeMfrAttestInfo(testCase.cIncludeMA)
+ .ClientIncludeMfrAttestRelatedCerts(testCase.cIncludeMARC)
+ .ServerIncludeRelatedCerts(testCase.sIncludeSOpRC)
+ .ExpectError(testCase.ExpectedResult.opName, testCase.ExpectedResult.err)
+ .LogMessageData(logData)
+ .Run();
+ }
+}
+
+uint32_t gFuzzTestDurationSecs = 5;
+
+void CertProvEngineTests_FuzzTests()
+{
+ time_t now, endTime;
+
+ time(&now);
+ endTime = now + gFuzzTestDurationSecs;
+
+ while (true)
+ {
+ time(&now);
+ if (now >= endTime)
+ break;
+
+ // Fuzz contents of GetCertificateRequest message, verify protocol error.
+ {
+ MessageFuzzer fuzzer = MessageFuzzer("GetCertificateRequest")
+ // .Skip(8, 8)
+ .TimeLimit(endTime);
+ CertProvEngineTest("Mutate GetCertificateRequest")
+ .Mutator(&fuzzer)
+ .ExpectError("Service:ProcessGetCertificateRequest", WEAVE_ERROR_WRONG_TLV_TYPE)
+ .ExpectError("Service:ProcessGetCertificateRequest", WEAVE_ERROR_UNEXPECTED_TLV_ELEMENT)
+ .ExpectError("Service:ProcessGetCertificateRequest", WEAVE_ERROR_INVALID_TLV_TAG)
+ .ExpectError("Service:ProcessGetCertificateRequest", WEAVE_ERROR_INVALID_TLV_ELEMENT)
+ .ExpectError("Service:ProcessGetCertificateRequest", WEAVE_END_OF_TLV)
+ .ExpectError("Service:ProcessGetCertificateRequest", WEAVE_ERROR_TLV_UNDERRUN)
+ .ExpectError("Service:ProcessGetCertificateRequest", WEAVE_ERROR_UNKNOWN_IMPLICIT_TLV_TAG)
+ .ExpectError("Service:ProcessGetCertificateRequest", WEAVE_ERROR_UNSUPPORTED_ELLIPTIC_CURVE)
+ .ExpectError("Service:ProcessGetCertificateRequest", WEAVE_ERROR_UNSUPPORTED_SIGNATURE_TYPE)
+ .ExpectError("Service:ProcessGetCertificateRequest", WEAVE_ERROR_INVALID_SIGNATURE)
+ .ExpectError("Service:ProcessGetCertificateRequest", WEAVE_ERROR_INVALID_ARGUMENT)
+ .ExpectError("Service:ProcessGetCertificateRequest", WEAVE_ERROR_CA_CERT_NOT_FOUND)
+ .ExpectError("Service:ProcessGetCertificateRequest", WEAVE_ERROR_UNSUPPORTED_CERT_FORMAT)
+ .ExpectError("Service:ProcessGetCertificateRequest", WEAVE_ERROR_WRONG_CERT_SUBJECT)
+ .ExpectError("Service:ProcessGetCertificateRequest", WEAVE_ERROR_WRONG_CERT_TYPE)
+ .ExpectError("Service:ProcessGetCertificateRequest", WEAVE_ERROR_INCORRECT_STATE)
+ .ExpectError("Service:ProcessGetCertificateRequest", WEAVE_ERROR_CERT_NOT_VALID_YET)
+ .ExpectError("Service:ProcessGetCertificateRequest", WEAVE_ERROR_CERT_EXPIRED)
+ .ExpectError("Service:ProcessGetCertificateRequest", WEAVE_ERROR_CERT_USAGE_NOT_ALLOWED)
+ .ExpectError("Service:ProcessGetCertificateRequest", WEAVE_ERROR_WRONG_CERT_SIGNATURE_ALGORITHM)
+ .ExpectError("Service:ProcessGetCertificateRequest", ASN1_ERROR_UNKNOWN_OBJECT_ID)
+ .ExpectError("Service:ProcessGetCertificateRequest", ASN1_ERROR_OVERFLOW)
+ .ExpectError("Service:ProcessGetCertificateRequest", ASN1_ERROR_UNSUPPORTED_ENCODING)
+ .ExpectError("Service:ProcessGetCertificateRequest", WEAVE_ERROR_NOT_IMPLEMENTED) // TODO: Remove once X509 RSA Certificates are Supported
+ .Run();
+ }
+
+ // Fuzz contents of GetCertificateResponse message, verify protocol error.
+ {
+ MessageFuzzer fuzzer = MessageFuzzer("GetCertificateResponse")
+ .TimeLimit(endTime);
+ CertProvEngineTest("Mutate GetCertificateResponse")
+ .Mutator(&fuzzer)
+ .ExpectError("Client:ProcessGetCertificateResponse", WEAVE_ERROR_WRONG_TLV_TYPE)
+ .ExpectError("Client:ProcessGetCertificateResponse", WEAVE_ERROR_UNEXPECTED_TLV_ELEMENT)
+ .ExpectError("Client:ProcessGetCertificateResponse", WEAVE_ERROR_INVALID_TLV_TAG)
+ .ExpectError("Client:ProcessGetCertificateResponse", WEAVE_ERROR_INVALID_TLV_ELEMENT)
+ .ExpectError("Client:ProcessGetCertificateResponse", WEAVE_END_OF_TLV)
+ .ExpectError("Client:ProcessGetCertificateResponse", WEAVE_ERROR_TLV_UNDERRUN)
+ .ExpectError("Client:ProcessGetCertificateResponse", WEAVE_ERROR_UNKNOWN_IMPLICIT_TLV_TAG)
+ .ExpectError("Client:ProcessGetCertificateResponse", WEAVE_ERROR_UNSUPPORTED_ELLIPTIC_CURVE)
+ .ExpectError("Client:ProcessGetCertificateResponse", WEAVE_ERROR_UNSUPPORTED_SIGNATURE_TYPE)
+ .ExpectError("Client:ProcessGetCertificateResponse", WEAVE_ERROR_INVALID_SIGNATURE)
+ .ExpectError("Client:ProcessGetCertificateResponse", WEAVE_ERROR_INVALID_ARGUMENT)
+ .ExpectError("Client:ProcessGetCertificateResponse", WEAVE_ERROR_CA_CERT_NOT_FOUND)
+ .ExpectError("Client:ProcessGetCertificateResponse", WEAVE_ERROR_UNSUPPORTED_CERT_FORMAT)
+ .ExpectError("Client:ProcessGetCertificateResponse", WEAVE_ERROR_WRONG_CERT_SUBJECT)
+ .ExpectError("Client:ProcessGetCertificateResponse", WEAVE_ERROR_WRONG_CERT_TYPE)
+ .ExpectError("Client:ProcessGetCertificateResponse", WEAVE_ERROR_INCORRECT_STATE)
+ .ExpectError("Client:ProcessGetCertificateResponse", WEAVE_ERROR_CERT_NOT_VALID_YET)
+ .ExpectError("Client:ProcessGetCertificateResponse", WEAVE_ERROR_CERT_EXPIRED)
+ .ExpectError("Client:ProcessGetCertificateResponse", WEAVE_ERROR_CERT_USAGE_NOT_ALLOWED)
+ .ExpectError("Client:ProcessGetCertificateResponse", ASN1_ERROR_UNKNOWN_OBJECT_ID)
+ .ExpectError("Client:ProcessGetCertificateResponse", ASN1_ERROR_OVERFLOW)
+ .ExpectError("Client:ProcessGetCertificateResponse", ASN1_ERROR_UNSUPPORTED_ENCODING)
+ .ExpectError("Client:ProcessGetCertificateResponse", WEAVE_ERROR_NOT_IMPLEMENTED) // TODO: Remove once X509 RSA Certificates are Supported
+ .LogMessageData(false)
+ .Run();
+ }
+ }
+
+}
+
+static OptionDef gToolOptionDefs[] =
+{
+ { "fuzz-duration", kArgumentRequired, 'f' },
+ { NULL }
+};
+
+static const char *const gToolOptionHelp =
+ " -f, --fuzz-duration <seconds>\n"
+ " Fuzzing duration in seconds.\n"
+ "\n";
+
+static OptionSet gToolOptions =
+{
+ HandleOption,
+ gToolOptionDefs,
+ "GENERAL OPTIONS",
+ gToolOptionHelp
+};
+
+static HelpOptions gHelpOptions(
+ TOOL_NAME,
+ "Usage: " TOOL_NAME " [<options...>]\n",
+ WEAVE_VERSION_STRING "\n" WEAVE_TOOL_COPYRIGHT,
+ "Unit tests for Weave CASE engine.\n"
+);
+
+static OptionSet *gToolOptionSets[] =
+{
+ &gToolOptions,
+ &gHelpOptions,
+ NULL
+};
+
+int main(int argc, char *argv[])
+{
+ WEAVE_ERROR err;
+
+#if WEAVE_SYSTEM_CONFIG_USE_LWIP
+ tcpip_init(NULL, NULL);
+#endif // WEAVE_SYSTEM_CONFIG_USE_LWIP
+
+ err = nl::Weave::Platform::Security::InitSecureRandomDataSource(NULL, 64, NULL, 0);
+ FAIL_ERROR(err, "InitSecureRandomDataSource() failed");
+
+ if (!ParseArgs(TOOL_NAME, argc, argv, gToolOptionSets))
+ {
+ exit(EXIT_FAILURE);
+ }
+
+ CertProvEngineTests_GetInitialCertTests();
+ CertProvEngineTests_FuzzTests();
+
+ printf("All tests succeeded\n");
+
+ exit(EXIT_SUCCESS);
+}
+
+static bool HandleOption(const char *progName, OptionSet *optSet, int id, const char *name, const char *arg)
+{
+ switch (id)
+ {
+ case 'f':
+ if (!ParseInt(arg, gFuzzTestDurationSecs))
+ {
+ PrintArgError("%s: Invalid value specified for fuzz duration: %s\n", progName, arg);
+ return false;
+ }
+ break;
+ default:
+ PrintArgError("%s: INTERNAL ERROR: Unhandled option: %s\n", progName, name);
+ return false;
+ }
+
+ return true;
+}
diff --git a/src/test-apps/TestWeaveCert.cpp b/src/test-apps/TestWeaveCert.cpp
index fc1dad1..d4a5059 100644
--- a/src/test-apps/TestWeaveCert.cpp
+++ b/src/test-apps/TestWeaveCert.cpp
@@ -804,65 +804,6 @@
printf("%s passed\n", __FUNCTION__);
}
-void WeaveCertTest_GenerateAndPrintTestOperationalDeviceCert()
-{
- WEAVE_ERROR err;
- uint64_t deviceId;
- uint8_t certBuf[kTestCertBufSize];
- uint16_t certLen;
- uint8_t keyBuf[kTestCertBufSize];
- uint32_t keyLen;
- uint8_t devicePrivKeyBuf[EncodedECPrivateKey::kMaxValueLength];
- uint8_t devicePubKeyBuf[EncodedECPublicKey::kMaxValueLength];
- EncodedECPublicKey devicePubKey;
-
- enum
- {
- kTestDevice_OpDeviceIdBase = 0x1AB4300000000000ULL,
- kTestDevice_NumberOfOpCerts = 10,
- };
-
- sDevicePrivKey.PrivKey = devicePrivKeyBuf;
- sDevicePrivKey.PrivKeyLen = sizeof(devicePrivKeyBuf);
-
- devicePubKey.ECPoint = devicePubKeyBuf;
- devicePubKey.ECPointLen = sizeof(devicePubKeyBuf);
-
-
- for (int i = 1; i <= kTestDevice_NumberOfOpCerts; i++)
- {
- deviceId = kTestDevice_OpDeviceIdBase + i;
-
- err = GenerateECDHKey(WeaveCurveIdToOID(WEAVE_CONFIG_OPERATIONAL_DEVICE_CERT_CURVE_ID), devicePubKey, sDevicePrivKey);
- SuccessOrFail(err, "GenerateECDHKey() returned error");
-
- err = EncodeWeaveECPrivateKey(WEAVE_CONFIG_OPERATIONAL_DEVICE_CERT_CURVE_ID, &devicePubKey, sDevicePrivKey,
- keyBuf, sizeof(keyBuf), keyLen);
- SuccessOrFail(err, "EncodeWeaveECPrivateKey() returned error");
-
- err = GenerateOperationalDeviceCert(deviceId, devicePubKey, certBuf, sizeof(certBuf), certLen, sGenerateCertSignature);
- SuccessOrFail(err, "GenerateOperationalDeviceCert() returned error");
-
- printf("// Operational node Id, self-signed certificate and private key for Test Device %d\n//\n\n", i);
-
- printf("uint64_t TestDevice%d_OperationalNodeId = 0x%" PRIX64 "ULL;\n\n", i, deviceId);
-
- printf("uint8_t TestDevice%d_OperationalCert[] = \n{\n", i);
- DumpMemoryCStyle(certBuf, certLen, " ", 16);
- printf("};\n\n");
-
- printf("uint16_t TestDevice%d_OperationalCertLength = sizeof(TestDevice%d_OperationalCert);\n\n", i, i);
-
- printf("uint8_t TestDevice%d_OperationalPrivateKey[] = \n{\n", i);
- DumpMemoryCStyle(keyBuf, keyLen, " ", 16);
- printf("};\n\n");
-
- printf("uint16_t TestDevice%d_OperationalPrivateKeyLength = sizeof(TestDevice%d_OperationalPrivateKey);\n\n\n", i, i);
- }
-
- printf("%s passed\n", __FUNCTION__);
-}
-
int main(int argc, char *argv[])
{
WeaveCertTest_WeaveToX509();
@@ -872,8 +813,5 @@
WeaveCertTest_CertUsage();
WeaveCertTest_CertType();
WeaveCertTest_GenerateOperationalDeviceCert();
-#if DEBUG_PRINT_ENABLE
- WeaveCertTest_GenerateAndPrintTestOperationalDeviceCert();
-#endif
printf("All tests passed.\n");
}
diff --git a/src/test-apps/ToolCommon.h b/src/test-apps/ToolCommon.h
index 13cdb00..4849a45 100644
--- a/src/test-apps/ToolCommon.h
+++ b/src/test-apps/ToolCommon.h
@@ -1,5 +1,6 @@
/*
*
+ * Copyright (c) 2019-2020 Google LLC.
* Copyright (c) 2013-2017 Nest Labs, Inc.
* All rights reserved.
*
@@ -51,6 +52,7 @@
#include "TAKEOptions.h"
#include "KeyExportOptions.h"
#include "DeviceDescOptions.h"
+#include "TestWeaveCertData.h"
#include <Weave/WeaveVersion.h>
#include <SystemLayer/SystemLayer.h>
@@ -58,6 +60,7 @@
#include <Weave/Core/WeaveCore.h>
#include <Weave/Support/CodeUtils.h>
#include <Weave/Support/ErrorStr.h>
+#include <Weave/Support/crypto/RSA.h>
#include <Weave/Core/WeaveStats.h>
#if CONFIG_BLE_PLATFORM_BLUEZ
@@ -66,7 +69,6 @@
#include <PlatformLayer/Ble/Bluez/WoBluezLayer.h>
#endif // CONFIG_BLE_PLATFORM_BLUEZ
-
using namespace nl::Inet;
using namespace nl::Weave;
using namespace nl::Weave::Profiles;
@@ -123,6 +125,29 @@
extern uint8_t TestDevice2_PrivateKey[];
extern uint16_t TestDevice2_PrivateKeyLength;
+extern const uint8_t TestDevice1_X509_RSA_PrivateKey[];
+extern const uint16_t TestDevice1_X509_RSA_PrivateKeyLength;
+extern const uint8_t TestDevice1_X509_RSA_Cert[];
+extern const uint16_t TestDevice1_X509_RSA_CertLength;
+extern const uint8_t TestDevice1_X509_RSA_ICACert1[];
+extern const uint16_t TestDevice1_X509_RSA_ICACert1Length;
+extern const uint8_t TestDevice1_X509_RSA_ICACert2[];
+extern const uint16_t TestDevice1_X509_RSA_ICACert2Length;
+
+extern const uint8_t TestDevice_X509_RSA_RootCert[];
+extern const uint16_t TestDevice_X509_RSA_RootCertLength;
+
+extern const uint8_t TestPairingToken[];
+extern const uint16_t TestPairingTokenLength;
+extern const uint8_t TestPairingInitData[];
+extern const uint16_t TestPairingInitDataLength;
+
+extern const uint32_t TestDevice1_MfrAttest_HMACKeyId;
+extern const uint8_t TestDevice1_MfrAttest_HMACMetaData[];
+extern const uint16_t TestDevice1_MfrAttest_HMACMetaDataLength;
+extern const uint8_t TestDevice1_MfrAttest_HMACKey[];
+extern const uint16_t TestDevice1_MfrAttest_HMACKeyLength;
+
extern bool sSuppressAccessControls;
extern void InitToolCommon();
@@ -154,6 +179,8 @@
extern bool GetTestCACert(uint64_t caId, const uint8_t *& cert, uint16_t& certLen);
extern bool GetTestCAPrivateKey(uint64_t caId, const uint8_t *& key, uint16_t& keyLen);
+extern WEAVE_ERROR ValidateWeaveDeviceCert(WeaveCertificateSet & certSet);
+
#if CONFIG_BLE_PLATFORM_BLUEZ
void *WeaveBleIOLoop(void *arg);
nl::Ble::Platform::BlueZ::BluezBlePlatformDelegate *getBluezPlatformDelegate();
diff --git a/src/test-apps/ToolCommonOptions.cpp b/src/test-apps/ToolCommonOptions.cpp
index d8b25a3..272c2dd 100644
--- a/src/test-apps/ToolCommonOptions.cpp
+++ b/src/test-apps/ToolCommonOptions.cpp
@@ -1,5 +1,6 @@
/*
*
+ * Copyright (c) 2019 Google LLC.
* Copyright (c) 2013-2017 Nest Labs, Inc.
* All rights reserved.
*
@@ -32,6 +33,7 @@
#include <stdint.h>
#include <stdio.h>
+#include "ToolCommon.h"
#include "ToolCommonOptions.h"
#include "TestPersistedStorageImplementation.h"
#include <Weave/WeaveVersion.h>
@@ -39,6 +41,7 @@
#include <SystemLayer/SystemFaultInjection.h>
#include <Weave/Support/WeaveFaultInjection.h>
#include <InetLayer/InetFaultInjection.h>
+#include <Weave/Support/Base64.h>
using namespace nl::Inet;
using namespace nl::Weave;
@@ -1120,4 +1123,64 @@
return true;
}
+bool ReadCertFile(const char *fileName, uint8_t *& certBuf, uint16_t& certLen)
+{
+ uint32_t len;
+
+ static const char *certB64Prefix = "1QAABAAB";
+ static const size_t certB64PrefixLen = sizeof(certB64Prefix) - 1;
+
+ // Read the specified file into a malloced buffer.
+ certBuf = ReadFileArg(fileName, len, UINT16_MAX);
+ if (certBuf == NULL)
+ return false;
+
+ // If the certificate is in base-64 format, convert it to raw TLV.
+ if (len > certB64PrefixLen && memcmp(certBuf, certB64Prefix, certB64PrefixLen) == 0)
+ {
+ len = nl::Base64Decode((const char *)certBuf, len, (uint8_t *)certBuf);
+ if (len == UINT16_MAX)
+ {
+ printf("Invalid certificate format: %s\n", fileName);
+ free(certBuf);
+ certBuf = NULL;
+ return false;
+ }
+ }
+
+ certLen = (uint16_t)len;
+
+ return true;
+}
+
+bool ReadPrivateKeyFile(const char *fileName, uint8_t *& keyBuf, uint16_t& keyLen)
+{
+ uint32_t len;
+
+ static const char *keyB64Prefix = "1QAABAAC";
+ static const size_t keyB64PrefixLen = sizeof(keyB64Prefix) - 1;
+
+ // Read the specified file into a malloced buffer.
+ keyBuf = ReadFileArg(fileName, len, UINT16_MAX);
+ if (keyBuf == NULL)
+ return false;
+
+ // If the private key is in base-64 format, convert it to raw TLV.
+ if (len > keyB64PrefixLen && memcmp(keyBuf, keyB64Prefix, keyB64PrefixLen) == 0)
+ {
+ len = nl::Base64Decode((const char *)keyBuf, len, (uint8_t *)keyBuf);
+ if (len == UINT16_MAX)
+ {
+ printf("Invalid private key format: %s\n", fileName);
+ free(keyBuf);
+ keyBuf = NULL;
+ return false;
+ }
+ }
+
+ keyLen = (uint16_t)len;
+
+ return true;
+}
+
#endif // WEAVE_CONFIG_ENABLE_DNS_RESOLVER
diff --git a/src/test-apps/ToolCommonOptions.h b/src/test-apps/ToolCommonOptions.h
index d4a4b56..734895a 100644
--- a/src/test-apps/ToolCommonOptions.h
+++ b/src/test-apps/ToolCommonOptions.h
@@ -1,5 +1,6 @@
/*
*
+ * Copyright (c) 2019-2020 Google LLC.
* Copyright (c) 2013-2017 Nest Labs, Inc.
* All rights reserved.
*
@@ -54,6 +55,18 @@
kToolCommonOpt_NodeKey,
kToolCommonOpt_CACert,
kToolCommonOpt_NoCACert,
+ kToolCommonOpt_GetCertReqType,
+ kToolCommonOpt_OpCert,
+ kToolCommonOpt_OpKey,
+ kToolCommonOpt_OpICACerts,
+ kToolCommonOpt_SendOpICACerts,
+ kToolCommonOpt_MfrAttestType,
+ kToolCommonOpt_MfrAttestNodeId,
+ kToolCommonOpt_MfrAttestCert,
+ kToolCommonOpt_MfrAttestKey,
+ kToolCommonOpt_MfrAttestICACert1,
+ kToolCommonOpt_MfrAttestICACert2,
+ kToolCommonOpt_SendMfrAttestICACerts,
kToolCommonOpt_EventDelay,
kToolCommonOpt_FaultInjection,
kToolCommonOpt_FaultTestIterations,
@@ -67,6 +80,9 @@
kToolCommonOpt_KeyExportConfig,
kToolCommonOpt_AllowedKeyExportConfigs,
kToolCommonOpt_AccessToken,
+ kToolCommonOpt_SendAuthorizeInfo,
+ kToolCommonOpt_PairingToken,
+ kToolCommonOpt_PairingInitData,
kToolCommonOpt_DebugLwIP,
kToolCommonOpt_DeviceSerialNum,
kToolCommonOpt_DeviceVendorId,
@@ -296,6 +312,9 @@
extern bool ResolveWeaveNetworkOptions(const char * progName, WeaveNodeOptions &weaveOptions, NetworkOptions &networkOptions);
+extern bool ReadCertFile(const char *fileName, uint8_t *& certBuf, uint16_t& certLen);
+
+extern bool ReadPrivateKeyFile(const char *fileName, uint8_t *& keyBuf, uint16_t& keyLen);
#endif // TOOLCOMMONOPTIONS_H_
diff --git a/src/test-apps/weave-cert-prov-client.cpp b/src/test-apps/weave-cert-prov-client.cpp
new file mode 100644
index 0000000..e7357fd
--- /dev/null
+++ b/src/test-apps/weave-cert-prov-client.cpp
@@ -0,0 +1,498 @@
+/*
+ *
+ * Copyright (c) 2019 Google LLC.
+ * All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file
+ * This file implements a command line tool, weave-cert-prov-client, for the
+ * Weave Certificate Provisioning Protocol (Security Profile).
+ *
+ * The weave-cert-prov-client tool implements a facility for acting as a client
+ * (originator) for the certificate provisioning request, with a variety of options.
+ *
+ */
+
+#define __STDC_FORMAT_MACROS
+#define __STDC_LIMIT_MACROS
+
+#include <inttypes.h>
+#include <limits.h>
+#include <signal.h>
+
+#include "ToolCommon.h"
+#include "CertProvOptions.h"
+#include <Weave/WeaveVersion.h>
+#include <Weave/Core/WeaveSecurityMgr.h>
+#include <Weave/Core/WeaveTLV.h>
+#include <Weave/Profiles/security/WeaveSecurity.h>
+#include <Weave/Profiles/security/WeaveCertProvisioning.h>
+#include <Weave/Profiles/service-directory/ServiceDirectory.h>
+#include <Weave/Support/crypto/WeaveCrypto.h>
+#include <Weave/Support/TimeUtils.h>
+#include <Weave/Support/WeaveFaultInjection.h>
+
+using nl::StatusReportStr;
+using namespace nl::Weave::TLV;
+using namespace nl::Weave::Profiles::Security;
+using namespace nl::Weave::Profiles::Security::CertProvisioning;
+
+#define TOOL_NAME "weave-cert-prov-client"
+
+static bool HandleOption(const char *progName, OptionSet *optSet, int id, const char *name, const char *arg);
+static bool HandleNonOptionArgs(const char *progName, int argc, char *argv[]);
+static void DriveSending();
+static void HandleConnectionReceived(WeaveMessageLayer *msgLayer, WeaveConnection *con);
+static void ParseDestAddress();
+static void BindingEventHandler(void *appState, Binding::EventType eventType, const Binding::InEventParam& inParam, Binding::OutEventParam& outParam);
+
+const nl::Weave::ExchangeContext::Timeout kResponseTimeoutMsec = 5000;
+
+uint32_t MaxGetCertCount = UINT32_MAX;
+uint32_t GetCertInterval = 5000; // 5 sec
+bool UseTCP = true;
+bool Debug = false;
+uint64_t DestNodeId;
+const char *DestAddr = NULL;
+IPAddress DestIPAddr;
+uint16_t DestPort = WEAVE_PORT;
+InterfaceId DestIntf = INET_NULL_INTERFACEID;
+uint64_t LastGetCertTime = 0;
+bool WaitingForGetCertResponse = false;
+uint32_t GetCertRequestCount = 0;
+uint32_t GetCertResponseCount = 0;
+
+WeaveCertProvEngine CertProvClient;
+
+#if WEAVE_CONFIG_ENABLE_RELIABLE_MESSAGING
+bool UseWRMP = false;
+#endif // WEAVE_CONFIG_ENABLE_RELIABLE_MESSAGING
+
+static OptionDef gToolOptionDefs[] =
+{
+ { "dest-addr", kArgumentRequired, 'D' },
+ { "count", kArgumentRequired, 'c' },
+ { "interval", kArgumentRequired, 'i' },
+ { "tcp", kNoArgument, 't' },
+ { "udp", kNoArgument, 'u' },
+#if WEAVE_CONFIG_ENABLE_RELIABLE_MESSAGING
+ { "wrmp", kNoArgument, 'w' },
+#endif // WEAVE_CONFIG_ENABLE_RELIABLE_MESSAGING
+ { NULL }
+};
+
+static const char *const gToolOptionHelp =
+ " -D, --dest-addr <host>[:<port>][%<interface>]\n"
+ " Send Get Certificate Requests to a specific address rather than one\n"
+ " derived from the destination node id. <host> can be a hostname,\n"
+ " an IPv4 address or an IPv6 address. If <port> is specified, Get Certificate\n"
+ " Requests will be sent to the specified port. If <interface> is\n"
+ " specified, Get Certificate Requests will be sent over the specified local\n"
+ " interface.\n"
+ "\n"
+ " NOTE: When specifying a port with an IPv6 address, the IPv6 address\n"
+ " must be enclosed in brackets, e.g. [fd00:0:1:1::1]:11095.\n"
+ "\n"
+ " -c, --count <num>\n"
+ " Send the specified number of Get Certificate Requests and exit.\n"
+ "\n"
+ " -i, --interval <ms>\n"
+ " Send Get Certificate Requests at the specified interval in milliseconds.\n"
+ "\n"
+ " -t, --tcp\n"
+ " Use TCP to send Get Certificate Requests. This is the default.\n"
+ "\n"
+ " -u, --udp\n"
+ " Use UDP to send Get Certificate Requests.\n"
+ "\n"
+#if WEAVE_CONFIG_ENABLE_RELIABLE_MESSAGING
+ " -w, --wrmp\n"
+ " Use UDP with Weave reliable messaging to send Get Certificate Requests.\n"
+ "\n"
+#endif
+ ;
+
+static OptionSet gToolOptions =
+{
+ HandleOption,
+ gToolOptionDefs,
+ "GENERAL OPTIONS",
+ gToolOptionHelp
+};
+
+static HelpOptions gHelpOptions(
+ TOOL_NAME,
+ "Usage: " TOOL_NAME " [<options...>] <dest-node-id>[@<dest-host>[:<dest-port>][%<interface>]]\n"
+ WEAVE_VERSION_STRING "\n" WEAVE_TOOL_COPYRIGHT,
+ "Send key export request and receive key export response messages.\n"
+);
+
+static OptionSet *gToolOptionSets[] =
+{
+ &gToolOptions,
+ &gNetworkOptions,
+ &gWeaveNodeOptions,
+ &gWRMPOptions,
+ &gCASEOptions,
+ &gCertProvOptions,
+ &gDeviceDescOptions,
+ &gServiceDirClientOptions,
+ &gFaultInjectionOptions,
+ &gHelpOptions,
+ NULL
+};
+
+static void ResetTestContext(void)
+{
+ Done = false;
+ WaitingForGetCertResponse = false;
+ GetCertRequestCount = 0;
+ GetCertResponseCount = 0;
+}
+
+int main(int argc, char *argv[])
+{
+ WEAVE_ERROR err;
+ nl::Weave::System::Stats::Snapshot before;
+ nl::Weave::System::Stats::Snapshot after;
+ const bool printStats = true;
+ uint32_t iter;
+
+#if WEAVE_CONFIG_TEST
+ SetupFaultInjectionContext(argc, argv);
+ SetSignalHandler(DoneOnHandleSIGUSR1);
+#endif
+
+ {
+ unsigned int seed;
+ err = nl::Weave::Platform::Security::GetSecureRandomData((uint8_t *)&seed, sizeof(seed));
+ FAIL_ERROR(err, "Random number generator seeding failed");
+ srand(seed);
+ }
+
+ if (argc == 1)
+ {
+ gHelpOptions.PrintBriefUsage(stderr);
+ exit(EXIT_FAILURE);
+ }
+
+ if (!ParseArgsFromEnvVar(TOOL_NAME, TOOL_OPTIONS_ENV_VAR_NAME, gToolOptionSets, NULL, true) ||
+ !ParseArgs(TOOL_NAME, argc, argv, gToolOptionSets, HandleNonOptionArgs) ||
+ !ResolveWeaveNetworkOptions(TOOL_NAME, gWeaveNodeOptions, gNetworkOptions))
+ {
+ exit(EXIT_FAILURE);
+ }
+
+ InitSystemLayer();
+ InitNetwork();
+ InitWeaveStack(!UseTCP, true);
+
+ // Create a binding for the CertProvClient.
+ Binding *binding = ExchangeMgr.NewBinding(BindingEventHandler, NULL);
+
+ // Initialize the CertProvClient object.
+ err = CertProvClient.Init(binding, &gCertProvOptions, &gCertProvOptions, gCertProvOptions.CertProvClientEventHandler, &gCertProvOptions);
+ FAIL_ERROR(err, "WeaveCertProvEngine.Init failed");
+
+ // Release the binding (the CertProvClient retains its own reference).
+ binding->Release();
+
+#if WEAVE_CONFIG_TEST
+ nl::Weave::Stats::UpdateSnapshot(before);
+#endif
+
+ // Arrange to get called for various activities in the message layer.
+ MessageLayer.OnConnectionReceived = HandleConnectionReceived;
+ MessageLayer.OnReceiveError = HandleMessageReceiveError;
+ MessageLayer.OnAcceptError = HandleAcceptConnectionError;
+
+ PrintNodeConfig();
+
+ if (!UseTCP && DestAddr != NULL)
+ ParseDestAddress();
+
+ printf("Sending");
+ if (MaxGetCertCount != UINT32_MAX)
+ printf(" %u", MaxGetCertCount);
+ printf(" Get Certificate Requests via %s to node %" PRIX64, UseTCP ? "TCP" : (UseWRMP ? "UDP with WRMP" : "UDP"), DestNodeId);
+ if (DestAddr != NULL)
+ printf(" (%s)", DestAddr);
+ printf(" every %" PRId32 " ms\n", GetCertInterval);
+
+#if WEAVE_CONFIG_TEST
+ for (iter = 0; iter < gFaultInjectionOptions.TestIterations; iter++)
+ {
+ printf("Iteration %u\n", iter);
+#endif // WEAVE_CONFIG_TEST
+
+ while (!Done)
+ {
+ struct timeval sleepTime;
+ sleepTime.tv_sec = 0;
+ sleepTime.tv_usec = 100000;
+
+ ServiceNetwork(sleepTime);
+
+ if (!Done)
+ DriveSending();
+
+ fflush(stdout);
+ }
+
+ ResetTestContext();
+
+#if WEAVE_CONFIG_TEST
+ if (gSigusr1Received)
+ {
+ printf("Sigusr1Received\n");
+ break;
+ }
+ }
+#endif // WEAVE_CONFIG_TEST
+
+ CertProvClient.Shutdown();
+
+#if WEAVE_CONFIG_TEST
+ ProcessStats(before, after, printStats, NULL);
+ PrintFaultInjectionCounters();
+#endif // WEAVE_CONFIG_TEST
+
+ ShutdownWeaveStack();
+ ShutdownNetwork();
+ ShutdownSystemLayer();
+
+ return EXIT_SUCCESS;
+}
+
+bool HandleOption(const char *progName, OptionSet *optSet, int id, const char *name, const char *arg)
+{
+ switch (id)
+ {
+ case 't':
+ UseTCP = true;
+ break;
+ case 'u':
+ UseTCP = false;
+ break;
+#if WEAVE_CONFIG_ENABLE_RELIABLE_MESSAGING
+ case 'w':
+ UseTCP = false;
+ UseWRMP = true;
+ break;
+#endif // WEAVE_CONFIG_ENABLE_RELIABLE_MESSAGING
+ case 'c':
+ if (!ParseInt(arg, MaxGetCertCount))
+ {
+ PrintArgError("%s: Invalid value specified for send count: %s\n", progName, arg);
+ return false;
+ }
+ break;
+ case 'i':
+ if (!ParseInt(arg, GetCertInterval))
+ {
+ PrintArgError("%s: Invalid value specified for send interval: %s\n", progName, arg);
+ return false;
+ }
+ break;
+ case 'D':
+ DestAddr = arg;
+ break;
+ default:
+ PrintArgError("%s: INTERNAL ERROR: Unhandled option: %s\n", progName, name);
+ return false;
+ }
+
+ return true;
+}
+
+bool HandleNonOptionArgs(const char *progName, int argc, char *argv[])
+{
+ if (argc > 0)
+ {
+ if (argc > 1)
+ {
+ PrintArgError("%s: Unexpected argument: %s\n", progName, argv[1]);
+ return false;
+ }
+
+ const char *nodeId = argv[0];
+ char *p = (char *)strchr(nodeId, '@');
+ if (p != NULL)
+ {
+ *p = 0;
+ DestAddr = p+1;
+ }
+
+ if (!ParseNodeId(nodeId, DestNodeId))
+ {
+ PrintArgError("%s: Invalid value specified for destination node Id: %s\n", progName, nodeId);
+ return false;
+ }
+ }
+ else
+ {
+ PrintArgError("%s: Please specify destination node Id\n", progName);
+ return false;
+ }
+
+ return true;
+}
+
+void DriveSending()
+{
+ WEAVE_ERROR err;
+
+ if (Now() < LastGetCertTime + GetCertInterval)
+ return;
+
+ if (WaitingForGetCertResponse)
+ {
+ printf("No get certificate response received\n");
+
+ WaitingForGetCertResponse = false;
+
+ // Rescan interfaces to see if we got any new IP addresses
+ if (!UseTCP)
+ {
+ printf("Refreshing endpoints\n");
+ err = MessageLayer.RefreshEndpoints();
+ if (err != WEAVE_NO_ERROR)
+ printf("WeaveMessageLayer.RefreshEndpoints() failed: %s\n", ErrorStr(err));
+ }
+ }
+
+ if (MaxGetCertCount != UINT32_MAX && GetCertRequestCount >= MaxGetCertCount)
+ {
+ Done = true;
+ return;
+ }
+
+ err = CertProvClient.StartCertificateProvisioning(gCertProvOptions.RequestType, (gCertProvOptions.RequestType == WeaveCertProvEngine::kReqType_GetInitialOpDeviceCert));
+ LastGetCertTime = Now();
+ if (err == WEAVE_NO_ERROR)
+ {
+ GetCertRequestCount++;
+ WaitingForGetCertResponse = true;
+ }
+ else
+ {
+ printf("CertProvClient.StartCertificateProvisioning() failed: %s\n", ErrorStr(err));
+ }
+}
+
+void HandleConnectionReceived(WeaveMessageLayer *msgLayer, WeaveConnection *con)
+{
+ char ipAddrStr[64];
+ con->PeerAddr.ToString(ipAddrStr, sizeof(ipAddrStr));
+
+ printf("Connection received from node %" PRIX64 " (%s)\n", con->PeerNodeId, ipAddrStr);
+}
+
+void ParseDestAddress()
+{
+ // NOTE: This function is only used when communicating over UDP. Code in the WeaveConnection object handles
+ // parsing the destination node address for TCP connections.
+
+ WEAVE_ERROR err;
+ const char *addr;
+ uint16_t addrLen;
+ const char *intfName;
+ uint16_t intfNameLen;
+
+ err = ParseHostPortAndInterface(DestAddr, strlen(DestAddr), addr, addrLen, DestPort, intfName, intfNameLen);
+ if (err != INET_NO_ERROR)
+ {
+ printf("Invalid destination address: %s\n", DestAddr);
+ exit(EXIT_FAILURE);
+ }
+
+ if (!IPAddress::FromString(addr, DestIPAddr))
+ {
+ printf("Invalid destination address: %s\n", DestAddr);
+ exit(EXIT_FAILURE);
+ }
+
+ if (intfName != NULL)
+ {
+ err = InterfaceNameToId(intfName, DestIntf);
+ if (err != INET_NO_ERROR)
+ {
+ printf("Invalid interface name: %s\n", intfName);
+ exit(EXIT_FAILURE);
+ }
+ }
+}
+
+void BindingEventHandler(void *appState, Binding::EventType eventType, const Binding::InEventParam& inParam, Binding::OutEventParam& outParam)
+{
+ switch (eventType)
+ {
+ case Binding::kEvent_PrepareRequested:
+ {
+ Binding::Configuration bindingConfig = inParam.Source->BeginConfiguration();
+
+ // Configure the target node Id.
+ bindingConfig.Target_NodeId(DestNodeId);
+
+ // Configure the target address.
+ if (DestAddr != NULL)
+ {
+ bindingConfig.TargetAddress_IP(DestIPAddr, DestPort, DestIntf);
+ }
+
+ // Configure the transport.
+ if (UseTCP)
+ {
+ bindingConfig.Transport_TCP();
+ }
+ else if (!UseWRMP)
+ {
+ bindingConfig.Transport_UDP();
+ }
+ else
+ {
+ bindingConfig.Transport_UDP_WRM();
+ bindingConfig.Transport_DefaultWRMPConfig(gWRMPOptions.GetWRMPConfig());
+ }
+
+ // Configure the security mode.
+ switch (gWeaveSecurityMode.SecurityMode)
+ {
+ case WeaveSecurityMode::kNone:
+ default:
+ bindingConfig.Security_None();
+ break;
+ case WeaveSecurityMode::kCASE:
+ bindingConfig.Security_CASESession();
+ break;
+ case WeaveSecurityMode::kCASEShared:
+ bindingConfig.Security_SharedCASESession();
+ break;
+ case WeaveSecurityMode::kGroupEnc:
+ bindingConfig.Security_Key(gGroupKeyEncOptions.GetEncKeyId());
+ break;
+ }
+
+ bindingConfig.Exchange_ResponseTimeoutMsec(kResponseTimeoutMsec);
+
+ outParam.PrepareRequested.PrepareError = bindingConfig.PrepareBinding();
+ break;
+ }
+ default:
+ Binding::DefaultEventHandler(appState, eventType, inParam, outParam);
+ break;
+ }
+}
diff --git a/src/test-apps/weave-cert-prov-server.cpp b/src/test-apps/weave-cert-prov-server.cpp
new file mode 100644
index 0000000..4c7b9b6
--- /dev/null
+++ b/src/test-apps/weave-cert-prov-server.cpp
@@ -0,0 +1,243 @@
+/*
+ *
+ * Copyright (c) 2019 Google LLC.
+ * All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file
+ * This file implements a command line tool, weave-cert-prov-server, for the
+ * Weave Certificate Provisioning Protocol (Security Profile).
+ *
+ * The weave-cert-prov-server tool implements a facility for acting as a CA server
+ * (responder) for the certificate provisioning request, with a variety of options.
+ *
+ */
+
+#define __STDC_FORMAT_MACROS
+#define __STDC_LIMIT_MACROS
+
+#include <inttypes.h>
+#include <limits.h>
+#include <signal.h>
+
+#include "ToolCommon.h"
+#include "CertProvOptions.h"
+#include "MockCAService.h"
+#include <Weave/WeaveVersion.h>
+#include <Weave/Core/WeaveSecurityMgr.h>
+#include <Weave/Core/WeaveTLV.h>
+#include <Weave/Profiles/security/WeaveSecurity.h>
+#include <Weave/Profiles/security/WeaveCertProvisioning.h>
+#include <Weave/Profiles/service-directory/ServiceDirectory.h>
+#include <Weave/Support/crypto/WeaveCrypto.h>
+#include <Weave/Support/TimeUtils.h>
+#include <Weave/Support/WeaveFaultInjection.h>
+
+using nl::StatusReportStr;
+using namespace nl::Weave::TLV;
+using namespace nl::Weave::Profiles::Security;
+using namespace nl::Weave::Profiles::Security::CertProvisioning;
+
+#define TOOL_NAME "weave-cert-prov-server"
+
+static bool HandleOption(const char *progName, OptionSet *optSet, int id, const char *name, const char *arg);
+static void HandleConnectionReceived(WeaveMessageLayer *msgLayer, WeaveConnection *con);
+
+MockCAService CertProvServer;
+
+enum NameResolutionStateEnum
+{
+ kNameResolutionState_NotStarted,
+ kNameResolutionState_InProgress,
+ kNameResolutionState_Complete
+} NameResolutionState = kNameResolutionState_NotStarted;
+
+static OptionDef gToolOptionDefs[] =
+{
+ { "ca-cert", kArgumentRequired, 'c' },
+ { "ca-key", kArgumentRequired, 'k' },
+ { "send-ca-cert", kNoArgument, 's' },
+ { "do-not-rotate", kNoArgument, 'r' },
+ { NULL }
+};
+
+static const char *const gToolOptionHelp =
+ " -c, --ca-cert <cert-file>\n"
+ " File containing device operational CA certificate to be included along with the node's\n"
+ " operational certificate in the Get Certificat Response message. The file can contain\n"
+ " either raw TLV or base-64. If not specified the default test CA certificate is used.\n"
+ "\n"
+ " -k, --ca-key <key-file>\n"
+ " File containing device operaional CA private key to be used to sign all leaf (node's)\n"
+ " operational certificates. The file can contain either raw TLV orbase-64. If not\n"
+ " specified the default test CA key is used.\n"
+ "\n"
+ " -s, --send-ca-cert\n"
+ " Include device operational CA certificate in the Get Certificat Response message.\n"
+ " This option is set automatically when ca-cert is specified.\n"
+ "\n"
+ " -r, --do-not-rotate\n"
+ " Do not issue new certificate to the Rotate Device Operational Certificate Request.\n"
+ " By default the GetCertificateResponse will be sent to this request.\n"
+ "\n"
+ ;
+
+static OptionSet gToolOptions =
+{
+ HandleOption,
+ gToolOptionDefs,
+ "GENERAL OPTIONS",
+ gToolOptionHelp
+};
+
+static HelpOptions gHelpOptions(
+ TOOL_NAME,
+ "Usage: " TOOL_NAME " [<options...>]\n"
+ WEAVE_VERSION_STRING "\n" WEAVE_TOOL_COPYRIGHT,
+ "Receive and process get certificate request and send get certificate response messages.\n"
+);
+
+static OptionSet *gToolOptionSets[] =
+{
+ &gToolOptions,
+ &gNetworkOptions,
+ &gWeaveNodeOptions,
+ &gWRMPOptions,
+ &gDeviceDescOptions,
+ &gHelpOptions,
+ NULL
+};
+
+int main(int argc, char *argv[])
+{
+ WEAVE_ERROR err;
+
+ {
+ unsigned int seed;
+ err = nl::Weave::Platform::Security::GetSecureRandomData((uint8_t *)&seed, sizeof(seed));
+ FAIL_ERROR(err, "Random number generator seeding failed");
+ srand(seed);
+ }
+
+ if (argc == 1)
+ {
+ gHelpOptions.PrintBriefUsage(stderr);
+ exit(EXIT_FAILURE);
+ }
+
+ if (!ParseArgsFromEnvVar(TOOL_NAME, TOOL_OPTIONS_ENV_VAR_NAME, gToolOptionSets, NULL, true) ||
+ !ParseArgs(TOOL_NAME, argc, argv, gToolOptionSets) ||
+ !ResolveWeaveNetworkOptions(TOOL_NAME, gWeaveNodeOptions, gNetworkOptions))
+ {
+ exit(EXIT_FAILURE);
+ }
+
+ InitSystemLayer();
+ InitNetwork();
+ InitWeaveStack(true, true);
+ MessageLayer.RefreshEndpoints();
+
+ // Initialize the CertProvServer object.
+ err = CertProvServer.Init(&ExchangeMgr);
+ FAIL_ERROR(err, "MockCAService.Init failed");
+
+ // Arrange to get called for various activities in the message layer.
+ MessageLayer.OnConnectionReceived = HandleConnectionReceived;
+ MessageLayer.OnReceiveError = HandleMessageReceiveError;
+ MessageLayer.OnAcceptError = HandleAcceptConnectionError;
+
+ PrintNodeConfig();
+
+ while (!Done)
+ {
+ struct timeval sleepTime;
+ sleepTime.tv_sec = 0;
+ sleepTime.tv_usec = 100000;
+
+ ServiceNetwork(sleepTime);
+ fflush(stdout);
+ }
+
+ if (gSigusr1Received)
+ {
+ printf("Sigusr1Received\n");
+ fflush(stdout);
+ }
+
+ CertProvServer.Shutdown();
+
+ ShutdownWeaveStack();
+ ShutdownNetwork();
+ ShutdownSystemLayer();
+
+ return EXIT_SUCCESS;
+}
+
+bool HandleOption(const char *progName, OptionSet *optSet, int id, const char *name, const char *arg)
+{
+ switch (id)
+ {
+ case 'c':
+ {
+ uint8_t * cert;
+ uint16_t certLen;
+
+ if (!ReadCertFile(arg, cert, certLen))
+ return false;
+
+ CertProvServer.SetCACert(cert, certLen);
+
+ CertProvServer.IncludeRelatedCerts(true);
+
+ break;
+ }
+
+ case 'k':
+ {
+ uint8_t * key;
+ uint16_t keyLen;
+
+ if (!ReadPrivateKeyFile(arg, key, keyLen))
+ return false;
+
+ CertProvServer.SetCAPrivateKey(key, keyLen);
+
+ break;
+ }
+
+ case 's':
+ CertProvServer.IncludeRelatedCerts(true);
+ break;
+
+ case 'r':
+ CertProvServer.DoNotRotateCert(true);
+ break;
+
+ default:
+ PrintArgError("%s: INTERNAL ERROR: Unhandled option: %s\n", progName, name);
+ return false;
+ }
+
+ return true;
+}
+
+void HandleConnectionReceived(WeaveMessageLayer *msgLayer, WeaveConnection *con)
+{
+ char ipAddrStr[64];
+ con->PeerAddr.ToString(ipAddrStr, sizeof(ipAddrStr));
+
+ printf("Connection received from node %" PRIX64 " (%s)\n", con->PeerNodeId, ipAddrStr);
+}