blob: a2471b0a75b11a5c56718dbb7d816826c7c79f97 [file] [log] [blame]
/*
*
* Copyright (c) 2016-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
* This file defines types, classes and interfaces associated with
* key export protocol.
*
*/
#ifndef WEAVEKEYEXPORT_H_
#define WEAVEKEYEXPORT_H_
#include <stdint.h>
#include <string.h>
#include <Weave/Core/WeaveConfig.h>
#include "WeaveApplicationKeys.h"
#include <Weave/Support/NLDLLUtil.h>
#include <Weave/Support/crypto/CTRMode.h>
#include <Weave/Support/crypto/HashAlgos.h>
#include <Weave/Core/WeaveError.h>
#include <Weave/Core/WeaveCore.h>
/**
* @namespace nl::Weave::Profiles::Security::KeyExport
*
* @brief
* This namespace includes all interfaces within Weave for the
* key export protocol within the Weave security profile.
*/
namespace nl {
namespace Weave {
namespace Profiles {
namespace Security {
namespace KeyExport {
using nl::Weave::WeaveEncryptionKey;
using nl::Weave::Profiles::Security::AppKeys::WeaveGroupKey;
using nl::Weave::Profiles::Security::AppKeys::GroupKeyStoreBase;
class WeaveKeyExport;
enum
{
// Protocol configurations.
kKeyExportConfig_Unspecified = 0x00,
kKeyExportConfig_Config1 = 0x01,
kKeyExportConfig_Config2 = 0x02,
kKeyExportConfig_ConfigLast = kKeyExportConfig_Config2,
// Supported Configurations Bit Masks.
kKeyExportSupportedConfig_Config1 = 0x01,
kKeyExportSupportedConfig_Config2 = 0x02,
kKeyExportSupportedConfig_All = (0x00 |
#if WEAVE_CONFIG_SUPPORT_KEY_EXPORT_CONFIG1
kKeyExportSupportedConfig_Config1 |
#endif
#if WEAVE_CONFIG_SUPPORT_KEY_EXPORT_CONFIG2
kKeyExportSupportedConfig_Config2 |
#endif
0x00)
};
// Protocol Control Header field definitions.
enum
{
// --- Requester Control Header fields.
kReqControlHeader_AltConfigCountMask = 0x07,
kReqControlHeader_AltConfigCountShift = 0,
kReqControlHeader_SignMessagesFlag = 0x80,
kReqControlHeader_UnusedBits = ~((kReqControlHeader_AltConfigCountMask << kReqControlHeader_AltConfigCountShift ) |
kReqControlHeader_SignMessagesFlag),
// --- Responder Control Header fields.
kResControlHeader_SignMessagesFlag = 0x80,
kResControlHeader_UnusedBits = ~kResControlHeader_SignMessagesFlag,
};
// Protocol configuration specific sizes (in bytes).
enum
{
// Sizes declaration for Config1.
kConfig1_CurveSize = 28,
kConfig1_ECDHPrivateKeySize = kConfig1_CurveSize + 1,
kConfig1_ECDHPublicKeySize = 2 * kConfig1_CurveSize + 1,
// Sizes declaration for Config2.
kConfig2_CurveSize = 32,
kConfig2_ECDHPrivateKeySize = kConfig2_CurveSize + 1,
kConfig2_ECDHPublicKeySize = 2 * kConfig2_CurveSize + 1,
// Maximum possible sizes.
#if WEAVE_CONFIG_SUPPORT_KEY_EXPORT_CONFIG2
kMaxECDHPrivateKeySize = kConfig2_ECDHPrivateKeySize,
kMaxECDHPublicKeySize = kConfig2_ECDHPublicKeySize,
kMaxECDHSharedSecretSize = kConfig2_CurveSize,
#else
kMaxECDHPrivateKeySize = kConfig1_ECDHPrivateKeySize,
kMaxECDHPublicKeySize = kConfig1_ECDHPublicKeySize,
kMaxECDHSharedSecretSize = kConfig1_CurveSize,
#endif
};
// Protocol data sizes (in bytes).
enum
{
kMaxAltConfigsCount = 7,
kExportedKeyAuthenticatorSize = Platform::Security::SHA256::kHashLength,
kMaxNodePrivateKeySize = ((WEAVE_CONFIG_MAX_EC_BITS + 7) / 8) + 1,
kEncryptionKeySize = Crypto::AES128CTRMode::kKeyLength,
kAuthenticationKeySize = Platform::Security::SHA256::kHashLength,
kEncryptionAndAuthenticationKeySize = kEncryptionKeySize + kAuthenticationKeySize,
kMinKeySaltSize = 2 * sizeof(uint8_t) + sizeof(uint32_t),
kMaxKeySaltSize = kMinKeySaltSize + kMaxAltConfigsCount,
kKeyExportReconfigureMsgSize = sizeof(uint8_t),
};
/**
* @class WeaveKeyExportDelegate
*
* @brief
* Abstract delegate class called by KeyExport engine to perform various
* actions related to authentication during key export.
*
*/
class WeaveKeyExportDelegate
{
public:
// ===== Abstract Interface methods
#if !WEAVE_CONFIG_LEGACY_KEY_EXPORT_DELEGATE
/**
* Get the key export certificate set for the local node.
*
* Called when the key export engine is preparing to sign a key export message. This method
* is responsible for initializing certificate set and loading all certificates that will be
* included or referenced in the signature of the message. The last certificate loaded must
* be the signing certificate.
*/
virtual WEAVE_ERROR GetNodeCertSet(WeaveKeyExport * keyExport, WeaveCertificateSet & certSet) = 0;
/**
* Release the node's certificate set.
*
* Called when the key export engine is done with the certificate set returned by GetNodeCertSet().
*/
virtual WEAVE_ERROR ReleaseNodeCertSet(WeaveKeyExport * keyExport, WeaveCertificateSet & certSet) = 0;
/**
* Generate a signature for a key export message.
*
* This method is responsible for computing a signature of the given hash value using the local
* node's private key and writing the signature to the supplied TLV writer as a WeaveSignature
* TLV structure.
*/
virtual WEAVE_ERROR GenerateNodeSignature(WeaveKeyExport * keyExport, const uint8_t * msgHash,
uint8_t msgHashLen, TLVWriter & writer) = 0;
/**
* Prepare for validating the peer's certificate.
*
* Called at the start of certificate validation. This method is responsible for preparing the
* supplied certificate set and validation context for use in validating the peer node's
* certificate. Implementations must initialize the supplied WeaveCertificateSet object with
* sufficient resources to handle the upcoming certificate validation. The implementation
* must also load any necessary trusted root or CA certificates into the certificate set.
*
* The supplied validation context will be initialized with a set of default validation
* criteria, which the implementation may alter as necessary. The implementation must
* either set the EffectiveTime field, or set the appropriate validation flags to suppress
* certificate lifetime validation.
*
* The implementation is required to maintain any resources allocated during BeginCertValidation()
* until the corresponding EndCertValidation() is called is made. Implementations are guaranteed
* that EndCertValidation() will be called exactly once for each successful call to
* BeginCertValidation().
*/
virtual WEAVE_ERROR BeginCertValidation(WeaveKeyExport * keyExport, ValidationContext & validCtx,
WeaveCertificateSet & certSet) = 0;
/**
* Process the results of validating the peer's certificate.
*
* Called when validation of the peer node's certificate has completed. This method is only
* called if certificate validation completes successfully. Implementations may use this call
* to inspect the results of validation, and possibly override the result with an error.
*
* For a responding node, the method is expected to verify the requestor's authority to export the
* requested key.
*
* For an initiating node, the method is expected to verify that the validated certificate properly
* identifies the peer to which the key export request was sent.
*/
virtual WEAVE_ERROR HandleCertValidationResult(WeaveKeyExport * keyExport, ValidationContext & validCtx,
WeaveCertificateSet & certSet, uint32_t requestedKeyId) = 0;
/**
* Release resources associated with peer certificate validation.
*
* Called when peer certificate validation and request verification are complete.
*/
virtual WEAVE_ERROR EndCertValidation(WeaveKeyExport * keyExport, ValidationContext & validCtx,
WeaveCertificateSet & certSet) = 0;
/**
* Verify the security of an unsigned key export message.
*
* Called when the node receives a key export message that isn't signed. The method is expected to
* verify the security of an unsigned key export message based on the context of its communication,
* e.g. via the attributes of a security session used to send the message.
*
* For a responding node, the method is expected to verify the initiator's authority to export the
* requested key.
*
* For an initiating node, the method is expected to verify the message legitimately originated from
* the peer to which the key export request was sent.
*/
virtual WEAVE_ERROR ValidateUnsignedKeyExportMessage(WeaveKeyExport * keyExport, uint32_t requestedKeyId) = 0;
#else // !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.
virtual WEAVE_ERROR GetNodeCertSet(bool isInitiator, WeaveCertificateSet& certSet) = 0;
// Called when the key export engine is done with the certificate set returned by GetNodeCertSet().
virtual WEAVE_ERROR ReleaseNodeCertSet(bool isInitiator, WeaveCertificateSet& certSet) = 0;
// Get the local node's private key.
virtual WEAVE_ERROR GetNodePrivateKey(bool isInitiator, const uint8_t *& weavePrivKey, uint16_t& weavePrivKeyLen) = 0;
// Called when the key export engine is done with the buffer returned by GetNodePrivateKey().
virtual WEAVE_ERROR ReleaseNodePrivateKey(bool isInitiator, const uint8_t *& weavePrivKey) = 0;
// 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.
virtual WEAVE_ERROR BeginCertValidation(bool isInitiator, WeaveCertificateSet& certSet, ValidationContext& validCtx) = 0;
// Called with the results of validating the peer's certificate.
// Responder verifies that requestor is authorized to export the specified key.
// Requestor verifies that response came from expected node.
virtual WEAVE_ERROR HandleCertValidationResult(bool isInitiator, WeaveCertificateSet& certSet, ValidationContext& validCtx,
const IPPacketInfo *pktInfo, const WeaveMessageInfo *msgInfo, uint32_t requestedKeyId) = 0;
// Called when peer certificate validation and request verification are complete.
virtual WEAVE_ERROR EndCertValidation(bool isInitiator, WeaveCertificateSet& certSet, ValidationContext& validCtx) = 0;
// Called by requestor and responder to verify that received message was appropriately secured when the message isn't signed.
virtual WEAVE_ERROR ValidateUnsignedKeyExportMessage(bool isInitiator, const IPPacketInfo *pktInfo, const WeaveMessageInfo *msgInfo, uint32_t requestedKeyId) = 0;
private:
// ===== Private members that provide API compatibility with the non-legacy interface.
friend class WeaveKeyExport;
WEAVE_ERROR GetNodeCertSet(WeaveKeyExport * keyExport, WeaveCertificateSet & certSet);
WEAVE_ERROR ReleaseNodeCertSet(WeaveKeyExport * keyExport, WeaveCertificateSet & certSet);
WEAVE_ERROR BeginCertValidation(WeaveKeyExport * keyExport, ValidationContext & validCtx,
WeaveCertificateSet & certSet);
WEAVE_ERROR HandleCertValidationResult(WeaveKeyExport * keyExport, ValidationContext & validCtx,
WeaveCertificateSet & certSet, uint32_t requestedKeyId);
WEAVE_ERROR EndCertValidation(WeaveKeyExport * keyExport, ValidationContext & validCtx,
WeaveCertificateSet & certSet);
WEAVE_ERROR ValidateUnsignedKeyExportMessage(WeaveKeyExport * keyExport, uint32_t requestedKeyId);
#endif // WEAVE_CONFIG_LEGACY_KEY_EXPORT_DELEGATE
};
/**
* @class WeaveKeyExport
*
* @brief
* Implements the core logic of the Weave key export protocol.
*
*/
class NL_DLL_EXPORT WeaveKeyExport
{
public:
/**
* The current state of the WeaveKeyExport object.
*/
enum
{
kState_Reset = 0, /**< The initial (and final) state of a WeaveKeyExport object. */
kState_InitiatorGeneratingRequest = 10, /**< Initiator state indicating that the key export request message is being generated. */
kState_InitiatorRequestGenerated = 11, /**< Initiator state indicating that the key export request message has been generated. */
kState_InitiatorReconfigureProcessed = 12, /**< Initiator state indicating that the key export reconfigure message was processed. */
kState_InitiatorDone = 13, /**< Initiator state indicating that the key export response was processed. */
kState_ResponderProcessingRequest = 20, /**< Responder state indicating that the key export request message is being processed. */
kState_ResponderRequestProcessed = 21, /**< Responder state indicating that the key export request message has been processed. */
kState_ResponderDone = 22 /**< Responder state indicating that the key export response message was generated. */
};
WeaveKeyExportDelegate * KeyExportDelegate; /**< Pointer to a key export delegate object. */
GroupKeyStoreBase * GroupKeyStore; /**< Pointer to a platform group key store object. */
void Init(WeaveKeyExportDelegate * keyExportDelegate, GroupKeyStoreBase * groupKeyStore = NULL);
void Reset(void);
void Shutdown(void);
uint8_t State() const;
bool IsInitiator() const;
uint8_t ProtocolConfig() const;
uint32_t KeyId() const;
uint8_t AllowedConfigs() const;
void SetAllowedConfigs(uint8_t allowedConfigs);
bool IsAllowedConfig(uint8_t config) const;
bool SignMessages() const;
const WeaveMessageInfo * MessageInfo() const;
WEAVE_ERROR GenerateKeyExportRequest(uint8_t *buf, uint16_t bufSize, uint16_t& msgLen, uint8_t proposedConfig, uint32_t keyId, bool signMessages);
WEAVE_ERROR ProcessKeyExportRequest(const uint8_t *buf, uint16_t msgSize, const WeaveMessageInfo *msgInfo);
WEAVE_ERROR GenerateKeyExportResponse(uint8_t *buf, uint16_t bufSize, uint16_t& msgLen, const WeaveMessageInfo *msgInfo);
WEAVE_ERROR ProcessKeyExportResponse(const uint8_t *buf, uint16_t msgSize, const WeaveMessageInfo *msgInfo,
uint8_t *exportedKeyBuf, uint16_t exportedKeyBufSize, uint16_t &exportedKeyLen, uint32_t &exportedKeyId);
WEAVE_ERROR GenerateKeyExportReconfigure(uint8_t *buf, uint16_t bufSize, uint16_t& msgLen);
WEAVE_ERROR ProcessKeyExportReconfigure(const uint8_t *buf, uint16_t msgSize, uint8_t &config);
private:
uint32_t mKeyId; /**< Exported key Id. */
const WeaveMessageInfo * mMsgInfo;
union
{
struct
{
uint16_t ECDHPrivateKeyLen;
uint8_t ECDHPublicKey[kMaxECDHPublicKeySize];
uint8_t ECDHPrivateKey[kMaxECDHPrivateKeySize];
};
struct
{
uint16_t SharedSecretLen;
uint8_t SharedSecret[kMaxECDHSharedSecretSize];
};
struct
{
uint8_t EncryptionAndAuthenticationKey[kEncryptionAndAuthenticationKeySize];
};
};
uint8_t mState; /**< Current state of the WeaveKeyExport object. */
uint8_t mProtocolConfig; /**< Selected key export protocol config. */
uint8_t mAllowedConfigs; /**< Allowed protocol configurations. */
uint8_t mAltConfigsCount;
uint8_t mAltConfigs[kMaxAltConfigsCount];
bool mSignMessages; /**< Sign protocol messages flag. */
WEAVE_ERROR AppendNewECDHKey(uint8_t *& buf);
WEAVE_ERROR AppendSignature(uint8_t *msgStart, uint16_t msgBufSize, uint16_t& msgLen);
WEAVE_ERROR VerifySignature(const uint8_t *msgStart, uint16_t msgBufSize, uint16_t& msgLen,
const WeaveMessageInfo *msgInfo);
WEAVE_ERROR EncryptExportedKey(uint8_t *& buf, uint16_t bufSize, uint16_t& msgLen, uint16_t& exportedKeyLen);
WEAVE_ERROR DecryptExportedKey(const uint8_t *& buf, uint8_t *exportedKey, uint16_t exportedKeyLen);
WEAVE_ERROR ComputeSharedSecret(const uint8_t *peerPubKey);
WEAVE_ERROR DeriveKeyEncryptionKey(void);
void EncryptDecryptKey(const uint8_t *keyIn, uint8_t *keyOut, uint8_t keyLen);
void AuthenticateKey(const uint8_t *key, uint8_t keyLen, uint8_t* authenticator);
WEAVE_ERROR GenerateAltConfigsList(void);
WEAVE_ERROR ValidateProtocolConfig(void);
uint16_t GetECDHPublicKeyLen(void) const;
OID GetCurveOID(void) const;
};
extern WEAVE_ERROR SimulateDeviceKeyExport(const uint8_t *deviceCert, uint16_t deviceCertLen,
const uint8_t *devicePrivKey, uint16_t devicePrivKeyLen,
const uint8_t *trustRootCert, uint16_t trustRootCertLen,
const uint8_t *exportReq, uint16_t exportReqLen,
uint8_t *exportRespBuf, uint16_t exportRespBufSize, uint16_t& exportRespLen,
bool& respIsReconfig);
#if WEAVE_CONFIG_LEGACY_KEY_EXPORT_DELEGATE
inline WEAVE_ERROR WeaveKeyExportDelegate::GetNodeCertSet(WeaveKeyExport * keyExport, WeaveCertificateSet & certSet)
{
return GetNodeCertSet(keyExport->IsInitiator(), certSet);
}
inline WEAVE_ERROR WeaveKeyExportDelegate::ReleaseNodeCertSet(WeaveKeyExport * keyExport, WeaveCertificateSet & certSet)
{
return ReleaseNodeCertSet(keyExport->IsInitiator(), certSet);
}
inline WEAVE_ERROR WeaveKeyExportDelegate::BeginCertValidation(WeaveKeyExport * keyExport, ValidationContext & validCtx,
WeaveCertificateSet & certSet)
{
return BeginCertValidation(keyExport->IsInitiator(), certSet, validCtx);
}
inline WEAVE_ERROR WeaveKeyExportDelegate::HandleCertValidationResult(WeaveKeyExport * keyExport, ValidationContext & validCtx,
WeaveCertificateSet & certSet, uint32_t requestedKeyId)
{
return HandleCertValidationResult(keyExport->IsInitiator(), certSet, validCtx, NULL, keyExport->MessageInfo(), requestedKeyId);
}
inline WEAVE_ERROR WeaveKeyExportDelegate::EndCertValidation(WeaveKeyExport * keyExport, ValidationContext & validCtx,
WeaveCertificateSet & certSet)
{
return EndCertValidation(keyExport->IsInitiator(), certSet, validCtx);
}
inline WEAVE_ERROR WeaveKeyExportDelegate::ValidateUnsignedKeyExportMessage(WeaveKeyExport * keyExport, uint32_t requestedKeyId)
{
return ValidateUnsignedKeyExportMessage(keyExport->IsInitiator(), NULL, keyExport->MessageInfo(), requestedKeyId);
}
#endif // WEAVE_CONFIG_LEGACY_KEY_EXPORT_DELEGATE
inline uint8_t WeaveKeyExport::State() const
{
return mState;
}
inline uint8_t WeaveKeyExport::ProtocolConfig() const
{
return mProtocolConfig;
}
inline uint32_t WeaveKeyExport::KeyId() const
{
return mKeyId;
}
inline uint8_t WeaveKeyExport::AllowedConfigs() const
{
return mAllowedConfigs;
}
inline void WeaveKeyExport::SetAllowedConfigs(uint8_t allowedConfigs)
{
mAllowedConfigs = kKeyExportSupportedConfig_All & allowedConfigs;
}
inline const WeaveMessageInfo * WeaveKeyExport::MessageInfo() const
{
return mMsgInfo;
}
inline bool WeaveKeyExport::SignMessages() const
{
return mSignMessages;
}
} // namespace KeyExport
} // namespace Security
} // namespace Profiles
} // namespace Weave
} // namespace nl
#endif /* WEAVEKEYEXPORT_H_ */