| /* |
| * |
| * Copyright (c) 2017 Nest Labs, Inc. |
| * 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 KeyExportConfig object, which provides an implementation of the WeaveKeyExportDelegate |
| * interface for use in test applications. |
| * |
| */ |
| |
| #include "stdio.h" |
| |
| #include "ToolCommon.h" |
| #include <Weave/Support/CodeUtils.h> |
| #include <Weave/Core/WeaveTLV.h> |
| #include <Weave/Profiles/WeaveProfiles.h> |
| #include <Weave/Profiles/security/WeaveAccessToken.h> |
| #include <Weave/Profiles/security/WeaveSig.h> |
| #include <Weave/Profiles/security/WeaveSecurityDebug.h> |
| #include <Weave/Profiles/service-provisioning/ServiceProvisioning.h> |
| #include <Weave/Support/NestCerts.h> |
| #include <Weave/Support/ErrorStr.h> |
| #include <Weave/Support/ASN1.h> |
| #include "KeyExportOptions.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::KeyExport; |
| |
| static uint8_t sAccessToken[] = |
| { |
| /* |
| -----BEGIN ACCESS TOKEN----- |
| 1QAABAAJADUBMAEITi8yS0HXOtskAgQ3AyyBEERVTU1ZLUFDQ09VTlQtSUQYJgTLqPobJgVLNU9C |
| NwYsgRBEVU1NWS1BQ0NPVU5ULUlEGCQHAiYIJQBaIzAKOQQr2dtaYu+6sVMqD5ljt4owxYpBKaUZ |
| TksL837axemzNfB1GG1JXYbERCUHQbTTqe/utCrWCl2d4DWDKQEYNYIpASQCBRg1hCkBNgIEAgQB |
| GBg1gTACCEI8lV9GHlLbGDWAMAIIQjyVX0YeUtsYNQwwAR0AimGGYj0XstLP0m05PeQlaeCR6gVq |
| dc7dReuDzzACHHS0K6RtFGW3t3GaWq9k0ohgbrOxoDHKkm/K8kMYGDUCJgElAFojMAIcuvzjT4a/ |
| fDgScCv5oxC/T5vz7zAPpURNQjpnajADOQQr2dtaYu+6sVMqD5ljt4owxYpBKaUZTksL837axemz |
| NfB1GG1JXYbERCUHQbTTqe/utCrWCl2d4BgY |
| -----END ACCESS 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, |
| }; |
| |
| static uint16_t sAccessTokenLength = sizeof(sAccessToken); |
| |
| KeyExportOptions gKeyExportOptions; |
| |
| // Parse a sequence of zero or more unsigned integers corresponding to a list |
| // of allowed KeyExport configurations. Integer values must be separated by either |
| // a comma or a space. |
| bool ParseAllowedKeyExportConfigs(const char *strConst, uint8_t& output) |
| { |
| bool res = true; |
| char *str = strdup(strConst); |
| uint32_t configNum; |
| |
| output = 0; |
| |
| for (char *p = str; p != NULL; ) |
| { |
| char *sep = strchr(p, ','); |
| if (sep == NULL) |
| sep = strchr(p, ' '); |
| |
| if (sep != NULL) |
| *sep = 0; |
| |
| if (!ParseInt(p, configNum)) |
| { |
| res = false; |
| break; |
| } |
| |
| if (configNum == 1) |
| output |= kKeyExportSupportedConfig_Config1; |
| else if (configNum == 2) |
| output |= kKeyExportSupportedConfig_Config2; |
| else |
| { |
| res = false; |
| break; |
| } |
| |
| p = (sep != NULL) ? sep + 1 : NULL; |
| } |
| |
| free(str); |
| |
| return res; |
| } |
| |
| KeyExportOptions::KeyExportOptions() |
| { |
| static OptionDef optionDefs[] = |
| { |
| #if WEAVE_CONFIG_ENABLE_KEY_EXPORT_INITIATOR || WEAVE_CONFIG_ENABLE_KEY_EXPORT_RESPONDER |
| { "allowed-key-export-configs", kArgumentRequired, kToolCommonOpt_AllowedKeyExportConfigs }, |
| { "access-token", kArgumentRequired, kToolCommonOpt_AccessToken }, |
| #endif |
| { } |
| }; |
| OptionDefs = optionDefs; |
| |
| HelpGroupName = "KEY EXPORT OPTIONS"; |
| |
| OptionHelp = |
| #if WEAVE_CONFIG_ENABLE_KEY_EXPORT_INITIATOR || WEAVE_CONFIG_ENABLE_KEY_EXPORT_RESPONDER |
| " --allowed-key-export-configs <int>[,<int>]\n" |
| " Accept the specified set of key export configurations when either initiating or\n" |
| " responding to a key export request.\n" |
| "\n" |
| " --access-token <access-token-file>\n" |
| " File containing a Weave Access Token to be used to authenticate the key\n" |
| " export request. (Must be in Weave TLV format). In not specified the default\n" |
| " test access token is used.\n" |
| "\n" |
| #endif |
| ""; |
| |
| // Defaults |
| AllowedKeyExportConfigs = 0; // 0 causes code to use default value provided by WeaveSecurityManager |
| mAccessToken = NULL; |
| mAccessTokenLength = 0; |
| } |
| |
| bool KeyExportOptions::HandleOption(const char *progName, OptionSet *optSet, int id, const char *name, const char *arg) |
| { |
| uint32_t len; |
| |
| switch (id) |
| { |
| #if WEAVE_CONFIG_ENABLE_KEY_EXPORT_INITIATOR || WEAVE_CONFIG_ENABLE_KEY_EXPORT_RESPONDER |
| case kToolCommonOpt_AllowedKeyExportConfigs: |
| if (!ParseAllowedKeyExportConfigs(arg, AllowedKeyExportConfigs)) |
| { |
| PrintArgError("%s: Invalid value specified for allowed KeyExport configs: %s\n", progName, arg); |
| return false; |
| } |
| break; |
| case kToolCommonOpt_AccessToken: |
| mAccessToken = ReadFileArg(arg, len); |
| if (mAccessToken == NULL) |
| return false; |
| mAccessTokenLength = len; |
| break; |
| #endif // WEAVE_CONFIG_ENABLE_KEY_EXPORT_INITIATOR || WEAVE_CONFIG_ENABLE_KEY_EXPORT_RESPONDER |
| |
| default: |
| PrintArgError("%s: INTERNAL ERROR: Unhandled option: %s\n", progName, name); |
| return false; |
| } |
| |
| return true; |
| } |
| |
| enum |
| { |
| // Max Device Private Key Size -- Size of the temporary buffer used to hold |
| // a device's TLV encoded private key. |
| kMaxDevicePrivateKeySize = 300, |
| |
| // Max Validation Certs -- This controls the maximum number of certificates |
| // that can be involved in the validation of an image signature. It must |
| // include room for the signing cert, the trust anchors and any intermediate |
| // certs included in the signature object. |
| kMaxCerts = 10, |
| |
| // Certificate Decode Buffer Size -- Size of the temporary buffer used to decode |
| // certs. The buffer must be big enough to hold the ASN1 DER encoding of the |
| // TBSCertificate portion of the largest cert involved in signature verification. |
| // Note that all certificates included in the signature are decoded using this |
| // buffer, even if they are ultimately not involved in verifying the image |
| // signature. |
| kCertDecodeBufferSize = 1024 |
| }; |
| |
| #if !WEAVE_CONFIG_LEGACY_KEY_EXPORT_DELEGATE |
| |
| WEAVE_ERROR KeyExportOptions::GetNodeCertSet(WeaveKeyExport * keyExport, WeaveCertificateSet & certSet) |
| { |
| return GetNodeCertSet(keyExport->IsInitiator(), certSet); |
| } |
| |
| WEAVE_ERROR KeyExportOptions::ReleaseNodeCertSet(WeaveKeyExport * keyExport, WeaveCertificateSet & certSet) |
| { |
| return ReleaseNodeCertSet(keyExport->IsInitiator(), certSet); |
| } |
| |
| WEAVE_ERROR KeyExportOptions::GenerateNodeSignature(WeaveKeyExport * keyExport, const uint8_t * msgHash, uint8_t msgHashLen, |
| TLVWriter & writer) |
| { |
| WEAVE_ERROR err; |
| const uint8_t * privKey = NULL; |
| uint16_t privKeyLen; |
| |
| err = GetNodePrivateKey(keyExport->IsInitiator(), privKey, privKeyLen); |
| SuccessOrExit(err); |
| |
| err = GenerateAndEncodeWeaveECDSASignature(writer, TLV::ContextTag(kTag_WeaveSignature_ECDSASignatureData), msgHash, msgHashLen, privKey, privKeyLen); |
| SuccessOrExit(err); |
| |
| exit: |
| if (privKey != NULL) |
| { |
| WEAVE_ERROR relErr = ReleaseNodePrivateKey(keyExport->IsInitiator(), privKey); |
| err = (err == WEAVE_NO_ERROR) ? relErr : err; |
| } |
| return err; |
| } |
| |
| WEAVE_ERROR KeyExportOptions::BeginCertValidation(WeaveKeyExport * keyExport, ValidationContext & validCtx, |
| WeaveCertificateSet & certSet) |
| { |
| return BeginCertValidation(keyExport->IsInitiator(), certSet, validCtx); |
| } |
| |
| WEAVE_ERROR KeyExportOptions::HandleCertValidationResult(WeaveKeyExport * keyExport, ValidationContext & validCtx, |
| WeaveCertificateSet & certSet, uint32_t requestedKeyId) |
| { |
| return HandleCertValidationResult(keyExport->IsInitiator(), certSet, validCtx, NULL, keyExport->MessageInfo(), requestedKeyId); |
| } |
| |
| WEAVE_ERROR KeyExportOptions::EndCertValidation(WeaveKeyExport * keyExport, ValidationContext & validCtx, |
| WeaveCertificateSet & certSet) |
| { |
| return EndCertValidation(keyExport->IsInitiator(), certSet, validCtx); |
| } |
| |
| WEAVE_ERROR KeyExportOptions::ValidateUnsignedKeyExportMessage(WeaveKeyExport * keyExport, uint32_t requestedKeyId) |
| { |
| // Unsigned key export messages are not supported. |
| return keyExport->IsInitiator() |
| ? WEAVE_ERROR_UNAUTHORIZED_KEY_EXPORT_RESPONSE |
| : WEAVE_ERROR_UNAUTHORIZED_KEY_EXPORT_REQUEST; |
| } |
| |
| #endif // !WEAVE_CONFIG_LEGACY_KEY_EXPORT_DELEGATE |
| |
| // Get the key export certificate set for the local node. |
| // This method is responsible for initializing certificate set and loading all certificates |
| // that will be included in the signature of the message. |
| WEAVE_ERROR KeyExportOptions::GetNodeCertSet(bool isInitiator, WeaveCertificateSet& certSet) |
| { |
| WEAVE_ERROR err = WEAVE_NO_ERROR; |
| WeaveCertificateData *cert; |
| bool certSetInitialized = false; |
| |
| err = certSet.Init(kMaxCerts, kCertDecodeBufferSize, nl::Weave::Platform::Security::MemoryAlloc, nl::Weave::Platform::Security::MemoryFree); |
| SuccessOrExit(err); |
| certSetInitialized = true; |
| |
| if (isInitiator) |
| { |
| #if WEAVE_CONFIG_ENABLE_KEY_EXPORT_INITIATOR |
| const uint8_t *accessToken = mAccessToken; |
| uint16_t accessTokenLen = mAccessTokenLength; |
| |
| if (accessToken == NULL || accessTokenLen == 0) |
| { |
| accessToken = sAccessToken; |
| accessTokenLen = sAccessTokenLength; |
| } |
| |
| err = LoadAccessTokenCerts(accessToken, accessTokenLen, certSet, 0, cert); |
| SuccessOrExit(err); |
| |
| #else // !WEAVE_CONFIG_ENABLE_KEY_EXPORT_INITIATOR |
| ExitNow(err = WEAVE_ERROR_INVALID_ARGUMENT); |
| #endif // WEAVE_CONFIG_ENABLE_KEY_EXPORT_INITIATOR |
| } |
| else |
| { |
| #if WEAVE_CONFIG_ENABLE_KEY_EXPORT_RESPONDER |
| // Responder uses the same device certificate that is specified for CASE. |
| const uint8_t *nodeCert = gCASEOptions.NodeCert; |
| uint16_t nodeCertLen = gCASEOptions.NodeCertLength; |
| |
| if (nodeCert == NULL || nodeCertLen == 0) |
| { |
| GetTestNodeCert(FabricState.LocalNodeId, nodeCert, nodeCertLen); |
| } |
| if (nodeCert == NULL || nodeCertLen == 0) |
| { |
| printf("ERROR: Node certificate not configured\n"); |
| ExitNow(err = WEAVE_ERROR_CERT_NOT_FOUND); |
| } |
| |
| err = certSet.LoadCert(nodeCert, nodeCertLen, 0, cert); |
| SuccessOrExit(err); |
| |
| #else // !WEAVE_CONFIG_ENABLE_KEY_EXPORT_RESPONDER |
| ExitNow(err = WEAVE_ERROR_INVALID_ARGUMENT); |
| #endif // WEAVE_CONFIG_ENABLE_KEY_EXPORT_RESPONDER |
| } |
| |
| exit: |
| if (err != WEAVE_NO_ERROR && certSetInitialized) |
| certSet.Release(); |
| |
| return err; |
| } |
| |
| // Called when the key export engine is done with the certificate set returned by GetNodeCertSet(). |
| WEAVE_ERROR KeyExportOptions::ReleaseNodeCertSet(bool isInitiator, WeaveCertificateSet& certSet) |
| { |
| certSet.Release(); |
| |
| return WEAVE_NO_ERROR; |
| } |
| |
| // Get the local node's private key. |
| WEAVE_ERROR KeyExportOptions::GetNodePrivateKey(bool isInitiator, const uint8_t *& weavePrivKey, uint16_t& weavePrivKeyLen) |
| { |
| WEAVE_ERROR err = WEAVE_NO_ERROR; |
| uint8_t *privKeyBuf = NULL; |
| |
| if (isInitiator) |
| { |
| #if WEAVE_CONFIG_ENABLE_KEY_EXPORT_INITIATOR |
| const uint8_t *accessToken = mAccessToken; |
| uint16_t accessTokenLen = mAccessTokenLength; |
| |
| if (accessToken == NULL || accessTokenLen == 0) |
| { |
| accessToken = sAccessToken; |
| accessTokenLen = sAccessTokenLength; |
| } |
| |
| // Allocate a buffer to hold the private key. |
| privKeyBuf = (uint8_t *)nl::Weave::Platform::Security::MemoryAlloc(kMaxDevicePrivateKeySize); |
| VerifyOrExit(privKeyBuf != NULL, err = WEAVE_ERROR_NO_MEMORY); |
| |
| // Extract the private key from the access token, converting the encoding to a EllipticCurvePrivateKey TLV object. |
| err = ExtractPrivateKeyFromAccessToken(accessToken, accessTokenLen, privKeyBuf, accessTokenLen, weavePrivKeyLen); |
| SuccessOrExit(err); |
| |
| // Pass the extracted key back to the caller. |
| weavePrivKey = privKeyBuf; |
| privKeyBuf = NULL; |
| |
| #else // !WEAVE_CONFIG_ENABLE_KEY_EXPORT_INITIATOR |
| ExitNow(err = WEAVE_ERROR_INVALID_ARGUMENT); |
| #endif // WEAVE_CONFIG_ENABLE_KEY_EXPORT_INITIATOR |
| } |
| else |
| { |
| #if WEAVE_CONFIG_ENABLE_KEY_EXPORT_RESPONDER |
| // Responder uses the same device private key that was specified for CASE authentication. |
| weavePrivKey = gCASEOptions.NodePrivateKey; |
| weavePrivKeyLen = gCASEOptions.NodePrivateKeyLength; |
| |
| if (weavePrivKey == NULL || weavePrivKeyLen == 0) |
| { |
| GetTestNodePrivateKey(FabricState.LocalNodeId, weavePrivKey, weavePrivKeyLen); |
| } |
| if (weavePrivKey == NULL || weavePrivKeyLen == 0) |
| { |
| printf("ERROR: Node private key not configured\n"); |
| ExitNow(err = WEAVE_ERROR_KEY_NOT_FOUND); |
| } |
| |
| #else // !WEAVE_CONFIG_ENABLE_KEY_EXPORT_RESPONDER |
| ExitNow(err = WEAVE_ERROR_INVALID_ARGUMENT); |
| #endif // WEAVE_CONFIG_ENABLE_KEY_EXPORT_RESPONDER |
| } |
| |
| exit: |
| if (privKeyBuf != NULL) |
| nl::Weave::Platform::Security::MemoryFree(privKeyBuf); |
| |
| return err; |
| } |
| |
| // Called when the key export engine is done with the buffer returned by GetNodePrivateKey(). |
| WEAVE_ERROR KeyExportOptions::ReleaseNodePrivateKey(bool isInitiator, const uint8_t *& weavePrivKey) |
| { |
| #if WEAVE_CONFIG_ENABLE_KEY_EXPORT_INITIATOR |
| if (isInitiator && weavePrivKey != NULL) |
| { |
| nl::Weave::Platform::Security::MemoryFree((void *)weavePrivKey); |
| weavePrivKey = NULL; |
| } |
| #endif |
| |
| return WEAVE_NO_ERROR; |
| } |
| |
| // Prepare the supplied certificate set and validation context for use in validating the certificate of a peer. |
| // This method is responsible for loading the trust anchors into the certificate set. |
| WEAVE_ERROR KeyExportOptions::BeginCertValidation(bool isInitiator, WeaveCertificateSet& certSet, ValidationContext& validContext) |
| { |
| WEAVE_ERROR err; |
| WeaveCertificateData *cert; |
| bool certSetInitialized = false; |
| |
| err = certSet.Init(kMaxCerts, kCertDecodeBufferSize, nl::Weave::Platform::Security::MemoryAlloc, nl::Weave::Platform::Security::MemoryFree); |
| SuccessOrExit(err); |
| certSetInitialized = true; |
| |
| if (isInitiator) |
| { |
| #if WEAVE_CONFIG_ENABLE_KEY_EXPORT_INITIATOR |
| err = certSet.LoadCert(nl::NestCerts::Development::Root::Cert, nl::NestCerts::Development::Root::CertLength, 0, cert); |
| SuccessOrExit(err); |
| cert->CertFlags |= kCertFlag_IsTrusted; |
| |
| err = certSet.LoadCert(nl::NestCerts::Production::Root::Cert, nl::NestCerts::Production::Root::CertLength, 0, cert); |
| SuccessOrExit(err); |
| cert->CertFlags |= kCertFlag_IsTrusted; |
| |
| err = certSet.LoadCert(nl::NestCerts::Development::DeviceCA::Cert, nl::NestCerts::Development::DeviceCA::CertLength, kDecodeFlag_GenerateTBSHash, cert); |
| SuccessOrExit(err); |
| |
| err = certSet.LoadCert(nl::NestCerts::Production::DeviceCA::Cert, nl::NestCerts::Production::DeviceCA::CertLength, kDecodeFlag_GenerateTBSHash, cert); |
| SuccessOrExit(err); |
| |
| #else // !WEAVE_CONFIG_ENABLE_KEY_EXPORT_INITIATOR |
| ExitNow(err = WEAVE_ERROR_INVALID_ARGUMENT); |
| #endif // WEAVE_CONFIG_ENABLE_KEY_EXPORT_INITIATOR |
| } |
| else |
| { |
| #if WEAVE_CONFIG_ENABLE_KEY_EXPORT_RESPONDER |
| const uint8_t *accessToken = mAccessToken; |
| uint16_t accessTokenLen = mAccessTokenLength; |
| |
| if (accessToken == NULL || accessTokenLen == 0) |
| { |
| accessToken = sAccessToken; |
| accessTokenLen = sAccessTokenLength; |
| } |
| |
| err = LoadAccessTokenCerts(accessToken, accessTokenLen, certSet, 0, cert); |
| SuccessOrExit(err); |
| cert->CertFlags |= kCertFlag_IsTrusted; |
| |
| #else // !WEAVE_CONFIG_ENABLE_KEY_EXPORT_RESPONDER |
| ExitNow(err = WEAVE_ERROR_INVALID_ARGUMENT); |
| #endif // WEAVE_CONFIG_ENABLE_KEY_EXPORT_RESPONDER |
| } |
| |
| // Initialize the validation context. |
| memset(&validContext, 0, sizeof(validContext)); |
| validContext.EffectiveTime = SecondsSinceEpochToPackedCertTime(time(NULL)); |
| validContext.RequiredKeyUsages = kKeyUsageFlag_DigitalSignature; |
| validContext.ValidateFlags = kValidateFlag_IgnoreNotAfter; |
| |
| exit: |
| if (err != WEAVE_NO_ERROR && certSetInitialized) |
| certSet.Release(); |
| |
| return err; |
| } |
| |
| // Called with the results of validating the peer's certificate. |
| // Responder verifies that requestor is authorized to export the specified key. |
| WEAVE_ERROR KeyExportOptions::HandleCertValidationResult(bool isInitiator, WeaveCertificateSet& certSet, ValidationContext& validContext, |
| const IPPacketInfo *pktInfo, const WeaveMessageInfo *msgInfo, uint32_t requestedKeyId) |
| { |
| WEAVE_ERROR err = WEAVE_NO_ERROR; |
| WeaveCertificateData *peerCert = validContext.SigningCert; |
| |
| if (isInitiator) |
| { |
| #if WEAVE_CONFIG_ENABLE_KEY_EXPORT_INITIATOR |
| // Verify that it is device certificate and its subject matches the responder node id. |
| VerifyOrExit(peerCert->SubjectDN.AttrOID == ASN1::kOID_AttributeType_WeaveDeviceId && |
| peerCert->SubjectDN.AttrValue.WeaveId == msgInfo->SourceNodeId, err = WEAVE_ERROR_UNAUTHORIZED_KEY_EXPORT_RESPONSE); |
| |
| #else // !WEAVE_CONFIG_ENABLE_KEY_EXPORT_INITIATOR |
| ExitNow(err = WEAVE_ERROR_INVALID_ARGUMENT); |
| #endif // WEAVE_CONFIG_ENABLE_KEY_EXPORT_INITIATOR |
| } |
| else |
| { |
| #if WEAVE_CONFIG_ENABLE_KEY_EXPORT_RESPONDER |
| // Verify that requested key is Client Root Key and that peer's signing certificate |
| // has all the correct attributes of access token certificate: |
| // -- it is trusted. |
| // -- it is self-signed. |
| // -- it has CommonName attribute type. |
| VerifyOrExit((requestedKeyId == WeaveKeyId::kClientRootKey) && |
| (peerCert->CertFlags & kCertFlag_IsTrusted) && |
| peerCert->IssuerDN.IsEqual(peerCert->SubjectDN) && |
| peerCert->AuthKeyId.IsEqual(peerCert->SubjectKeyId) && |
| peerCert->SubjectDN.AttrOID == ASN1::kOID_AttributeType_CommonName, err = WEAVE_ERROR_UNAUTHORIZED_KEY_EXPORT_REQUEST); |
| |
| #else // !WEAVE_CONFIG_ENABLE_KEY_EXPORT_RESPONDER |
| ExitNow(err = WEAVE_ERROR_INVALID_ARGUMENT); |
| #endif // WEAVE_CONFIG_ENABLE_KEY_EXPORT_RESPONDER |
| } |
| |
| exit: |
| return err; |
| } |
| |
| // Called when peer certificate validation is complete. |
| WEAVE_ERROR KeyExportOptions::EndCertValidation(bool isInitiator, WeaveCertificateSet& certSet, ValidationContext& validContext) |
| { |
| certSet.Release(); |
| |
| return WEAVE_NO_ERROR; |
| } |
| |
| // Called by requestor and responder to verify that received message was appropriately secured when the message isn't signed. |
| WEAVE_ERROR KeyExportOptions::ValidateUnsignedKeyExportMessage(bool isInitiator, const IPPacketInfo *pktInfo, const WeaveMessageInfo *msgInfo, uint32_t requestedKeyId) |
| { |
| // Unsigned key export messages are not supported. |
| return isInitiator ? WEAVE_ERROR_UNAUTHORIZED_KEY_EXPORT_RESPONSE : |
| WEAVE_ERROR_UNAUTHORIZED_KEY_EXPORT_REQUEST; |
| } |