blob: e8c0758bafa4c9f598efa3f30f38da3b7b283ce4 [file] [log] [blame]
/*
*
* Copyright (c) 2020 Project CHIP Authors
* 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 the CHIP SPAKE2P Session object that provides
* APIs for constructing spake2p messages and establishing encryption
* keys.
*
*/
#ifndef __SECUREPAIRINGSESSION_H__
#define __SECUREPAIRINGSESSION_H__
#include <core/ReferenceCounted.h>
#include <crypto/CHIPCryptoPAL.h>
#include <system/SystemPacketBuffer.h>
#include <transport/SecureSession.h>
namespace chip {
extern const char * kSpake2pI2RSessionInfo;
extern const char * kSpake2pR2ISessionInfo;
using namespace Crypto;
class DLL_EXPORT SecurePairingSessionDelegate : public ReferenceCounted<SecurePairingSessionDelegate>
{
public:
/**
* @brief
* Called when pairing session generates a new message that should be sent to peer.
*
* @param msgBuf the new message that should be sent to the peer
*/
virtual CHIP_ERROR OnNewMessageForPeer(System::PacketBuffer * msgBuf) { return CHIP_NO_ERROR; }
/**
* @brief
* Called when pairing fails with an error
*
* @param error error code
*/
virtual void OnPairingError(CHIP_ERROR error) {}
/**
* @brief
* Called when the pairing is complete and the new secure session has been established
*
* @param peerNodeId Node ID of peer
* @param peerKeyId Encrytion key ID assigned by the peer node for this connection
*/
virtual void OnPairingComplete(Optional<NodeId> peerNodeId, uint16_t peerKeyId) {}
virtual ~SecurePairingSessionDelegate() {}
};
class DLL_EXPORT SecurePairingSession
{
public:
SecurePairingSession(void);
SecurePairingSession(SecurePairingSession &&) = default;
SecurePairingSession(const SecurePairingSession &) = delete;
SecurePairingSession & operator=(const SecurePairingSession &) = delete;
SecurePairingSession & operator=(SecurePairingSession &&) = default;
~SecurePairingSession(void);
/**
* @brief
* Initialize using setup PIN code and wait for pairing requests.
*
* @param mySetUpPINCode Setup PIN code of the local device
* @param pbkdf2IterCount Iteration count for PBKDF2 function
* @param salt Salt to be used for SPAKE2P opertation
* @param saltLen Length of salt
* @param myNodeId Optional node id of local node
* @param mKeyId Key ID to be assigned to the secure session on the peer node
* @param delegate Callback object
*
* @return CHIP_ERROR The result of initialization
*/
CHIP_ERROR WaitForPairing(uint32_t mySetUpPINCode, uint32_t pbkdf2IterCount, const unsigned char * salt, size_t saltLen,
Optional<NodeId> myNodeId, uint16_t myKeyId, SecurePairingSessionDelegate * delegate);
/**
* @brief
* Create a pairing request using peer's setup PIN code.
*
* @param peerSetUpPINCode Setup PIN code of the peer device
* @param pbkdf2IterCount Iteration count for PBKDF2 function
* @param salt Salt to be used for SPAKE2P opertation
* @param saltLen Length of salt
* @param myNodeId Optional node id of local node
* @param mKeyId Key ID to be assigned to the secure session on the peer node
* @param delegate Callback object
*
* @return CHIP_ERROR The result of initialization
*/
CHIP_ERROR Pair(uint32_t peerSetUpPINCode, uint32_t pbkdf2IterCount, const unsigned char * salt, size_t saltLen,
Optional<NodeId> myNodeId, uint16_t myKeyId, SecurePairingSessionDelegate * delegate);
/**
* @brief
* Derive a secure session from the paired session. The API will return error
* if called before pairing is established.
*
* @param info Information string used for key derivation
* @param info_len Length of info string
* @param session Referene to the sescure session that will be
* initialized once pairing is complete
* @return CHIP_ERROR The result of session derivation
*/
virtual CHIP_ERROR DeriveSecureSession(const unsigned char * info, size_t info_len, SecureSession & session);
/**
* @brief
* Handler for peer's messages, exchanged during pairing handshake.
*
* @param header Message header for the received message
* @param msg Message sent by the peer
* @return CHIP_ERROR The result of message processing
*/
CHIP_ERROR HandlePeerMessage(MessageHeader & header, System::PacketBuffer * msg);
private:
CHIP_ERROR Init(uint32_t setupCode, uint32_t pbkdf2IterCount, const unsigned char * salt, size_t saltLen,
Optional<NodeId> myNodeId, uint16_t myKeyId, SecurePairingSessionDelegate * delegate);
CHIP_ERROR HandleCompute_pA(const MessageHeader & header, System::PacketBuffer * msg);
CHIP_ERROR HandleCompute_pB_cB(const MessageHeader & header, System::PacketBuffer * msg);
CHIP_ERROR HandleCompute_cA(const MessageHeader & header, System::PacketBuffer * msg);
CHIP_ERROR AttachHeaderAndSend(uint8_t msgType, System::PacketBuffer * msgBuf);
static constexpr uint16_t kSecurePairingProtocol = 1;
static constexpr size_t kSpake2p_WS_Length = kP256_FE_Length + 8;
enum Spake2pMsgType : uint8_t
{
kSpake2pCompute_pA = 0,
kSpake2pCompute_pB_cB = 1,
kSpake2pCompute_cA = 2,
kSpake2pMsgTypeMax = 3,
};
SecurePairingSessionDelegate * mDelegate = nullptr;
Spake2pMsgType mNextExpectedMsg = Spake2pMsgType::kSpake2pMsgTypeMax;
Spake2p_P256_SHA256_HKDF_HMAC mSpake2p;
uint8_t mPoint[kMAX_Point_Length];
/* w0s and w1s */
uint8_t mWS[2][kSpake2p_WS_Length];
uint8_t mKe[kMAX_Hash_Length];
size_t mKeLen = sizeof(mKe);
bool mPairingComplete = false;
Optional<NodeId> mLocalNodeId;
Optional<NodeId> mPeerNodeId;
uint16_t mKeyId;
uint16_t mPeerKeyId;
};
} // namespace chip
#endif // __SECUREPAIRINGSESSION_H__