From 10895789e03019f399d2b66214a04a327bfb65af Mon Sep 17 00:00:00 2001 From: Tennessee Carmel-Veilleux Date: Thu, 19 May 2022 21:04:25 -0400 Subject: [PATCH] Implement CSR generation from first principles to support commissioners (#18631) * Implement CSR generation from first principles to support commissioners - When a commissioner is backing their key with OS or hardware support, the built-in P256Keypair::NewCertificateSigningRequest will not be usable since it relies on internal P256Keypair base class access to key state, as opposed to just using Pubkey() and ECDSA_sign_message primitives. This is OK on some embedded usecases that make use of P256Keypair backend directly, but not for many other usecases. - On iOS/Darwin and on native Android, backing the P256Keypair * by derived classes is bridgeable to platform APIs, but those platform APIs do not offer easy/direct CSR generation, and on Darwin, there are not ASN.1 APIs anymore. - If trying to make use of Darwin APIs introduced in #18519, there is no easy way to write code interfacing with an external CA to provide a CSR for a natively bridged keypair. This PR adds a first-principle CSR generator, written and audited by Google personel, using the ASN1Writer API already used in CHIPCert.h and used by all Commissioner code making use of SDK today. This is a straightforward implementation that directly uses a P256Keypair * (or a derived class thereof!) to generate a CSR against it, without depending on direct key access like like the native version P256Keypair::NewCerticateSigningRequest does. This PR also fixes constness of operations on P256Keypair. Issue #18444 Testing done: - Added unit tests for the new primitive - Validated generated CSR with OpenSSL - Validated equivalence to generated CSR from P256Keypair, on both mbedTLS and OpenSSL - Not used by CHIP-tool but usable by Darwin and Android framework users. * Update src/crypto/CHIPCryptoPAL.h Co-authored-by: Boris Zbarsky * Fix CI * Restyled by clang-format Co-authored-by: Boris Zbarsky Co-authored-by: Restyled.io --- src/crypto/BUILD.gn | 1 + src/crypto/CHIPCryptoPAL.cpp | 185 ++++++++++++++++++ src/crypto/CHIPCryptoPAL.h | 35 +++- src/crypto/CHIPCryptoPALOpenSSL.cpp | 6 +- src/crypto/CHIPCryptoPALmbedTLS.cpp | 6 +- .../hsm/nxp/CHIPCryptoPALHsm_SE05X_P256.cpp | 6 +- src/crypto/tests/CHIPCryptoPALTest.cpp | 60 +++++- .../Framework/CHIP/CHIPP256KeypairBridge.h | 8 +- .../Framework/CHIP/CHIPP256KeypairBridge.mm | 7 +- src/lib/asn1/gen_asn1oid.py | 2 + .../Darwin/CHIPP256KeypairNativeBridge.cpp | 7 +- .../Darwin/CHIPP256KeypairNativeBridge.h | 6 +- 12 files changed, 299 insertions(+), 30 deletions(-) diff --git a/src/crypto/BUILD.gn b/src/crypto/BUILD.gn index 12fca39ee39240..45ab4dc4355b68 100644 --- a/src/crypto/BUILD.gn +++ b/src/crypto/BUILD.gn @@ -70,6 +70,7 @@ static_library("crypto") { public_deps = [ ":crypto_buildconfig", + "${chip_root}/src/lib/asn1", "${chip_root}/src/lib/core", "${nlassert_root}:nlassert", ] diff --git a/src/crypto/CHIPCryptoPAL.cpp b/src/crypto/CHIPCryptoPAL.cpp index ed89f0dc50a724..f70a4ae5b86d93 100644 --- a/src/crypto/CHIPCryptoPAL.cpp +++ b/src/crypto/CHIPCryptoPAL.cpp @@ -21,6 +21,8 @@ */ #include "CHIPCryptoPAL.h" +#include +#include #include #include #include @@ -34,6 +36,8 @@ using chip::MutableByteSpan; using chip::Encoding::BufferWriter; using chip::Encoding::LittleEndian::Reader; +using namespace chip::ASN1; + namespace { constexpr uint8_t kIntegerTag = 0x02u; @@ -869,5 +873,186 @@ CHIP_ERROR ExtractVIDPIDFromAttributeString(DNAttrType attrType, const ByteSpan return CHIP_NO_ERROR; } +// Generates the to-be-signed portion of a PKCS#10 CSR (`CertificationRequestInformation`) +// that contains the +static CHIP_ERROR GenerateCertificationRequestInformation(ASN1Writer & writer, const Crypto::P256PublicKey & pubkey) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + /** + * + * CertificationRequestInfo ::= + * SEQUENCE { + * version INTEGER { v1(0) } (v1,...), + * subject Name, + * subjectPKInfo SubjectPublicKeyInfo{{ PKInfoAlgorithms }}, + * attributes [0] Attributes{{ CRIAttributes }} + * } + */ + ASN1_START_SEQUENCE + { + ASN1_ENCODE_INTEGER(0); // version INTEGER { v1(0) } + + // subject Name + ASN1_START_SEQUENCE + { + ASN1_START_SET + { + ASN1_START_SEQUENCE + { + // Any subject, placeholder is good, since this + // is going to usually be ignored + ASN1_ENCODE_OBJECT_ID(kOID_AttributeType_OrganizationalUnitName); + ASN1_ENCODE_STRING(kASN1UniversalTag_UTF8String, "CSA", static_cast(strlen("CSA"))); + } + ASN1_END_SEQUENCE; + } + ASN1_END_SET; + } + ASN1_END_SEQUENCE; + + // subjectPKInfo + ASN1_START_SEQUENCE + { + ASN1_START_SEQUENCE + { + ASN1_ENCODE_OBJECT_ID(kOID_PubKeyAlgo_ECPublicKey); + ASN1_ENCODE_OBJECT_ID(kOID_EllipticCurve_prime256v1); + } + ASN1_END_SEQUENCE; + ReturnErrorOnFailure(writer.PutBitString(0, pubkey, static_cast(pubkey.Length()))); + } + ASN1_END_SEQUENCE; + + // attributes [0] + ASN1_START_CONSTRUCTED(kASN1TagClass_ContextSpecific, 0) + { + // Using a plain empty attributes request + ASN1_START_SEQUENCE + { + ASN1_ENCODE_OBJECT_ID(kOID_Extension_CSRRequest); + ASN1_START_SET + { + ASN1_START_SEQUENCE {} + ASN1_END_SEQUENCE; + } + ASN1_END_SET; + } + ASN1_END_SEQUENCE; + } + ASN1_END_CONSTRUCTED; + } + ASN1_END_SEQUENCE; +exit: + return err; +} + +CHIP_ERROR GenerateCertificateSigningRequest(const P256Keypair * keypair, MutableByteSpan & csr_span) +{ + VerifyOrReturnError(keypair != nullptr, CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(csr_span.size() >= kMAX_CSR_Length, CHIP_ERROR_BUFFER_TOO_SMALL); + + // First pass: Generate the CertificatioRequestInformation inner + // encoding one time, to sign it, before re-generating it within the + // full ASN1 writer later, since it's easier than trying to + // figure-out the span we need to sign of the overall object. + P256ECDSASignature signature; + + { + // The first pass will just generate a signature, so we can use the + // output buffer as scratch to avoid needing more stack space. There + // are no secrets here and the contents is not reused since all we + // need is the signature which is already separately stored. + ASN1Writer toBeSignedWriter; + toBeSignedWriter.Init(csr_span); + CHIP_ERROR err = GenerateCertificationRequestInformation(toBeSignedWriter, keypair->Pubkey()); + ReturnErrorOnFailure(err); + + size_t encodedLen = (uint16_t) toBeSignedWriter.GetLengthWritten(); + // This should not/will not happen + if (encodedLen > csr_span.size()) + { + return CHIP_ERROR_INTERNAL; + } + + err = keypair->ECDSA_sign_msg(csr_span.data(), encodedLen, signature); + ReturnErrorOnFailure(err); + } + + // Second pass: Generate the entire CSR body, restarting a new write + // of the CertificationRequestInformation (cheap) and adding the + // signature. + // + // See RFC2986 for ASN.1 module, repeated here in snippets + CHIP_ERROR err = CHIP_NO_ERROR; + + ASN1Writer writer; + writer.Init(csr_span); + + ASN1_START_SEQUENCE + { + + /* CertificationRequestInfo ::= + * SEQUENCE { + * version INTEGER { v1(0) } (v1,...), + * subject Name, + * subjectPKInfo SubjectPublicKeyInfo{{ PKInfoAlgorithms }}, + * attributes [0] Attributes{{ CRIAttributes }} + * } + */ + GenerateCertificationRequestInformation(writer, keypair->Pubkey()); + + // algorithm AlgorithmIdentifier + ASN1_START_SEQUENCE + { + // See RFC5480 sec 2.1 + ASN1_ENCODE_OBJECT_ID(kOID_SigAlgo_ECDSAWithSHA256); + } + ASN1_END_SEQUENCE; + + // signature BIT STRING --> ECDSA-with-SHA256 signature with P256 key with R,S integers format + // (see RFC3279 sec 2.2.3 ECDSA Signature Algorithm) + ASN1_START_BIT_STRING_ENCAPSULATED + { + // Convert raw signature to embedded signature + FixedByteSpan rawSig(signature.Bytes()); + + uint8_t derInt[kP256_FE_Length + kEmitDerIntegerWithoutTagOverhead]; + + // Ecdsa-Sig-Value ::= SEQUENCE + ASN1_START_SEQUENCE + { + using P256IntegerSpan = FixedByteSpan; + // r INTEGER + { + MutableByteSpan derIntSpan(derInt, sizeof(derInt)); + ReturnErrorOnFailure(ConvertIntegerRawToDerWithoutTag(P256IntegerSpan(rawSig.data()), derIntSpan)); + ReturnErrorOnFailure(writer.PutValue(kASN1TagClass_Universal, kASN1UniversalTag_Integer, false, + derIntSpan.data(), static_cast(derIntSpan.size()))); + } + + // s INTEGER + { + MutableByteSpan derIntSpan(derInt, sizeof(derInt)); + ReturnErrorOnFailure( + ConvertIntegerRawToDerWithoutTag(P256IntegerSpan(rawSig.data() + kP256_FE_Length), derIntSpan)); + ReturnErrorOnFailure(writer.PutValue(kASN1TagClass_Universal, kASN1UniversalTag_Integer, false, + derIntSpan.data(), static_cast(derIntSpan.size()))); + } + } + ASN1_END_SEQUENCE; + } + ASN1_END_ENCAPSULATED; + } + ASN1_END_SEQUENCE; + +exit: + // Update size of output buffer on success + if (err == CHIP_NO_ERROR) + { + csr_span.reduce_size(writer.GetLengthWritten()); + } + return err; +} + } // namespace Crypto } // namespace chip diff --git a/src/crypto/CHIPCryptoPAL.h b/src/crypto/CHIPCryptoPAL.h index 41aea26aff09a4..d89c42af6e9d52 100644 --- a/src/crypto/CHIPCryptoPAL.h +++ b/src/crypto/CHIPCryptoPAL.h @@ -322,7 +322,7 @@ class ECPKeypair *CSR. * @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise **/ - virtual CHIP_ERROR NewCertificateSigningRequest(uint8_t * csr, size_t & csr_length) = 0; + virtual CHIP_ERROR NewCertificateSigningRequest(uint8_t * csr, size_t & csr_length) const = 0; /** * @brief A function to sign a msg using ECDSA @@ -332,7 +332,7 @@ class ECPKeypair * in raw point form (see SEC1). * @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise **/ - virtual CHIP_ERROR ECDSA_sign_msg(const uint8_t * msg, size_t msg_length, Sig & out_signature) = 0; + virtual CHIP_ERROR ECDSA_sign_msg(const uint8_t * msg, size_t msg_length, Sig & out_signature) const = 0; /** * @brief A function to sign a hash using ECDSA @@ -342,7 +342,7 @@ class ECPKeypair * in raw point form (see SEC1). * @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise **/ - virtual CHIP_ERROR ECDSA_sign_hash(const uint8_t * hash, size_t hash_length, Sig & out_signature) = 0; + virtual CHIP_ERROR ECDSA_sign_hash(const uint8_t * hash, size_t hash_length, Sig & out_signature) const = 0; /** @brief A function to derive a shared secret using ECDH * @param remote_public_key Public key of remote peer with which we are trying to establish secure channel. remote_public_key is @@ -416,7 +416,7 @@ class P256Keypair : public P256KeypairBase *CSR. * @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise **/ - CHIP_ERROR NewCertificateSigningRequest(uint8_t * csr, size_t & csr_length) override; + CHIP_ERROR NewCertificateSigningRequest(uint8_t * csr, size_t & csr_length) const override; /** * @brief A function to sign a msg using ECDSA @@ -426,7 +426,7 @@ class P256Keypair : public P256KeypairBase * in raw point form (see SEC1). * @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise **/ - CHIP_ERROR ECDSA_sign_msg(const uint8_t * msg, size_t msg_length, P256ECDSASignature & out_signature) override; + CHIP_ERROR ECDSA_sign_msg(const uint8_t * msg, size_t msg_length, P256ECDSASignature & out_signature) const override; /** * @brief A function to sign a hash using ECDSA @@ -436,7 +436,7 @@ class P256Keypair : public P256KeypairBase * in raw point form (see SEC1). * @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise **/ - CHIP_ERROR ECDSA_sign_hash(const uint8_t * hash, size_t hash_length, P256ECDSASignature & out_signature) override; + CHIP_ERROR ECDSA_sign_hash(const uint8_t * hash, size_t hash_length, P256ECDSASignature & out_signature) const override; /** * @brief A function to derive a shared secret using ECDH @@ -462,7 +462,7 @@ class P256Keypair : public P256KeypairBase private: P256PublicKey mPublicKey; - P256KeypairContext mKeypair; + mutable P256KeypairContext mKeypair; bool mInitialized = false; }; @@ -616,6 +616,27 @@ CHIP_ERROR AES_CCM_decrypt(const uint8_t * ciphertext, size_t ciphertext_length, const uint8_t * tag, size_t tag_length, const uint8_t * key, size_t key_length, const uint8_t * nonce, size_t nonce_length, uint8_t * plaintext); +/** + * @brief Generate a PKCS#10 CSR, usable for Matter, from a P256Keypair. + * + * This uses first principles ASN.1 encoding to avoid relying on the CHIPCryptoPAL backend + * itself, other than to provide an implementation of a P256Keypair * that supports + * at least `::Pubkey()` and `::ECDSA_sign_msg`. This allows using it with + * OS/Platform-bridged private key handling, without requiring a specific + * implementation of other bits like ASN.1. + * + * The CSR will have subject OU set to `CSA`. This is needed since omiting + * subject altogether often trips CSR parsing code. The profile at the CA can + * be configured to ignore CSR requested subject. + * + * @param keypair The key pair for which a CSR should be generated. Must not be null. + * @param csr_span Span to hold the resulting CSR. Must be at least kMAX_CSR_Length. Otherwise returns CHIP_ERROR_BUFFER_TOO_SMALL. + * It will get resized to actual size needed on success. + + * @return Returns a CHIP_ERROR from P256Keypair or ASN.1 backend on error, CHIP_NO_ERROR otherwise + **/ +CHIP_ERROR GenerateCertificateSigningRequest(const P256Keypair * keypair, MutableByteSpan & csr_span); + /** * @brief Verify the Certificate Signing Request (CSR). If successfully verified, it outputs the public key from the CSR. * @param csr CSR in DER format diff --git a/src/crypto/CHIPCryptoPALOpenSSL.cpp b/src/crypto/CHIPCryptoPALOpenSSL.cpp index ce69bb7202ca91..b03c3564a8d964 100644 --- a/src/crypto/CHIPCryptoPALOpenSSL.cpp +++ b/src/crypto/CHIPCryptoPALOpenSSL.cpp @@ -609,7 +609,7 @@ static inline const EC_KEY * to_const_EC_KEY(const P256KeypairContext * context) return *SafePointerCast(context); } -CHIP_ERROR P256Keypair::ECDSA_sign_msg(const uint8_t * msg, const size_t msg_length, P256ECDSASignature & out_signature) +CHIP_ERROR P256Keypair::ECDSA_sign_msg(const uint8_t * msg, const size_t msg_length, P256ECDSASignature & out_signature) const { VerifyOrReturnError((msg != nullptr) && (msg_length > 0), CHIP_ERROR_INVALID_ARGUMENT); @@ -620,7 +620,7 @@ CHIP_ERROR P256Keypair::ECDSA_sign_msg(const uint8_t * msg, const size_t msg_len return ECDSA_sign_hash(&digest[0], sizeof(digest), out_signature); } -CHIP_ERROR P256Keypair::ECDSA_sign_hash(const uint8_t * hash, const size_t hash_length, P256ECDSASignature & out_signature) +CHIP_ERROR P256Keypair::ECDSA_sign_hash(const uint8_t * hash, const size_t hash_length, P256ECDSASignature & out_signature) const { ERR_clear_error(); @@ -1110,7 +1110,7 @@ P256Keypair::~P256Keypair() Clear(); } -CHIP_ERROR P256Keypair::NewCertificateSigningRequest(uint8_t * out_csr, size_t & csr_length) +CHIP_ERROR P256Keypair::NewCertificateSigningRequest(uint8_t * out_csr, size_t & csr_length) const { ERR_clear_error(); CHIP_ERROR error = CHIP_NO_ERROR; diff --git a/src/crypto/CHIPCryptoPALmbedTLS.cpp b/src/crypto/CHIPCryptoPALmbedTLS.cpp index 970e5a74018134..56a33edb85a5d9 100644 --- a/src/crypto/CHIPCryptoPALmbedTLS.cpp +++ b/src/crypto/CHIPCryptoPALmbedTLS.cpp @@ -503,7 +503,7 @@ static inline const mbedtls_ecp_keypair * to_const_keypair(const P256KeypairCont return SafePointerCast(context); } -CHIP_ERROR P256Keypair::ECDSA_sign_msg(const uint8_t * msg, const size_t msg_length, P256ECDSASignature & out_signature) +CHIP_ERROR P256Keypair::ECDSA_sign_msg(const uint8_t * msg, const size_t msg_length, P256ECDSASignature & out_signature) const { #if defined(MBEDTLS_ECDSA_C) VerifyOrReturnError(mInitialized, CHIP_ERROR_INCORRECT_STATE); @@ -519,7 +519,7 @@ CHIP_ERROR P256Keypair::ECDSA_sign_msg(const uint8_t * msg, const size_t msg_len #endif } -CHIP_ERROR P256Keypair::ECDSA_sign_hash(const uint8_t * hash, const size_t hash_length, P256ECDSASignature & out_signature) +CHIP_ERROR P256Keypair::ECDSA_sign_hash(const uint8_t * hash, const size_t hash_length, P256ECDSASignature & out_signature) const { #if defined(MBEDTLS_ECDSA_C) VerifyOrReturnError(mInitialized, CHIP_ERROR_INCORRECT_STATE); @@ -812,7 +812,7 @@ P256Keypair::~P256Keypair() Clear(); } -CHIP_ERROR P256Keypair::NewCertificateSigningRequest(uint8_t * out_csr, size_t & csr_length) +CHIP_ERROR P256Keypair::NewCertificateSigningRequest(uint8_t * out_csr, size_t & csr_length) const { CHIP_ERROR error = CHIP_NO_ERROR; diff --git a/src/crypto/hsm/nxp/CHIPCryptoPALHsm_SE05X_P256.cpp b/src/crypto/hsm/nxp/CHIPCryptoPALHsm_SE05X_P256.cpp index 5ef2fa88183207..a3e451e15429b8 100644 --- a/src/crypto/hsm/nxp/CHIPCryptoPALHsm_SE05X_P256.cpp +++ b/src/crypto/hsm/nxp/CHIPCryptoPALHsm_SE05X_P256.cpp @@ -121,7 +121,7 @@ CHIP_ERROR P256KeypairHSM::Initialize() return CHIP_NO_ERROR; } -CHIP_ERROR P256KeypairHSM::ECDSA_sign_msg(const uint8_t * msg, size_t msg_length, P256ECDSASignature & out_signature) +CHIP_ERROR P256KeypairHSM::ECDSA_sign_msg(const uint8_t * msg, size_t msg_length, P256ECDSASignature & out_signature) const { CHIP_ERROR error = CHIP_ERROR_INTERNAL; sss_digest_t digest_ctx = { 0 }; @@ -205,7 +205,7 @@ CHIP_ERROR P256KeypairHSM::ECDSA_sign_msg(const uint8_t * msg, size_t msg_length return error; } -CHIP_ERROR P256KeypairHSM::ECDSA_sign_hash(const uint8_t * hash, size_t hash_length, P256ECDSASignature & out_signature) +CHIP_ERROR P256KeypairHSM::ECDSA_sign_hash(const uint8_t * hash, size_t hash_length, P256ECDSASignature & out_signature) const { CHIP_ERROR error = CHIP_ERROR_INTERNAL; sss_asymmetric_t asymm_ctx = { 0 }; @@ -574,7 +574,7 @@ static void add_tlv(uint8_t * buf, size_t buf_index, uint8_t tag, size_t len, ui * */ -CHIP_ERROR P256KeypairHSM::NewCertificateSigningRequest(uint8_t * csr, size_t & csr_length) +CHIP_ERROR P256KeypairHSM::NewCertificateSigningRequest(uint8_t * csr, size_t & csr_length) const { CHIP_ERROR error = CHIP_ERROR_INTERNAL; sss_status_t status = kStatus_SSS_Success; diff --git a/src/crypto/tests/CHIPCryptoPALTest.cpp b/src/crypto/tests/CHIPCryptoPALTest.cpp index 588af82a6d545d..eb95e9d9d8a7b6 100644 --- a/src/crypto/tests/CHIPCryptoPALTest.cpp +++ b/src/crypto/tests/CHIPCryptoPALTest.cpp @@ -64,8 +64,19 @@ #define HSM_ECC_KEYID 0x11223344 +#include +#include +#include + +#include +#include +#include +#include +#include + using namespace chip; using namespace chip::Crypto; +using namespace chip::TLV; namespace { @@ -1286,7 +1297,51 @@ static void TestP256_Keygen(nlTestSuite * inSuite, void * inContext) NL_TEST_ASSERT(inSuite, keypair.Pubkey().ECDSA_validate_msg_signature(test_msg, msglen, test_sig) == CHIP_NO_ERROR); } -static void TestCSR_Gen(nlTestSuite * inSuite, void * inContext) +void TestCSR_GenDirect(nlTestSuite * inSuite, void * inContext) +{ + uint8_t csrBuf[kMAX_CSR_Length]; + ClearSecretData(csrBuf); + MutableByteSpan csrSpan(csrBuf); + + Test_P256Keypair keypair; + + NL_TEST_ASSERT(inSuite, keypair.Initialize() == CHIP_NO_ERROR); + + // Validate case of buffer too small + uint8_t csrBufTooSmall[kMAX_CSR_Length - 1]; + MutableByteSpan csrSpanTooSmall(csrBufTooSmall); + NL_TEST_ASSERT(inSuite, GenerateCertificateSigningRequest(&keypair, csrSpanTooSmall) == CHIP_ERROR_BUFFER_TOO_SMALL); + + // Validate case of null keypair + NL_TEST_ASSERT(inSuite, GenerateCertificateSigningRequest(nullptr, csrSpan) == CHIP_ERROR_INVALID_ARGUMENT); + + // Validate normal case + ClearSecretData(csrBuf); + NL_TEST_ASSERT(inSuite, GenerateCertificateSigningRequest(&keypair, csrSpan) == CHIP_NO_ERROR); + + P256PublicKey pubkey; + + CHIP_ERROR err = VerifyCertificateSigningRequest(csrSpan.data(), csrSpan.size(), pubkey); + if (err != CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE) + { + NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); + NL_TEST_ASSERT(inSuite, pubkey.Length() == kP256_PublicKey_Length); + NL_TEST_ASSERT(inSuite, memcmp(pubkey.ConstBytes(), keypair.Pubkey().ConstBytes(), pubkey.Length()) == 0); + + // Let's corrupt the CSR buffer and make sure it fails to verify + size_t length = csrSpan.size(); + csrBuf[length - 2] = (uint8_t)(csrBuf[length - 2] + 1); + csrBuf[length - 1] = (uint8_t)(csrBuf[length - 1] + 1); + + NL_TEST_ASSERT(inSuite, VerifyCertificateSigningRequest(csrSpan.data(), csrSpan.size(), pubkey) != CHIP_NO_ERROR); + } + else + { + ChipLogError(Crypto, "The current platform does not support CSR parsing."); + } +} + +static void TestCSR_GenByKeypair(nlTestSuite * inSuite, void * inContext) { HeapChecker heapChecker(inSuite); uint8_t csr[kMAX_CSR_Length]; @@ -2363,7 +2418,8 @@ static const nlTest sTests[] = { NL_TEST_DEF("Test adding entropy sources", TestAddEntropySources), NL_TEST_DEF("Test PBKDF2 SHA256", TestPBKDF2_SHA256_TestVectors), NL_TEST_DEF("Test P256 Keygen", TestP256_Keygen), - NL_TEST_DEF("Test CSR Generation", TestCSR_Gen), + NL_TEST_DEF("Test CSR Generation via P256Keypair method", TestCSR_GenByKeypair), + NL_TEST_DEF("Test Direct CSR Generation", TestCSR_GenDirect), NL_TEST_DEF("Test Keypair Serialize", TestKeypair_Serialize), NL_TEST_DEF("Test Spake2p_spake2p FEMul", TestSPAKE2P_spake2p_FEMul), NL_TEST_DEF("Test Spake2p_spake2p FELoad/FEWrite", TestSPAKE2P_spake2p_FELoadWrite), diff --git a/src/darwin/Framework/CHIP/CHIPP256KeypairBridge.h b/src/darwin/Framework/CHIP/CHIPP256KeypairBridge.h index b1beb7a846e168..738d035eb1daf1 100644 --- a/src/darwin/Framework/CHIP/CHIPP256KeypairBridge.h +++ b/src/darwin/Framework/CHIP/CHIPP256KeypairBridge.h @@ -37,11 +37,13 @@ class CHIPP256KeypairBridge : public chip::Crypto::P256KeypairBase CHIP_ERROR Deserialize(chip::Crypto::P256SerializedKeypair & input) override; - CHIP_ERROR NewCertificateSigningRequest(uint8_t * csr, size_t & csr_length) override; + CHIP_ERROR NewCertificateSigningRequest(uint8_t * csr, size_t & csr_length) const override; - CHIP_ERROR ECDSA_sign_msg(const uint8_t * msg, size_t msg_length, chip::Crypto::P256ECDSASignature & out_signature) override; + CHIP_ERROR ECDSA_sign_msg(const uint8_t * msg, size_t msg_length, + chip::Crypto::P256ECDSASignature & out_signature) const override; - CHIP_ERROR ECDSA_sign_hash(const uint8_t * hash, size_t hash_length, chip::Crypto::P256ECDSASignature & out_signature) override; + CHIP_ERROR ECDSA_sign_hash(const uint8_t * hash, size_t hash_length, + chip::Crypto::P256ECDSASignature & out_signature) const override; CHIP_ERROR ECDH_derive_secret(const chip::Crypto::P256PublicKey & remote_public_key, chip::Crypto::P256ECDHDerivedSecret & out_secret) const override; diff --git a/src/darwin/Framework/CHIP/CHIPP256KeypairBridge.mm b/src/darwin/Framework/CHIP/CHIPP256KeypairBridge.mm index e9e5c2f055c31c..47a25f1defcb75 100644 --- a/src/darwin/Framework/CHIP/CHIPP256KeypairBridge.mm +++ b/src/darwin/Framework/CHIP/CHIPP256KeypairBridge.mm @@ -66,7 +66,7 @@ return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; } -CHIP_ERROR CHIPP256KeypairBridge::NewCertificateSigningRequest(uint8_t * csr, size_t & csr_length) +CHIP_ERROR CHIPP256KeypairBridge::NewCertificateSigningRequest(uint8_t * csr, size_t & csr_length) const { if (!HasKeypair()) { return CHIP_ERROR_INCORRECT_STATE; @@ -75,7 +75,7 @@ return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; } -CHIP_ERROR CHIPP256KeypairBridge::ECDSA_sign_msg(const uint8_t * msg, size_t msg_length, P256ECDSASignature & out_signature) +CHIP_ERROR CHIPP256KeypairBridge::ECDSA_sign_msg(const uint8_t * msg, size_t msg_length, P256ECDSASignature & out_signature) const { if (!HasKeypair()) { CHIP_LOG_ERROR("ECDSA sign msg failure: no keypair to sign with."); @@ -121,7 +121,8 @@ return CHIP_NO_ERROR; } -CHIP_ERROR CHIPP256KeypairBridge::ECDSA_sign_hash(const uint8_t * hash, size_t hash_length, P256ECDSASignature & out_signature) +CHIP_ERROR CHIPP256KeypairBridge::ECDSA_sign_hash( + const uint8_t * hash, size_t hash_length, P256ECDSASignature & out_signature) const { if (!HasKeypair()) { return CHIP_ERROR_INCORRECT_STATE; diff --git a/src/lib/asn1/gen_asn1oid.py b/src/lib/asn1/gen_asn1oid.py index 2566a67bc0a1a9..a2e71c171b40db 100755 --- a/src/lib/asn1/gen_asn1oid.py +++ b/src/lib/asn1/gen_asn1oid.py @@ -162,6 +162,8 @@ def identity(n): 4, [joint_iso_ccitt(2), ds(5), 29, 14]), ("Extension", "AuthorityKeyIdentifier", 5, [joint_iso_ccitt(2), ds(5), 29, 35]), + ("Extension", "CSRRequest", + 6, [iso(1), member_body(2), us(840), rsadsi(113549), pkcs(1), 9, 14]), # Key Purposes ("KeyPurpose", "ServerAuth", 1, [iso(1), organization( diff --git a/src/platform/Darwin/CHIPP256KeypairNativeBridge.cpp b/src/platform/Darwin/CHIPP256KeypairNativeBridge.cpp index 650f3d70951620..7a55abaee27b79 100644 --- a/src/platform/Darwin/CHIPP256KeypairNativeBridge.cpp +++ b/src/platform/Darwin/CHIPP256KeypairNativeBridge.cpp @@ -36,13 +36,14 @@ CHIP_ERROR CHIPP256KeypairNativeBridge::Deserialize(P256SerializedKeypair & inpu return mKeypairBase.Deserialize(input); } -CHIP_ERROR CHIPP256KeypairNativeBridge::ECDSA_sign_msg(const uint8_t * msg, size_t msg_length, P256ECDSASignature & out_signature) +CHIP_ERROR CHIPP256KeypairNativeBridge::ECDSA_sign_msg(const uint8_t * msg, size_t msg_length, + P256ECDSASignature & out_signature) const { return mKeypairBase.ECDSA_sign_msg(msg, msg_length, out_signature); } CHIP_ERROR CHIPP256KeypairNativeBridge::ECDSA_sign_hash(const uint8_t * hash, size_t hash_length, - P256ECDSASignature & out_signature) + P256ECDSASignature & out_signature) const { return mKeypairBase.ECDSA_sign_hash(hash, hash_length, out_signature); } @@ -53,7 +54,7 @@ CHIP_ERROR CHIPP256KeypairNativeBridge::ECDH_derive_secret(const P256PublicKey & return mKeypairBase.ECDH_derive_secret(remote_public_key, out_secret); } -CHIP_ERROR CHIPP256KeypairNativeBridge::NewCertificateSigningRequest(uint8_t * csr, size_t & csr_length) +CHIP_ERROR CHIPP256KeypairNativeBridge::NewCertificateSigningRequest(uint8_t * csr, size_t & csr_length) const { return mKeypairBase.NewCertificateSigningRequest(csr, csr_length); } diff --git a/src/platform/Darwin/CHIPP256KeypairNativeBridge.h b/src/platform/Darwin/CHIPP256KeypairNativeBridge.h index 3b51cafd29d620..629006bf1e2bd9 100644 --- a/src/platform/Darwin/CHIPP256KeypairNativeBridge.h +++ b/src/platform/Darwin/CHIPP256KeypairNativeBridge.h @@ -41,13 +41,13 @@ class CHIPP256KeypairNativeBridge : public P256Keypair CHIP_ERROR Deserialize(P256SerializedKeypair & input) override; - CHIP_ERROR ECDSA_sign_msg(const uint8_t * msg, size_t msg_length, P256ECDSASignature & out_signature) override; + CHIP_ERROR ECDSA_sign_msg(const uint8_t * msg, size_t msg_length, P256ECDSASignature & out_signature) const override; - CHIP_ERROR ECDSA_sign_hash(const uint8_t * hash, size_t hash_length, P256ECDSASignature & out_signature) override; + CHIP_ERROR ECDSA_sign_hash(const uint8_t * hash, size_t hash_length, P256ECDSASignature & out_signature) const override; CHIP_ERROR ECDH_derive_secret(const P256PublicKey & remote_public_key, P256ECDHDerivedSecret & out_secret) const override; - CHIP_ERROR NewCertificateSigningRequest(uint8_t * csr, size_t & csr_length) override; + CHIP_ERROR NewCertificateSigningRequest(uint8_t * csr, size_t & csr_length) const override; const P256PublicKey & Pubkey() const override { return mKeypairBase.Pubkey(); }