blob: 5884fd7f97d138195e21b15a1a9c7ac8b4e903d7 [file] [log] [blame]
/*
*
* Copyright (c) 2013-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 TAKEConfig object, which provides an implementation of the WeaveTAKEAuthDelegate
* interface for use in test applications.
*
*/
#include "ToolCommon.h"
#include <Weave/Support/ASN1.h>
#include "TAKEOptions.h"
TAKEOptions gTAKEOptions;
MockTAKEChallengerDelegate gMockTAKEChallengerDelegate;
MockTAKETokenDelegate gMockTAKETokenDelegate;
TAKEOptions::TAKEOptions()
{
static OptionDef optionDefs[] =
{
#if WEAVE_CONFIG_ENABLE_TAKE_INITIATOR || WEAVE_CONFIG_ENABLE_TAKE_RESPONDER
{ "take-reauth", kNoArgument, kToolCommonOpt_TAKEReauth },
#endif
{ NULL }
};
OptionDefs = optionDefs;
HelpGroupName = "TAKE OPTIONS";
OptionHelp =
#if WEAVE_CONFIG_ENABLE_TAKE_INITIATOR || WEAVE_CONFIG_ENABLE_TAKE_RESPONDER
" --take-reauth\n"
" Pre-populate the challenger token data store with the AK and\n"
" encrypted-AK for the token such that the initial TAKE interaction\n"
" is a re-authentication.\n"
"\n"
#endif
"";
// Defaults
static const uint8_t ik[] = { 0x05, 0x26, 0xAD, 0xB7, 0xBB, 0xD7, 0x82, 0x52, 0x78, 0x2D, 0x60, 0xD6, 0x40, 0xFD, 0xE6, 0xF9 };
static const uint8_t challengerId[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F };
static uint8_t tPub[] = { 0x04, 0x55, 0x7B, 0x11, 0x55, 0xE5, 0xE2, 0x59, 0xB1, 0x98, 0xB2, 0x56, 0x13, 0xE3, 0x5B, 0xA7, 0x91, 0x5C, 0xB1, 0x4A, 0x8D, 0xC4, 0x08, 0x99, 0x03, 0x8F, 0x51, 0xB4, 0xAE, 0xC4, 0xA8, 0x95, 0x1F, 0xF6, 0x65, 0xFF, 0x21, 0x12, 0x3E, 0x8E, 0x1C, 0x36, 0x60, 0xB3, 0x3D, 0xB3, 0x02, 0x5B, 0xA5, 0xB7, 0xD9, 0xFE, 0xA2, 0xB1, 0x01, 0x42, 0x13 };
static const uint8_t tPriv[] = { 0x54, 0x7A, 0x86, 0xF5, 0x6E, 0xFF, 0xDC, 0x52, 0x22, 0x13, 0xBA, 0x8C, 0x00, 0x88, 0x0A, 0x9C, 0x62, 0x1D, 0xCB, 0xA5, 0xD1, 0xD7, 0x70, 0xDF, 0x23, 0x40, 0x7D, 0x18 };
static const uint8_t irk[] = { 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F };
static const uint8_t masterKey[] = { 0x11, 0xFF, 0xF1, 0x1F, 0xD1, 0x3F, 0xB1, 0x5F, 0x91, 0x7F, 0x71, 0x9F, 0x51, 0xBF, 0x31, 0xDF, 0x11, 0xFF, 0xF1, 0x1F, 0xD1, 0x3F, 0xB1, 0x5F, 0x91, 0x7F, 0x71, 0x9F, 0x51, 0xBF, 0x31, 0xDF };
static const uint8_t ak[] = { 0x9F, 0x0F, 0x92, 0xE3, 0xB9, 0x04, 0x96, 0xA1, 0xCB, 0x7C, 0x94, 0x99, 0xAB, 0x34, 0xDD, 0x04 };
static const uint8_t encAK[] = { 0xE6, 0xC4, 0x03, 0xE8, 0xEE, 0xA3, 0x80, 0x56, 0xE0, 0xB1, 0x9C, 0xE9, 0xE3, 0xA6, 0xD8, 0x3A };
IK = ik;
ChallengerId = challengerId;
ChallengerIdLen = sizeof(challengerId);
TPub = tPub;
TPubLen = sizeof(tPub);
TPriv = tPriv;
TPrivLen = sizeof(tPriv);
IRK = irk;
MasterKey = masterKey;
AK = ak;
EncAK = encAK;
ForceReauth = false;
}
bool TAKEOptions::HandleOption(const char *progName, OptionSet *optSet, int id, const char *name, const char *arg)
{
switch (id)
{
case kToolCommonOpt_TAKEReauth:
ForceReauth = true;
break;
default:
PrintArgError("%s: INTERNAL ERROR: Unhandled option: %s\n", progName, name);
return false;
}
return true;
}
WEAVE_ERROR TAKEOptions::PrepopulateTokenData()
{
WEAVE_ERROR err;
uint16_t authKeyLen = TAKE::kAuthenticationKeySize;
uint16_t encryptedAuthKeyLen = kTokenEncryptedStateSize;
err = gMockTAKEChallengerDelegate.StoreTokenAuthData(1, kTAKEConfig_Config1, AK, authKeyLen, EncAK, encryptedAuthKeyLen);
SuccessOrExit(err);
exit:
return err;
}
static uint8_t AuthenticationKeyBuffer[TAKE::kAuthenticationKeySize];
static uint8_t EncryptedAuthenticationKeyBuffer[TAKE::kTokenEncryptedStateSize];
MockTAKEChallengerDelegate::MockTAKEChallengerDelegate() :
AuthenticationKeySet(false),
Rewinded(false)
{
return;
}
// Rewind Identification Key Iterator.
// Called to prepare for a new Identification Key search.
WEAVE_ERROR MockTAKEChallengerDelegate::RewindIdentificationKeyIterator()
{
Rewinded = true;
return WEAVE_NO_ERROR;
}
// Get next {tokenId, IK} pair.
// returns tokenId = kNodeIdNotSpecified if no more IKs are available.
WEAVE_ERROR MockTAKEChallengerDelegate::GetNextIdentificationKey(uint64_t & tokenId, uint8_t *identificationKey, uint16_t & identificationKeyLen)
{
if (Rewinded)
{
if (identificationKeyLen < kIdentificationKeySize)
return WEAVE_ERROR_BUFFER_TOO_SMALL;
tokenId = 1;
identificationKeyLen = kIdentificationKeySize;
memcpy(identificationKey, gTAKEOptions.IK, identificationKeyLen);
Rewinded = false;
}
else
{
tokenId = nl::Weave::kNodeIdNotSpecified;
}
return WEAVE_NO_ERROR;
}
// Get Token Authentication Data.
// Function returns {takeConfig = kTAKEConfig_Invalid, 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.
WEAVE_ERROR MockTAKEChallengerDelegate::GetTokenAuthData(uint64_t tokenId, uint8_t &takeConfig, uint8_t *authKey, uint16_t &authKeyLen, uint8_t *encAuthBlob, uint16_t &encAuthBlobLen)
{
if (tokenId == 1)
{
if (!AuthenticationKeySet)
{
takeConfig = kTAKEConfig_Invalid;
authKey = NULL;
encAuthBlob = NULL;
return WEAVE_NO_ERROR;
}
if (authKeyLen < TAKE::kAuthenticationKeySize)
return WEAVE_ERROR_BUFFER_TOO_SMALL;
if (encAuthBlobLen < kTokenEncryptedStateSize)
return WEAVE_ERROR_BUFFER_TOO_SMALL;
takeConfig = kTAKEConfig_Config1;
authKeyLen = TAKE::kAuthenticationKeySize;
encAuthBlobLen = kTokenEncryptedStateSize;
memcpy(authKey, AuthenticationKeyBuffer, authKeyLen);
memcpy(encAuthBlob, EncryptedAuthenticationKeyBuffer, encAuthBlobLen);
}
else
{
return WEAVE_ERROR_INVALID_ARGUMENT;
}
return WEAVE_NO_ERROR;
}
// Store Token Authentication Data.
// This function should clear Authentication Data that was previously stored on the device for the specified Token (if any).
WEAVE_ERROR MockTAKEChallengerDelegate::StoreTokenAuthData(uint64_t tokenId, uint8_t takeConfig, const uint8_t *authKey, uint16_t authKeyLen, const uint8_t *encAuthBlob, uint16_t encAuthBlobLen)
{
if (tokenId == 1 && takeConfig == kTAKEConfig_Config1)
{
if (authKeyLen < TAKE::kAuthenticationKeySize)
return WEAVE_ERROR_BUFFER_TOO_SMALL;
if (encAuthBlobLen < kTokenEncryptedStateSize)
return WEAVE_ERROR_BUFFER_TOO_SMALL;
memcpy(AuthenticationKeyBuffer, authKey, authKeyLen);
memcpy(EncryptedAuthenticationKeyBuffer, encAuthBlob, encAuthBlobLen);
AuthenticationKeySet = true;
}
else
{
return WEAVE_ERROR_INVALID_ARGUMENT;
}
return WEAVE_NO_ERROR;
}
// Clear Token Authentication Data.
// This function should be called if ReAuthentication phase with the Token Authentication Data stored on the device failed.
WEAVE_ERROR MockTAKEChallengerDelegate::ClearTokenAuthData(uint64_t tokenId)
{
if (tokenId == 1 && AuthenticationKeySet)
{
AuthenticationKeySet = false;
return WEAVE_NO_ERROR;
}
return WEAVE_ERROR_INVALID_ARGUMENT;
}
// Get Token public key.
// On the function call tokenPubKeyLen input specifies size of the tokenPubKey buffer. Function should update this parameter to reflect actual sizes.
WEAVE_ERROR MockTAKEChallengerDelegate::GetTokenPublicKey(uint64_t tokenId, OID& curveOID, EncodedECPublicKey& tokenPubKey)
{
if (tokenId == 1)
{
if (tokenPubKey.ECPointLen < kConfig1_ECPointX962FormatSize)
return WEAVE_ERROR_BUFFER_TOO_SMALL;
tokenPubKey.ECPointLen = kConfig1_ECPointX962FormatSize;
memcpy(tokenPubKey.ECPoint, gTAKEOptions.TPub, tokenPubKey.ECPointLen);
curveOID = nl::Weave::ASN1::kOID_EllipticCurve_secp224r1;
return WEAVE_NO_ERROR;
}
return WEAVE_ERROR_INVALID_ARGUMENT;
}
// Get the challenger ID.
WEAVE_ERROR MockTAKEChallengerDelegate::GetChallengerID(uint8_t *challengerID, uint8_t &challengerIDLen) const
{
if (challengerIDLen < gTAKEOptions.ChallengerIdLen)
return WEAVE_ERROR_BUFFER_TOO_SMALL;
challengerIDLen = gTAKEOptions.ChallengerIdLen;
memcpy(challengerID, gTAKEOptions.ChallengerId, challengerIDLen);
return WEAVE_NO_ERROR;
}
// Get the token Master key. size: kTokenMasterKeySize
WEAVE_ERROR MockTAKETokenDelegate::GetTokenMasterKey(uint8_t *tokenMasterKey) const
{
memcpy(tokenMasterKey, gTAKEOptions.MasterKey, kTokenMasterKeySize);
return WEAVE_NO_ERROR;
}
// Get the Identification Root Key. size: kIdentificationRootKeySize
WEAVE_ERROR MockTAKETokenDelegate::GetIdentificationRootKey(uint8_t *identificationRootKey) const
{
memcpy(identificationRootKey, gTAKEOptions.IRK, kIdentificationRootKeySize);
return WEAVE_NO_ERROR;
}
// 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.
WEAVE_ERROR MockTAKETokenDelegate::GetTokenPrivateKey(OID& curveOID, EncodedECPrivateKey& tokenPrivKey) const
{
if (tokenPrivKey.PrivKeyLen < gTAKEOptions.TPrivLen)
return WEAVE_ERROR_BUFFER_TOO_SMALL;
tokenPrivKey.PrivKeyLen = gTAKEOptions.TPrivLen;
memcpy(tokenPrivKey.PrivKey, gTAKEOptions.TPriv, gTAKEOptions.TPrivLen);
curveOID = nl::Weave::ASN1::kOID_EllipticCurve_secp224r1;
return WEAVE_NO_ERROR;
}
// 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.
WEAVE_ERROR MockTAKETokenDelegate::GetTAKETime(uint32_t &takeTime) const
{
takeTime = 17167; // number of days til 01/01/2017
return WEAVE_NO_ERROR;
}