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

TC_RR_1_1: Updated Method that Was Used to Generate Large Sized Operational Certificates #22088

Merged
Show file tree
Hide file tree
Changes from 1 commit
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
39 changes: 17 additions & 22 deletions src/controller/ExampleOperationalCredentialsIssuer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,11 @@ CHIP_ERROR IssueX509Cert(uint32_t now, uint32_t validity, ChipDN issuerDn, ChipD
const Crypto::P256PublicKey & subjectPublicKey, Crypto::P256Keypair & issuerKeypair,
MutableByteSpan & outX509Cert)
{
constexpr size_t kDERCertDnEncodingOverhead = 11;
constexpr size_t kTLVCertDnEncodingOverhead = 3;
constexpr size_t kMaxCertPaddingLength = 150;
constexpr size_t kTLVDesiredSize = kMaxCHIPCertLength - 50;
constexpr size_t kDERCertFutureExtEncodingOverhead = 12;
constexpr size_t kTLVCertFutureExtEncodingOverhead = kDERCertFutureExtEncodingOverhead + 5;
constexpr size_t kMaxCertPaddingLength = 200;
constexpr size_t kTLVDesiredSize = kMaxCHIPCertLength;
constexpr uint8_t sOID_Extension_SubjectAltName[] = { 0x55, 0x1d, 0x11 };

Platform::ScopedMemoryBuffer<uint8_t> derBuf;
ReturnErrorCodeIf(!derBuf.Alloc(kMaxDERCertLength), CHIP_ERROR_NO_MEMORY);
Expand Down Expand Up @@ -84,7 +85,7 @@ CHIP_ERROR IssueX509Cert(uint32_t now, uint32_t validity, ChipDN issuerDn, ChipD
return CHIP_ERROR_INVALID_ARGUMENT;
}

if (maximizeSize && (desiredDn.RDNCount() < CHIP_CONFIG_CERT_MAX_RDN_ATTRIBUTES))
if (maximizeSize)
{
Platform::ScopedMemoryBuffer<uint8_t> paddedTlvBuf;
ReturnErrorCodeIf(!paddedTlvBuf.Alloc(kMaxCHIPCertLength + kMaxCertPaddingLength), CHIP_ERROR_NO_MEMORY);
Expand All @@ -99,15 +100,8 @@ CHIP_ERROR IssueX509Cert(uint32_t now, uint32_t validity, ChipDN issuerDn, ChipD
ReturnErrorCodeIf(!fillerBuf.Alloc(kMaxCertPaddingLength), CHIP_ERROR_NO_MEMORY);
memset(fillerBuf.Get(), 'A', kMaxCertPaddingLength);

int derPaddingLen = static_cast<int>(kMaxDERCertLength - kDERCertDnEncodingOverhead - derSpan.size());
int tlvPaddingLen = static_cast<int>(kTLVDesiredSize - kTLVCertDnEncodingOverhead - paddedTlvSpan.size());
if (certType == CertType::kRcac)
{
// For RCAC the issuer/subject DN are the same so padding will be present in both
derPaddingLen = (derPaddingLen - static_cast<int>(kDERCertDnEncodingOverhead)) / 2;
tlvPaddingLen = (tlvPaddingLen - static_cast<int>(kTLVCertDnEncodingOverhead)) / 2;
}

int derPaddingLen = static_cast<int>(kMaxDERCertLength - kDERCertFutureExtEncodingOverhead - derSpan.size());
int tlvPaddingLen = static_cast<int>(kTLVDesiredSize - kTLVCertFutureExtEncodingOverhead - paddedTlvSpan.size());
size_t paddingLen = 0;
if (derPaddingLen >= 1 && tlvPaddingLen >= 1)
{
Expand All @@ -119,24 +113,25 @@ CHIP_ERROR IssueX509Cert(uint32_t now, uint32_t validity, ChipDN issuerDn, ChipD
paddedDerSpan = MutableByteSpan{ paddedDerBuf.Get(), kMaxDERCertLength + kMaxCertPaddingLength };
paddedTlvSpan = MutableByteSpan{ paddedTlvBuf.Get(), kMaxCHIPCertLength + kMaxCertPaddingLength };

ChipDN certDn = desiredDn;
// Fill the padding in the DomainNameQualifier DN
certDn.AddAttribute_DNQualifier(CharSpan(fillerBuf.Get(), paddingLen), false);
Optional<FutureExtension> futureExt;
FutureExtension ext = { ByteSpan(sOID_Extension_SubjectAltName),
ByteSpan(reinterpret_cast<uint8_t *>(fillerBuf.Get()), paddingLen) };
futureExt.SetValue(ext);

switch (certType)
{
case CertType::kRcac: {
X509CertRequestParams rcacRequest = { serialNumber, now, now + validity, certDn, certDn };
X509CertRequestParams rcacRequest = { serialNumber, now, now + validity, desiredDn, desiredDn, futureExt };
ReturnErrorOnFailure(NewRootX509Cert(rcacRequest, issuerKeypair, paddedDerSpan));
break;
}
case CertType::kIcac: {
X509CertRequestParams icacRequest = { serialNumber, now, now + validity, certDn, issuerDn };
X509CertRequestParams icacRequest = { serialNumber, now, now + validity, desiredDn, issuerDn, futureExt };
ReturnErrorOnFailure(NewICAX509Cert(icacRequest, subjectPublicKey, issuerKeypair, paddedDerSpan));
break;
}
case CertType::kNoc: {
X509CertRequestParams nocRequest = { serialNumber, now, now + validity, certDn, issuerDn };
X509CertRequestParams nocRequest = { serialNumber, now, now + validity, desiredDn, issuerDn, futureExt };
ReturnErrorOnFailure(NewNodeOperationalX509Cert(nocRequest, subjectPublicKey, issuerKeypair, paddedDerSpan));
break;
}
Expand All @@ -146,10 +141,10 @@ CHIP_ERROR IssueX509Cert(uint32_t now, uint32_t validity, ChipDN issuerDn, ChipD

ReturnErrorOnFailure(ConvertX509CertToChipCert(paddedDerSpan, paddedTlvSpan));

ChipLogProgress(Controller, "Generated maximized certificate with %u DER bytes, %u TLV bytes",
static_cast<unsigned>(paddedDerSpan.size()), static_cast<unsigned>(paddedTlvSpan.size()));
if (paddedDerSpan.size() <= kMaxDERCertLength && paddedTlvSpan.size() <= kMaxCHIPCertLength)
{
ChipLogProgress(Controller, "Generated maximized certificate with %u DER bytes, %u TLV bytes",
static_cast<unsigned>(paddedDerSpan.size()), static_cast<unsigned>(paddedTlvSpan.size()));
return CopySpanToMutableSpan(paddedDerSpan, outX509Cert);
}
}
Expand Down
7 changes: 7 additions & 0 deletions src/credentials/CHIPCert.h
Original file line number Diff line number Diff line change
Expand Up @@ -507,13 +507,20 @@ CHIP_ERROR ConvertChipCertToX509Cert(const ByteSpan chipCert, MutableByteSpan &
*/
CHIP_ERROR ValidateChipRCAC(const ByteSpan & rcac);

struct FutureExtension
{
ByteSpan OID;
ByteSpan Extension;
};

struct X509CertRequestParams
{
int64_t SerialNumber;
uint32_t ValidityStart;
uint32_t ValidityEnd;
ChipDN SubjectDN;
ChipDN IssuerDN;
Optional<FutureExtension> FutureExt;
};

/**
Expand Down
30 changes: 28 additions & 2 deletions src/credentials/GenerateChipX509Cert.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,31 @@ CHIP_ERROR EncodeNOCSpecificExtensions(ASN1Writer & writer)
return err;
}

CHIP_ERROR EncodeExtensions(bool isCA, const Crypto::P256PublicKey & SKI, const Crypto::P256PublicKey & AKI, ASN1Writer & writer)
CHIP_ERROR EncodeFutureExtension(const Optional<FutureExtension> & futureExt, ASN1Writer & writer)
{
CHIP_ERROR err = CHIP_NO_ERROR;

VerifyOrReturnError(futureExt.HasValue(), CHIP_NO_ERROR);

ASN1_START_SEQUENCE
{
ReturnErrorOnFailure(writer.PutObjectId(futureExt.Value().OID.data(), static_cast<uint16_t>(futureExt.Value().OID.size())));

ASN1_START_OCTET_STRING_ENCAPSULATED
{
ReturnErrorOnFailure(writer.PutOctetString(futureExt.Value().Extension.data(),
static_cast<uint16_t>(futureExt.Value().Extension.size())));
}
ASN1_END_ENCAPSULATED;
}
ASN1_END_SEQUENCE;

exit:
return err;
}

CHIP_ERROR EncodeExtensions(bool isCA, const Crypto::P256PublicKey & SKI, const Crypto::P256PublicKey & AKI,
const Optional<FutureExtension> & futureExt, ASN1Writer & writer)
{
CHIP_ERROR err = CHIP_NO_ERROR;

Expand All @@ -250,6 +274,8 @@ CHIP_ERROR EncodeExtensions(bool isCA, const Crypto::P256PublicKey & SKI, const
ReturnErrorOnFailure(EncodeSubjectKeyIdentifierExtension(SKI, writer));

ReturnErrorOnFailure(EncodeAuthorityKeyIdentifierExtension(AKI, writer));

ReturnErrorOnFailure(EncodeFutureExtension(futureExt, writer));
}
ASN1_END_SEQUENCE;
}
Expand Down Expand Up @@ -336,7 +362,7 @@ CHIP_ERROR EncodeTBSCert(const X509CertRequestParams & requestParams, const Cryp
ReturnErrorOnFailure(EncodeSubjectPublicKeyInfo(subjectPubkey, writer));

// certificate extensions
ReturnErrorOnFailure(EncodeExtensions(isCA, subjectPubkey, issuerPubkey, writer));
ReturnErrorOnFailure(EncodeExtensions(isCA, subjectPubkey, issuerPubkey, requestParams.FutureExt, writer));
}
ASN1_END_SEQUENCE;

Expand Down
36 changes: 36 additions & 0 deletions src/credentials/tests/TestChipCert.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,14 @@ static const BitFlags<KeyUsageFlags> sKCandCR(sKC, sCR);
static const BitFlags<KeyUsageFlags> sKCandEO(sKC, sEO);
static const BitFlags<KeyUsageFlags> sKCandDO(sKC, sDO);

constexpr uint8_t sOID_Extension_SubjectAltName[] = { 0x55, 0x1d, 0x11 };
constexpr char kExtension_SubjectAltName[] = "[email protected]";
emargolis marked this conversation as resolved.
Show resolved Hide resolved

FutureExtension ext{ ByteSpan(sOID_Extension_SubjectAltName),
ByteSpan(reinterpret_cast<uint8_t *>(const_cast<char *>(kExtension_SubjectAltName)),
strlen(kExtension_SubjectAltName)) };
Optional<FutureExtension> kSubjectAltNameAsFutureExt(ext);

static CHIP_ERROR LoadTestCertSet01(ChipCertificateSet & certSet)
{
CHIP_ERROR err;
Expand Down Expand Up @@ -1247,6 +1255,15 @@ static void TestChipCert_GenerateRootCert(nlTestSuite * inSuite, void * inContex

NL_TEST_ASSERT(inSuite, DecodeChipCert(outCert, certData) == CHIP_NO_ERROR);

// Test with FutureExtension
X509CertRequestParams root_params2 = { 1234, 631161876, 729942000, root_dn, root_dn, kSubjectAltNameAsFutureExt };
MutableByteSpan signed_cert_span2(signed_cert);
NL_TEST_ASSERT(inSuite, NewRootX509Cert(root_params2, keypair, signed_cert_span2) == CHIP_NO_ERROR);
outCert = MutableByteSpan(outCertBuf);

NL_TEST_ASSERT(inSuite, ConvertX509CertToChipCert(signed_cert_span2, outCert) == CHIP_NO_ERROR);
NL_TEST_ASSERT(inSuite, DecodeChipCert(outCert, certData) == CHIP_NO_ERROR);

// Test error case: root cert subject provided ICA OID Attribute.
root_params.SubjectDN.Clear();
NL_TEST_ASSERT(inSuite, root_params.SubjectDN.AddAttribute_MatterICACId(0xabcdabcd) == CHIP_NO_ERROR);
Expand Down Expand Up @@ -1325,6 +1342,15 @@ static void TestChipCert_GenerateICACert(nlTestSuite * inSuite, void * inContext

NL_TEST_ASSERT(inSuite, DecodeChipCert(outCert, certData) == CHIP_NO_ERROR);

// Test with FutureExtension
X509CertRequestParams ica_params2 = { 1234, 631161876, 729942000, ica_dn, issuer_dn, kSubjectAltNameAsFutureExt };
MutableByteSpan signed_cert_span2(signed_cert);
NL_TEST_ASSERT(inSuite, NewICAX509Cert(ica_params2, ica_keypair.Pubkey(), keypair, signed_cert_span2) == CHIP_NO_ERROR);
outCert = MutableByteSpan(outCertBuf);

NL_TEST_ASSERT(inSuite, ConvertX509CertToChipCert(signed_cert_span2, outCert) == CHIP_NO_ERROR);
NL_TEST_ASSERT(inSuite, DecodeChipCert(outCert, certData) == CHIP_NO_ERROR);

// Test error case: ICA cert subject provided a node ID attribute
ica_params.SubjectDN.Clear();
NL_TEST_ASSERT(inSuite, ica_params.SubjectDN.AddAttribute_MatterNodeId(0xABCDABCDABCDABCD) == CHIP_NO_ERROR);
Expand Down Expand Up @@ -1372,6 +1398,16 @@ static void TestChipCert_GenerateNOCRoot(nlTestSuite * inSuite, void * inContext

NL_TEST_ASSERT(inSuite, DecodeChipCert(outCert, certData) == CHIP_NO_ERROR);

// Test with FutureExtension
X509CertRequestParams noc_params2 = { 123456, 631161876, 729942000, noc_dn, issuer_dn, kSubjectAltNameAsFutureExt };
MutableByteSpan signed_cert_span2(signed_cert);
NL_TEST_ASSERT(inSuite,
NewNodeOperationalX509Cert(noc_params2, noc_keypair.Pubkey(), keypair, signed_cert_span2) == CHIP_NO_ERROR);
outCert = MutableByteSpan(outCertBuf);

NL_TEST_ASSERT(inSuite, ConvertX509CertToChipCert(signed_cert_span2, outCert) == CHIP_NO_ERROR);
NL_TEST_ASSERT(inSuite, DecodeChipCert(outCert, certData) == CHIP_NO_ERROR);

// Test error case: NOC cert subject doesn't have NodeId attribute
noc_params.SubjectDN.Clear();
NL_TEST_ASSERT(inSuite, noc_params.SubjectDN.AddAttribute_MatterFabricId(0xFAB00000FAB00001) == CHIP_NO_ERROR);
Expand Down
4 changes: 2 additions & 2 deletions src/tools/chip-cert/CertUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -772,7 +772,7 @@ bool WriteChipCert(const char * fileName, const ByteSpan & chipCert, CertFormat
}

bool MakeCert(uint8_t certType, const ToolChipDN * subjectDN, X509 * caCert, EVP_PKEY * caKey, const struct tm & validFrom,
uint32_t validDays, int pathLen, const FutureExtension * futureExts, uint8_t futureExtsCount, X509 * newCert,
uint32_t validDays, int pathLen, const FutureExtensionWithNID * futureExts, uint8_t futureExtsCount, X509 * newCert,
EVP_PKEY * newKey, CertStructConfig & certConfig)
{
bool res = true;
Expand Down Expand Up @@ -925,7 +925,7 @@ bool MakeCert(uint8_t certType, const ToolChipDN * subjectDN, X509 * caCert, EVP
}

CHIP_ERROR MakeCertChipTLV(uint8_t certType, const ToolChipDN * subjectDN, X509 * caCert, EVP_PKEY * caKey,
const struct tm & validFrom, uint32_t validDays, int pathLen, const FutureExtension * futureExts,
const struct tm & validFrom, uint32_t validDays, int pathLen, const FutureExtensionWithNID * futureExts,
uint8_t futureExtsCount, X509 * x509Cert, EVP_PKEY * newKey, CertStructConfig & certConfig,
MutableByteSpan & chipCert)
{
Expand Down
26 changes: 13 additions & 13 deletions src/tools/chip-cert/Cmd_GenCert.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -243,19 +243,19 @@ OptionSet *gCmdOptionSets[] =
// clang-format on

ToolChipDN gSubjectDN;
uint8_t gCertType = kCertType_NotSpecified;
int gPathLengthConstraint = kPathLength_NotSpecified;
bool gSelfSign = false;
const char * gCACertFileName = nullptr;
const char * gCAKeyFileName = nullptr;
const char * gInKeyFileName = nullptr;
const char * gOutCertFileName = nullptr;
const char * gOutKeyFileName = nullptr;
CertFormat gOutCertFormat = kCertFormat_Default;
KeyFormat gOutKeyFormat = kKeyFormat_Default;
uint32_t gValidDays = kCertValidDays_Undefined;
FutureExtension gFutureExtensions[3] = { { 0, nullptr } };
uint8_t gFutureExtensionsCount = 0;
uint8_t gCertType = kCertType_NotSpecified;
int gPathLengthConstraint = kPathLength_NotSpecified;
bool gSelfSign = false;
const char * gCACertFileName = nullptr;
const char * gCAKeyFileName = nullptr;
const char * gInKeyFileName = nullptr;
const char * gOutCertFileName = nullptr;
const char * gOutKeyFileName = nullptr;
CertFormat gOutCertFormat = kCertFormat_Default;
KeyFormat gOutKeyFormat = kKeyFormat_Default;
uint32_t gValidDays = kCertValidDays_Undefined;
FutureExtensionWithNID gFutureExtensions[3] = { { 0, nullptr } };
uint8_t gFutureExtensionsCount = 0;
struct tm gValidFrom;
CertStructConfig gCertConfig;

Expand Down
12 changes: 6 additions & 6 deletions src/tools/chip-cert/chip-cert.h
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ enum AttCertType
kAttCertType_DAC, /**< Device Attestation Certificate (DAC). */
};

struct FutureExtension
struct FutureExtensionWithNID
{
int nid;
const char * info;
Expand Down Expand Up @@ -410,12 +410,12 @@ extern bool WriteCert(const char * fileName, X509 * cert, CertFormat certFmt);
extern bool WriteChipCert(const char * fileName, const chip::ByteSpan & cert, CertFormat certFmt);

extern bool MakeCert(uint8_t certType, const ToolChipDN * subjectDN, X509 * caCert, EVP_PKEY * caKey, const struct tm & validFrom,
uint32_t validDays, int pathLen, const FutureExtension * futureExts, uint8_t futureExtsCount, X509 * newCert,
EVP_PKEY * newKey, CertStructConfig & certConfig);
uint32_t validDays, int pathLen, const FutureExtensionWithNID * futureExts, uint8_t futureExtsCount,
X509 * newCert, EVP_PKEY * newKey, CertStructConfig & certConfig);
extern CHIP_ERROR MakeCertChipTLV(uint8_t certType, const ToolChipDN * subjectDN, X509 * caCert, EVP_PKEY * caKey,
const struct tm & validFrom, uint32_t validDays, int pathLen, const FutureExtension * futureExts,
uint8_t futureExtsCount, X509 * x509Cert, EVP_PKEY * newKey, CertStructConfig & certConfig,
chip::MutableByteSpan & chipCert);
const struct tm & validFrom, uint32_t validDays, int pathLen,
const FutureExtensionWithNID * futureExts, uint8_t futureExtsCount, X509 * x509Cert,
EVP_PKEY * newKey, CertStructConfig & certConfig, chip::MutableByteSpan & chipCert);
extern bool ResignCert(X509 * cert, X509 * caCert, EVP_PKEY * caKey);

extern bool MakeAttCert(AttCertType attCertType, const char * subjectCN, uint16_t subjectVID, uint16_t subjectPID,
Expand Down