Skip to content

Commit

Permalink
Fixed/Added CASE Identity Checks. (#15829)
Browse files Browse the repository at this point in the history
Added checks:
  -- Verify that peer NOC FabricId matches the expected Fabric ID.
  -- On Processing of Sigma2: Verify that peer NodeId matches one used to generate
     Destination Identifier in Sigma1.
  -- On Processing of Sigma3: Assign peer NodeId from peer NOC.
  -- If root certificate includes Fabric ID verify it matches ICAC and NOC Fabric IDs.
  • Loading branch information
emargolis authored Mar 5, 2022
1 parent 8125e96 commit dbbc6e9
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 18 deletions.
20 changes: 16 additions & 4 deletions src/credentials/FabricTable.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
*
* Copyright (c) 2021 Project CHIP Authors
* Copyright (c) 2021-2022 Project CHIP Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -312,12 +312,24 @@ CHIP_ERROR FabricInfo::VerifyCredentials(const ByteSpan & noc, const ByteSpan &
NodeId nodeId;
ReturnErrorOnFailure(ExtractNodeIdFabricIdFromOpCert(certificates.GetLastCert()[0], &nodeId, &fabricId));

FabricId icacFabricId = kUndefinedFabricId;
if (!icac.empty())
{
FabricId icacFabric = kUndefinedFabricId;
if (ExtractFabricIdFromCert(certificates.GetCertSet()[1], &icacFabric) == CHIP_NO_ERROR && icacFabric != kUndefinedFabricId)
if (ExtractFabricIdFromCert(certificates.GetCertSet()[1], &icacFabricId) == CHIP_NO_ERROR &&
icacFabricId != kUndefinedFabricId)
{
ReturnErrorCodeIf(icacFabric != fabricId, CHIP_ERROR_FABRIC_MISMATCH_ON_ICA);
ReturnErrorCodeIf(icacFabricId != fabricId, CHIP_ERROR_FABRIC_MISMATCH_ON_ICA);
}
}

FabricId rcacFabricId = kUndefinedFabricId;
if (ExtractFabricIdFromCert(certificates.GetCertSet()[0], &rcacFabricId) == CHIP_NO_ERROR && rcacFabricId != kUndefinedFabricId)
{
ReturnErrorCodeIf(rcacFabricId != fabricId, CHIP_ERROR_WRONG_CERT_DN);
if (!icac.empty())
{
// If FabricId attribute is present in RCAC then it SHOULD be present in ICAC as well.
ReturnErrorCodeIf(icacFabricId == kUndefinedFabricId, CHIP_ERROR_WRONG_CERT_DN);
}
}

Expand Down
32 changes: 20 additions & 12 deletions src/protocols/secure_channel/CASESession.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -756,7 +756,8 @@ CHIP_ERROR CASESession::HandleSigma2(System::PacketBufferHandle && msg)

P256ECDSASignature tbsData2Signature;

P256PublicKey remoteCredential;
NodeId responderNodeId;
P256PublicKey responderPublicKey;

uint8_t responderRandom[kSigmaParamRandomNumberSize];
ByteSpan responderNOC;
Expand Down Expand Up @@ -841,7 +842,11 @@ CHIP_ERROR CASESession::HandleSigma2(System::PacketBufferHandle && msg)

// Validate responder identity located in msg_r2_encrypted
// Constructing responder identity
SuccessOrExit(err = Validate_and_RetrieveResponderID(responderNOC, responderICAC, remoteCredential));
SuccessOrExit(err = ValidatePeerIdentity(responderNOC, responderICAC, responderNodeId, responderPublicKey));

// Verify that responderNodeId (from responderNOC) matches one that was included
// in the computation of the Destination Identifier when generating Sigma1.
VerifyOrReturnError(GetPeerNodeId() == responderNodeId, CHIP_ERROR_INVALID_CASE_PARAMETER);

// Construct msg_R2_Signed and validate the signature in msg_r2_encrypted
msg_r2_signed_len = TLV::EstimateStructOverhead(sizeof(uint16_t), responderNOC.size(), responderICAC.size(),
Expand All @@ -859,7 +864,7 @@ CHIP_ERROR CASESession::HandleSigma2(System::PacketBufferHandle && msg)
SuccessOrExit(err = decryptedDataTlvReader.GetBytes(tbsData2Signature, tbsData2Signature.Length()));

// Validate signature
SuccessOrExit(err = remoteCredential.ECDSA_validate_msg_signature(msg_R2_Signed.Get(), msg_r2_signed_len, tbsData2Signature));
SuccessOrExit(err = responderPublicKey.ECDSA_validate_msg_signature(msg_R2_Signed.Get(), msg_r2_signed_len, tbsData2Signature));

// Retrieve session resumption ID
SuccessOrExit(err = decryptedDataTlvReader.Next(TLV::kTLVType_ByteString, TLV::ContextTag(kTag_TBEData_ResumptionID)));
Expand Down Expand Up @@ -1043,7 +1048,8 @@ CHIP_ERROR CASESession::HandleSigma3(System::PacketBufferHandle && msg)

P256ECDSASignature tbsData3Signature;

P256PublicKey remoteCredential;
NodeId initiatorNodeId;
P256PublicKey initiatorPublicKey;

ByteSpan initiatorNOC;
ByteSpan initiatorICAC;
Expand Down Expand Up @@ -1106,7 +1112,8 @@ CHIP_ERROR CASESession::HandleSigma3(System::PacketBufferHandle && msg)
// Step 5/6
// Validate initiator identity located in msg->Start()
// Constructing responder identity
SuccessOrExit(err = Validate_and_RetrieveResponderID(initiatorNOC, initiatorICAC, remoteCredential));
SuccessOrExit(err = ValidatePeerIdentity(initiatorNOC, initiatorICAC, initiatorNodeId, initiatorPublicKey));
SetPeerNodeId(initiatorNodeId);

// Step 4 - Construct Sigma3 TBS Data
msg_r3_signed_len = TLV::EstimateStructOverhead(sizeof(uint16_t), initiatorNOC.size(), initiatorICAC.size(),
Expand All @@ -1129,7 +1136,7 @@ CHIP_ERROR CASESession::HandleSigma3(System::PacketBufferHandle && msg)
// current flow of code, a malicious node can trigger a DoS style attack on the device.
// The same change should be made in Sigma2 processing.
// Step 7 - Validate Signature
SuccessOrExit(err = remoteCredential.ECDSA_validate_msg_signature(msg_R3_Signed.Get(), msg_r3_signed_len, tbsData3Signature));
SuccessOrExit(err = initiatorPublicKey.ECDSA_validate_msg_signature(msg_R3_Signed.Get(), msg_r3_signed_len, tbsData3Signature));

SuccessOrExit(err = mCommissioningHash.Finish(messageDigestSpan));

Expand Down Expand Up @@ -1259,19 +1266,20 @@ CHIP_ERROR CASESession::ValidateSigmaResumeMIC(const ByteSpan & resumeMIC, const
return CHIP_NO_ERROR;
}

CHIP_ERROR CASESession::Validate_and_RetrieveResponderID(const ByteSpan & responderNOC, const ByteSpan & responderICAC,
Crypto::P256PublicKey & responderID)
CHIP_ERROR CASESession::ValidatePeerIdentity(const ByteSpan & peerNOC, const ByteSpan & peerICAC, NodeId & peerNodeId,
Crypto::P256PublicKey & peerPublicKey)
{
ReturnErrorCodeIf(mFabricInfo == nullptr, CHIP_ERROR_INCORRECT_STATE);

ReturnErrorOnFailure(SetEffectiveTime());

PeerId peerId;
FabricId rawFabricId;
ReturnErrorOnFailure(
mFabricInfo->VerifyCredentials(responderNOC, responderICAC, mValidContext, peerId, rawFabricId, responderID));
FabricId peerNOCFabricId;
ReturnErrorOnFailure(mFabricInfo->VerifyCredentials(peerNOC, peerICAC, mValidContext, peerId, peerNOCFabricId, peerPublicKey));

VerifyOrReturnError(mFabricInfo->GetFabricId() == peerNOCFabricId, CHIP_ERROR_INVALID_CASE_PARAMETER);

SetPeerNodeId(peerId.GetNodeId());
peerNodeId = peerId.GetNodeId();

return CHIP_NO_ERROR;
}
Expand Down
4 changes: 2 additions & 2 deletions src/protocols/secure_channel/CASESession.h
Original file line number Diff line number Diff line change
Expand Up @@ -198,8 +198,8 @@ class DLL_EXPORT CASESession : public Messaging::ExchangeDelegate, public Pairin

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 ValidatePeerIdentity(const ByteSpan & peerNOC, const ByteSpan & peerICAC, NodeId & peerNodeId,
Crypto::P256PublicKey & peerPublicKey);
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);
Expand Down

0 comments on commit dbbc6e9

Please sign in to comment.