Skip to content

Commit

Permalink
Implemented ExtractSerialNumberFromX509Cert() Method (#26485)
Browse files Browse the repository at this point in the history
  • Loading branch information
emargolis authored and pull[bot] committed Aug 21, 2023
1 parent 48b4621 commit 18e3c6d
Show file tree
Hide file tree
Showing 9 changed files with 299 additions and 16 deletions.
22 changes: 14 additions & 8 deletions src/crypto/CHIPCryptoPAL.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
*
* Copyright (c) 2020-2022 Project CHIP Authors
* Copyright (c) 2020-2023 Project CHIP Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -43,13 +43,14 @@ namespace Crypto {

constexpr size_t kMax_x509_Certificate_Length = 600;

constexpr size_t kP256_FE_Length = 32;
constexpr size_t kP256_ECDSA_Signature_Length_Raw = (2 * kP256_FE_Length);
constexpr size_t kP256_Point_Length = (2 * kP256_FE_Length + 1);
constexpr size_t kSHA256_Hash_Length = 32;
constexpr size_t kSHA1_Hash_Length = 20;
constexpr size_t kSubjectKeyIdentifierLength = kSHA1_Hash_Length;
constexpr size_t kAuthorityKeyIdentifierLength = kSHA1_Hash_Length;
constexpr size_t kP256_FE_Length = 32;
constexpr size_t kP256_ECDSA_Signature_Length_Raw = (2 * kP256_FE_Length);
constexpr size_t kP256_Point_Length = (2 * kP256_FE_Length + 1);
constexpr size_t kSHA256_Hash_Length = 32;
constexpr size_t kSHA1_Hash_Length = 20;
constexpr size_t kSubjectKeyIdentifierLength = kSHA1_Hash_Length;
constexpr size_t kAuthorityKeyIdentifierLength = kSHA1_Hash_Length;
constexpr size_t kMaxCertificateSerialNumberLength = 20;

constexpr size_t CHIP_CRYPTO_GROUP_SIZE_BYTES = kP256_FE_Length;
constexpr size_t CHIP_CRYPTO_PUBLIC_KEY_SIZE_BYTES = kP256_Point_Length;
Expand Down Expand Up @@ -1566,6 +1567,11 @@ CHIP_ERROR ExtractSKIDFromX509Cert(const ByteSpan & certificate, MutableByteSpan
**/
CHIP_ERROR ExtractAKIDFromX509Cert(const ByteSpan & certificate, MutableByteSpan & akid);

/**
* @brief Extracts Serial Number from X509 Certificate.
**/
CHIP_ERROR ExtractSerialNumberFromX509Cert(const ByteSpan & certificate, MutableByteSpan & serialNumber);

/**
* @brief Checks for resigned version of the certificate in the list and returns it.
*
Expand Down
33 changes: 32 additions & 1 deletion src/crypto/CHIPCryptoPALOpenSSL.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
*
* Copyright (c) 2020-2022 Project CHIP Authors
* Copyright (c) 2020-2023 Project CHIP Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -1970,6 +1970,37 @@ CHIP_ERROR ExtractAKIDFromX509Cert(const ByteSpan & certificate, MutableByteSpan
return ExtractKIDFromX509Cert(false, certificate, akid);
}

CHIP_ERROR ExtractSerialNumberFromX509Cert(const ByteSpan & certificate, MutableByteSpan & serialNumber)
{
CHIP_ERROR err = CHIP_NO_ERROR;
X509 * x509certificate = nullptr;
auto * pCertificate = Uint8::to_const_uchar(certificate.data());
const unsigned char ** ppCertificate = &pCertificate;
const ASN1_INTEGER * serialNumberASN1 = nullptr;
size_t serialNumberLen = 0;

VerifyOrReturnError(!certificate.empty() && CanCastTo<long>(certificate.size()), CHIP_ERROR_INVALID_ARGUMENT);

x509certificate = d2i_X509(nullptr, ppCertificate, static_cast<long>(certificate.size()));
VerifyOrExit(x509certificate != nullptr, err = CHIP_ERROR_NO_MEMORY);

serialNumberASN1 = X509_get_serialNumber(x509certificate);
VerifyOrExit(serialNumberASN1 != nullptr, err = CHIP_ERROR_INTERNAL);
VerifyOrExit(serialNumberASN1->data != nullptr, err = CHIP_ERROR_INTERNAL);
VerifyOrExit(CanCastTo<size_t>(serialNumberASN1->length), err = CHIP_ERROR_INTERNAL);

serialNumberLen = static_cast<size_t>(serialNumberASN1->length);
VerifyOrExit(serialNumberLen <= serialNumber.size(), err = CHIP_ERROR_BUFFER_TOO_SMALL);

memcpy(serialNumber.data(), serialNumberASN1->data, serialNumberLen);
serialNumber.reduce_size(serialNumberLen);

exit:
X509_free(x509certificate);

return err;
}

CHIP_ERROR ExtractVIDPIDFromX509Cert(const ByteSpan & certificate, AttestationCertVidPid & vidpid)
{
ASN1_OBJECT * commonNameObj = OBJ_txt2obj("2.5.4.3", 1);
Expand Down
36 changes: 35 additions & 1 deletion src/crypto/CHIPCryptoPALPSA.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
*
* Copyright (c) 2022 Project CHIP Authors
* Copyright (c) 2022-2023 Project CHIP Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -1651,6 +1651,40 @@ CHIP_ERROR ExtractAKIDFromX509Cert(const ByteSpan & certificate, MutableByteSpan
return ExtractKIDFromX509Cert(false, certificate, akid);
}

CHIP_ERROR ExtractSerialNumberFromX509Cert(const ByteSpan & certificate, MutableByteSpan & serialNumber)
{
#if defined(MBEDTLS_X509_CRT_PARSE_C)
CHIP_ERROR error = CHIP_NO_ERROR;
int result = 0;
uint8_t * p = nullptr;
size_t len = 0;
mbedtls_x509_crt mbed_cert;

mbedtls_x509_crt_init(&mbed_cert);

result = mbedtls_x509_crt_parse(&mbed_cert, Uint8::to_const_uchar(certificate.data()), certificate.size());
VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL);

p = mbed_cert.CHIP_CRYPTO_PAL_PRIVATE_X509(serial).CHIP_CRYPTO_PAL_PRIVATE_X509(p);
len = mbed_cert.CHIP_CRYPTO_PAL_PRIVATE_X509(serial).CHIP_CRYPTO_PAL_PRIVATE_X509(len);
VerifyOrExit(len <= serialNumber.size(), error = CHIP_ERROR_BUFFER_TOO_SMALL);

memcpy(serialNumber.data(), p, len);
serialNumber.reduce_size(len);

exit:
_log_mbedTLS_error(result);
mbedtls_x509_crt_free(&mbed_cert);

#else
(void) certificate;
(void) serialNumber;
CHIP_ERROR error = CHIP_ERROR_NOT_IMPLEMENTED;
#endif // defined(MBEDTLS_X509_CRT_PARSE_C)

return error;
}

CHIP_ERROR ExtractVIDPIDFromX509Cert(const ByteSpan & certificate, AttestationCertVidPid & vidpid)
{
#if defined(MBEDTLS_X509_CRT_PARSE_C)
Expand Down
36 changes: 35 additions & 1 deletion src/crypto/CHIPCryptoPALmbedTLS.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
*
* Copyright (c) 2020-2022 Project CHIP Authors
* Copyright (c) 2020-2023 Project CHIP Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -1768,6 +1768,40 @@ CHIP_ERROR ExtractAKIDFromX509Cert(const ByteSpan & certificate, MutableByteSpan
return ExtractKIDFromX509Cert(false, certificate, akid);
}

CHIP_ERROR ExtractSerialNumberFromX509Cert(const ByteSpan & certificate, MutableByteSpan & serialNumber)
{
#if defined(MBEDTLS_X509_CRT_PARSE_C)
CHIP_ERROR error = CHIP_NO_ERROR;
int result = 0;
uint8_t * p = nullptr;
size_t len = 0;
mbedtls_x509_crt mbed_cert;

mbedtls_x509_crt_init(&mbed_cert);

result = mbedtls_x509_crt_parse(&mbed_cert, Uint8::to_const_uchar(certificate.data()), certificate.size());
VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL);

p = mbed_cert.CHIP_CRYPTO_PAL_PRIVATE_X509(serial).CHIP_CRYPTO_PAL_PRIVATE_X509(p);
len = mbed_cert.CHIP_CRYPTO_PAL_PRIVATE_X509(serial).CHIP_CRYPTO_PAL_PRIVATE_X509(len);
VerifyOrExit(len <= serialNumber.size(), error = CHIP_ERROR_BUFFER_TOO_SMALL);

memcpy(serialNumber.data(), p, len);
serialNumber.reduce_size(len);

exit:
_log_mbedTLS_error(result);
mbedtls_x509_crt_free(&mbed_cert);

#else
(void) certificate;
(void) serialNumber;
CHIP_ERROR error = CHIP_ERROR_NOT_IMPLEMENTED;
#endif // defined(MBEDTLS_X509_CRT_PARSE_C)

return error;
}

CHIP_ERROR ExtractVIDPIDFromX509Cert(const ByteSpan & certificate, AttestationCertVidPid & vidpid)
{
#if defined(MBEDTLS_X509_CRT_PARSE_C)
Expand Down
44 changes: 43 additions & 1 deletion src/crypto/tests/CHIPCryptoPALTest.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
*
* Copyright (c) 2020-2022 Project CHIP Authors
* Copyright (c) 2020-2023 Project CHIP Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -2133,6 +2133,47 @@ static void TestAKID_x509Extraction(nlTestSuite * inSuite, void * inContext)
}
}

static void TestSerialNumber_x509Extraction(nlTestSuite * inSuite, void * inContext)
{
using namespace TestCerts;

HeapChecker heapChecker(inSuite);
CHIP_ERROR err = CHIP_NO_ERROR;

struct SerialNumberTestCase
{
uint8_t Cert;
ByteSpan mExpectedResult;
};

const uint8_t serialNumberRoot01[] = { 0x53, 0x4c, 0x45, 0x82, 0x73, 0x62, 0x35, 0x14 };
const uint8_t serialNumberICA01[] = { 0x69, 0xd8, 0x6a, 0x8d, 0x80, 0xfc, 0x8f, 0x5d };
const uint8_t serialNumberNode02_08[] = { 0x3e, 0x67, 0x94, 0x70, 0x7a, 0xec, 0xb8, 0x15 };

// clang-format off
static SerialNumberTestCase sSerialNumberTestCases[] = {
// Cert Expected Output
// ====================================================
{ TestCert::kRoot01, ByteSpan(serialNumberRoot01) },
{ TestCert::kICA01, ByteSpan(serialNumberICA01) },
{ TestCert::kNode02_08, ByteSpan(serialNumberNode02_08) },
};
// clang-format on

for (auto & testCase : sSerialNumberTestCases)
{
ByteSpan cert;
err = GetTestCert(testCase.Cert, TestCertLoadFlags::kDERForm, cert);
NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);

uint8_t serialNumberBuf[kMaxCertificateSerialNumberLength] = { 0 };
MutableByteSpan serialNumber(serialNumberBuf);
err = ExtractSerialNumberFromX509Cert(cert, serialNumber);
NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
NL_TEST_ASSERT(inSuite, serialNumber.data_equal(testCase.mExpectedResult));
}
}

static void TestVIDPID_StringExtraction(nlTestSuite * inSuite, void * inContext)
{
HeapChecker heapChecker(inSuite);
Expand Down Expand Up @@ -2560,6 +2601,7 @@ static const nlTest sTests[] = {
NL_TEST_DEF("Test x509 Certificate Timestamp Validation", TestX509_IssuingTimestampValidation),
NL_TEST_DEF("Test Subject Key Id Extraction from x509 Certificate", TestSKID_x509Extraction),
NL_TEST_DEF("Test Authority Key Id Extraction from x509 Certificate", TestAKID_x509Extraction),
NL_TEST_DEF("Test Serial Number Extraction from x509 Certificate", TestSerialNumber_x509Extraction),
NL_TEST_DEF("Test Vendor ID and Product ID Extraction from Attribute String", TestVIDPID_StringExtraction),
NL_TEST_DEF("Test Vendor ID and Product ID Extraction from x509 Attestation Certificate", TestVIDPID_x509Extraction),
NL_TEST_DEF("Test Replace Resigned Certificate Version if Found", TestX509_ReplaceCertIfResignedCertFound),
Expand Down
36 changes: 35 additions & 1 deletion src/platform/nxp/common/crypto/CHIPCryptoPALTinyCrypt.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
*
* Copyright (c) 2020-2022 Project CHIP Authors
* Copyright (c) 2020-2023 Project CHIP Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -1604,6 +1604,40 @@ CHIP_ERROR ExtractAKIDFromX509Cert(const ByteSpan & certificate, MutableByteSpan
return ExtractKIDFromX509Cert(false, certificate, akid);
}

CHIP_ERROR ExtractSerialNumberFromX509Cert(const ByteSpan & certificate, MutableByteSpan & serialNumber)
{
#if defined(MBEDTLS_X509_CRT_PARSE_C)
CHIP_ERROR error = CHIP_NO_ERROR;
int result = 0;
uint8_t * p = nullptr;
size_t len = 0;
mbedtls_x509_crt mbed_cert;

mbedtls_x509_crt_init(&mbed_cert);

result = mbedtls_x509_crt_parse(&mbed_cert, Uint8::to_const_uchar(certificate.data()), certificate.size());
VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL);

p = mbed_cert.CHIP_CRYPTO_PAL_PRIVATE_X509(serial).CHIP_CRYPTO_PAL_PRIVATE_X509(p);
len = mbed_cert.CHIP_CRYPTO_PAL_PRIVATE_X509(serial).CHIP_CRYPTO_PAL_PRIVATE_X509(len);
VerifyOrExit(len <= serialNumber.size(), error = CHIP_ERROR_BUFFER_TOO_SMALL);

memcpy(serialNumber.data(), p, len);
serialNumber.reduce_size(len);

exit:
_log_mbedTLS_error(result);
mbedtls_x509_crt_free(&mbed_cert);

#else
(void) certificate;
(void) serialNumber;
CHIP_ERROR error = CHIP_ERROR_NOT_IMPLEMENTED;
#endif // defined(MBEDTLS_X509_CRT_PARSE_C)

return error;
}

CHIP_ERROR ExtractVIDPIDFromX509Cert(const ByteSpan & certificate, AttestationCertVidPid & vidpid)
{
#if defined(MBEDTLS_X509_CRT_PARSE_C)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
*
* Copyright (c) 2020-2022 Project CHIP Authors
* Copyright (c) 2020-2023 Project CHIP Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -1573,6 +1573,40 @@ CHIP_ERROR ExtractAKIDFromX509Cert(const ByteSpan & certificate, MutableByteSpan
return ExtractKIDFromX509Cert(false, certificate, akid);
}

CHIP_ERROR ExtractSerialNumberFromX509Cert(const ByteSpan & certificate, MutableByteSpan & serialNumber)
{
#if defined(MBEDTLS_X509_CRT_PARSE_C)
CHIP_ERROR error = CHIP_NO_ERROR;
int result = 0;
uint8_t * p = nullptr;
size_t len = 0;
mbedtls_x509_crt mbed_cert;

mbedtls_x509_crt_init(&mbed_cert);

result = mbedtls_x509_crt_parse(&mbed_cert, Uint8::to_const_uchar(certificate.data()), certificate.size());
VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL);

p = mbed_cert.CHIP_CRYPTO_PAL_PRIVATE_X509(serial).CHIP_CRYPTO_PAL_PRIVATE_X509(p);
len = mbed_cert.CHIP_CRYPTO_PAL_PRIVATE_X509(serial).CHIP_CRYPTO_PAL_PRIVATE_X509(len);
VerifyOrExit(len <= serialNumber.size(), error = CHIP_ERROR_BUFFER_TOO_SMALL);

memcpy(serialNumber.data(), p, len);
serialNumber.reduce_size(len);

exit:
_log_mbedTLS_error(result);
mbedtls_x509_crt_free(&mbed_cert);

#else
(void) certificate;
(void) serialNumber;
CHIP_ERROR error = CHIP_ERROR_NOT_IMPLEMENTED;
#endif // defined(MBEDTLS_X509_CRT_PARSE_C)

return error;
}

CHIP_ERROR ExtractVIDPIDFromX509Cert(const ByteSpan & certificate, AttestationCertVidPid & vidpid)
{
#if defined(MBEDTLS_X509_CRT_PARSE_C)
Expand Down
36 changes: 35 additions & 1 deletion src/platform/silabs/SiWx917/CHIPCryptoPALTinyCrypt.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
*
* Copyright (c) 2020-2022 Project CHIP Authors
* Copyright (c) 2020-2023 Project CHIP Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -1604,6 +1604,40 @@ CHIP_ERROR ExtractAKIDFromX509Cert(const ByteSpan & certificate, MutableByteSpan
return ExtractKIDFromX509Cert(false, certificate, akid);
}

CHIP_ERROR ExtractSerialNumberFromX509Cert(const ByteSpan & certificate, MutableByteSpan & serialNumber)
{
#if defined(MBEDTLS_X509_CRT_PARSE_C)
CHIP_ERROR error = CHIP_NO_ERROR;
int result = 0;
uint8_t * p = nullptr;
size_t len = 0;
mbedtls_x509_crt mbed_cert;

mbedtls_x509_crt_init(&mbed_cert);

result = mbedtls_x509_crt_parse(&mbed_cert, Uint8::to_const_uchar(certificate.data()), certificate.size());
VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL);

p = mbed_cert.CHIP_CRYPTO_PAL_PRIVATE_X509(serial).CHIP_CRYPTO_PAL_PRIVATE_X509(p);
len = mbed_cert.CHIP_CRYPTO_PAL_PRIVATE_X509(serial).CHIP_CRYPTO_PAL_PRIVATE_X509(len);
VerifyOrExit(len <= serialNumber.size(), error = CHIP_ERROR_BUFFER_TOO_SMALL);

memcpy(serialNumber.data(), p, len);
serialNumber.reduce_size(len);

exit:
_log_mbedTLS_error(result);
mbedtls_x509_crt_free(&mbed_cert);

#else
(void) certificate;
(void) serialNumber;
CHIP_ERROR error = CHIP_ERROR_NOT_IMPLEMENTED;
#endif // defined(MBEDTLS_X509_CRT_PARSE_C)

return error;
}

CHIP_ERROR ExtractVIDPIDFromX509Cert(const ByteSpan & certificate, AttestationCertVidPid & vidpid)
{
#if defined(MBEDTLS_X509_CRT_PARSE_C)
Expand Down
Loading

0 comments on commit 18e3c6d

Please sign in to comment.