blob: be1ea75bcca3fe51efe9b06289195893e4fb89e8 [file] [log] [blame]
/*
*
* 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_ */