diff --git a/ChangeLog.md b/ChangeLog.md index 11101fa49aa..0d03e07c2e0 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -13,6 +13,15 @@ * Fixed `wc_PKCS7_DecodeEnvelopedData()` and `wc_PKCS7_DecodeAuthEnvelopedData()` failing on a message addressed to more than one recipient; AuthEnvelopedData never supported it at all. A message carrying no recipient for the reader now reports `PKCS7_RECIP_E` rather than a parse error. Streaming an AuthEnvelopedData now buffers the whole RecipientInfo set, as the EnvelopedData decoder already did, so peak memory rises by the size of that set. by @Frauschi (PR 11350) +## Behavioral Changes +* **Behavioral change (`X509_get0_pubkey()` returns a borrowed key)**: + `wolfSSL_X509_get_pubkey()` now returns the public key cached on the + certificate with a new reference, and the new `wolfSSL_X509_get0_pubkey()` + (`X509_get0_pubkey()`, `X509_REQ_get0_pubkey()`) returns it without one, as + in OpenSSL. Code that freed the result of `X509_get0_pubkey()` to avoid a + leak must stop doing so, and the returned key is shared with the + certificate, so it must be treated as read only. + # wolfSSL Release 5.9.4 (Sep 25, 2026) Release 5.9.4 has been developed according to wolfSSL's development and QA diff --git a/doc/dox_comments/header_files/ssl.h b/doc/dox_comments/header_files/ssl.h index 5d43a1414ac..f04449222eb 100644 --- a/doc/dox_comments/header_files/ssl.h +++ b/doc/dox_comments/header_files/ssl.h @@ -5411,6 +5411,92 @@ long wolfSSL_BIO_get_mem_ptr(WOLFSSL_BIO *bio, WOLFSSL_BUF_MEM **m); */ char* wolfSSL_X509_NAME_oneline(WOLFSSL_X509_NAME* name, char* in, int sz); +/*! + \ingroup CertsKeys + + \brief This function returns the public key of the certificate with a new + reference. The key is decoded once and cached on the certificate, so the + same object is returned on every call. Treat it as read only. Free the + reference with wolfSSL_EVP_PKEY_free(). + + \return pointer to the WOLFSSL_EVP_PKEY on success. + \return NULL if x509 is NULL, has no public key, or the key cannot be + decoded. + + \param x509 pointer to a WOLFSSL_X509 structure. + + _Example_ + \code + WOLFSSL_X509* x509; + WOLFSSL_EVP_PKEY* key; + ... + key = wolfSSL_X509_get_pubkey(x509); + if (key == NULL) { + // failed to get the public key + } + ... + wolfSSL_EVP_PKEY_free(key); + \endcode + + \sa wolfSSL_X509_get0_pubkey + \sa wolfSSL_EVP_PKEY_free +*/ +WOLFSSL_EVP_PKEY* wolfSSL_X509_get_pubkey(WOLFSSL_X509* x509); + +/*! + \ingroup CertsKeys + + \brief This function returns the public key of the certificate without a + new reference. The key is owned by the certificate and must not be freed. + It stays valid until the certificate is freed or its public key is + changed. Treat it as read only. + + \return pointer to the WOLFSSL_EVP_PKEY on success. + \return NULL if x509 is NULL, has no public key, or the key cannot be + decoded. + + \param x509 pointer to a WOLFSSL_X509 structure. + + _Example_ + \code + WOLFSSL_X509* x509; + WOLFSSL_EVP_PKEY* key; + ... + key = wolfSSL_X509_get0_pubkey(x509); + if (key == NULL) { + // failed to get the public key + } + // do not free key + \endcode + + \sa wolfSSL_X509_get_pubkey +*/ +WOLFSSL_EVP_PKEY* wolfSSL_X509_get0_pubkey(const WOLFSSL_X509* x509); + +/*! + \ingroup CertsKeys + + \brief This function returns the key held by a WOLFSSL_X509_PUBKEY without + a new reference. The key must not be freed. + + \return pointer to the WOLFSSL_EVP_PKEY on success. + \return NULL if key is NULL or holds no key. + + \param key pointer to a WOLFSSL_X509_PUBKEY structure. + + _Example_ + \code + WOLFSSL_X509* x509; + WOLFSSL_EVP_PKEY* pkey; + ... + pkey = wolfSSL_X509_PUBKEY_get0(wolfSSL_X509_get_X509_PUBKEY(x509)); + \endcode + + \sa wolfSSL_X509_PUBKEY_get + \sa wolfSSL_X509_get_X509_PUBKEY +*/ +WOLFSSL_EVP_PKEY* wolfSSL_X509_PUBKEY_get0(const WOLFSSL_X509_PUBKEY* key); + /*! \ingroup CertsKeys diff --git a/src/internal.c b/src/internal.c index e3052a49425..e933240882d 100644 --- a/src/internal.c +++ b/src/internal.c @@ -5798,19 +5798,27 @@ static void FreeX509Contents(WOLFSSL_X509* x509) wolfSSL_ASN1_OBJECT_free(x509->algor.algorithm); x509->algor.algorithm = NULL; } + if (x509->subjAltNameSrc != NULL) { + XFREE(x509->subjAltNameSrc, x509->heap, DYNAMIC_TYPE_X509_EXT); + x509->subjAltNameSrc= NULL; + } + #endif /* OPENSSL_ALL */ + #if (defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)) && \ + (defined(OPENSSL_ALL) || defined(OPENSSL_EXTRA) || \ + defined(WOLFSSL_APACHE_HTTPD) || defined(WOLFSSL_HAPROXY) || \ + defined(WOLFSSL_WPAS)) if (x509->key.algor) { wolfSSL_X509_ALGOR_free(x509->key.algor); x509->key.algor = NULL; } + #endif + #ifdef OPENSSL_EXTRA_X509_SMALL + /* Public key cached by wolfSSL_X509_get_pubkey() and friends. */ if (x509->key.pkey) { wolfSSL_EVP_PKEY_free(x509->key.pkey); x509->key.pkey = NULL; } - if (x509->subjAltNameSrc != NULL) { - XFREE(x509->subjAltNameSrc, x509->heap, DYNAMIC_TYPE_X509_EXT); - x509->subjAltNameSrc= NULL; - } - #endif /* OPENSSL_ALL */ + #endif #if defined(WOLFSSL_CERT_REQ) && defined(OPENSSL_ALL) if (x509->reqAttributes) { wolfSSL_sk_pop_free(x509->reqAttributes, NULL); @@ -15563,6 +15571,11 @@ static void CopyDecodedSepFields(WOLFSSL_X509* x509, DecodedCert* dCert) * error, matching the original. */ static int CopyDecodedPubKey(WOLFSSL_X509* x509, DecodedCert* dCert, int ret) { +#ifdef OPENSSL_EXTRA_X509_SMALL + /* Drop the key decoded from a previous public key. */ + wolfSSL_EVP_PKEY_free(x509->key.pkey); + x509->key.pkey = NULL; +#endif if (dCert->publicKey != NULL && dCert->pubKeySize != 0) { x509->pubKey.buffer = (byte*)XMALLOC( dCert->pubKeySize, x509->heap, DYNAMIC_TYPE_PUBLIC_KEY); @@ -15592,9 +15605,6 @@ static int CopyDecodedPubKey(WOLFSSL_X509* x509, DecodedCert* dCert, int ret) } } - wolfSSL_EVP_PKEY_free(x509->key.pkey); - x509->key.pkey = NULL; - switch (dCert->keyOID) { #ifdef HAVE_ED25519 case ED25519k: diff --git a/src/pk_ec.c b/src/pk_ec.c index 7f52df3ea76..23d22e54fdd 100644 --- a/src/pk_ec.c +++ b/src/pk_ec.c @@ -4394,6 +4394,11 @@ int SetECKeyExternal(WOLFSSL_EC_KEY* eckey) WOLFSSL_MSG("SetECKeyExternal ec_point_external_set failed"); ret = WOLFSSL_FATAL_ERROR; } + /* Both sides of the point match now, so readers of a shared key + * do not rebuild the internal one. */ + if (ret == 1) { + eckey->pub_key->inSet = 1; + } } /* set the external privkey */ diff --git a/src/x509.c b/src/x509.c index 66850941c18..bd3df2fae3b 100644 --- a/src/x509.c +++ b/src/x509.c @@ -6386,19 +6386,19 @@ int wolfSSL_X509_NAME_get_text_by_NID(WOLFSSL_X509_NAME* name, return (textSz - 1); /* do not include null character in size */ } -/* Creates a new WOLFSSL_EVP_PKEY structure that has the public key from x509 +/* Decodes the public key of x509 into a new WOLFSSL_EVP_PKEY. * * returns a pointer to the created WOLFSSL_EVP_PKEY on success and NULL on fail */ -WOLFSSL_EVP_PKEY* wolfSSL_X509_get_pubkey(WOLFSSL_X509* x509) +static WOLFSSL_EVP_PKEY* X509DecodePubKey(WOLFSSL_X509* x509) { WOLFSSL_EVP_PKEY* key = NULL; int ret = 0; (void)ret; - WOLFSSL_ENTER("wolfSSL_X509_get_pubkey"); - if (x509 != NULL) { + if (x509 != NULL && x509->pubKey.buffer != NULL && + x509->pubKey.length > 0) { key = wolfSSL_EVP_PKEY_new_ex(x509->heap); if (key != NULL) { if (x509->pubKeyOID == RSAk) { @@ -6543,6 +6543,60 @@ WOLFSSL_EVP_PKEY* wolfSSL_X509_get_pubkey(WOLFSSL_X509* x509) } return key; } + +/* Returns the public key cached in x509, decoding it on first use. + * The key is owned by x509 and freed with it. */ +static WOLFSSL_EVP_PKEY* X509CachedPubKey(WOLFSSL_X509* x509) +{ + WOLFSSL_EVP_PKEY* key; + + if (x509 == NULL) + return NULL; + key = x509->key.pkey; + if (key == NULL) { + key = X509DecodePubKey(x509); + if (key != NULL) { + x509->key.pubKeyOID = x509->pubKeyOID; + x509->key.pkey = key; + } + } + return key; +} + +/* Returns the public key of x509 with a new reference. + * + * returns a pointer to the WOLFSSL_EVP_PKEY on success and NULL on fail. + * The caller frees it with wolfSSL_EVP_PKEY_free(). + */ +WOLFSSL_EVP_PKEY* wolfSSL_X509_get_pubkey(WOLFSSL_X509* x509) +{ + WOLFSSL_EVP_PKEY* key; + + WOLFSSL_ENTER("wolfSSL_X509_get_pubkey"); + key = X509CachedPubKey(x509); + if (key != NULL) { + int ret; + wolfSSL_RefInc(&key->ref, &ret); + if (ret != 0) { + WOLFSSL_MSG("Failed to lock pkey mutex"); + key = NULL; + } + } + return key; +} + +/* Returns the public key of x509 without a new reference. + * + * returns a pointer to the WOLFSSL_EVP_PKEY on success and NULL on fail. + * The key must not be freed. It is valid until x509 is freed or its public + * key is changed. + */ +WOLFSSL_EVP_PKEY* wolfSSL_X509_get0_pubkey(const WOLFSSL_X509* x509) +{ + WOLFSSL_ENTER("wolfSSL_X509_get0_pubkey"); + /* Only the lazily decoded key cache is written. */ + return X509CachedPubKey((WOLFSSL_X509*)x509); +} #endif /* OPENSSL_EXTRA_X509_SMALL */ /* End of smaller subset of X509 compatibility functions. Avoid increasing the @@ -11578,6 +11632,10 @@ WOLFSSL_X509_PUBKEY* wolfSSL_X509_get_X509_PUBKEY(const WOLFSSL_X509* x509) return NULL; } + /* OpenSSL also takes a const X509 and returns a mutable X509_PUBKEY. + * Only the lazily decoded key cache is written here. */ + (void)X509CachedPubKey((WOLFSSL_X509*)x509); + return (WOLFSSL_X509_PUBKEY*)&x509->key; } @@ -11593,16 +11651,26 @@ int wolfSSL_X509_PUBKEY_get0_param(WOLFSSL_ASN1_OBJECT **ppkalg, WOLFSSL_MSG("X509_PUBKEY struct not populated"); return WOLFSSL_FAILURE; } + if ((pk || ppklen) && !pub->pkey) { + WOLFSSL_MSG("X509_PUBKEY has no decoded key"); + return WOLFSSL_FAILURE; + } if (!pub->algor) { - if (!(pub->algor = wolfSSL_X509_ALGOR_new())) { + /* Build the algorithm fully before storing it, so a failure + * never leaves a half built one behind. */ + WOLFSSL_X509_ALGOR* algor = wolfSSL_X509_ALGOR_new(); + if (algor == NULL) { return WOLFSSL_FAILURE; } - pub->algor->algorithm = wolfSSL_OBJ_nid2obj(pub->pubKeyOID); - if (pub->algor->algorithm == NULL) { + algor->algorithm = wolfSSL_OBJ_nid2obj( + oid2nid((word32)pub->pubKeyOID, oidKeyType)); + if (algor->algorithm == NULL) { WOLFSSL_MSG("Failed to create object from NID"); + wolfSSL_X509_ALGOR_free(algor); return WOLFSSL_FAILURE; } + pub->algor = algor; } if (pa) @@ -11633,6 +11701,15 @@ WOLFSSL_EVP_PKEY* wolfSSL_X509_PUBKEY_get(WOLFSSL_X509_PUBKEY* key) return key->pkey; } +/* Returns the pkey without a new reference. */ +WOLFSSL_EVP_PKEY* wolfSSL_X509_PUBKEY_get0(const WOLFSSL_X509_PUBKEY* key) +{ + WOLFSSL_ENTER("wolfSSL_X509_PUBKEY_get0"); + if (key == NULL) + return NULL; + return key->pkey; +} + int wolfSSL_X509_PUBKEY_set(WOLFSSL_X509_PUBKEY **x, WOLFSSL_EVP_PKEY *key) { WOLFSSL_X509_PUBKEY *pk = NULL; @@ -16846,6 +16923,7 @@ int wolfSSL_X509_set_pubkey(WOLFSSL_X509 *cert, WOLFSSL_EVP_PKEY *pkey) return WOLFSSL_FAILURE; } cert->pubKeyOID = ECDSAk; + cert->pkCurveOID = ecc->dp->oidSum; } break; #endif @@ -16963,6 +17041,19 @@ int wolfSSL_X509_set_pubkey(WOLFSSL_X509 *cert, WOLFSSL_EVP_PKEY *pkey) XFREE(cert->pubKey.buffer, cert->heap, DYNAMIC_TYPE_PUBLIC_KEY); cert->pubKey.buffer = p; cert->pubKey.length = (unsigned int)derSz; + /* Drop what was decoded from the previous public key, unless the caller + * passed that very key. */ + if (cert->key.pkey != pkey) { + wolfSSL_EVP_PKEY_free(cert->key.pkey); + cert->key.pkey = NULL; + } + cert->key.pubKeyOID = cert->pubKeyOID; +#if defined(OPENSSL_ALL) || defined(OPENSSL_EXTRA) || \ + defined(WOLFSSL_APACHE_HTTPD) || defined(WOLFSSL_HAPROXY) || \ + defined(WOLFSSL_WPAS) + wolfSSL_X509_ALGOR_free(cert->key.algor); + cert->key.algor = NULL; +#endif return WOLFSSL_SUCCESS; } diff --git a/tests/api/test_evp_pkey.c b/tests/api/test_evp_pkey.c index dff8fab086e..42e77bf8ca9 100644 --- a/tests/api/test_evp_pkey.c +++ b/tests/api/test_evp_pkey.c @@ -3182,6 +3182,56 @@ int test_wolfSSL_d2i_PUBKEY_mldsa_reuse(void) return EXPECT_RESULT(); } +/* Raw ML-DSA public key bytes must decode into an EVP_PKEY holding the + * whole key. */ +int test_wolfSSL_d2i_PUBKEY_mldsa_raw(void) +{ + EXPECT_DECLS; +#if defined(OPENSSL_EXTRA) && defined(WOLFSSL_HAVE_MLDSA) && \ + defined(WOLFSSL_MLDSA_PUBLIC_KEY) && !defined(WOLFSSL_NO_ML_DSA_44) && \ + !defined(NO_FILESYSTEM) + WOLFSSL_EVP_PKEY* pkey = NULL; + const unsigned char* p; + const unsigned char* raw = NULL; + unsigned char* der = NULL; + int derSz = 0; + XFILE f = XBADFILE; + + ExpectNotNull(der = (unsigned char*)XMALLOC(2048, NULL, + DYNAMIC_TYPE_TMP_BUFFER)); + ExpectTrue((f = XFOPEN("./certs/mldsa/mldsa44_pub-spki.der", "rb")) + != XBADFILE); + ExpectIntGT(derSz = (int)XFREAD(der, 1, 2048, f), 0); + if (f != XBADFILE) { + XFCLOSE(f); + } + /* The raw key is the tail of the SPKI BIT STRING. */ + ExpectIntGT(derSz, WC_MLDSA_44_PUB_KEY_SIZE); + if (EXPECT_SUCCESS()) { + raw = der + derSz - WC_MLDSA_44_PUB_KEY_SIZE; + } + + p = raw; + ExpectNotNull(pkey = wolfSSL_d2i_PUBKEY(NULL, &p, + (long)WC_MLDSA_44_PUB_KEY_SIZE)); + ExpectIntEQ(wolfSSL_EVP_PKEY_id(pkey), WC_EVP_PKEY_DILITHIUM); +#if defined(WC_ENABLE_ASYM_KEY_EXPORT) && !defined(WOLFSSL_MLDSA_NO_ASN1) + /* Raw input is cached as SPKI DER. */ + if (pkey != NULL) { + ExpectIntEQ(pkey->pkey_sz, derSz); + ExpectNotNull(pkey->pkey.ptr); + if (pkey->pkey.ptr != NULL) { + ExpectIntEQ(XMEMCMP(pkey->pkey.ptr, der, (size_t)derSz), 0); + } + } +#endif + + wolfSSL_EVP_PKEY_free(pkey); + XFREE(der, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + return EXPECT_RESULT(); +} + /* Typed d2i entry points for ML-DSA: a PKCS#8 key of another algorithm * and raw (non-DER) bytes must both be rejected; a matching PKCS#8 * ML-DSA key must decode. */ diff --git a/tests/api/test_evp_pkey.h b/tests/api/test_evp_pkey.h index 8af6d24712e..fd8c75e866c 100644 --- a/tests/api/test_evp_pkey.h +++ b/tests/api/test_evp_pkey.h @@ -72,6 +72,7 @@ int test_wolfSSL_EVP_PKEY_ed25519(void); int test_wolfSSL_CTX_use_PrivateKey_ed25519(void); int test_wolfSSL_EVP_PKEY_ed448(void); int test_wolfSSL_d2i_PUBKEY_mldsa_reuse(void); +int test_wolfSSL_d2i_PUBKEY_mldsa_raw(void); int test_wolfSSL_d2i_PrivateKey_mldsa(void); int test_wolfSSL_EVP_PKEY_x25519(void); int test_wolfSSL_EVP_PKEY_x448(void); @@ -129,6 +130,7 @@ int test_wolfSSL_CTX_use_PrivateKey_pkcs8_repopulate(void); TEST_DECL_GROUP("evp_pkey", test_wolfSSL_CTX_use_PrivateKey_ed25519), \ TEST_DECL_GROUP("evp_pkey", test_wolfSSL_EVP_PKEY_ed448), \ TEST_DECL_GROUP("evp_pkey", test_wolfSSL_d2i_PUBKEY_mldsa_reuse), \ + TEST_DECL_GROUP("evp_pkey", test_wolfSSL_d2i_PUBKEY_mldsa_raw), \ TEST_DECL_GROUP("evp_pkey", test_wolfSSL_d2i_PrivateKey_mldsa), \ TEST_DECL_GROUP("evp_pkey", test_wolfSSL_EVP_PKEY_x25519), \ TEST_DECL_GROUP("evp_pkey", test_wolfSSL_EVP_PKEY_x448), \ diff --git a/tests/api/test_ossl_x509_pk.c b/tests/api/test_ossl_x509_pk.c index 3265f87052f..6a1e90c81c8 100644 --- a/tests/api/test_ossl_x509_pk.c +++ b/tests/api/test_ossl_x509_pk.c @@ -680,3 +680,119 @@ int test_wolfSSL_X509_set_pubkey(void) return EXPECT_RESULT(); } +int test_wolfSSL_X509_get0_pubkey(void) +{ + EXPECT_DECLS; +#if defined(OPENSSL_EXTRA) && !defined(NO_RSA) && !defined(NO_FILESYSTEM) && \ + !defined(NO_CERTS) + X509* x509 = NULL; + EVP_PKEY* borrowed = NULL; + EVP_PKEY* owned = NULL; + ASN1_OBJECT* obj = NULL; + const unsigned char* pk = NULL; + int pkLen = 0; + + ExpectNull(X509_get0_pubkey(NULL)); + ExpectNull(X509_get_pubkey(NULL)); + + /* A certificate without a public key has nothing to hand out. */ + ExpectNotNull(x509 = X509_new()); + ExpectNull(X509_get0_pubkey(x509)); + ExpectNull(X509_get_pubkey(x509)); + X509_free(x509); + x509 = NULL; + + ExpectNotNull(x509 = X509_load_certificate_file(caCertFile, + SSL_FILETYPE_PEM)); + + /* get0 hands out the same borrowed key every time. */ + ExpectNotNull(borrowed = X509_get0_pubkey(x509)); + ExpectPtrEq(X509_get0_pubkey(x509), borrowed); + ExpectIntEQ(EVP_PKEY_id(borrowed), EVP_PKEY_RSA); + ExpectIntEQ(X509_verify(x509, borrowed), WOLFSSL_SUCCESS); + /* The embedded X509_PUBKEY reports the same key. */ + ExpectIntEQ(X509_PUBKEY_get0_param(&obj, &pk, &pkLen, NULL, + X509_get_X509_PUBKEY(x509)), 1); + ExpectIntEQ(OBJ_obj2nid(obj), EVP_PKEY_RSA); + ExpectNotNull(pk); + ExpectIntGT(pkLen, 0); + + /* get_pubkey hands out a new reference to that same key. */ + ExpectNotNull(owned = X509_get_pubkey(x509)); + ExpectPtrEq(owned, borrowed); + EVP_PKEY_free(owned); + owned = NULL; + /* The borrowed key is still alive after the owned reference is freed. */ + ExpectPtrEq(X509_get0_pubkey(x509), borrowed); + ExpectIntEQ(X509_verify(x509, borrowed), WOLFSSL_SUCCESS); + + /* X509_PUBKEY_get returns yet another reference to the same key, and + * X509_PUBKEY_get0 the same borrowed pointer. */ + ExpectNotNull(owned = X509_PUBKEY_get(X509_get_X509_PUBKEY(x509))); + ExpectPtrEq(owned, borrowed); + EVP_PKEY_free(owned); + owned = NULL; + ExpectPtrEq(X509_PUBKEY_get0(X509_get_X509_PUBKEY(x509)), borrowed); + ExpectNull(X509_PUBKEY_get0(NULL)); + + /* Setting the certificate's own key back keeps the cached key. */ + ExpectIntEQ(X509_set_pubkey(x509, borrowed), WOLFSSL_SUCCESS); + ExpectPtrEq(X509_get0_pubkey(x509), borrowed); + ExpectIntEQ(X509_verify(x509, borrowed), WOLFSSL_SUCCESS); + + /* An owned reference outlives the certificate. */ + ExpectNotNull(owned = X509_get_pubkey(x509)); + X509_free(x509); + x509 = NULL; + ExpectIntEQ(EVP_PKEY_bits(owned), 2048); + EVP_PKEY_free(owned); + owned = NULL; + + /* Freeing the owned reference before the certificate is fine too. */ + ExpectNotNull(x509 = X509_load_certificate_file(caCertFile, + SSL_FILETYPE_PEM)); + ExpectNotNull(owned = X509_get_pubkey(x509)); + ExpectNotNull(borrowed = X509_get0_pubkey(x509)); + EVP_PKEY_free(owned); + owned = NULL; + ExpectIntEQ(EVP_PKEY_bits(borrowed), 2048); + X509_free(x509); + x509 = NULL; + +#ifdef HAVE_ECC + /* Setting a new public key drops the cached key. */ + { + X509* ecX509 = NULL; + EVP_PKEY* ecKey = NULL; + EVP_PKEY* rsaKey = NULL; + + ExpectNotNull(x509 = X509_load_certificate_file(caCertFile, + SSL_FILETYPE_PEM)); + ExpectNotNull(ecX509 = X509_load_certificate_file(caEccCertFile, + SSL_FILETYPE_PEM)); + ExpectNotNull(rsaKey = X509_get_pubkey(x509)); + ExpectNotNull(ecKey = X509_get_pubkey(ecX509)); + ExpectIntEQ(X509_set_pubkey(x509, ecKey), WOLFSSL_SUCCESS); + ExpectNotNull(borrowed = X509_get0_pubkey(x509)); + ExpectIntEQ(EVP_PKEY_id(borrowed), EVP_PKEY_EC); + /* The algorithm reported by the X509_PUBKEY follows the key. */ + ExpectIntEQ(X509_PUBKEY_get0_param(&obj, NULL, NULL, NULL, + X509_get_X509_PUBKEY(x509)), 1); + ExpectIntEQ(OBJ_obj2nid(obj), EVP_PKEY_EC); + ExpectIntEQ(X509_set_pubkey(x509, rsaKey), WOLFSSL_SUCCESS); + ExpectNotNull(borrowed = X509_get0_pubkey(x509)); + ExpectIntEQ(EVP_PKEY_id(borrowed), EVP_PKEY_RSA); + ExpectIntEQ(X509_PUBKEY_get0_param(&obj, NULL, NULL, NULL, + X509_get_X509_PUBKEY(x509)), 1); + ExpectIntEQ(OBJ_obj2nid(obj), EVP_PKEY_RSA); + /* rsaKey is a separate reference and survives the cache drop. */ + ExpectIntEQ(EVP_PKEY_bits(rsaKey), 2048); + EVP_PKEY_free(rsaKey); + EVP_PKEY_free(ecKey); + X509_free(ecX509); + X509_free(x509); + } +#endif +#endif + return EXPECT_RESULT(); +} diff --git a/tests/api/test_ossl_x509_pk.h b/tests/api/test_ossl_x509_pk.h index cb949bbb88d..4fee22a4432 100644 --- a/tests/api/test_ossl_x509_pk.h +++ b/tests/api/test_ossl_x509_pk.h @@ -30,6 +30,7 @@ int test_wolfSSL_X509_PUBKEY_EC(void); int test_wolfSSL_X509_PUBKEY_DSA(void); int test_wolfSSL_X509_PUBKEY_get(void); int test_wolfSSL_X509_set_pubkey(void); +int test_wolfSSL_X509_get0_pubkey(void); #define TEST_OSSL_X509_PK_DECLS \ TEST_DECL_GROUP("ossl_x509_pk", test_wolfSSL_X509_get_X509_PUBKEY), \ @@ -37,6 +38,7 @@ int test_wolfSSL_X509_set_pubkey(void); TEST_DECL_GROUP("ossl_x509_pk", test_wolfSSL_X509_PUBKEY_EC), \ TEST_DECL_GROUP("ossl_x509_pk", test_wolfSSL_X509_PUBKEY_DSA), \ TEST_DECL_GROUP("ossl_x509_pk", test_wolfSSL_X509_PUBKEY_get), \ - TEST_DECL_GROUP("ossl_x509_pk", test_wolfSSL_X509_set_pubkey) + TEST_DECL_GROUP("ossl_x509_pk", test_wolfSSL_X509_set_pubkey), \ + TEST_DECL_GROUP("ossl_x509_pk", test_wolfSSL_X509_get0_pubkey) #endif /* WOLFCRYPT_TEST_OSSL_X509_PK_H */ diff --git a/wolfssl/openssl/ssl.h b/wolfssl/openssl/ssl.h index 71312d68ec8..5187297d109 100644 --- a/wolfssl/openssl/ssl.h +++ b/wolfssl/openssl/ssl.h @@ -584,8 +584,9 @@ typedef STACK_OF(ACCESS_DESCRIPTION) AUTHORITY_INFO_ACCESS; #define X509_get_subject_name(x) wolfSSL_X509_get_subject_name((WOLFSSL_X509*)(x)) #define X509_REQ_get_subject_name wolfSSL_X509_get_subject_name #define X509_get_pubkey wolfSSL_X509_get_pubkey -#define X509_get0_pubkey wolfSSL_X509_get_pubkey +#define X509_get0_pubkey wolfSSL_X509_get0_pubkey #define X509_REQ_get_pubkey wolfSSL_X509_get_pubkey +#define X509_REQ_get0_pubkey wolfSSL_X509_get0_pubkey #define X509_get_notBefore wolfSSL_X509_get_notBefore #define X509_get0_notBefore wolfSSL_X509_get_notBefore #define X509_getm_notBefore wolfSSL_X509_get_notBefore @@ -905,6 +906,7 @@ wolfSSL_X509_STORE_set_verify_cb((WOLFSSL_X509_STORE *)(s), (WOLFSSL_X509_STORE_ #define X509_get0_tbs_sigalg wolfSSL_X509_get0_tbs_sigalg #define X509_PUBKEY_get0_param wolfSSL_X509_PUBKEY_get0_param #define X509_PUBKEY_get wolfSSL_X509_PUBKEY_get +#define X509_PUBKEY_get0 wolfSSL_X509_PUBKEY_get0 #define X509_PUBKEY_set wolfSSL_X509_PUBKEY_set #define X509_ALGOR_get0 wolfSSL_X509_ALGOR_get0 #define X509_ALGOR_set0 wolfSSL_X509_ALGOR_set0 diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index 871308c7a6f..a94ea75d420 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -2518,6 +2518,8 @@ WOLFSSL_API WOLFSSL_ASN1_TIME* wolfSSL_X509_CRL_get_nextUpdate(WOLFSSL_X509_CRL* WOLFSSL_API int wolfSSL_X509_CRL_set_nextUpdate(WOLFSSL_X509_CRL* crl, const WOLFSSL_ASN1_TIME* time); WOLFSSL_API WOLFSSL_EVP_PKEY* wolfSSL_X509_get_pubkey(WOLFSSL_X509* x509); +WOLFSSL_API WOLFSSL_EVP_PKEY* wolfSSL_X509_get0_pubkey( + const WOLFSSL_X509* x509); WOLFSSL_API int wolfSSL_X509_CRL_verify(WOLFSSL_X509_CRL* crl, WOLFSSL_EVP_PKEY* pkey); WOLFSSL_API void wolfSSL_X509_OBJECT_free_contents(WOLFSSL_X509_OBJECT* obj); WOLFSSL_API WOLFSSL_PKCS8_PRIV_KEY_INFO* wolfSSL_d2i_PKCS8_PKEY_bio( @@ -6327,6 +6329,8 @@ WOLFSSL_API void wolfSSL_X509_PUBKEY_free(WOLFSSL_X509_PUBKEY *x); WOLFSSL_API WOLFSSL_X509_PUBKEY *wolfSSL_X509_get_X509_PUBKEY(const WOLFSSL_X509* x509); WOLFSSL_API int wolfSSL_X509_PUBKEY_get0_param(WOLFSSL_ASN1_OBJECT **ppkalg, const unsigned char **pk, int *ppklen, WOLFSSL_X509_ALGOR **pa, WOLFSSL_X509_PUBKEY *pub); WOLFSSL_API WOLFSSL_EVP_PKEY* wolfSSL_X509_PUBKEY_get(WOLFSSL_X509_PUBKEY* key); +WOLFSSL_API WOLFSSL_EVP_PKEY* wolfSSL_X509_PUBKEY_get0( + const WOLFSSL_X509_PUBKEY* key); WOLFSSL_API int wolfSSL_X509_PUBKEY_set(WOLFSSL_X509_PUBKEY **x, WOLFSSL_EVP_PKEY *key); WOLFSSL_API int wolfSSL_i2t_ASN1_OBJECT(char *buf, int buf_len, WOLFSSL_ASN1_OBJECT *a); WOLFSSL_API WOLFSSL_ASN1_OBJECT *wolfSSL_d2i_ASN1_OBJECT(WOLFSSL_ASN1_OBJECT **a,