Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update CASE session to match latest specifications #9904

Merged
merged 7 commits into from
Sep 28, 2021
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
824 changes: 566 additions & 258 deletions src/protocols/secure_channel/CASESession.cpp

Large diffs are not rendered by default.

99 changes: 61 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,16 @@ struct CASESessionSerialized;

struct CASESessionSerializable
{
uint8_t mVersion;
uint8_t mCASESessionWasEstablished;
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 +92,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 +108,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 +193,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 +251,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 +271,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];
pan-apple marked this conversation as resolved.
Show resolved Hide resolved

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