Skip to content

Commit

Permalink
Update CASE session to match latest specifications (#9904)
Browse files Browse the repository at this point in the history
* Update CASE session to match latest specifications

* deleted unused function

* fix build issue

* fix failing tests

* address review comments

* address comments

* more cleanup
  • Loading branch information
pan-apple authored Sep 28, 2021
1 parent d3d0d06 commit a3af3ac
Show file tree
Hide file tree
Showing 15 changed files with 759 additions and 396 deletions.
9 changes: 9 additions & 0 deletions src/lib/core/CHIPError.h
Original file line number Diff line number Diff line change
Expand Up @@ -2189,6 +2189,15 @@ using CHIP_ERROR = ::chip::ChipError;
*/
#define CHIP_ERROR_REBOOT_SIGNAL_RECEIVED CHIP_CORE_ERROR(0xc8)

/**
* @def CHIP_ERROR_NO_SHARED_TRUSTED_ROOT
*
* @brief
* The CASE session could not be established as peer's credentials do not have
* a common root of trust.
*/
#define CHIP_ERROR_NO_SHARED_TRUSTED_ROOT CHIP_CORE_ERROR(0xc9)

/**
* @}
*/
Expand Down
8 changes: 4 additions & 4 deletions src/messaging/ApplicationExchangeDispatch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,10 @@ bool ApplicationExchangeDispatch::MessagePermitted(uint16_t protocol, uint8_t ty
case static_cast<uint8_t>(Protocols::SecureChannel::MsgType::PASE_Pake2):
case static_cast<uint8_t>(Protocols::SecureChannel::MsgType::PASE_Pake3):
case static_cast<uint8_t>(Protocols::SecureChannel::MsgType::PASE_PakeError):
case static_cast<uint8_t>(Protocols::SecureChannel::MsgType::CASE_SigmaR1):
case static_cast<uint8_t>(Protocols::SecureChannel::MsgType::CASE_SigmaR2):
case static_cast<uint8_t>(Protocols::SecureChannel::MsgType::CASE_SigmaR3):
case static_cast<uint8_t>(Protocols::SecureChannel::MsgType::CASE_SigmaErr):
case static_cast<uint8_t>(Protocols::SecureChannel::MsgType::CASE_Sigma1):
case static_cast<uint8_t>(Protocols::SecureChannel::MsgType::CASE_Sigma2):
case static_cast<uint8_t>(Protocols::SecureChannel::MsgType::CASE_Sigma3):
case static_cast<uint8_t>(Protocols::SecureChannel::MsgType::CASE_Sigma2Resume):
return false;

default:
Expand Down
8 changes: 4 additions & 4 deletions src/protocols/secure_channel/CASEServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,14 +85,14 @@ CHIP_ERROR CASEServer::InitCASEHandshake(Messaging::ExchangeContext * ec)
CHIP_ERROR CASEServer::OnMessageReceived(Messaging::ExchangeContext * ec, const PayloadHeader & payloadHeader,
System::PacketBufferHandle && payload)
{
ChipLogProgress(Inet, "CASE Server received SigmaR1 message. Starting handshake. EC %p", ec);
ChipLogProgress(Inet, "CASE Server received Sigma1 message. Starting handshake. EC %p", ec);
CHIP_ERROR err = InitCASEHandshake(ec);
SuccessOrExit(err);

// TODO - Enable multiple concurrent CASE session establishment
// https://github.com/project-chip/connectedhomeip/issues/8342
ChipLogProgress(Inet, "CASE Server disabling CASE session setups");
mExchangeManager->UnregisterUnsolicitedMessageHandlerForType(Protocols::SecureChannel::MsgType::CASE_SigmaR1);
mExchangeManager->UnregisterUnsolicitedMessageHandlerForType(Protocols::SecureChannel::MsgType::CASE_Sigma1);

err = GetSession().OnMessageReceived(ec, payloadHeader, std::move(payload));
SuccessOrExit(err);
Expand All @@ -107,10 +107,10 @@ CHIP_ERROR CASEServer::OnMessageReceived(Messaging::ExchangeContext * ec, const

void CASEServer::Cleanup()
{
// Let's re-register for CASE SigmaR1 message, so that the next CASE session setup request can be processed.
// Let's re-register for CASE Sigma1 message, so that the next CASE session setup request can be processed.
// https://github.com/project-chip/connectedhomeip/issues/8342
ChipLogProgress(Inet, "CASE Server enabling CASE session setups");
mExchangeManager->RegisterUnsolicitedMessageHandlerForType(Protocols::SecureChannel::MsgType::CASE_SigmaR1, this);
mExchangeManager->RegisterUnsolicitedMessageHandlerForType(Protocols::SecureChannel::MsgType::CASE_Sigma1, this);

GetSession().Clear();
}
Expand Down
2 changes: 1 addition & 1 deletion src/protocols/secure_channel/CASEServer.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ class CASEServer : public SessionEstablishmentDelegate, public Messaging::Exchan
{
if (mExchangeManager != nullptr)
{
mExchangeManager->UnregisterUnsolicitedMessageHandlerForType(Protocols::SecureChannel::MsgType::CASE_SigmaR1);
mExchangeManager->UnregisterUnsolicitedMessageHandlerForType(Protocols::SecureChannel::MsgType::CASE_Sigma1);
}
}

Expand Down
827 changes: 568 additions & 259 deletions src/protocols/secure_channel/CASESession.cpp

Large diffs are not rendered by default.

98 changes: 60 additions & 38 deletions src/protocols/secure_channel/CASESession.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ constexpr uint16_t kMaxTrustedRootIds = 5;

constexpr uint16_t kIPKSize = 16;

constexpr size_t kCASEResumptionIDSize = 16;

#ifdef ENABLE_HSM_CASE_EPHEMERAL_KEY
#define CASE_EPHEMERAL_KEY 0xCA5EECD0
#endif
Expand All @@ -63,16 +65,15 @@ struct CASESessionSerialized;

struct CASESessionSerializable
{
uint8_t mVersion;
uint16_t mSharedSecretLen;
uint8_t mSharedSecret[Crypto::kMax_ECDH_Secret_Length];
uint16_t mMessageDigestLen;
uint8_t mMessageDigest[Crypto::kSHA256_Hash_Length];
uint16_t mIPKLen;
uint8_t mIPK[kIPKSize];
uint8_t mPairingComplete;
NodeId mPeerNodeId;
uint16_t mLocalSessionId;
uint16_t mPeerSessionId;
uint8_t mResumptionId[kCASEResumptionIDSize];
};

class DLL_EXPORT CASESession : public Messaging::ExchangeDelegate, public PairingSession
Expand All @@ -90,13 +91,13 @@ class DLL_EXPORT CASESession : public Messaging::ExchangeDelegate, public Pairin
* @brief
* Initialize using configured fabrics and wait for session establishment requests.
*
* @param myKeyId Key ID to be assigned to the secure session on the peer node
* @param mySessionId Session ID to be assigned to the secure session on the peer node
* @param fabrics Table of fabrics that are currently configured on the device
* @param delegate Callback object
*
* @return CHIP_ERROR The result of initialization
*/
CHIP_ERROR ListenForSessionEstablishment(uint16_t myKeyId, Transport::FabricTable * fabrics,
CHIP_ERROR ListenForSessionEstablishment(uint16_t mySessionId, Transport::FabricTable * fabrics,
SessionEstablishmentDelegate * delegate);

/**
Expand All @@ -106,16 +107,32 @@ class DLL_EXPORT CASESession : public Messaging::ExchangeDelegate, public Pairin
* @param peerAddress Address of peer with which to establish a session.
* @param fabric The fabric that should be used for connecting with the peer
* @param peerNodeId Node id of the peer node
* @param myKeyId Key ID to be assigned to the secure session on the peer node
* @param mySessionId Session 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, Transport::FabricInfo * fabric, NodeId peerNodeId,
uint16_t myKeyId, Messaging::ExchangeContext * exchangeCtxt,
uint16_t mySessionId, Messaging::ExchangeContext * exchangeCtxt,
SessionEstablishmentDelegate * delegate);

/**
* Parse the message to check if it has a session resumption request.
* A valid session resumption request must have Resumption ID, and InitiationResumeMIC.
*
* If the message is a valid session resumption request, the output parameter resumptionRequested is set to true,
* and corresponding resumption ID and MIC are returned in the output parameters. Return value is set to CHIP_NO_ERROR.
*
* If the message is not a session resumption request (i.e. it doesn't contain both Resumption ID, and InitiationResumeMIC),
* the output parameter resumptionRequested is set to false. Return value is set to CHIP_NO_ERROR.
*
* If the message doesn't contain either Resumption ID or InitiationResumeMIC (i.e. contains only one of these fields), the
* function returns CHIP_ERROR_INVALID_ARGUMENT.
*/
static CHIP_ERROR IsResumptionRequestPresent(const System::PacketBufferHandle & message, bool & resumptionRequested,
ByteSpan & resumptionID, ByteSpan & resume1MIC);

/**
* @brief
* Derive a secure session from the established session. The API will return error
Expand Down Expand Up @@ -175,47 +192,53 @@ class DLL_EXPORT CASESession : public Messaging::ExchangeDelegate, public Pairin
void Clear();

private:
enum SigmaErrorType : uint8_t
enum State : uint8_t
{
kInvalidSignature = 0x04,
kInvalidResumptionTag = 0x05,
kUnsupportedVersion = 0x06,
kUnexpected = 0xff,
kInitialized = 0,
kSentSigma1 = 1,
kSentSigma2 = 2,
kSentSigma3 = 3,
kSentSigma2Resume = 4,
};

CHIP_ERROR Init(uint16_t myKeyId, SessionEstablishmentDelegate * delegate);
CHIP_ERROR Init(uint16_t mySessionId, SessionEstablishmentDelegate * delegate);

CHIP_ERROR SendSigmaR1();
CHIP_ERROR HandleSigmaR1_and_SendSigmaR2(System::PacketBufferHandle && msg);
CHIP_ERROR HandleSigmaR1(System::PacketBufferHandle && msg);
CHIP_ERROR SendSigmaR2();
CHIP_ERROR HandleSigmaR2_and_SendSigmaR3(System::PacketBufferHandle && msg);
CHIP_ERROR HandleSigmaR2(System::PacketBufferHandle && msg);
CHIP_ERROR SendSigmaR3();
CHIP_ERROR HandleSigmaR3(System::PacketBufferHandle && msg);
CHIP_ERROR SendSigma1();
CHIP_ERROR HandleSigma1_and_SendSigma2(System::PacketBufferHandle && msg);
CHIP_ERROR HandleSigma1(System::PacketBufferHandle && msg);
CHIP_ERROR SendSigma2();
CHIP_ERROR HandleSigma2_and_SendSigma3(System::PacketBufferHandle && msg);
CHIP_ERROR HandleSigma2(System::PacketBufferHandle && msg);
CHIP_ERROR HandleSigma2Resume(System::PacketBufferHandle && msg);
CHIP_ERROR SendSigma3();
CHIP_ERROR HandleSigma3(System::PacketBufferHandle && msg);

CHIP_ERROR SendSigmaR1Resume();
CHIP_ERROR SendSigma2Resume(const ByteSpan & initiatorRandom);

CHIP_ERROR ConstructSaltSigmaR2(const ByteSpan & rand, const Crypto::P256PublicKey & pubkey, const ByteSpan & ipk,
MutableByteSpan & salt);
CHIP_ERROR ConstructSaltSigma2(const ByteSpan & rand, const Crypto::P256PublicKey & pubkey, const ByteSpan & ipk,
MutableByteSpan & salt);
CHIP_ERROR Validate_and_RetrieveResponderID(const ByteSpan & responderNOC, const ByteSpan & responderICAC,
Crypto::P256PublicKey & responderID);
CHIP_ERROR ConstructSaltSigmaR3(const ByteSpan & ipk, MutableByteSpan & salt);
CHIP_ERROR ConstructTBSData(const ByteSpan & senderNOC, const ByteSpan & senderICAC, const ByteSpan & senderPubKey,
const ByteSpan & receiverPubKey, uint8_t * tbsData, size_t & tbsDataLen);
CHIP_ERROR ConstructSaltSigma3(const ByteSpan & ipk, MutableByteSpan & salt);
CHIP_ERROR RetrieveIPK(FabricId fabricId, MutableByteSpan & ipk);

CHIP_ERROR ConstructSigmaResumeKey(const ByteSpan & initiatorRandom, const ByteSpan & resumptionID, const ByteSpan & skInfo,
const ByteSpan & nonce, MutableByteSpan & resumeKey);

CHIP_ERROR GenerateSigmaResumeMIC(const ByteSpan & initiatorRandom, const ByteSpan & resumptionID, const ByteSpan & skInfo,
const ByteSpan & nonce, MutableByteSpan & resumeMIC);
CHIP_ERROR ValidateSigmaResumeMIC(const ByteSpan & resumeMIC, const ByteSpan & initiatorRandom, const ByteSpan & resumptionID,
const ByteSpan & skInfo, const ByteSpan & nonce);

static constexpr size_t EstimateTLVStructOverhead(size_t dataLen, size_t nFields)
{
return dataLen + (sizeof(uint64_t) * nFields);
}

void SendErrorMsg(SigmaErrorType errorCode);

// This function always returns an error. The error value corresponds to the error in the received message.
// The returned error value helps top level message receiver/dispatcher to close the exchange context
// in a more seamless manner.
CHIP_ERROR HandleErrorMsg(const System::PacketBufferHandle & msg);
void OnSuccessStatusReport() override;
CHIP_ERROR OnFailureStatusReport(Protocols::SecureChannel::GeneralStatusCode generalCode, uint16_t protocolCode) override;

void CloseExchange();

Expand All @@ -227,8 +250,6 @@ class DLL_EXPORT CASESession : public Messaging::ExchangeDelegate, public Pairin

SessionEstablishmentDelegate * mDelegate = nullptr;

Protocols::SecureChannel::MsgType mNextExpectedMsg = Protocols::SecureChannel::MsgType::CASE_SigmaErr;

Crypto::Hash_SHA256_stream mCommissioningHash;
Crypto::P256PublicKey mRemotePubKey;
#ifdef ENABLE_HSM_CASE_EPHEMERAL_KEY
Expand All @@ -249,13 +270,14 @@ class DLL_EXPORT CASESession : public Messaging::ExchangeDelegate, public Pairin
Transport::FabricTable * mFabricsTable = nullptr;
Transport::FabricInfo * mFabricInfo = nullptr;

struct SigmaErrorMsg
{
SigmaErrorType error;
};
uint8_t mResumptionId[kCASEResumptionIDSize];
// Sigma1 initiator random, maintained to be reused post-Sigma1, such as when generating Sigma2 S2RK key
uint8_t mInitiatorRandom[kSigmaParamRandomNumberSize];

State mState;

protected:
bool mPairingComplete = false;
bool mCASESessionEstablished = false;

virtual ByteSpan * GetIPKList() const
{
Expand Down
8 changes: 4 additions & 4 deletions src/protocols/secure_channel/Constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,10 @@ enum class MsgType : uint8_t
PASE_PakeError = 0x2F,

// Certificate-based session establishment Message Types
CASE_SigmaR1 = 0x30,
CASE_SigmaR2 = 0x31,
CASE_SigmaR3 = 0x32,
CASE_SigmaErr = 0x3F,
CASE_Sigma1 = 0x30,
CASE_Sigma2 = 0x31,
CASE_Sigma3 = 0x32,
CASE_Sigma2Resume = 0x33,

StatusReport = 0x40,
};
Expand Down
Loading

0 comments on commit a3af3ac

Please sign in to comment.