| /* |
| * |
| * Copyright (c) 2021 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 CASE Session object that provides |
| * APIs for constructing a secure session using a certificate from the device's |
| * operational credentials. |
| */ |
| |
| #pragma once |
| |
| #include <credentials/CHIPCert.h> |
| #include <credentials/CHIPOperationalCredentials.h> |
| #include <crypto/CHIPCryptoPAL.h> |
| #include <messaging/ExchangeContext.h> |
| #include <messaging/ExchangeDelegate.h> |
| #include <protocols/secure_channel/Constants.h> |
| #include <protocols/secure_channel/SessionEstablishmentExchangeDispatch.h> |
| #include <support/Base64.h> |
| #include <system/SystemPacketBuffer.h> |
| #include <transport/PairingSession.h> |
| #include <transport/PeerConnectionState.h> |
| #include <transport/SecureSession.h> |
| #include <transport/SessionEstablishmentDelegate.h> |
| #include <transport/raw/MessageHeader.h> |
| #include <transport/raw/PeerAddress.h> |
| |
| namespace chip { |
| |
| constexpr uint16_t kAEADKeySize = 16; |
| |
| constexpr uint16_t kSigmaParamRandomNumberSize = 32; |
| constexpr uint16_t kTrustedRootIdSize = 20; |
| constexpr uint16_t kMaxTrustedRootIds = 5; |
| |
| constexpr uint16_t kIPKSize = 32; |
| |
| using namespace Crypto; |
| using namespace Credentials; |
| |
| struct CASESessionSerialized; |
| |
| struct CASESessionSerializable |
| { |
| uint16_t mSharedSecretLen; |
| uint8_t mSharedSecret[kMax_ECDH_Secret_Length]; |
| uint16_t mMessageDigestLen; |
| uint8_t mMessageDigest[kSHA256_Hash_Length]; |
| uint8_t mPairingComplete; |
| NodeId mPeerNodeId; |
| uint16_t mLocalKeyId; |
| uint16_t mPeerKeyId; |
| }; |
| |
| class DLL_EXPORT CASESession : public Messaging::ExchangeDelegateBase, public PairingSession |
| { |
| public: |
| CASESession(); |
| CASESession(CASESession &&) = default; |
| CASESession(const CASESession &) = default; |
| CASESession & operator=(const CASESession &) = default; |
| CASESession & operator=(CASESession &&) = default; |
| |
| virtual ~CASESession(); |
| |
| /** |
| * @brief |
| * Initialize using operational credentials code and wait for session establishment requests. |
| * |
| * @param operationalCredentialSet CHIP Certificate Set used to store the chain root of trust an validate peer node |
| * certificates |
| * @param myKeyId 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 WaitForSessionEstablishment(OperationalCredentialSet * operationalCredentialSet, uint16_t myKeyId, |
| SessionEstablishmentDelegate * delegate); |
| |
| /** |
| * @brief |
| * Create and send session establishment request using device's operational credentials. |
| * |
| * @param peerAddress Address of peer with which to establish a session. |
| * @param operationalCredentialSet CHIP Certificate Set used to store the chain root of trust an validate peer node |
| * certificates |
| * @param peerNodeId Node id of the peer node |
| * @param myKeyId Key ID to be assigned to the secure session on the peer node |
| * @param exchangeCtxt The exchange context to send and receive messages with the peer |
| * @param delegate Callback object |
| * |
| * @return CHIP_ERROR The result of initialization |
| */ |
| CHIP_ERROR EstablishSession(const Transport::PeerAddress peerAddress, OperationalCredentialSet * operationalCredentialSet, |
| NodeId peerNodeId, uint16_t myKeyId, Messaging::ExchangeContext * exchangeCtxt, |
| SessionEstablishmentDelegate * delegate); |
| |
| /** |
| * @brief |
| * Derive a secure session from the established session. The API will return error |
| * if called before session is established. |
| * |
| * @param session Reference to the secure session that will be |
| * initialized once session establishment is complete |
| * @param role Role of the new session (initiator or responder) |
| * @return CHIP_ERROR The result of session derivation |
| */ |
| virtual CHIP_ERROR DeriveSecureSession(SecureSession & session, SecureSession::SessionRole role) override; |
| |
| /** |
| * @brief |
| * Return the associated secure session peer NodeId |
| * |
| * @return NodeId The associated peer NodeId |
| */ |
| NodeId GetPeerNodeId() const { return mConnectionState.GetPeerNodeId(); } |
| |
| /** |
| * @brief |
| * Return the associated peer key id |
| * |
| * @return uint16_t The associated peer key id |
| */ |
| uint16_t GetPeerKeyId() override { return mConnectionState.GetPeerKeyID(); } |
| |
| /** |
| * @brief |
| * Return the associated local key id |
| * |
| * @return uint16_t The assocated local key id |
| */ |
| uint16_t GetLocalKeyId() override { return mConnectionState.GetLocalKeyID(); } |
| |
| const char * GetI2RSessionInfo() const override { return "Sigma I2R Key"; } |
| |
| const char * GetR2ISessionInfo() const override { return "Sigma R2I Key"; } |
| |
| Transport::PeerConnectionState & PeerConnection() { return mConnectionState; } |
| |
| /** |
| * @brief Serialize the Pairing Session to a string. |
| **/ |
| CHIP_ERROR Serialize(CASESessionSerialized & output); |
| |
| /** |
| * @brief Deserialize the Pairing Session from the string. |
| **/ |
| CHIP_ERROR Deserialize(CASESessionSerialized & input); |
| |
| /** |
| * @brief Serialize the CASESession to the given serializable data structure for secure pairing |
| **/ |
| CHIP_ERROR ToSerializable(CASESessionSerializable & output); |
| |
| /** |
| * @brief Reconstruct secure pairing class from the serializable data structure. |
| **/ |
| CHIP_ERROR FromSerializable(const CASESessionSerializable & output); |
| |
| SessionEstablishmentExchangeDispatch & MessageDispatch() { return mMessageDispatch; } |
| |
| //// ExchangeDelegate Implementation //// |
| void OnMessageReceived(Messaging::ExchangeContext * ec, const PacketHeader & packetHeader, const PayloadHeader & payloadHeader, |
| System::PacketBufferHandle payload) override; |
| void OnResponseTimeout(Messaging::ExchangeContext * ec) override; |
| Messaging::ExchangeMessageDispatch * GetMessageDispatch(Messaging::ReliableMessageMgr * rmMgr, |
| SecureSessionMgr * sessionMgr) override |
| { |
| return &mMessageDispatch; |
| } |
| |
| private: |
| enum SigmaErrorType : uint8_t |
| { |
| kNoSharedTrustRoots = 0x01, |
| kInvalidSignature = 0x04, |
| kInvalidResumptionTag = 0x05, |
| kUnsupportedVersion = 0x06, |
| kUnexpected = 0xff, |
| }; |
| |
| CHIP_ERROR Init(OperationalCredentialSet * operationalCredentialSet, uint16_t myKeyId, SessionEstablishmentDelegate * delegate); |
| |
| CHIP_ERROR SendSigmaR1(); |
| CHIP_ERROR HandleSigmaR1_and_SendSigmaR2(const System::PacketBufferHandle & msg); |
| CHIP_ERROR HandleSigmaR1(const System::PacketBufferHandle & msg); |
| CHIP_ERROR SendSigmaR2(); |
| CHIP_ERROR HandleSigmaR2_and_SendSigmaR3(const System::PacketBufferHandle & msg); |
| CHIP_ERROR HandleSigmaR2(const System::PacketBufferHandle & msg); |
| CHIP_ERROR SendSigmaR3(); |
| CHIP_ERROR HandleSigmaR3(const System::PacketBufferHandle & msg); |
| |
| CHIP_ERROR SendSigmaR1Resume(); |
| CHIP_ERROR HandleSigmaR1Resume_and_SendSigmaR2Resume(const PacketHeader & header, const System::PacketBufferHandle & msg); |
| |
| CHIP_ERROR FindValidTrustedRoot(const uint8_t ** msgIterator, uint32_t nTrustedRoots); |
| CHIP_ERROR ConstructSaltSigmaR2(const System::PacketBufferHandle & rand, const P256PublicKey & pubkey, const uint8_t * ipk, |
| size_t ipkLen, System::PacketBufferHandle & salt); |
| CHIP_ERROR Validate_and_RetrieveResponderID(const uint8_t ** msgIterator, P256PublicKey & responderID, |
| const uint8_t ** responderOpCert, uint16_t & responderOpCertLen); |
| CHIP_ERROR ConstructSaltSigmaR3(const uint8_t * ipk, size_t ipkLen, System::PacketBufferHandle & salt); |
| CHIP_ERROR ConstructSignedCredentials(const uint8_t ** msgIterator, const uint8_t * responderOpCert, |
| uint16_t responderOpCertLen, System::PacketBufferHandle & signedCredentials, |
| P256ECDSASignature & signature, size_t sigLen); |
| CHIP_ERROR ComputeIPK(const uint16_t sessionID, uint8_t * ipk, size_t ipkLen); |
| |
| void SendErrorMsg(SigmaErrorType errorCode); |
| void HandleErrorMsg(const System::PacketBufferHandle & msg); |
| |
| // TODO: Remove this and replace with system method to retrieve current time |
| CHIP_ERROR SetEffectiveTime(void); |
| |
| CHIP_ERROR AttachHeaderAndSend(Protocols::SecureChannel::MsgType msgType, System::PacketBufferHandle msgBuf); |
| |
| void Clear(); |
| |
| CHIP_ERROR ValidateReceivedMessage(Messaging::ExchangeContext * ec, const PacketHeader & packetHeader, |
| const PayloadHeader & payloadHeader, System::PacketBufferHandle & msg); |
| |
| SessionEstablishmentDelegate * mDelegate = nullptr; |
| |
| Protocols::SecureChannel::MsgType mNextExpectedMsg = Protocols::SecureChannel::MsgType::CASE_SigmaErr; |
| |
| Hash_SHA256_stream mCommissioningHash; |
| P256PublicKey mRemotePubKey; |
| P256Keypair mEphemeralKey; |
| P256ECDHDerivedSecret mSharedSecret; |
| OperationalCredentialSet * mOpCredSet; |
| CertificateKeyId mTrustedRootId; |
| ValidationContext mValidContext; |
| |
| uint8_t mMessageDigest[kSHA256_Hash_Length]; |
| uint8_t mIPK[kIPKSize]; |
| uint8_t mRemoteIPK[kIPKSize]; |
| |
| Messaging::ExchangeContext * mExchangeCtxt = nullptr; |
| SessionEstablishmentExchangeDispatch mMessageDispatch; |
| |
| struct SigmaErrorMsg |
| { |
| SigmaErrorType error; |
| }; |
| |
| protected: |
| bool mPairingComplete = false; |
| |
| Transport::PeerConnectionState mConnectionState; |
| }; |
| |
| typedef struct CASESessionSerialized |
| { |
| // Extra uint64_t to account for padding bytes (NULL termination, and some decoding overheads) |
| uint8_t inner[BASE64_ENCODED_LEN(sizeof(CASESessionSerializable) + sizeof(uint64_t))]; |
| } CASESessionSerialized; |
| |
| } // namespace chip |