Skip to content

Commit

Permalink
CHIPCert: Update to Support Single CASE Authenticated Tag OID. (#11697)
Browse files Browse the repository at this point in the history
-- Support single CAT OID to match spec changes.
  -- Added Utility function to Extract OID array from the subject of OpCert.
  -- Updated test vectors to match the change. Added new test vector which
     includes 3 CAT OIDs in its subject.
  • Loading branch information
emargolis authored and pull[bot] committed Sep 29, 2022
1 parent 7bf2eb7 commit 1223089
Show file tree
Hide file tree
Showing 10 changed files with 1,350 additions and 1,100 deletions.
26 changes: 26 additions & 0 deletions src/credentials/CHIPCert.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -883,6 +883,32 @@ CHIP_ERROR ExtractFabricIdFromCert(const ChipCertificateData & cert, FabricId *
return CHIP_ERROR_INVALID_ARGUMENT;
}

CHIP_ERROR ExtractCATsFromOpCert(const ChipCertificateData & opcert, uint32_t * cats, uint8_t catsSize)
{
uint8_t catCount = 0;
uint8_t certType;

ReturnErrorOnFailure(opcert.mSubjectDN.GetCertType(certType));
VerifyOrReturnError(certType == kCertType_Node, CHIP_ERROR_INVALID_ARGUMENT);

const ChipDN & subjectDN = opcert.mSubjectDN;
for (uint8_t i = 0; i < subjectDN.RDNCount(); ++i)
{
const auto & rdn = subjectDN.rdn[i];
if (rdn.mAttrOID == ASN1::kOID_AttributeType_ChipCASEAuthenticatedTag)
{
ReturnErrorCodeIf(catCount == catsSize, CHIP_ERROR_BUFFER_TOO_SMALL);
cats[catCount++] = static_cast<uint32_t>(rdn.mChipVal);
}
}
for (uint8_t i = catCount; i < catsSize; ++i)
{
cats[i] = 0;
}

return CHIP_NO_ERROR;
}

CHIP_ERROR ExtractNodeIdFabricIdFromOpCert(const ByteSpan & opcert, NodeId * nodeId, FabricId * fabricId)
{
ChipCertificateSet certSet;
Expand Down
16 changes: 15 additions & 1 deletion src/credentials/CHIPCert.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ static constexpr uint32_t kMaxDERCertLength = 600;
// The decode buffer is used to reconstruct TBS section of X.509 certificate, which doesn't include signature.
static constexpr uint32_t kMaxCHIPCertDecodeBufLength = kMaxDERCertLength - Crypto::kMax_ECDSA_Signature_Length_Der;

// Muximum number of CASE Authenticated Tags (CAT) in the CHIP certificate subject.
static constexpr size_t kMaxSubjectCATAttributeCount = CHIP_CONFIG_CERT_MAX_RDN_ATTRIBUTES - 2;

/** Data Element Tags for the CHIP Certificate
*/
enum
Expand Down Expand Up @@ -715,7 +718,7 @@ inline bool IsChip64bitDNAttr(chip::ASN1::OID oid)
**/
inline bool IsChip32bitDNAttr(chip::ASN1::OID oid)
{
return (oid == chip::ASN1::kOID_AttributeType_ChipAuthTag1 || oid == chip::ASN1::kOID_AttributeType_ChipAuthTag2);
return (oid == chip::ASN1::kOID_AttributeType_ChipCASEAuthenticatedTag);
}

/**
Expand Down Expand Up @@ -796,6 +799,17 @@ CHIP_ERROR ExtractFabricIdFromCert(const ChipCertificateData & cert, FabricId *
*/
CHIP_ERROR ExtractNodeIdFabricIdFromOpCert(const ChipCertificateData & opcert, NodeId * nodeId, FabricId * fabricId);

/**
* Extract CASE Authenticated Tags from an operational certificate that has already been
* parsed.
*
* All values in the 'cats' array will be set either to a valid CAT value or zero (undefined) value.
*
* @return CHIP_ERROR_INVALID_ARGUMENT if the passed-in cert is not NOC.
* @return CHIP_ERROR_BUFFER_TOO_SMALL if the passed-in CATs array is too small.
*/
CHIP_ERROR ExtractCATsFromOpCert(const ChipCertificateData & opcert, uint32_t * cats, uint8_t catsSize);

/**
* Extract Node ID and Fabric ID from an operational certificate in ByteSpan TLV-encoded
* form. This does not perform any sort of validation on the certificate
Expand Down
2,084 changes: 1,115 additions & 969 deletions src/credentials/tests/CHIPCert_test_vectors.cpp

Large diffs are not rendered by default.

196 changes: 105 additions & 91 deletions src/credentials/tests/CHIPCert_test_vectors.h

Large diffs are not rendered by default.

77 changes: 77 additions & 0 deletions src/credentials/tests/TestChipCert.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1039,6 +1039,7 @@ static void TestChipCert_ExtractPeerId(nlTestSuite * inSuite, void * inContext)
{ TestCert::kNode02_05, TestCert::kICA02, 0xDEDEDEDE00020005, 0xFAB000000000001D },
{ TestCert::kNode02_06, TestCert::kICA02, 0xDEDEDEDE00020006, 0xFAB000000000001D },
{ TestCert::kNode02_07, TestCert::kICA02, 0xDEDEDEDE00020007, 0xFAB000000000001D },
{ TestCert::kNode02_08, TestCert::kICA02, 0xDEDEDEDE00020008, 0xFAB000000000001D },
};
// clang-format on

Expand Down Expand Up @@ -1107,6 +1108,80 @@ static void TestChipCert_ExtractPeerId(nlTestSuite * inSuite, void * inContext)
}
}

static void TestChipCert_ExtractCATsFromOpCert(nlTestSuite * inSuite, void * inContext)
{
struct TestCase
{
uint8_t Cert;
uint32_t ExpectedCAT[kMaxSubjectCATAttributeCount];
};

// clang-format off
static constexpr TestCase sTestCases[] = {
// Cert CATs
// =============================================================
{ TestCert::kNode01_01, { 0, 0, 0 } },
{ TestCert::kNode01_02, { 0, 0, 0 } },
{ TestCert::kNode02_01, { 0, 0, 0 } },
{ TestCert::kNode02_02, { 0, 0, 0 } },
{ TestCert::kNode02_03, { 0xABCD0001, 0, 0 } },
{ TestCert::kNode02_04, { 0xABCE1002, 0xABCD0003, 0 } },
{ TestCert::kNode02_05, { 0xABCD0010, 0xABCE1008, 0 } },
{ TestCert::kNode02_06, { 0, 0, 0 } },
{ TestCert::kNode02_07, { 0, 0, 0 } },
{ TestCert::kNode02_08, { 0xABCF00A0, 0xABCD0020, 0xABCE0100 } },
};
// clang-format on

// Test extraction from the raw ByteSpan form.
ChipCertificateSet certSet;
for (auto & testCase : sTestCases)
{
CHIP_ERROR err = certSet.Init(1);
NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);

err = LoadTestCert(certSet, testCase.Cert, sNullLoadFlag, sNullDecodeFlag);
NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);

uint32_t cats[kMaxSubjectCATAttributeCount];
err = ExtractCATsFromOpCert(certSet.GetCertSet()[0], cats, ArraySize(cats));
NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
NL_TEST_ASSERT(inSuite, memcmp(cats, testCase.ExpectedCAT, sizeof(cats)) == 0);

certSet.Release();
}

// Error case: trying to extract CAT from Root Cert.
{
CHIP_ERROR err = certSet.Init(1);
NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);

err = LoadTestCert(certSet, TestCert::kRoot01, sNullLoadFlag, sNullDecodeFlag);
NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);

uint32_t cats[kMaxSubjectCATAttributeCount];
err = ExtractCATsFromOpCert(certSet.GetCertSet()[0], cats, ArraySize(cats));
NL_TEST_ASSERT(inSuite, err == CHIP_ERROR_INVALID_ARGUMENT);

certSet.Release();
}

// Error case: CAT array is too small.
{
CHIP_ERROR err = certSet.Init(1);
NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);

err = LoadTestCert(certSet, TestCert::kNode02_08, sNullLoadFlag, sNullDecodeFlag);
NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);

uint32_t cats[kMaxSubjectCATAttributeCount - 1];
err = ExtractCATsFromOpCert(certSet.GetCertSet()[0], cats, ArraySize(cats));
NL_TEST_ASSERT(inSuite, err == CHIP_ERROR_BUFFER_TOO_SMALL);

certSet.Release();
}
}

static void TestChipCert_ExtractPublicKeyAndSKID(nlTestSuite * inSuite, void * inContext)
{
struct TestCase
Expand Down Expand Up @@ -1134,6 +1209,7 @@ static void TestChipCert_ExtractPublicKeyAndSKID(nlTestSuite * inSuite, void * i
{ TestCert::kNode02_05, sTestCert_Node02_05_PublicKey, sTestCert_Node02_05_SubjectKeyId },
{ TestCert::kNode02_06, sTestCert_Node02_06_PublicKey, sTestCert_Node02_06_SubjectKeyId },
{ TestCert::kNode02_07, sTestCert_Node02_07_PublicKey, sTestCert_Node02_07_SubjectKeyId },
{ TestCert::kNode02_08, sTestCert_Node02_08_PublicKey, sTestCert_Node02_08_SubjectKeyId },
};
// clang-format on

Expand Down Expand Up @@ -1200,6 +1276,7 @@ static const nlTest sTests[] = {
NL_TEST_DEF("Test CHIP Verify Generated Cert Chain", TestChipCert_VerifyGeneratedCerts),
NL_TEST_DEF("Test CHIP Verify Generated Cert Chain No ICA", TestChipCert_VerifyGeneratedCertsNoICA),
NL_TEST_DEF("Test extracting PeerId from node certificate", TestChipCert_ExtractPeerId),
NL_TEST_DEF("Test extracting CAST Authenticated Tags from node certificate", TestChipCert_ExtractCATsFromOpCert),
NL_TEST_DEF("Test extracting PublicKey and SKID from chip certificate", TestChipCert_ExtractPublicKeyAndSKID),
NL_TEST_SENTINEL()
};
Expand Down
4 changes: 1 addition & 3 deletions src/lib/asn1/gen_asn1oid.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,10 +144,8 @@ def identity(n):
3), dod(6), internet(1), private(4), enterprise(1), zigbee(37244), chip(1), 4]),
("AttributeType", "ChipFabricId", 21, [iso(1), organization(
3), dod(6), internet(1), private(4), enterprise(1), zigbee(37244), chip(1), 5]),
("AttributeType", "ChipAuthTag1", 22, [iso(1), organization(
("AttributeType", "ChipCASEAuthenticatedTag", 22, [iso(1), organization(
3), dod(6), internet(1), private(4), enterprise(1), zigbee(37244), chip(1), 6]),
("AttributeType", "ChipAuthTag2", 23, [iso(1), organization(
3), dod(6), internet(1), private(4), enterprise(1), zigbee(37244), chip(1), 7]),

# Elliptic Curves
("EllipticCurve", "prime256v1", 1, [
Expand Down
7 changes: 2 additions & 5 deletions src/tools/chip-cert/CertUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,8 @@ bool ToolChipDN::SetCertSubjectDN(X509 * cert) const
case kOID_AttributeType_ChipFabricId:
attrNID = gNIDChipFabricId;
break;
case kOID_AttributeType_ChipAuthTag1:
attrNID = gNIDChipAuthTag1;
break;
case kOID_AttributeType_ChipAuthTag2:
attrNID = gNIDChipAuthTag2;
case kOID_AttributeType_ChipCASEAuthenticatedTag:
attrNID = gNIDChipCASEAuthenticatedTag;
break;
default:
ExitNow(res = false);
Expand Down
21 changes: 4 additions & 17 deletions src/tools/chip-cert/Cmd_GenCert.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ OptionDef gCmdOptionDefs[] =
{ "type", kArgumentRequired, 't' },
{ "subject-chip-id", kArgumentRequired, 'i' },
{ "subject-fab-id", kArgumentRequired, 'f' },
{ "subject-at", kArgumentRequired, 'a' },
{ "subject-cat", kArgumentRequired, 'a' },
{ "subject-cn-u", kArgumentRequired, 'c' },
{ "path-len-constraint", kArgumentRequired, 'p' },
{ "future-ext-sub", kArgumentRequired, 'x' },
Expand Down Expand Up @@ -83,9 +83,9 @@ const char * const gCmdOptionHelp =
"\n"
" Subject DN Fabric Id attribute (in hex).\n"
"\n"
" -a, --subject-at <hex-digits>\n"
" -a, --subject-cat <hex-digits>\n"
"\n"
" Subject DN CHIP Authentication Tag (in hex).\n"
" Subject DN CHIP CASE Authentication Tag (in hex).\n"
"\n"
" -c, --subject-cn-u <string>\n"
"\n"
Expand Down Expand Up @@ -266,20 +266,7 @@ bool HandleOption(const char * progName, OptionSet * optSet, int id, const char
PrintArgError("%s: Invalid value specified for the subject authentication tag attribute: %s\n", progName, arg);
return false;
}

if (!gSubjectDN.HasAttr(kOID_AttributeType_ChipAuthTag1))
{
attrOID = kOID_AttributeType_ChipAuthTag1;
}
else if (!gSubjectDN.HasAttr(kOID_AttributeType_ChipAuthTag2))
{
attrOID = kOID_AttributeType_ChipAuthTag2;
}
else
{
PrintArgError("%s: Too many authentication tag attributes are specified: %s\n", progName, arg);
return false;
}
attrOID = kOID_AttributeType_ChipCASEAuthenticatedTag;

err = gSubjectDN.AddAttribute(attrOID, chip32bitAttr);
if (err != CHIP_NO_ERROR)
Expand Down
16 changes: 4 additions & 12 deletions src/tools/chip-cert/GeneralUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,7 @@ int gNIDChipFirmwareSigningId;
int gNIDChipICAId;
int gNIDChipRootId;
int gNIDChipFabricId;
int gNIDChipAuthTag1;
int gNIDChipAuthTag2;
int gNIDChipCASEAuthenticatedTag;
int gNIDChipAttAttrVID;
int gNIDChipAttAttrPID;
int gNIDChipCurveP256 = EC_curve_nist2nid("P-256");
Expand Down Expand Up @@ -83,14 +82,8 @@ bool InitOpenSSL()
ReportOpenSSLErrorAndExit("OBJ_create", res = false);
}

gNIDChipAuthTag1 = OBJ_create("1.3.6.1.4.1.37244.1.6", "ChipAuthTag1", "ChipAuthTag1");
if (gNIDChipAuthTag1 == 0)
{
ReportOpenSSLErrorAndExit("OBJ_create", res = false);
}

gNIDChipAuthTag2 = OBJ_create("1.3.6.1.4.1.37244.1.7", "ChipAuthTag2", "ChipAuthTag2");
if (gNIDChipAuthTag2 == 0)
gNIDChipCASEAuthenticatedTag = OBJ_create("1.3.6.1.4.1.37244.1.6", "ChipCASEAuthenticatedTag", "ChipCASEAuthenticatedTag");
if (gNIDChipCASEAuthenticatedTag == 0)
{
ReportOpenSSLErrorAndExit("OBJ_create", res = false);
}
Expand All @@ -112,8 +105,7 @@ bool InitOpenSSL()
ASN1_STRING_TABLE_add(gNIDChipICAId, 16, 16, B_ASN1_UTF8STRING, 0);
ASN1_STRING_TABLE_add(gNIDChipRootId, 16, 16, B_ASN1_UTF8STRING, 0);
ASN1_STRING_TABLE_add(gNIDChipFabricId, 16, 16, B_ASN1_UTF8STRING, 0);
ASN1_STRING_TABLE_add(gNIDChipAuthTag1, 8, 8, B_ASN1_UTF8STRING, 0);
ASN1_STRING_TABLE_add(gNIDChipAuthTag2, 8, 8, B_ASN1_UTF8STRING, 0);
ASN1_STRING_TABLE_add(gNIDChipCASEAuthenticatedTag, 8, 8, B_ASN1_UTF8STRING, 0);
ASN1_STRING_TABLE_add(gNIDChipAttAttrVID, 4, 4, B_ASN1_UTF8STRING, 0);
ASN1_STRING_TABLE_add(gNIDChipAttAttrPID, 4, 4, B_ASN1_UTF8STRING, 0);

Expand Down
3 changes: 1 addition & 2 deletions src/tools/chip-cert/chip-cert.h
Original file line number Diff line number Diff line change
Expand Up @@ -164,8 +164,7 @@ extern int gNIDChipFirmwareSigningId;
extern int gNIDChipICAId;
extern int gNIDChipRootId;
extern int gNIDChipFabricId;
extern int gNIDChipAuthTag1;
extern int gNIDChipAuthTag2;
extern int gNIDChipCASEAuthenticatedTag;
extern int gNIDChipCurveP256;
extern int gNIDChipAttAttrVID;
extern int gNIDChipAttAttrPID;
Expand Down

0 comments on commit 1223089

Please sign in to comment.