diff --git a/src/credentials/tests/CHIPCert_test_vectors.cpp b/src/credentials/tests/CHIPCert_test_vectors.cpp index f6c91258428883..f5fca309147fda 100644 --- a/src/credentials/tests/CHIPCert_test_vectors.cpp +++ b/src/credentials/tests/CHIPCert_test_vectors.cpp @@ -96,6 +96,7 @@ CHIP_ERROR GetTestCert(uint8_t certType, BitFlags certLoadFla SELECT_CERT(Node02_05); SELECT_CERT(Node02_06); SELECT_CERT(Node02_07); +#undef SELECT_CERT err = CHIP_ERROR_CA_CERT_NOT_FOUND; @@ -133,6 +134,44 @@ const char * GetTestCertName(uint8_t certType) return nullptr; } +CHIP_ERROR GetTestCertPubkey(uint8_t certType, const uint8_t *& certPubkey, uint32_t & certPubkeyLen) +{ + CHIP_ERROR err; + +#define SELECT_CERT(NAME) \ + do \ + { \ + if (certType == TestCert::k##NAME) \ + { \ + certPubkey = sTestCert_##NAME##_PublicKey; \ + certPubkeyLen = sTestCert_##NAME##_PublicKey_Len; \ + ExitNow(err = CHIP_NO_ERROR); \ + } \ + } while (0) + + SELECT_CERT(Root01); + SELECT_CERT(Root02); + SELECT_CERT(ICA01); + SELECT_CERT(ICA02); + SELECT_CERT(ICA01_1); + SELECT_CERT(FWSign01); + SELECT_CERT(Node01_01); + SELECT_CERT(Node01_02); + SELECT_CERT(Node02_01); + SELECT_CERT(Node02_02); + SELECT_CERT(Node02_03); + SELECT_CERT(Node02_04); + SELECT_CERT(Node02_05); + SELECT_CERT(Node02_06); + SELECT_CERT(Node02_07); +#undef SELECT_CERT + + err = CHIP_ERROR_CA_CERT_NOT_FOUND; + +exit: + return err; +} + CHIP_ERROR LoadTestCert(ChipCertificateSet & certSet, uint8_t certType, BitFlags certLoadFlags, BitFlags decodeFlags) { diff --git a/src/credentials/tests/CHIPCert_test_vectors.h b/src/credentials/tests/CHIPCert_test_vectors.h index b377adc769ba27..88b581ce08496c 100644 --- a/src/credentials/tests/CHIPCert_test_vectors.h +++ b/src/credentials/tests/CHIPCert_test_vectors.h @@ -71,6 +71,7 @@ enum class TestCertLoadFlags : uint8_t extern CHIP_ERROR GetTestCert(uint8_t certType, BitFlags certLoadFlags, const uint8_t *& certData, uint32_t & certDataLen); extern const char * GetTestCertName(uint8_t certType); +extern CHIP_ERROR GetTestCertPubkey(uint8_t certType, const uint8_t *& certPubkey, uint32_t & certPubkeyLen); extern CHIP_ERROR LoadTestCert(ChipCertificateSet & certSet, uint8_t certType, BitFlags certLoadFlags, BitFlags decodeFlags); diff --git a/src/crypto/CHIPCryptoPAL.h b/src/crypto/CHIPCryptoPAL.h index a54e1fbfcfe3c3..c242c4057b7bb4 100644 --- a/src/crypto/CHIPCryptoPAL.h +++ b/src/crypto/CHIPCryptoPAL.h @@ -29,6 +29,7 @@ #include #include +#include #include #include @@ -36,7 +37,7 @@ namespace chip { namespace Crypto { -const size_t kMax_x509_Certificate_Length = 1024; +const size_t kMax_x509_Certificate_Length = 600; const size_t kP256_FE_Length = 32; const size_t kP256_Point_Length = (2 * kP256_FE_Length + 1); @@ -911,6 +912,8 @@ CHIP_ERROR GetNumberOfCertsFromPKCS7(const uint8_t * pkcs7, uint32_t * n_certs); CHIP_ERROR ValidateCertificateChain(const uint8_t * rootCertificate, size_t rootCertificateLen, const uint8_t * caCertificate, size_t caCertificateLen, const uint8_t * leafCertificate, size_t leafCertificateLen); +CHIP_ERROR ExtractPubkeyFromX509Cert(const ByteSpan & certificate, Crypto::P256PublicKey & pubkey); + } // namespace Crypto } // namespace chip diff --git a/src/crypto/CHIPCryptoPALOpenSSL.cpp b/src/crypto/CHIPCryptoPALOpenSSL.cpp index 1579adf7dd092c..06f45ed98f0ba1 100644 --- a/src/crypto/CHIPCryptoPALOpenSSL.cpp +++ b/src/crypto/CHIPCryptoPALOpenSSL.cpp @@ -1584,7 +1584,6 @@ CHIP_ERROR LoadCertsFromPKCS7(const uint8_t * pkcs7, X509DerCertificate * x509li bio_cert = BIO_new_mem_buf(pkcs7, -1); p7 = PEM_read_bio_PKCS7(bio_cert, NULL, NULL, NULL); - // TODO -> error value VerifyOrExit(p7 != nullptr, err = CHIP_ERROR_WRONG_CERT_TYPE); p7_type = OBJ_obj2nid(p7->type); @@ -1597,7 +1596,6 @@ CHIP_ERROR LoadCertsFromPKCS7(const uint8_t * pkcs7, X509DerCertificate * x509li certs = p7->d.signed_and_enveloped->cert; } - // TODO -> error value VerifyOrExit(certs != NULL, err = CHIP_ERROR_WRONG_CERT_TYPE); VerifyOrExit(static_cast(sk_X509_num(certs)) <= *max_certs, err = CHIP_ERROR_WRONG_CERT_TYPE); @@ -1639,7 +1637,6 @@ CHIP_ERROR LoadCertFromPKCS7(const uint8_t * pkcs7, X509DerCertificate * x509lis bio_cert = BIO_new_mem_buf(pkcs7, -1); p7 = PEM_read_bio_PKCS7(bio_cert, NULL, NULL, NULL); - // TODO -> error value VerifyOrExit(p7 != nullptr, err = CHIP_ERROR_WRONG_CERT_TYPE); p7_type = OBJ_obj2nid(p7->type); @@ -1652,7 +1649,6 @@ CHIP_ERROR LoadCertFromPKCS7(const uint8_t * pkcs7, X509DerCertificate * x509lis certs = p7->d.signed_and_enveloped->cert; } - // TODO -> error value VerifyOrExit(certs != NULL, err = CHIP_ERROR_WRONG_CERT_TYPE); VerifyOrExit(n_cert < static_cast(sk_X509_num(certs)), err = CHIP_ERROR_INVALID_ARGUMENT); @@ -1691,7 +1687,6 @@ CHIP_ERROR GetNumberOfCertsFromPKCS7(const uint8_t * pkcs7, uint32_t * n_certs) bio_cert = BIO_new_mem_buf(pkcs7, -1); p7 = PEM_read_bio_PKCS7(bio_cert, NULL, NULL, NULL); - // TODO -> error value VerifyOrExit(p7 != nullptr, err = CHIP_ERROR_WRONG_CERT_TYPE); p7_type = OBJ_obj2nid(p7->type); @@ -1704,7 +1699,6 @@ CHIP_ERROR GetNumberOfCertsFromPKCS7(const uint8_t * pkcs7, uint32_t * n_certs) certs = p7->d.signed_and_enveloped->cert; } - // TODO -> error value VerifyOrExit(certs != NULL, err = CHIP_ERROR_WRONG_CERT_TYPE); *n_certs = static_cast(sk_X509_num(certs)); @@ -1765,5 +1759,36 @@ CHIP_ERROR ValidateCertificateChain(const uint8_t * rootCertificate, size_t root return err; } +CHIP_ERROR ExtractPubkeyFromX509Cert(const ByteSpan & certificate, Crypto::P256PublicKey & pubkey) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + EVP_PKEY * pkey = nullptr; + X509 * x509certificate = nullptr; + const unsigned char * pCertificate = certificate.data(); + const unsigned char ** ppCertificate = &pCertificate; + unsigned char * pPubkey = pubkey; + unsigned char ** ppPubkey = &pPubkey; + int pkeyLen; + + x509certificate = d2i_X509(NULL, ppCertificate, static_cast(certificate.size())); + VerifyOrExit(x509certificate != nullptr, err = CHIP_ERROR_NO_MEMORY); + + pkey = X509_get_pubkey(x509certificate); + VerifyOrExit(pkey != nullptr, err = CHIP_ERROR_INTERNAL); + VerifyOrExit(EVP_PKEY_base_id(pkey) == EVP_PKEY_EC, err = CHIP_ERROR_INTERNAL); + VerifyOrExit(EVP_PKEY_bits(pkey) == 256, err = CHIP_ERROR_INTERNAL); + + pkeyLen = i2d_PublicKey(pkey, NULL); + VerifyOrExit(pkeyLen == static_cast(pubkey.Length()), err = CHIP_ERROR_INTERNAL); + + VerifyOrExit(i2d_PublicKey(pkey, ppPubkey) == pkeyLen, err = CHIP_ERROR_INTERNAL); + +exit: + EVP_PKEY_free(pkey); + X509_free(x509certificate); + + return err; +} + } // namespace Crypto } // namespace chip diff --git a/src/crypto/CHIPCryptoPALmbedTLS.cpp b/src/crypto/CHIPCryptoPALmbedTLS.cpp index 3bc041be0273c5..389c8de075854a 100644 --- a/src/crypto/CHIPCryptoPALmbedTLS.cpp +++ b/src/crypto/CHIPCryptoPALmbedTLS.cpp @@ -1219,5 +1219,10 @@ CHIP_ERROR ValidateCertificateChain(const uint8_t * rootCertificate, size_t root return CHIP_ERROR_NOT_IMPLEMENTED; } +CHIP_ERROR ExtractPubkeyFromX509Cert(const ByteSpan & certificate, Crypto::P256PublicKey & pubkey) +{ + return CHIP_ERROR_NOT_IMPLEMENTED; +} + } // namespace Crypto } // namespace chip diff --git a/src/crypto/tests/BUILD.gn b/src/crypto/tests/BUILD.gn index 1c74d1aeaa8d33..dac85992799849 100644 --- a/src/crypto/tests/BUILD.gn +++ b/src/crypto/tests/BUILD.gn @@ -44,6 +44,7 @@ chip_test_suite("tests") { cflags = [ "-Wconversion" ] public_deps = [ + "${chip_root}/src/credentials/tests:cert_test_vectors", "${chip_root}/src/crypto", "${chip_root}/src/lib/core", "${chip_root}/src/platform", diff --git a/src/crypto/tests/CHIPCryptoPALTest.cpp b/src/crypto/tests/CHIPCryptoPALTest.cpp index 60f9b1d685cf3a..cbd82694009bff 100644 --- a/src/crypto/tests/CHIPCryptoPALTest.cpp +++ b/src/crypto/tests/CHIPCryptoPALTest.cpp @@ -32,7 +32,6 @@ #include "SPAKE2P_POINT_RW_test_vectors.h" #include "SPAKE2P_POINT_VALID_test_vectors.h" #include "SPAKE2P_RFC_test_vectors.h" -#include "X509_PKCS7Extraction_test_vectors.h" #include #if CHIP_CRYPTO_HSM @@ -50,6 +49,13 @@ #include #include +#if CHIP_CRYPTO_OPENSSL +#include "X509_PKCS7Extraction_test_vectors.h" +#endif + +#include +#include + #define HSM_ECC_KEYID 0x11223344 using namespace chip; @@ -1429,6 +1435,8 @@ static void TestSPAKE2P_RFC(nlTestSuite * inSuite, void * inContext) NL_TEST_ASSERT(inSuite, numOfTestsRan == numOfTestVectors); } +// TODO: Add mbedTLS implementation for PKCS7 and Pubkey Extraction methods +#if CHIP_CRYPTO_OPENSSL static void TestX509_PKCS7Extraction(nlTestSuite * inSuite, void * inContext) { CHIP_ERROR err = CHIP_NO_ERROR; @@ -1448,6 +1456,34 @@ static void TestX509_PKCS7Extraction(nlTestSuite * inSuite, void * inContext) NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); } +static void TestPubkey_x509Extraction(nlTestSuite * inSuite, void * inContext) +{ + using namespace TestCerts; + + CHIP_ERROR err = CHIP_NO_ERROR; + P256PublicKey publicKey; + + const uint8_t * cert; + uint32_t certLen; + const uint8_t * certPubkey; + uint32_t certPubkeyLen; + + for (size_t i = 0; i < gNumTestCerts; i++) + { + uint8_t certType = TestCerts::gTestCerts[i]; + + err = GetTestCert(certType, TestCertLoadFlags::kDERForm, cert, certLen); + NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); + err = GetTestCertPubkey(certType, certPubkey, certPubkeyLen); + NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); + + err = ExtractPubkeyFromX509Cert(ByteSpan(cert, certLen), publicKey); + NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); + NL_TEST_ASSERT(inSuite, memcmp(publicKey, certPubkey, certPubkeyLen) == 0); + } +} +#endif // CHIP_CRYPTO_OPENSSL + /** * Test Suite. It lists all the test functions. */ @@ -1502,7 +1538,10 @@ static const nlTest sTests[] = { NL_TEST_DEF("Test Spake2p_spake2p PointLoad/PointWrite", TestSPAKE2P_spake2p_PointLoadWrite), NL_TEST_DEF("Test Spake2p_spake2p PointIsValid", TestSPAKE2P_spake2p_PointIsValid), NL_TEST_DEF("Test Spake2+ against RFC test vectors", TestSPAKE2P_RFC), +#if CHIP_CRYPTO_OPENSSL NL_TEST_DEF("Test x509 Certificate Extraction from PKCS7", TestX509_PKCS7Extraction), + NL_TEST_DEF("Test Pubkey Extraction from x509 Certificate", TestPubkey_x509Extraction), +#endif // CHIP_CRYPTO_OPENSSL NL_TEST_SENTINEL() };