Skip to content

Commit

Permalink
Validate RCAC Prior to Setting on AddTrustedRootCertificate Command.
Browse files Browse the repository at this point in the history
  • Loading branch information
emargolis committed Jul 11, 2022
1 parent d271f7b commit bc91961
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1176,8 +1176,6 @@ bool emberAfOperationalCredentialsClusterAddTrustedRootCertificateCallback(
commandObj->FlushAcksRightAwayOnSlowCommand();

// TODO(#17208): Handle checking for byte-to-byte match with existing fabrics before allowing the add

// TODO(#17208): Validate cert signature prior to setting.
err = fabricTable.AddNewPendingTrustedRootCert(rootCertificate);
VerifyOrExit(err != CHIP_ERROR_NO_MEMORY, finalStatus = Status::ResourceExhausted);

Expand Down
32 changes: 32 additions & 0 deletions src/credentials/CHIPCert.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1145,6 +1145,38 @@ DLL_EXPORT CHIP_ERROR ChipEpochToASN1Time(uint32_t epochTime, chip::ASN1::ASN1Un
return CHIP_NO_ERROR;
}

CHIP_ERROR ValidateChipRCAC(const ByteSpan & rcac)
{
ChipCertificateSet certSet;
ChipCertificateData certData;
ValidationContext validContext;
uint8_t certType;

// Note that this function doesn't check RCAC NotBefore / NotAfter time validity.
// It is assumed that RCAC should be valid at the time of installation by definition.

ReturnErrorOnFailure(certSet.Init(&certData, 1));

ReturnErrorOnFailure(certSet.LoadCert(rcac, CertDecodeFlags::kGenerateTBSHash));

ReturnErrorOnFailure(certData.mSubjectDN.GetCertType(certType));
VerifyOrReturnError(certType == kCertType_Root, CHIP_ERROR_WRONG_CERT_TYPE);

VerifyOrReturnError(certData.mSubjectDN.IsEqual(certData.mIssuerDN), CHIP_ERROR_WRONG_CERT_TYPE);

VerifyOrReturnError(certData.mSubjectKeyId.data_equal(certData.mAuthKeyId), CHIP_ERROR_WRONG_CERT_TYPE);

VerifyOrReturnError(certData.mCertFlags.Has(CertFlags::kIsCA), CHIP_ERROR_CERT_USAGE_NOT_ALLOWED);
if (certData.mCertFlags.Has(CertFlags::kPathLenConstraintPresent))
{
VerifyOrReturnError(certData.mPathLenConstraint <= 1, CHIP_ERROR_CERT_USAGE_NOT_ALLOWED);
}

VerifyOrReturnError(certData.mKeyUsageFlags.Has(KeyUsageFlags::kKeyCertSign), CHIP_ERROR_CERT_USAGE_NOT_ALLOWED);

return ChipCertificateSet::VerifySignature(&certData, &certData);
}

CHIP_ERROR ConvertIntegerDERToRaw(ByteSpan derInt, uint8_t * rawInt, const uint16_t rawIntLen)
{
VerifyOrReturnError(!derInt.empty(), CHIP_ERROR_INVALID_ARGUMENT);
Expand Down
11 changes: 10 additions & 1 deletion src/credentials/CHIPCert.h
Original file line number Diff line number Diff line change
Expand Up @@ -498,6 +498,15 @@ CHIP_ERROR ConvertX509CertToChipCert(const ByteSpan x509Cert, MutableByteSpan &
**/
CHIP_ERROR ConvertChipCertToX509Cert(const ByteSpan chipCert, MutableByteSpan & x509Cert);

/**
* Validate CHIP Root CA Certificate (RCAC) in ByteSpan TLV-encoded form.
* This function performs RCAC parcing, checks SubjectDN validity, verifies that SubjectDN
* and IssuerDN are equal, verifies that SKID and AKID are equal, validates certificate signature.
*
* @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise
*/
CHIP_ERROR ValidateChipRCAC(const ByteSpan & rcac);

struct X509CertRequestParams
{
int64_t SerialNumber;
Expand Down Expand Up @@ -708,7 +717,7 @@ CHIP_ERROR ExtractCATsFromOpCert(const ByteSpan & opcert, CATValues & cats);
CHIP_ERROR ExtractCATsFromOpCert(const ChipCertificateData & opcert, CATValues & cats);

/**
* Extract the and Fabric ID from an operational certificate in ByteSpan TLV-encoded
* Extract Fabric ID from an operational certificate in ByteSpan TLV-encoded
* form. This does not perform any sort of validation on the certificate
* structure other than parsing it.
*
Expand Down
2 changes: 2 additions & 0 deletions src/credentials/FabricTable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1530,6 +1530,8 @@ CHIP_ERROR FabricTable::AddNewPendingTrustedRootCert(const ByteSpan & rcac)
mStateFlags.HasAny(StateFlags::kIsTrustedRootPending, StateFlags::kIsUpdatePending, StateFlags::kIsAddPending),
CHIP_ERROR_INCORRECT_STATE);

ReturnErrorOnFailure(ValidateChipRCAC(rcac));

EnsureNextAvailableFabricIndexUpdated();
FabricIndex fabricIndexToUse = kUndefinedFabricIndex;

Expand Down
32 changes: 32 additions & 0 deletions src/credentials/tests/TestChipCert.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -736,6 +736,37 @@ static void TestChipCert_CertValidTime(nlTestSuite * inSuite, void * inContext)
certSet.Release();
}

static void TestChipCert_ValidateChipRCAC(nlTestSuite * inSuite, void * inContext)
{
struct RCACTestCase
{
uint8_t Cert;
CHIP_ERROR mExpectedResult;
};

// clang-format off
static RCACTestCase sRCACTestCases[] = {
// Cert Expected Result
// ====================================================
{ TestCert::kRoot01, CHIP_NO_ERROR },
{ TestCert::kRoot02, CHIP_NO_ERROR },
{ TestCert::kICA01, CHIP_ERROR_WRONG_CERT_TYPE },
{ TestCert::kICA02, CHIP_ERROR_WRONG_CERT_TYPE },
{ TestCert::kICA01_1, CHIP_ERROR_WRONG_CERT_TYPE },
{ TestCert::kFWSign01, CHIP_ERROR_WRONG_CERT_TYPE },
{ TestCert::kNode01_01, CHIP_ERROR_WRONG_CERT_TYPE },
{ TestCert::kNode02_08, CHIP_ERROR_WRONG_CERT_TYPE },
};
// clang-format on

for (auto & testCase : sRCACTestCases)
{
ByteSpan cert;
NL_TEST_ASSERT(inSuite, GetTestCert(testCase.Cert, sNullLoadFlag, cert) == CHIP_NO_ERROR);
NL_TEST_ASSERT(inSuite, ValidateChipRCAC(cert) == testCase.mExpectedResult);
}
}

class AlwaysAcceptValidityPolicy : public CertificateValidityPolicy
{
public:
Expand Down Expand Up @@ -1961,6 +1992,7 @@ static const nlTest sTests[] = {
NL_TEST_DEF("Test CHIP Certificate Distinguish Name", TestChipCert_ChipDN),
NL_TEST_DEF("Test CHIP Certificate Validation", TestChipCert_CertValidation),
NL_TEST_DEF("Test CHIP Certificate Validation time", TestChipCert_CertValidTime),
NL_TEST_DEF("Test CHIP Root Certificate Validation", TestChipCert_ValidateChipRCAC),
NL_TEST_DEF("Test CHIP Certificate Validity Policy injection", TestChipCert_CertValidityPolicyInjection),
NL_TEST_DEF("Test CHIP Certificate Usage", TestChipCert_CertUsage),
NL_TEST_DEF("Test CHIP Certificate Type", TestChipCert_CertType),
Expand Down

0 comments on commit bc91961

Please sign in to comment.