blob: fe5b61f1e239f4222324e60e1cfa74a5c59d53c0 [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
* This file defines data types and objects for initiators and
* responders for the Weave Password Authenticated Session
* Establishment (PASE) protocol.
*
*/
#ifndef WEAVEPASE_H_
#define WEAVEPASE_H_
#include <Weave/Core/WeaveConfig.h>
#define WEAVE_IS_EC_PASE_ENABLED ( WEAVE_CONFIG_SUPPORT_PASE_CONFIG2 || \
WEAVE_CONFIG_SUPPORT_PASE_CONFIG3 || \
WEAVE_CONFIG_SUPPORT_PASE_CONFIG4 || \
WEAVE_CONFIG_SUPPORT_PASE_CONFIG5 )
#include <Weave/Support/NLDLLUtil.h>
#include <Weave/Core/WeaveCore.h>
#include <Weave/Core/WeaveVendorIdentifiers.hpp>
#include <Weave/Core/WeaveEncoding.h>
#include <Weave/Core/WeaveTLV.h>
#include <Weave/Support/crypto/HashAlgos.h>
#include <Weave/Support/crypto/HMAC.h>
#include <Weave/Support/crypto/HKDF.h>
#if WEAVE_CONFIG_SUPPORT_PASE_CONFIG1 && !WEAVE_WITH_OPENSSL
#error "INVALID WEAVE CONFIG: PASE Config1 enabled but OpenSSL not available (WEAVE_CONFIG_SUPPORT_PASE_CONFIG1 == 1 && WEAVE_WITH_OPENSSL == 0)."
#endif
#if WEAVE_IS_EC_PASE_ENABLED
#include <Weave/Support/crypto/EllipticCurve.h>
#endif
#if WEAVE_CONFIG_SUPPORT_PASE_CONFIG1
#include "openssl/bn.h"
struct JPAKE_CTX;
#endif
/**
* @namespace nl::Weave::Profiles::Security::PASE
*
* @brief
* This namespace includes all interfaces within Weave for the
* Password Authenticated Session Establishment (PASE) protocol
* within the Weave security profile.
*/
namespace nl {
namespace Weave {
namespace Profiles {
namespace Security {
namespace PASE {
using nl::Weave::System::PacketBuffer;
using nl::Weave::WeaveEncryptionKey;
#if WEAVE_IS_EC_PASE_ENABLED
using nl::Weave::ASN1::OID;
using nl::Weave::Crypto::EllipticCurveJPAKE;
#endif
// PASE Protocol Configurations
enum
{
// -- PASE Protocol Configuration Values
kPASEConfig_Unspecified = 0,
kPASEConfig_Config0_TEST_ONLY = (kWeaveVendor_NestLabs << 16) | 0,
kPASEConfig_Config1 = (kWeaveVendor_NestLabs << 16) | 1,
kPASEConfig_Config2 = (kWeaveVendor_NestLabs << 16) | 2,
kPASEConfig_Config3 = (kWeaveVendor_NestLabs << 16) | 3,
kPASEConfig_Config4 = (kWeaveVendor_NestLabs << 16) | 4,
kPASEConfig_Config5 = (kWeaveVendor_NestLabs << 16) | 5,
kPASEConfig_ConfigLast = (kWeaveVendor_NestLabs << 16) | 5,
kPASEConfig_ConfigDefault = kPASEConfig_Config4,
kPASEConfig_ConfigNestNumberMask = 0x07,
// -- Security Strength Metric for PASE Configuration
kPASEConfig_Config0SecurityStrength = 10,
kPASEConfig_Config1SecurityStrength = 80,
kPASEConfig_Config2SecurityStrength = 80,
kPASEConfig_Config3SecurityStrength = 96,
kPASEConfig_Config4SecurityStrength = 112,
kPASEConfig_Config5SecurityStrength = 128,
// -- PASE Supported Configurations Bit Masks
kPASEConfig_SupportConfig0Bit_TEST_ONLY = 0x01,
kPASEConfig_SupportConfig1Bit = 0x02,
kPASEConfig_SupportConfig2Bit = 0x04,
kPASEConfig_SupportConfig3Bit = 0x08,
kPASEConfig_SupportConfig4Bit = 0x10,
kPASEConfig_SupportConfig5Bit = 0x20,
kPASEConfig_SupportedConfigs = (0x00 |
#if WEAVE_CONFIG_SUPPORT_PASE_CONFIG0_TEST_ONLY
kPASEConfig_SupportConfig0Bit_TEST_ONLY |
#endif
#if WEAVE_CONFIG_SUPPORT_PASE_CONFIG1
kPASEConfig_SupportConfig1Bit |
#endif
#if WEAVE_CONFIG_SUPPORT_PASE_CONFIG2
kPASEConfig_SupportConfig2Bit |
#endif
#if WEAVE_CONFIG_SUPPORT_PASE_CONFIG3
kPASEConfig_SupportConfig3Bit |
#endif
#if WEAVE_CONFIG_SUPPORT_PASE_CONFIG4
kPASEConfig_SupportConfig4Bit |
#endif
#if WEAVE_CONFIG_SUPPORT_PASE_CONFIG5
kPASEConfig_SupportConfig5Bit |
#endif
0x00)
};
// PASE Header Field Definitions
enum
{
// Control Header Fields
kPASEHeader_SessionKeyMask = 0x0000FFFF,
kPASEHeader_SessionKeyShift = 0,
kPASEHeader_EncryptionTypeMask = 0x000F0000,
kPASEHeader_EncryptionTypeShift = 16,
kPASEHeader_PasswordSourceMask = 0x00F00000,
kPASEHeader_PasswordSourceShift = 20,
kPASEHeader_PerformKeyConfirmFlag = 0x80000000,
kPASEHeader_ControlHeaderUnusedBits = ~(kPASEHeader_SessionKeyMask |
kPASEHeader_EncryptionTypeMask |
kPASEHeader_PasswordSourceMask |
kPASEHeader_PerformKeyConfirmFlag),
// Size Header Fields and Values
kPASEHeader_GXWordCountMask = 0x000000FF,
kPASEHeader_GXWordCountShift = 0,
kPASEHeader_GXWordCountMaxConfig0 = 16,
kPASEHeader_GXWordCountMaxConfig1 = 32,
kPASEHeader_ZKPXGRWordCountMask = 0x0000FF00,
kPASEHeader_ZKPXGRWordCountShift = 8,
kPASEHeader_ZKPXGRWordCountMaxConfig0 = 16,
kPASEHeader_ZKPXGRWordCountMaxConfig1 = 32,
kPASEHeader_ZKPXBWordCountMask = 0x00FF0000,
kPASEHeader_ZKPXBWordCountShift = 16,
kPASEHeader_ZKPXBWordCountMaxConfig0 = 8,
kPASEHeader_ZKPXBWordCountMaxConfig1 = 5,
kPASEHeader_AlternateConfigCountMask = 0xFF000000,
kPASEHeader_AlternateConfigCountShift = 24,
kPASEHeader_KeyConfirmWordCountMask = kPASEHeader_AlternateConfigCountMask, // Alternate interpretation of 0xFF000000 field used in
kPASEHeader_KeyConfirmWordCountShift = kPASEHeader_AlternateConfigCountShift, // InitiatorStep2Message.
kPASESizeHeader_MaxConstantSizesConfig0 =
((kPASEHeader_GXWordCountMaxConfig0 << kPASEHeader_GXWordCountShift) & kPASEHeader_GXWordCountMask) |
((kPASEHeader_ZKPXGRWordCountMaxConfig0 << kPASEHeader_ZKPXGRWordCountShift) & kPASEHeader_ZKPXGRWordCountMask) |
((kPASEHeader_ZKPXBWordCountMaxConfig0 << kPASEHeader_ZKPXBWordCountShift) & kPASEHeader_ZKPXBWordCountMask),
kPASESizeHeader_MaxConstantSizesConfig1 =
((kPASEHeader_GXWordCountMaxConfig1 << kPASEHeader_GXWordCountShift) & kPASEHeader_GXWordCountMask) |
((kPASEHeader_ZKPXGRWordCountMaxConfig1 << kPASEHeader_ZKPXGRWordCountShift) & kPASEHeader_ZKPXGRWordCountMask) |
((kPASEHeader_ZKPXBWordCountMaxConfig1 << kPASEHeader_ZKPXBWordCountShift) & kPASEHeader_ZKPXBWordCountMask)
};
// PASE Config0 Parameters
#if WEAVE_CONFIG_SUPPORT_PASE_CONFIG0_TEST_ONLY
enum
{
kPASEConfig0_GXByteCount = 4 * kPASEHeader_GXWordCountMaxConfig0,
kPASEConfig0_ZKPXGRByteCount = 4 * kPASEHeader_ZKPXGRWordCountMaxConfig0,
kPASEConfig0_ZKPXBByteCount = 4 * kPASEHeader_ZKPXBWordCountMaxConfig0,
kPASEConfig0_GXStep1p1Value = 0x3A,
kPASEConfig0_ZKPXGRStep1p1Value = 0xF1,
kPASEConfig0_ZKPXBStep1p1Value = 0xAA,
kPASEConfig0_GXStep1p2Value = 0x5C,
kPASEConfig0_ZKPXGRStep1p2Value = 0x55,
kPASEConfig0_ZKPXBStep1p2Value = 0x6B,
kPASEConfig0_GXStep2Value = 0x9E,
kPASEConfig0_ZKPXGRStep2Value = 0x37,
kPASEConfig0_ZKPXBStep2Value = 0xDA
};
#endif
enum
{
// Key Meterial Length for Config 0 and Ellipric Curve Configs
kKeyMaterialLength_Config0_EC = Platform::Security::SHA256::kHashLength,
// Hash Length of ZKP_GR value
kStep2ZKPXGRHashLength_Config1 = Platform::Security::SHA1::kHashLength,
kStep2ZKPXGRHashLength_Config0_EC = Platform::Security::SHA256::kHashLength,
kStep2ZKPXGRHashLengthMax = Platform::Security::SHA256::kHashLength,
// Length of Key Confirmation Key, which is used to generate Key Configmation Hashes
kKeyConfirmKeyLength_Config1 = Platform::Security::SHA1::kHashLength,
kKeyConfirmKeyLength_Config0_EC = Platform::Security::SHA256::kHashLength,
kKeyConfirmKeyLengthMax = Platform::Security::SHA256::kHashLength,
// Length of Key Confirmation Hash
kKeyConfirmHashLength_Config1 = Platform::Security::SHA1::kHashLength,
kKeyConfirmHashLength_Config0_EC = Platform::Security::SHA256::kHashLength,
kKeyConfirmHashLengthMax = Platform::Security::SHA256::kHashLength
};
enum
{
kMaxAlternateProtocolConfigs = 3,
};
// Implements the core logic of the Weave PASE protocol.
class NL_DLL_EXPORT WeavePASEEngine
{
public:
enum EngineState
{
kState_Reset = 0,
// Initiator States
kState_InitiatorStatesBase = 10,
kState_InitiatorStatesEnd = 19,
kState_InitiatorStep1Generated = kState_InitiatorStatesBase + 0,
kState_ResponderReconfigProcessed = kState_InitiatorStatesBase + 1,
kState_ResponderStep1Processed = kState_InitiatorStatesBase + 2,
kState_ResponderStep2Processed = kState_InitiatorStatesBase + 3,
kState_InitiatorStep2Generated = kState_InitiatorStatesBase + 4,
kState_InitiatorDone = kState_InitiatorStatesBase + 5,
kState_InitiatorFailed = kState_InitiatorStatesBase + 6,
// Responder States
kState_ResponderStatesBase = 20,
kState_ResponderStatesEnd = 29,
kState_InitiatorStep1Processed = kState_ResponderStatesBase + 0,
kState_ResponderStep1Generated = kState_ResponderStatesBase + 1,
kState_ResponderStep2Generated = kState_ResponderStatesBase + 2,
kState_InitiatorStep2Processed = kState_ResponderStatesBase + 3,
kState_ResponderDone = kState_ResponderStatesBase + 4,
kState_ResponderFailed = kState_ResponderStatesBase + 5
};
#if WEAVE_CONFIG_SUPPORT_PASE_CONFIG1
struct JPAKE_CTX *JPAKECtx;
#endif
#if WEAVE_IS_EC_PASE_ENABLED
EllipticCurveJPAKE mEllipticCurveJPAKE;
#endif
EngineState State;
uint32_t ProtocolConfig;
const uint8_t *Pw;
uint16_t PwLen;
uint16_t SessionKeyId;
uint8_t EncryptionType;
uint8_t AllowedPASEConfigs;
uint8_t PwSource;
bool PerformKeyConfirmation;
void Init(void);
void Shutdown(void);
void Reset(void);
bool IsInitiator(void) const;
bool IsResponder(void) const;
WEAVE_ERROR GenerateInitiatorStep1(PacketBuffer *buf, uint32_t proposedPASEConfig, uint64_t localNodeId, uint64_t peerNodeId, uint16_t sessionKeyId, uint8_t encType, uint8_t pwSrc, WeaveFabricState *FabricState, bool confirmKey);
WEAVE_ERROR ProcessInitiatorStep1(PacketBuffer *buf, uint64_t localNodeId, uint64_t peerNodeId, WeaveFabricState *FabricState);
WEAVE_ERROR GenerateResponderStep1(PacketBuffer *buf);
WEAVE_ERROR GenerateResponderStep2(PacketBuffer *buf);
WEAVE_ERROR ProcessResponderStep1(PacketBuffer *buf);
WEAVE_ERROR ProcessResponderStep2(PacketBuffer *buf);
WEAVE_ERROR GenerateInitiatorStep2(PacketBuffer *buf);
WEAVE_ERROR ProcessInitiatorStep2(PacketBuffer *buf);
WEAVE_ERROR GenerateResponderKeyConfirm(PacketBuffer *buf);
WEAVE_ERROR ProcessResponderKeyConfirm(PacketBuffer *buf);
WEAVE_ERROR GenerateResponderReconfigure(PacketBuffer *buf);
WEAVE_ERROR ProcessResponderReconfigure(PacketBuffer *buf, uint32_t & proposedPASEConfig);
WEAVE_ERROR GetSessionKey(const WeaveEncryptionKey *& encKey);
private:
union
{
WeaveEncryptionKey EncryptionKey;
#if WEAVE_CONFIG_SUPPORT_PASE_CONFIG0_TEST_ONLY
uint8_t KeyMeterial_Config0[kKeyMaterialLength_Config0_EC];
#endif
};
union
{
uint8_t ResponderKeyConfirmHash[kKeyConfirmHashLengthMax];
uint8_t ResponderStep2ZKPXGRHash[kStep2ZKPXGRHashLengthMax];
};
WEAVE_ERROR InitState(uint64_t localNodeId, uint64_t peerNodeId, uint8_t pwSrc, WeaveFabricState *FabricState, uint32_t *altConfigs, uint8_t altConfigsCount, bool isInitiator);
#if WEAVE_CONFIG_SUPPORT_PASE_CONFIG1
WEAVE_ERROR FormProtocolContextString(uint64_t localNodeId, uint64_t peerNodeId, uint8_t pwSrc, uint32_t *altConfigs, uint8_t altConfigsCount, bool isInitiator, char *buf, size_t bufSize);
WEAVE_ERROR GenerateStep1Data_Config1(PacketBuffer *buf, uint16_t &stepDataLen);
WEAVE_ERROR ProcessStep1Data_Config1(PacketBuffer *buf, uint16_t &stepDataLen, uint8_t gxWordCount, uint8_t zkpxgrWordCount, uint8_t zpkxbWordCount);
WEAVE_ERROR GenerateStep2Data_Config1(PacketBuffer *buf, uint16_t &stepDataLen, uint8_t *Step2ZKPXGRHash);
WEAVE_ERROR ProcessStep2Data_Config1(PacketBuffer *buf, uint16_t &stepDataLen, uint8_t gxWordCount, uint8_t zkpxgrWordCount, uint8_t zpkxbWordCount, uint8_t *step2ZKPXGRHash);
#endif
#if WEAVE_CONFIG_SUPPORT_PASE_CONFIG0_TEST_ONLY || WEAVE_IS_EC_PASE_ENABLED
WEAVE_ERROR FormProtocolContextData(uint64_t localNodeId, uint64_t peerNodeId, uint8_t pwSrc, uint32_t *altConfigs, uint8_t altConfigsCount, bool isInitiator, uint8_t *buf, size_t bufSize, uint16_t &contextLen);
#endif
#if WEAVE_CONFIG_SUPPORT_PASE_CONFIG0_TEST_ONLY
WEAVE_ERROR GenerateStep1Data_Config0_TEST_ONLY(PacketBuffer *buf, uint16_t &stepDataLen);
WEAVE_ERROR ProcessStep1Data_Config0_TEST_ONLY(PacketBuffer *buf, uint16_t &stepDataLen, uint8_t gxWordCount, uint8_t zkpxgrWordCount, uint8_t zkpxbWordCount);
WEAVE_ERROR GenerateStep2Data_Config0_TEST_ONLY(PacketBuffer *buf, uint16_t &stepDataLen, uint8_t *Step2ZKPXGRHash);
WEAVE_ERROR ProcessStep2Data_Config0_TEST_ONLY(PacketBuffer *buf, uint16_t &stepDataLen, uint8_t gxWordCount, uint8_t zkpxgrWordCount, uint8_t zkpxbWordCount, uint8_t *Step2ZKPXGRHash);
#endif
#if WEAVE_IS_EC_PASE_ENABLED
WEAVE_ERROR GenerateStep1Data_ConfigEC(PacketBuffer *buf, uint16_t &stepDataLen);
WEAVE_ERROR ProcessStep1Data_ConfigEC(PacketBuffer *buf, uint16_t &stepDataLen, uint8_t gxWordCount, uint8_t zkpxgrWordCount, uint8_t zkpxbWordCount);
WEAVE_ERROR GenerateStep2Data_ConfigEC(PacketBuffer *buf, uint16_t &stepDataLen, uint8_t *Step2ZKPXGRHash);
WEAVE_ERROR ProcessStep2Data_ConfigEC(PacketBuffer *buf, uint16_t &stepDataLen, uint8_t gxWordCount, uint8_t zkpxgrWordCount, uint8_t zkpxbWordCount, uint8_t *Step2ZKPXGRHash);
#endif
void ProtocolHash(const uint8_t *data, const uint16_t dataLen, uint8_t *h);
WEAVE_ERROR DeriveKeys(const uint8_t *initiatorStep2ZKPXGRHash, const uint8_t step2ZKPXGRHashLength, uint8_t *keyConfirmKey, const uint8_t keyConfirmKeyLength);
void GenerateKeyConfirmHashes(const uint8_t *keyConfirmKey, const uint8_t keyConfirmKeyLength, uint8_t *initiatorHash, uint8_t *responderHash, const uint8_t keyConfirmHashLength);
bool IsAllowedPASEConfig(uint32_t config) const;
uint32_t PackSizeHeader(uint8_t altConfigCount);
WEAVE_ERROR GenerateAltConfigsList(uint32_t *altConfigs, uint8_t &altConfigsCount);
WEAVE_ERROR FindStrongerAltConfig(uint32_t *altConfigs, uint8_t altConfigsCount);
};
} // namespace PASE
} // namespace Security
} // namespace Profiles
} // namespace Weave
} // namespace nl
#endif /* WEAVEPASE_H_ */