diff --git a/tests/api.c b/tests/api.c index e67f38f7d..60db1b4fb 100644 --- a/tests/api.c +++ b/tests/api.c @@ -22755,6 +22755,151 @@ static int test_wc_GetPubKeyDerFromCert(void) return EXPECT_RESULT(); } +static int test_wc_GetSubjectPubKeyInfoDerFromCert(void) +{ + EXPECT_DECLS; +#if !defined(NO_RSA) || defined(HAVE_ECC) + int ret; + word32 idx = 0; + byte keyDer[TWOK_BUF]; /* large enough for up to RSA 2048 */ + word32 keyDerSz = (word32)sizeof(keyDer); +#if !defined(NO_RSA) && defined(WOLFSSL_CERT_REQ) && !defined(NO_FILESYSTEM) + byte certBuf[6000]; /* for PEM and CSR, client-cert.pem is 5-6kB */ + word32 certBufSz = sizeof(certBuf); +#endif +#if ((!defined(USE_CERT_BUFFERS_2048) && !defined(USE_CERT_BUFFERS_1024)) || \ + defined(WOLFSSL_CERT_REQ)) && !defined(NO_RSA) && !defined(NO_FILESYSTEM) + XFILE fp = XBADFILE; +#endif +#ifndef NO_RSA + RsaKey rsaKey; + #if defined(USE_CERT_BUFFERS_2048) + byte* rsaCertDer = (byte*)client_cert_der_2048; + word32 rsaCertDerSz = sizeof_client_cert_der_2048; + #elif defined(USE_CERT_BUFFERS_1024) + byte* rsaCertDer = (byte*)client_cert_der_1024; + word32 rsaCertDerSz = sizeof_client_cert_der_1024; + #else + unsigned char rsaCertDer[TWOK_BUF]; + word32 rsaCertDerSz; + #endif +#endif +#ifdef HAVE_ECC + ecc_key eccKey; + #if defined(USE_CERT_BUFFERS_256) + byte* eccCert = (byte*)cliecc_cert_der_256; + word32 eccCertSz = sizeof_cliecc_cert_der_256; + #else + unsigned char eccCert[ONEK_BUF]; + word32 eccCertSz; + XFILE fp2 = XBADFILE; + #endif +#endif + +#ifndef NO_RSA + +#if !defined(USE_CERT_BUFFERS_1024) && !defined(USE_CERT_BUFFERS_2048) + ExpectTrue((fp = XFOPEN("./certs/1024/client-cert.der", "rb")) != XBADFILE); + ExpectIntGT(rsaCertDerSz = (word32)XFREAD(rsaCertDer, 1, sizeof(rsaCertDer), + fp), 0); + if (fp != XBADFILE) { + XFCLOSE(fp); + fp = XBADFILE; + } +#endif + + /* good test case - RSA DER cert */ + ExpectIntEQ(wc_GetSubjectPubKeyInfoDerFromCert(rsaCertDer, rsaCertDerSz, + keyDer, &keyDerSz), 0); + ExpectIntGT(keyDerSz, 0); + + /* sanity check, verify we can import DER public key */ + ret = wc_InitRsaKey(&rsaKey, HEAP_HINT); + ExpectIntEQ(ret, 0); + ExpectIntEQ(wc_RsaPublicKeyDecode(keyDer, &idx, &rsaKey, keyDerSz), 0); + if (ret == 0) { + wc_FreeRsaKey(&rsaKey); + } + + /* bad args: certDer */ + keyDerSz = (word32)sizeof(keyDer); + ExpectIntEQ(wc_GetSubjectPubKeyInfoDerFromCert(NULL, rsaCertDerSz, keyDer, + &keyDerSz), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + /* bad args: 0 sized certSz */ + keyDerSz = (word32)sizeof(keyDer); + ExpectIntEQ(wc_GetSubjectPubKeyInfoDerFromCert(rsaCertDer, 0, keyDer, + &keyDerSz), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + /* bad args: NULL inout size */ + ExpectIntEQ(ret = wc_GetSubjectPubKeyInfoDerFromCert(rsaCertDer, + rsaCertDerSz, keyDer, + NULL), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + /* Certificate Request Tests */ + #if defined(WOLFSSL_CERT_REQ) && !defined(NO_FILESYSTEM) + { + XMEMSET(certBuf, 0, sizeof(certBuf)); + ExpectTrue((fp = XFOPEN("./certs/csr.signed.der", "rb")) != XBADFILE); + ExpectIntGT(certBufSz = (word32)XFREAD(certBuf, 1, certBufSz, fp), 0); + if (fp != XBADFILE) { + XFCLOSE(fp); + } + + /* good test case - RSA DER certificate request */ + keyDerSz = sizeof(keyDer); + ExpectIntEQ(ret = wc_GetSubjectPubKeyInfoDerFromCert(rsaCertDer, + rsaCertDerSz, + keyDer, + &keyDerSz), 0); + ExpectIntGT(keyDerSz, 0); + + /* sanity check, verify we can import DER public key */ + ret = wc_InitRsaKey(&rsaKey, HEAP_HINT); + ExpectIntEQ(ret, 0); + idx = 0; + ExpectIntEQ(wc_RsaPublicKeyDecode(keyDer, &idx, &rsaKey, keyDerSz), 0); + if (ret == 0) { + wc_FreeRsaKey(&rsaKey); + } + } + #endif /* WOLFSSL_CERT_REQ */ +#endif /* NO_RSA */ + +#ifdef HAVE_ECC + #ifndef USE_CERT_BUFFERS_256 + ExpectTrue((fp2 = XFOPEN("./certs/client-ecc-cert.der", "rb")) != + XBADFILE); + ExpectIntGT(eccCertSz = (word32)XFREAD(eccCert, 1, ONEK_BUF, fp2), 0); + if (fp2 != XBADFILE) { + XFCLOSE(fp2); + } + #endif + + /* good test case - ECC */ + XMEMSET(keyDer, 0, sizeof(keyDer)); + keyDerSz = sizeof(keyDer); + ExpectIntEQ(wc_GetSubjectPubKeyInfoDerFromCert(eccCert, eccCertSz, keyDer, + &keyDerSz), 0); + ExpectIntGT(keyDerSz, 0); + + /* sanity check, verify we can import DER public key */ + ret = wc_ecc_init(&eccKey); + ExpectIntEQ(ret, 0); + idx = 0; /* reset idx to 0, used above in RSA case */ + ExpectIntEQ(wc_EccPublicKeyDecode(keyDer, &idx, &eccKey, keyDerSz), 0); + if (ret == 0) { + wc_ecc_free(&eccKey); + } + +#endif +#endif /* !NO_RSA || HAVE_ECC */ + return EXPECT_RESULT(); +} + static int test_wc_CheckCertSigPubKey(void) { EXPECT_DECLS; @@ -66846,6 +66991,7 @@ TEST_CASE testCases[] = { TEST_DECL(test_wc_PubKeyPemToDer), TEST_DECL(test_wc_PemPubKeyToDer), TEST_DECL(test_wc_GetPubKeyDerFromCert), + TEST_DECL(test_wc_GetSubjectPubKeyInfoDerFromCert), TEST_DECL(test_wc_CheckCertSigPubKey), /* wolfCrypt ASN tests */ diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index 30afd46e5..787026be7 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -23030,7 +23030,8 @@ static int CheckDate(ASNGetData *dataASN, int dateType) * @param [out] badDateRet Bad date return code. * @param [in] stopAtPubKey Stop parsing before subjectPublicKeyInfo. * @param [in] stopAfterPubKey Stop parsing after subjectPublicKeyInfo. - * @return 0 on success. + * @return 0 on success if of the stop arguments is not set, otherwise set to + * the corresponding byte offset at which the parsing stopped. * @return ASN_CRIT_EXT_E when a critical extension was not recognized. * @return ASN_TIME_E when date BER tag is nor UTC or GENERALIZED time. * @return ASN_DATE_SZ_E when time data is not supported. @@ -24657,6 +24658,82 @@ int wc_CertGetPubKey(const byte* cert, word32 certSz, return ret; } #endif + +/* + * @brief Export the SubjectPublicKeyInfo from an X.509 certificate + * + * This function extracts the SubjectPublicKeyInfo (SPKI) section from an X.509 + * certificate in DER format. The SPKI contains the public key algorithm and + * the public key itself. + * + * @param certDer [in] Pointer to the DER encoded certificate + * @param certSz [in] Size of the DER encoded certificate + * @param pubKeyDer [out] Buffer to hold the extracted SPKI (can be NULL to + * get size) + * @param pubKeyDerSz [in,out] On input, size of pubKeyDer buffer + * On output, actual size of the SPKI + * + * @return 0 on success, negative on error + * @return BAD_FUNC_ARG if certDer is NULL, certSz is 0, or pubKeyDerSz is NULL + * @return BUFFER_E if the provided buffer is too small + */ +WOLFSSL_API int wc_GetSubjectPubKeyInfoDerFromCert(const byte* certDer, + word32 certDerSz, + byte* pubKeyDer, + word32* pubKeyDerSz) +{ + DecodedCert cert; + int ret; + word32 startIdx; + word32 idx; + word32 length; + int badDate; + + if (certDer == NULL || certDerSz == 0 || pubKeyDerSz == NULL) { + return BAD_FUNC_ARG; + } + + length = 0; + badDate = 0; + + wc_InitDecodedCert(&cert, certDer, certDerSz, NULL); + + /* Parse up to the SubjectPublicKeyInfo */ + ret = wc_GetPubX509(&cert, 0, &badDate); + if (ret >= 0) { + /* Save the starting index of SubjectPublicKeyInfo */ + startIdx = cert.srcIdx; + + /* Get the length of the SubjectPublicKeyInfo sequence */ + idx = startIdx; + ret = GetSequence(certDer, &idx, (int*)&length, certDerSz); + if (ret >= 0) { + /* Calculate total length including sequence header */ + length += (idx - startIdx); + + /* Copy the SubjectPublicKeyInfo if buffer provided */ + if (pubKeyDer != NULL) { + if (*pubKeyDerSz < (word32)length) { + ret = BUFFER_E; + } + else { + XMEMCPY(pubKeyDer, &certDer[startIdx], length); + } + } + } + } + + if (ret >= 0) { + ret = 0; + } + + *pubKeyDerSz = length; + wc_FreeDecodedCert(&cert); + + return ret; +} + + #ifdef HAVE_OCSP Signer* findSignerByKeyHash(Signer *list, byte *hash) { diff --git a/wolfssl/wolfcrypt/asn_public.h b/wolfssl/wolfcrypt/asn_public.h index 44396bb5a..fba7bfe31 100644 --- a/wolfssl/wolfcrypt/asn_public.h +++ b/wolfssl/wolfcrypt/asn_public.h @@ -862,6 +862,10 @@ WOLFSSL_API int wc_ParseCert( WOLFSSL_API int wc_GetPubKeyDerFromCert(struct DecodedCert* cert, byte* derKey, word32* derKeySz); +WOLFSSL_API int wc_GetSubjectPubKeyInfoDerFromCert(const byte* certDer, + word32 certDerSz, + byte* pubKeyDer, + word32* pubKeyDerSz); #ifdef WOLFSSL_FPKI WOLFSSL_API int wc_GetUUIDFromCert(struct DecodedCert* cert,