| /* |
| * |
| * Copyright (c) 2015-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 data types and objects for initiators and |
| * responders for the Weave Token Authenticated Key Exchange |
| * (TAKE) protocol. |
| * |
| */ |
| |
| #ifndef WEAVETAKE_H_ |
| #define WEAVETAKE_H_ |
| |
| |
| #include <Weave/Core/WeaveConfig.h> |
| |
| #include <Weave/Support/NLDLLUtil.h> |
| #include <Weave/Core/WeaveError.h> |
| #include <Weave/Core/WeaveCore.h> |
| #include <SystemLayer/SystemPacketBuffer.h> |
| #include <micro-ecc/uECC.h> |
| |
| #include <stdint.h> |
| #include <string.h> |
| |
| /** |
| * @namespace nl::Weave::Profiles::Security::TAKE |
| * |
| * @brief |
| * This namespace includes all interfaces within Weave for the |
| * Token Authenticated Key Exchange (TAKE) protocol within the |
| * Weave Security profile. |
| */ |
| |
| namespace nl { |
| namespace Weave { |
| namespace Profiles { |
| namespace Security { |
| namespace TAKE { |
| |
| using nl::Weave::System::PacketBuffer; |
| using nl::Weave::WeaveEncryptionKey; |
| |
| static const uint8_t kSaltTimeUnlimitedIdentificationKey[] = { 0x12, 0x34, 0x56, 0x78 }; |
| static const uint8_t kSaltProtocolEncryption[] = { 0x54, 0x41, 0x4B, 0x45 }; // TAKE |
| |
| // TAKE Control Header Field Definitions |
| enum |
| { |
| // |
| kControlHeader_NumOptionalConfigurationMask = 0b00001111, |
| kControlHeader_NumOptionalConfigurationShift = 0, |
| kControlHeader_EncryptAuthenticationPhaseFlag = 0b00010000, |
| kControlHeader_EncryptCommunicationsPhaseFlag = 0b00100000, |
| kControlHeader_TimeLimitFlag = 0b01000000, |
| kControlHeader_HasChallengerIdFlag = 0b10000000 |
| }; |
| |
| enum |
| { |
| kConfig1_CurveSize = 28, |
| kConfig1_PrivKeySize = kConfig1_CurveSize + 1, |
| kConfig1_ECPointX962FormatSize = 2 * kConfig1_CurveSize + 1, |
| kConfig1_HMACSignatureSize = Platform::Security::SHA1::kHashLength |
| }; |
| |
| //size of data, in bytes |
| enum |
| { |
| kIdentificationRootKeySize = 16, |
| kNonceSize = 16, |
| kMaxChallengerIdSize = 16, |
| kIdentificationKeySize = 16, |
| kTokenMasterKeySize = 32, |
| kTokenEncryptedStateSize = 16, |
| kMaxOptionalConfigurations = 16, |
| kAuthenticationKeySize = 16, |
| kMaxTokenPrivateKeySize = ((WEAVE_CONFIG_MAX_EC_BITS + 7) / 8) + 1, |
| // NOTE: These parameters should be reviewed and updated when new TAKE Configs are introduced |
| kMaxCurveSize = kConfig1_CurveSize, |
| kMaxECDHPrivateKeySize = kConfig1_PrivKeySize, |
| kMaxECDHPublicKeySize = kConfig1_ECPointX962FormatSize, |
| kMaxIdentifyTokenResponseKeySaltSize = kMaxChallengerIdSize + 4, |
| kMaxECDSASignatureSize = 56, |
| kMaxProtocolEncryptionKeySaltSize = 6 + kMaxOptionalConfigurations + 2 * kNonceSize + sizeof(kSaltProtocolEncryption), |
| kMaxAuthenticationKeySaltSize = 6 + kMaxOptionalConfigurations + 2 * kNonceSize + kMaxChallengerIdSize |
| }; |
| |
| //size of messages, in bytes |
| enum |
| { |
| kIdentifyTokenMsgMinSize = 3 + kNonceSize, |
| kIdentifyTokenResponseMsgSize = 1 + kNonceSize + Platform::Security::SHA1::kHashLength, |
| kAuthenticateTokenMsgMinSize = kConfig1_HMACSignatureSize, |
| kAuthenticateTokenResponseMsgMinSize = kTokenEncryptedStateSize, |
| kReAuthenticateTokenMsgSize = kTokenEncryptedStateSize + kConfig1_HMACSignatureSize, |
| kReAuthenticateTokenResponseMsgSize = kConfig1_HMACSignatureSize, |
| kTokenRecongfigureMsgSize = 1 |
| }; |
| |
| enum { |
| kTAKEConfig_Invalid = 0, |
| kTAKEConfig_Config1 = 1 |
| }; |
| |
| // Abstract delegate class called by TAKE engine to perform various |
| // actions related to authentication during a TAKE exchange. |
| class WeaveTAKEChallengerAuthDelegate |
| { |
| public: |
| // Rewind Identification Key Iterator. |
| // Called to prepare for a new Identification Key search. |
| virtual WEAVE_ERROR RewindIdentificationKeyIterator(void) = 0; |
| |
| // Get next {tokenId, IK} pair. |
| // returns tokenId = kNodeIdNotSpecified if no more IKs are available. |
| virtual WEAVE_ERROR GetNextIdentificationKey(uint64_t & tokenId, uint8_t *identificationKey, uint16_t & identificationKeyLen) = 0; |
| |
| // Get Token Authentication Data. |
| // Function returns {takeConfig = 0x00, authKey = NULL, encAuthBlob = NULL} if Authentication Data associated with a specified Token |
| // is not stored on the device. |
| // On the function call authKeyLen and encAuthBlobLen inputs specify sizes of the authKey and encAuthBlob buffers, respectively. |
| // Function should update these parameters to reflect actual sizes. |
| virtual WEAVE_ERROR GetTokenAuthData(uint64_t tokenId, uint8_t &takeConfig, uint8_t *authKey, uint16_t &authKeyLen, uint8_t *encAuthBlob, uint16_t &encAuthBlobLen) = 0; |
| |
| // Store Token Authentication Data. |
| // This function should clear Authentication Data that was previously stored on the device for the specified Token (if any). |
| virtual WEAVE_ERROR StoreTokenAuthData(uint64_t tokenId, uint8_t takeConfig, const uint8_t *authKey, uint16_t authKeyLen, const uint8_t *encAuthBlob, uint16_t encAuthBlobLen) = 0; |
| |
| // Clear Token Authentication Data. |
| // This function should be called if ReAuthentication phase with the Token Authentication Data stored on the device failed. |
| virtual WEAVE_ERROR ClearTokenAuthData(uint64_t tokenId) = 0; |
| |
| // Get Token public key. |
| // On the function call tokenPubKey length input specifies size of the tokenPubKey buffer. Function should update this parameter to reflect actual sizes. |
| virtual WEAVE_ERROR GetTokenPublicKey(uint64_t tokenId, OID& curveOID, EncodedECPublicKey& tokenPubKey) = 0; |
| |
| // Get the challenger ID. |
| virtual WEAVE_ERROR GetChallengerID(uint8_t *challengerID, uint8_t &challengerIDLen) const = 0; |
| }; |
| |
| // Abstract delegate class called by TAKE Token to get |
| // token-specific infor related to the TAKE authentication. |
| class WeaveTAKETokenAuthDelegate |
| { |
| public: |
| // Get the token Master key. size: kTokenMasterKeySize |
| virtual WEAVE_ERROR GetTokenMasterKey(uint8_t *tokenMasterKey) const = 0; |
| |
| // Get the Identification Root Key. size: kIdentificationRootKeySize |
| virtual WEAVE_ERROR GetIdentificationRootKey(uint8_t *identificationRootKey) const = 0; |
| |
| // Get the token Private Key. |
| // On the function call tokenPrivKeyLen input specifies size of the tokenPrivKey buffer. |
| // Function should update this parameter to reflect actual sizes of the private key. |
| virtual WEAVE_ERROR GetTokenPrivateKey(OID& curveOID, EncodedECPrivateKey& tokenPrivKey) const = 0; |
| |
| // Get TAKE Time. |
| // Function returns takeTime, which is Unix time rounded with 24 hour granularity |
| // i.e. number of days elapsed after 1 January 1970. |
| virtual WEAVE_ERROR GetTAKETime(uint32_t &takeTime) const = 0; |
| }; |
| |
| // Implements the core logic of the Weave TAKE protocol. |
| class NL_DLL_EXPORT WeaveTAKEEngine |
| { |
| public: |
| |
| WeaveTAKEChallengerAuthDelegate *ChallengerAuthDelegate; // Challenger Authentication delegate object |
| WeaveTAKETokenAuthDelegate *TokenAuthDelegate; // Token Authentication delegate object |
| |
| uint8_t ChallengerNonce[kNonceSize]; |
| uint8_t TokenNonce[kNonceSize]; |
| |
| uint8_t ControlHeader; |
| uint8_t EncryptionType; |
| uint8_t ProtocolConfig; |
| |
| uint8_t OptionalConfigurations[kMaxOptionalConfigurations]; |
| |
| uint16_t SessionKeyId; |
| |
| uint8_t ChosenConfiguration; |
| |
| uint8_t ChallengerId[kMaxChallengerIdSize]; |
| uint8_t ChallengerIdLen; |
| |
| void Init(void); |
| void Shutdown(void); |
| |
| // First handshake. |
| WEAVE_ERROR GenerateIdentifyTokenMessage(uint16_t sessionKeyId, uint8_t takeConfig, bool encryptAuthPhase, bool encryptCommPhase, bool timeLimitedIK, |
| bool sendChallengerId, uint8_t encryptionType, uint64_t localNodeId, PacketBuffer *msgBuf); |
| WEAVE_ERROR ProcessIdentifyTokenMessage(uint64_t peerNodeId, const PacketBuffer *msgBuf); |
| WEAVE_ERROR GenerateIdentifyTokenResponseMessage(PacketBuffer *msgBuf); |
| WEAVE_ERROR ProcessIdentifyTokenResponseMessage(const PacketBuffer *buf); |
| |
| // In case a reconfigure is needed. |
| WEAVE_ERROR GenerateTokenReconfigureMessage(PacketBuffer *msgBuf); |
| WEAVE_ERROR ProcessTokenReconfigureMessage(uint8_t& config, const PacketBuffer *msgBuf); |
| |
| // Generate the encryption key. |
| WEAVE_ERROR GenerateProtocolEncryptionKey(void); |
| |
| // Second handshake, assuming no reauthentication. |
| WEAVE_ERROR GenerateAuthenticateTokenMessage(PacketBuffer *msgBuf); |
| WEAVE_ERROR ProcessAuthenticateTokenMessage(const PacketBuffer *msgBuf); |
| WEAVE_ERROR GenerateAuthenticateTokenResponseMessage(PacketBuffer *msgBuf); |
| WEAVE_ERROR ProcessAuthenticateTokenResponseMessage(const PacketBuffer *msgBuf); |
| |
| // Second handshake, assuming reauthentication. |
| WEAVE_ERROR GenerateReAuthenticateTokenMessage(PacketBuffer *msgBuf); |
| WEAVE_ERROR ProcessReAuthenticateTokenMessage(const PacketBuffer *msgBuf); |
| WEAVE_ERROR GenerateReAuthenticateTokenResponseMessage(PacketBuffer *msgBuf); |
| WEAVE_ERROR ProcessReAuthenticateTokenResponseMessage(const PacketBuffer *msgBuf); |
| |
| // Returns the session key. |
| WEAVE_ERROR GetSessionKey(const WeaveEncryptionKey *& encKey) const; |
| uint8_t GetEncryptionType(void); |
| |
| bool UseSessionKey(void) const; |
| |
| uint8_t GetNumOptionalConfigurations(void) const; |
| bool IsEncryptAuthPhase(void) const; |
| bool IsEncryptCommPhase(void) const; |
| bool IsTimeLimitedIK(void) const; |
| bool HasSentChallengerId(void) const; |
| |
| uint16_t GetCurveLen(void) const; |
| uint16_t GetPrivKeyLen(void) const; |
| uint16_t GetECPointLen(void) const; |
| OID GetCurveOID(void) const; |
| |
| private: |
| WeaveEncryptionKey EncryptionKey; |
| |
| enum EngineState |
| { |
| kState_Reset = 0, |
| |
| // Initiator States |
| kState_InitiatorStatesBase = 10, |
| kState_InitiatorStatesEnd = 19, |
| kState_InitiatorIdentifyTokenGenerated = kState_InitiatorStatesBase + 0, |
| kState_InitiatorIdentifyTokenResponseProcessed = kState_InitiatorStatesBase + 1, |
| kState_InitiatorAuthenticateTokenGenerated = kState_InitiatorStatesBase + 2, |
| kState_InitiatorAuthenticateTokenResponseProcessed = kState_InitiatorStatesBase + 3, |
| kState_InitiatorReAuthenticateTokenGenerated = kState_InitiatorStatesBase + 4, |
| kState_InitiatorReAuthenticateTokenResponseProcessed = kState_InitiatorStatesBase + 5, |
| kState_InitiatorReconfigureProcessed = kState_InitiatorStatesBase + 6, |
| |
| |
| // Responder States |
| kState_ResponderStatesBase = 20, |
| kState_ResponderStatesEnd = 29, |
| kState_ResponderIdentifyTokenProcessed = kState_ResponderStatesBase + 0, |
| kState_ResponderIdentifyTokenResponseGenerated = kState_ResponderStatesBase + 1, |
| kState_ResponderAuthenticateTokenProcessed = kState_ResponderStatesBase + 2, |
| kState_ResponderAuthenticateTokenResponseGenerated = kState_ResponderStatesBase + 3, |
| kState_ResponderReAuthenticateTokenProcessed = kState_ResponderStatesBase + 4, |
| kState_ResponderReAuthenticateTokenResponseGenerated = kState_ResponderStatesBase + 5, |
| kState_ResponderDone = kState_ResponderStatesBase + 6 |
| }; |
| |
| uint8_t State; |
| |
| enum EncryptionKeyState { |
| kEncryptionKeyState_Uninitialized, |
| kEncryptionKeyState_Initialized, |
| }; |
| |
| uint8_t KeyState; |
| |
| uint8_t IdentificationKey[kIdentificationKeySize]; |
| uint8_t AuthenticationKey[kAuthenticationKeySize]; |
| uint8_t EncryptedAuthenticationKey[kTokenEncryptedStateSize]; |
| |
| // Used only by the initiator |
| uint8_t ECDHPrivateKeyBuffer[kMaxECDHPrivateKeySize]; |
| uint16_t ECDHPrivateKeyLength; |
| uint8_t ECDHPublicKeyBuffer[kMaxECDHPublicKeySize]; |
| uint64_t TokenId; |
| |
| void GenerateHMACSignature(const uint8_t* key, uint8_t* dest, const uint8_t* additionalField = NULL, uint8_t additionalFieldLength = 0, uint16_t keyLength = kIdentificationKeySize); |
| |
| WEAVE_ERROR GenerateAuthenticationKey(const uint8_t* challengerId, uint8_t* privateKey, uint8_t* publicKey, uint16_t privateKeyLen); |
| |
| WEAVE_ERROR GenerateSignatureForAuthenticateTokenResponse(uint8_t* dest, const uint8_t* challengerECDHPublicKey, const uint8_t* tokenECDHPublicKey, EncodedECPrivateKey TPriv, const uint8_t* encryptedState, OID& curveOID); |
| WEAVE_ERROR VerifySignatureForAuthenticateTokenResponse(const uint8_t* signature, const uint8_t* challengerECDHPublicKey, const uint8_t* tokenECDHPublicKey, const uint8_t* encryptedState, OID& curveOID, EncodedECPublicKey& encodedPubKey); |
| void GenerateHashForAuthenticateTokenResponse(uint8_t* dest, const uint8_t* challengerECDHPublicKey, const uint8_t* tokenECDHPublicKey, const uint8_t* encryptedState); |
| |
| // Read/Write values from/to a message, incrementing the pointer by the length of the field. |
| static void ReadArray(uint8_t* dest, const uint8_t*& src, uint8_t length); |
| static void WriteArray(const uint8_t* src, uint8_t*& dest, uint8_t length); |
| |
| }; |
| |
| } // namespace TAKE |
| } // namespace Security |
| } // namespace Profiles |
| } // namespace Weave |
| } // namespace nl |
| |
| #endif /* WEAVETAKE_H_ */ |