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 authored and woody-apple committed Jun 16, 2021
1 parent 1397b4b commit 9cbe214
Show file tree
Hide file tree
Showing 13 changed files with 143 additions and 193 deletions.
85 changes: 36 additions & 49 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.data(), static_cast<uint16_t>(cert->mSignature.size()),
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
54 changes: 23 additions & 31 deletions src/credentials/CHIPCert.h
Original file line number Diff line number Diff line change
Expand Up @@ -186,16 +186,14 @@ enum
*/
struct ChipRDN
{
union
union mAttrValue
{
uint64_t mChipVal; /**< CHIP specific DN attribute value. */
struct
{
const uint8_t * mValue; /**< Pointer to the DN attribute value. */
uint32_t mLen; /**< DN attribute length. */
} mString; /**< DN attribute structure when encoded as a string. */
} mAttrValue; /**< DN attribute value union: string or unsigned integer. */
chip::ASN1::OID mAttrOID; /**< DN attribute CHIP OID. */
mAttrValue(){};
~mAttrValue(){};
uint64_t mChipVal; /**< CHIP specific DN attribute value. */
ByteSpan mString; /**< Attribute value when encoded as a string. */
} mAttrValue; /**< DN attribute value union: string or unsigned integer. */
chip::ASN1::OID mAttrOID; /**< DN attribute CHIP OID. */

bool IsEqual(const ChipRDN & other) const;
bool IsEmpty() const { return mAttrOID == chip::ASN1::kOID_NotSpecified; }
Expand Down Expand Up @@ -228,13 +226,12 @@ class ChipDN
* @brief Add string attribute to the DN.
*
* @param oid String OID for DN attribute.
* @param val Pointer to the DN string attribute. The value in the argument buffer should
* remain valid while the object is in use.
* @param valLen Length of the DN string attribute.
* @param val A ByteSpan object containing a pointer and length of the DN string attribute
* buffer. The value in the buffer should remain valid while the object is in use.
*
* @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise
**/
CHIP_ERROR AddAttribute(chip::ASN1::OID oid, const uint8_t * val, uint32_t valLen);
CHIP_ERROR AddAttribute(chip::ASN1::OID oid, ByteSpan val);

/**
* @brief Determine type of a CHIP certificate.
Expand Down Expand Up @@ -271,21 +268,19 @@ class ChipDN
};

/**
* @struct CertificateKeyId
*
* @brief
* A data structure representing a certificate key identifier.
* @brief A data structure for holding a certificate key identifier, without the ownership of it.
*/
struct CertificateKeyId
{
const uint8_t * mId = nullptr; /**< Pointer to the key identifier. Encoded as Octet String and represented as the ASN.1 DER
Integer (X.690 standard). */
uint8_t mLen = 0; /**< Key identifier length. */
typedef FixedByteSpan<kKeyIdentifierLength> CertificateKeyId;

bool IsEqual(const CertificateKeyId & other) const;
bool IsEmpty() const { return mId == nullptr; }
void Clear() { mId = nullptr; }
};
/**
* @brief A data structure for holding a P256 ECDSA signature, without the ownership of it.
*/
typedef FixedByteSpan<Crypto::kP256_ECDSA_Signature_Length_Raw> P256ECDSASignatureSpan;

/**
* @brief A data structure for holding a P256 Public Key, without the ownership of it.
*/
typedef FixedByteSpan<Crypto::kP256_Point_Length> P256PublicKeySpan;

/**
* @struct ChipCertificateData
Expand All @@ -306,25 +301,22 @@ struct ChipCertificateData
void Clear();
bool IsEqual(const ChipCertificateData & other) const;

// TODO: Review and consider replacing some data pointer/len pairs with ByteSpan and FixedByteSpan types.
ByteSpan mCertificate; /**< Original raw buffer data. */
ChipDN mSubjectDN; /**< Certificate Subject DN. */
ChipDN mIssuerDN; /**< Certificate Issuer DN. */
CertificateKeyId mSubjectKeyId; /**< Certificate Subject public key identifier. */
CertificateKeyId mAuthKeyId; /**< Certificate Authority public key identifier. */
uint32_t mNotBeforeTime; /**< Certificate validity: Not Before field. */
uint32_t mNotAfterTime; /**< Certificate validity: Not After field. */
const uint8_t * mPublicKey; /**< Pointer to the certificate public key. */
uint8_t mPublicKeyLen; /**< Certificate public key length. */
P256PublicKeySpan mPublicKey; /**< Certificate public key. */
uint16_t mPubKeyCurveOID; /**< Public key Elliptic Curve CHIP OID. */
uint16_t mPubKeyAlgoOID; /**< Public key algorithm CHIP OID. */
uint16_t mSigAlgoOID; /**< Certificate signature algorithm CHIP OID. */
BitFlags<CertFlags> mCertFlags; /**< Certificate data flags. */
BitFlags<KeyUsageFlags> mKeyUsageFlags; /**< Certificate key usage extensions flags. */
BitFlags<KeyPurposeFlags> mKeyPurposeFlags; /**< Certificate extended key usage extensions flags. */
uint8_t mPathLenConstraint; /**< Basic constraint: path length. */
const uint8_t * mSignature; /**< Pointer to the certificate signature. */
uint8_t mSignatureLen; /**< Certificate signature length. */
P256ECDSASignatureSpan mSignature; /**< Certificate signature. */

uint8_t mTBSHash[Crypto::kSHA256_Hash_Length]; /**< Certificate TBS hash. */
};
Expand Down
Loading

0 comments on commit 9cbe214

Please sign in to comment.