Skip to content

Commit

Permalink
Updated CHIP Certs Implementation to Use Spans instaed of Pointer/Len…
Browse files Browse the repository at this point in the history
… Pairs.

Specifically, added the following FixedSpan types:
  - CertificateKeyId
  - P256ECDSASignatureSpan
  - P256PublicKeySpan
Also redefined mString member in the ChipRDN structure to be ByteSpan.
  • Loading branch information
emargolis committed Jun 21, 2021
1 parent 82e6290 commit 36cabff
Show file tree
Hide file tree
Showing 21 changed files with 279 additions and 329 deletions.
4 changes: 2 additions & 2 deletions src/controller/CHIPDeviceController.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -241,15 +241,15 @@ CHIP_ERROR DeviceController::LoadLocalCredentials(Transport::AdminPairingInfo *

uint8_t * chipCert = buffer1.Get();
uint32_t chipCertLen = 0;
ReturnErrorOnFailure(ConvertX509CertToChipCert(cert, certLen, chipCert, kMaxCHIPOpCertLength, chipCertLen));
ReturnErrorOnFailure(ConvertX509CertToChipCert(ByteSpan(cert, certLen), chipCert, kMaxCHIPOpCertLength, chipCertLen));

ReturnErrorOnFailure(admin->SetOperationalCert(ByteSpan(chipCert, chipCertLen)));

ChipLogProgress(Controller, "Getting root certificate for the controller from the issuer");
ReturnErrorOnFailure(mOperationalCredentialsDelegate->GetRootCACertificate(0, cert, kMaxCHIPOpCertLength, certLen));

chipCertLen = 0;
ReturnErrorOnFailure(ConvertX509CertToChipCert(cert, certLen, chipCert, kMaxCHIPOpCertLength, chipCertLen));
ReturnErrorOnFailure(ConvertX509CertToChipCert(ByteSpan(cert, certLen), chipCert, kMaxCHIPOpCertLength, chipCertLen));

ReturnErrorOnFailure(admin->SetRootCert(ByteSpan(chipCert, chipCertLen)));

Expand Down
139 changes: 64 additions & 75 deletions src/credentials/CHIPCert.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,7 @@ const ChipCertificateData * ChipCertificateSet::FindCert(const CertificateKeyId
for (uint8_t i = 0; i < mCertCount; i++)
{
ChipCertificateData & cert = mCerts[i];
if (cert.mSubjectKeyId.IsEqual(subjectKeyId))
if (cert.mSubjectKeyId.data_equal(subjectKeyId))
{
return &cert;
}
Expand Down Expand Up @@ -380,12 +380,12 @@ CHIP_ERROR ChipCertificateSet::VerifySignature(const ChipCertificateData * cert,
P256ECDSASignature signature;
uint16_t derSigLen;

ReturnErrorOnFailure(ConvertECDSASignatureRawToDER(cert->mSignature, cert->mSignatureLen, signature,
static_cast<uint16_t>(signature.Capacity()), derSigLen));
ReturnErrorOnFailure(
ConvertECDSASignatureRawToDER(cert->mSignature, signature, static_cast<uint16_t>(signature.Capacity()), derSigLen));

ReturnErrorOnFailure(signature.SetLength(derSigLen));

memcpy(caPublicKey, caCert->mPublicKey, caCert->mPublicKeyLen);
memcpy(caPublicKey, caCert->mPublicKey.data(), caCert->mPublicKey.size());

ReturnErrorOnFailure(caPublicKey.ECDSA_validate_hash_signature(cert->mTBSHash, chip::Crypto::kSHA256_Hash_Length, signature));

Expand Down Expand Up @@ -483,7 +483,7 @@ CHIP_ERROR ChipCertificateSet::ValidateCert(const ChipCertificateData * cert, Va

// Fail validation if the certificate is self-signed. Since we don't trust this certificate (see the check above) and
// it has no path we can follow to a trust anchor, it can't be considered valid.
if (cert->mIssuerDN.IsEqual(cert->mSubjectDN) && cert->mAuthKeyId.IsEqual(cert->mSubjectKeyId))
if (cert->mIssuerDN.IsEqual(cert->mSubjectDN) && cert->mAuthKeyId.data_equal(cert->mSubjectKeyId))
{
ExitNow(err = CHIP_ERROR_CERT_NOT_TRUSTED);
}
Expand Down Expand Up @@ -524,7 +524,7 @@ CHIP_ERROR ChipCertificateSet::FindValidCert(const ChipDN & subjectDN, const Cer
err = (depth > 0) ? CHIP_ERROR_CA_CERT_NOT_FOUND : CHIP_ERROR_CERT_NOT_FOUND;

// Fail immediately if neither of the input criteria are specified.
if (subjectDN.IsEmpty() && subjectKeyId.IsEmpty())
if (subjectDN.IsEmpty() && subjectKeyId.empty())
{
ExitNow();
}
Expand All @@ -539,7 +539,7 @@ CHIP_ERROR ChipCertificateSet::FindValidCert(const ChipDN & subjectDN, const Cer
{
continue;
}
if (!subjectKeyId.IsEmpty() && !candidateCert->mSubjectKeyId.IsEqual(subjectKeyId))
if (!subjectKeyId.empty() && !candidateCert->mSubjectKeyId.data_equal(subjectKeyId))
{
continue;
}
Expand Down Expand Up @@ -569,36 +569,34 @@ void ChipCertificateData::Clear()
{
mSubjectDN.Clear();
mIssuerDN.Clear();
mSubjectKeyId.Clear();
mAuthKeyId.Clear();
mNotBeforeTime = 0;
mNotAfterTime = 0;
mPublicKey = nullptr;
mPublicKeyLen = 0;
mPubKeyCurveOID = 0;
mPubKeyAlgoOID = 0;
mSigAlgoOID = 0;
mSubjectKeyId = CertificateKeyId();
mAuthKeyId = CertificateKeyId();
mNotBeforeTime = 0;
mNotAfterTime = 0;
mPublicKey = P256PublicKeySpan();
mPubKeyCurveOID = 0;
mPubKeyAlgoOID = 0;
mSigAlgoOID = 0;
mPathLenConstraint = 0;
mCertFlags.ClearAll();
mKeyUsageFlags.ClearAll();
mKeyPurposeFlags.ClearAll();
mPathLenConstraint = 0;
mSignature = nullptr;
mSignatureLen = 0;
mSignature = P256ECDSASignatureSpan();

memset(mTBSHash, 0, sizeof(mTBSHash));
}

bool ChipCertificateData::IsEqual(const ChipCertificateData & other) const
{
// TODO - Add an operator== on BitFlags class.
return mSubjectDN.IsEqual(other.mSubjectDN) && mIssuerDN.IsEqual(other.mIssuerDN) &&
mSubjectKeyId.IsEqual(other.mSubjectKeyId) && mAuthKeyId.IsEqual(other.mAuthKeyId) &&
mSubjectKeyId.data_equal(other.mSubjectKeyId) && mAuthKeyId.data_equal(other.mAuthKeyId) &&
(mNotBeforeTime == other.mNotBeforeTime) && (mNotAfterTime == other.mNotAfterTime) &&
(mPublicKeyLen == other.mPublicKeyLen) && (memcmp(mPublicKey, other.mPublicKey, mPublicKeyLen) == 0) &&
(mPubKeyCurveOID == other.mPubKeyCurveOID) && (mPubKeyAlgoOID == other.mPubKeyAlgoOID) &&
(mSigAlgoOID == other.mSigAlgoOID) && (mCertFlags.Raw() == other.mCertFlags.Raw()) &&
(mKeyUsageFlags.Raw() == other.mKeyUsageFlags.Raw()) && (mKeyPurposeFlags.Raw() == other.mKeyPurposeFlags.Raw()) &&
(mPathLenConstraint == other.mPathLenConstraint) && (mSignatureLen == other.mSignatureLen) &&
(memcmp(mSignature, other.mSignature, mSignatureLen) == 0) && (memcmp(mTBSHash, other.mTBSHash, sizeof(mTBSHash)) == 0);
mPublicKey.data_equal(other.mPublicKey) && (mPubKeyCurveOID == other.mPubKeyCurveOID) &&
(mPubKeyAlgoOID == other.mPubKeyAlgoOID) && (mSigAlgoOID == other.mSigAlgoOID) &&
(mCertFlags.Raw() == other.mCertFlags.Raw()) && (mKeyUsageFlags.Raw() == other.mKeyUsageFlags.Raw()) &&
(mKeyPurposeFlags.Raw() == other.mKeyPurposeFlags.Raw()) && (mPathLenConstraint == other.mPathLenConstraint) &&
mSignature.data_equal(other.mSignature) && (memcmp(mTBSHash, other.mTBSHash, sizeof(mTBSHash)) == 0);
}

void ValidationContext::Reset()
Expand All @@ -625,8 +623,7 @@ bool ChipRDN::IsEqual(const ChipRDN & other) const
}
else
{
return (mAttrValue.mString.mLen == other.mAttrValue.mString.mLen &&
memcmp(mAttrValue.mString.mValue, other.mAttrValue.mString.mValue, mAttrValue.mString.mLen) == 0);
return mAttrValue.mString.data_equal(other.mAttrValue.mString);
}
}

Expand Down Expand Up @@ -659,39 +656,34 @@ uint8_t ChipDN::RDNCount() const

CHIP_ERROR ChipDN::AddAttribute(chip::ASN1::OID oid, uint64_t val)
{
CHIP_ERROR err = CHIP_NO_ERROR;
uint8_t rdnCount = RDNCount();

VerifyOrExit(rdnCount < CHIP_CONFIG_CERT_MAX_RDN_ATTRIBUTES, err = CHIP_ERROR_NO_MEMORY);
VerifyOrExit(IsChipDNAttr(oid), err = CHIP_ERROR_INVALID_ARGUMENT);
VerifyOrReturnError(rdnCount < CHIP_CONFIG_CERT_MAX_RDN_ATTRIBUTES, CHIP_ERROR_NO_MEMORY);
VerifyOrReturnError(IsChipDNAttr(oid), CHIP_ERROR_INVALID_ARGUMENT);

if (IsChip32bitDNAttr(oid))
{
VerifyOrExit(val <= UINT32_MAX, err = CHIP_ERROR_INVALID_ARGUMENT);
VerifyOrReturnError(val <= UINT32_MAX, CHIP_ERROR_INVALID_ARGUMENT);
}

rdn[rdnCount].mAttrOID = oid;
rdn[rdnCount].mAttrValue.mChipVal = val;

exit:
return err;
return CHIP_NO_ERROR;
}

CHIP_ERROR ChipDN::AddAttribute(chip::ASN1::OID oid, const uint8_t * val, uint32_t valLen)
CHIP_ERROR ChipDN::AddAttribute(chip::ASN1::OID oid, ByteSpan val)
{
CHIP_ERROR err = CHIP_NO_ERROR;
uint8_t rdnCount = RDNCount();

VerifyOrExit(rdnCount < CHIP_CONFIG_CERT_MAX_RDN_ATTRIBUTES, err = CHIP_ERROR_NO_MEMORY);
VerifyOrExit(!IsChipDNAttr(oid), err = CHIP_ERROR_INVALID_ARGUMENT);
VerifyOrExit(oid != kOID_NotSpecified, err = CHIP_ERROR_INVALID_ARGUMENT);
VerifyOrReturnError(rdnCount < CHIP_CONFIG_CERT_MAX_RDN_ATTRIBUTES, CHIP_ERROR_NO_MEMORY);
VerifyOrReturnError(!IsChipDNAttr(oid), CHIP_ERROR_INVALID_ARGUMENT);
VerifyOrReturnError(oid != kOID_NotSpecified, CHIP_ERROR_INVALID_ARGUMENT);

rdn[rdnCount].mAttrOID = oid;
rdn[rdnCount].mAttrValue.mString.mValue = val;
rdn[rdnCount].mAttrValue.mString.mLen = valLen;
rdn[rdnCount].mAttrOID = oid;
rdn[rdnCount].mAttrValue.mString = val;

exit:
return err;
return CHIP_NO_ERROR;
}

CHIP_ERROR ChipDN::GetCertType(uint8_t & certType) const
Expand Down Expand Up @@ -792,11 +784,6 @@ bool ChipDN::IsEqual(const ChipDN & other) const
return res;
}

bool CertificateKeyId::IsEqual(const CertificateKeyId & other) const
{
return mId != nullptr && other.mId != nullptr && mLen == other.mLen && memcmp(mId, other.mId, mLen) == 0;
}

DLL_EXPORT CHIP_ERROR ASN1ToChipEpochTime(const chip::ASN1::ASN1UniversalTime & asn1Time, uint32_t & epochTime)
{
CHIP_ERROR err = CHIP_NO_ERROR;
Expand Down Expand Up @@ -844,48 +831,52 @@ DLL_EXPORT CHIP_ERROR ChipEpochToASN1Time(uint32_t epochTime, chip::ASN1::ASN1Un
return CHIP_NO_ERROR;
}

CHIP_ERROR ConvertIntegerDERToRaw(const uint8_t * derInt, uint16_t derIntLen, uint8_t * rawInt, const uint16_t rawIntLen)
CHIP_ERROR ConvertIntegerDERToRaw(ByteSpan derInt, uint8_t * rawInt, const uint16_t rawIntLen)
{
VerifyOrReturnError(derInt != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
VerifyOrReturnError(derIntLen > 0, CHIP_ERROR_INVALID_ARGUMENT);
VerifyOrReturnError(!derInt.empty(), CHIP_ERROR_INVALID_ARGUMENT);
VerifyOrReturnError(rawInt != nullptr, CHIP_ERROR_INVALID_ARGUMENT);

const uint8_t * derIntData = derInt.data();
size_t derIntLen = derInt.size();

/* one leading zero is allowed for positive integer in ASN1 DER format */
if (*derInt == 0)
if (*derIntData == 0)
{
derInt++;
derIntData++;
derIntLen--;
}

VerifyOrReturnError(derIntLen <= rawIntLen, CHIP_ERROR_INVALID_ARGUMENT);

if (derIntLen > 0)
{
VerifyOrReturnError(*derInt != 0, CHIP_ERROR_INVALID_ARGUMENT);
VerifyOrReturnError(*derIntData != 0, CHIP_ERROR_INVALID_ARGUMENT);
}

memset(rawInt, 0, (rawIntLen - derIntLen));
memcpy(rawInt + (rawIntLen - derIntLen), derInt, derIntLen);
memcpy(rawInt + (rawIntLen - derIntLen), derIntData, derIntLen);

return CHIP_NO_ERROR;
}

CHIP_ERROR ConvertIntegerRawToDER(const uint8_t * rawInt, uint16_t rawIntLen, uint8_t * derInt, const uint16_t derIntBufSize,
uint16_t & derIntLen)
CHIP_ERROR ConvertIntegerRawToDER(P256IntegerSpan rawInt, uint8_t * derInt, const uint16_t derIntBufSize, uint16_t & derIntLen)
{
VerifyOrReturnError(rawInt != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
VerifyOrReturnError(rawIntLen > 0, CHIP_ERROR_INVALID_ARGUMENT);
static_assert(rawInt.size() <= UINT16_MAX - 1, "P256 raw integer doesn't fit in a uint16_t");

VerifyOrReturnError(!rawInt.empty(), CHIP_ERROR_INVALID_ARGUMENT);
VerifyOrReturnError(derInt != nullptr, CHIP_ERROR_INVALID_ARGUMENT);

while (*rawInt == 0)
const uint8_t * rawIntData = rawInt.data();
size_t rawIntLen = rawInt.size();

while (*rawIntData == 0)
{
rawInt++;
rawIntData++;
rawIntLen--;
}

if (*rawInt & 0x80) /* Need Leading Zero */
if (*rawIntData & 0x80) /* Need Leading Zero */
{
VerifyOrReturnError(rawIntLen <= UINT16_MAX - 1, CHIP_ERROR_BUFFER_TOO_SMALL);
VerifyOrReturnError(derIntBufSize >= rawIntLen + 1, CHIP_ERROR_BUFFER_TOO_SMALL);

*derInt++ = 0;
Expand All @@ -895,15 +886,15 @@ CHIP_ERROR ConvertIntegerRawToDER(const uint8_t * rawInt, uint16_t rawIntLen, ui
{
VerifyOrReturnError(derIntBufSize >= rawIntLen, CHIP_ERROR_BUFFER_TOO_SMALL);

derIntLen = rawIntLen;
derIntLen = static_cast<uint16_t>(rawIntLen);
}

memcpy(derInt, rawInt, rawIntLen);
memcpy(derInt, rawIntData, rawIntLen);

return CHIP_NO_ERROR;
}

CHIP_ERROR ConvertECDSASignatureRawToDER(const uint8_t * rawSig, uint16_t rawSigLen, uint8_t * derSig, const uint16_t derSigBufSize,
CHIP_ERROR ConvertECDSASignatureRawToDER(P256ECDSASignatureSpan rawSig, uint8_t * derSig, const uint16_t derSigBufSize,
uint16_t & derSigLen)
{
static constexpr size_t kMaxBytesForDeferredLenList = sizeof(uint8_t *) + // size of a single pointer in the deferred list
Expand All @@ -913,13 +904,11 @@ CHIP_ERROR ConvertECDSASignatureRawToDER(const uint8_t * rawSig, uint16_t rawSig
uint8_t localDERSigBuf[kMax_ECDSA_Signature_Length + kMaxBytesForDeferredLenList];
ASN1Writer writer;

VerifyOrReturnError(rawSig != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
VerifyOrReturnError(rawSigLen > 0, CHIP_ERROR_INVALID_ARGUMENT);
VerifyOrReturnError(derSig != nullptr, CHIP_ERROR_INVALID_ARGUMENT);

writer.Init(localDERSigBuf, sizeof(localDERSigBuf));

ReturnErrorOnFailure(ConvertECDSASignatureRawToDER(rawSig, rawSigLen, writer));
ReturnErrorOnFailure(ConvertECDSASignatureRawToDER(rawSig, writer));

ReturnErrorOnFailure(writer.Finalize());

Expand All @@ -932,24 +921,24 @@ CHIP_ERROR ConvertECDSASignatureRawToDER(const uint8_t * rawSig, uint16_t rawSig
return CHIP_NO_ERROR;
}

CHIP_ERROR ConvertECDSASignatureRawToDER(const uint8_t * rawSig, uint16_t rawSigLen, ASN1Writer & writer)
CHIP_ERROR ConvertECDSASignatureRawToDER(P256ECDSASignatureSpan rawSig, ASN1Writer & writer)
{
CHIP_ERROR err = CHIP_NO_ERROR;
uint8_t derInt[kP256_FE_Length + 1];
uint16_t derIntLen;

VerifyOrReturnError(rawSig != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
VerifyOrReturnError(rawSigLen == kP256_ECDSA_Signature_Length_Raw, CHIP_ERROR_INVALID_ARGUMENT);
VerifyOrReturnError(!rawSig.empty(), CHIP_ERROR_INVALID_ARGUMENT);

// Ecdsa-Sig-Value ::= SEQUENCE
ASN1_START_SEQUENCE
{
// r INTEGER
ReturnErrorOnFailure(ConvertIntegerRawToDER(rawSig, kP256_FE_Length, derInt, sizeof(derInt), derIntLen));
ReturnErrorOnFailure(ConvertIntegerRawToDER(P256IntegerSpan(rawSig.data()), derInt, sizeof(derInt), derIntLen));
ReturnErrorOnFailure(writer.PutValue(kASN1TagClass_Universal, kASN1UniversalTag_Integer, false, derInt, derIntLen));

// s INTEGER
ReturnErrorOnFailure(ConvertIntegerRawToDER(rawSig + kP256_FE_Length, kP256_FE_Length, derInt, sizeof(derInt), derIntLen));
ReturnErrorOnFailure(
ConvertIntegerRawToDER(P256IntegerSpan(rawSig.data() + kP256_FE_Length), derInt, sizeof(derInt), derIntLen));
ReturnErrorOnFailure(writer.PutValue(kASN1TagClass_Universal, kASN1UniversalTag_Integer, false, derInt, derIntLen));
}
ASN1_END_SEQUENCE;
Expand Down
Loading

0 comments on commit 36cabff

Please sign in to comment.