diff --git a/src/bio.c b/src/bio.c index 9d94144f57f..b964ec4737a 100644 --- a/src/bio.c +++ b/src/bio.c @@ -2119,6 +2119,23 @@ long wolfSSL_BIO_set_nbio(WOLFSSL_BIO* bio, long on) return WOLFSSL_SUCCESS; } +int wolfSSL_BIO_get_new_index(void) +{ + static int bio_type_idx = WOLFSSL_BIO_TYPE_START; + int idx; + + WOLFSSL_ENTER("wolfSSL_BIO_get_new_index"); + + idx = bio_type_idx; + if (idx > WOLFSSL_BIO_TYPE_MAX) { + WOLFSSL_MSG("BIO type index space exhausted"); + return -1; + } + bio_type_idx++; + + return idx; +} + /* creates a new custom WOLFSSL_BIO_METHOD */ WOLFSSL_BIO_METHOD *wolfSSL_BIO_meth_new(int type, const char *name) { diff --git a/src/ssl.c b/src/ssl.c index 5368c107fa7..78ac47af3b4 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -5562,12 +5562,7 @@ size_t wolfSSL_get_client_random(const WOLFSSL* ssl, unsigned char* out, const char* wolfSSLeay_version(int type) { - (void)type; -#if defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x10100000L return wolfSSL_OpenSSL_version(type); -#else - return wolfSSL_OpenSSL_version(); -#endif } #endif /* OPENSSL_EXTRA */ @@ -5899,19 +5894,36 @@ const char* wolfSSL_lib_version(void) } #ifdef OPENSSL_EXTRA -#if defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x10100000L -const char* wolfSSL_OpenSSL_version(int a) -{ - (void)a; - return "wolfSSL " LIBWOLFSSL_VERSION_STRING; -} +/* Signature deliberately does not depend on OPENSSL_VERSION_NUMBER. That macro + * can evaluate differently in the library and in the application (e.g. under + * OPENSSL_COEXIST the library also sees the real OpenSSL headers), which would + * make the caller and the definition disagree on the argument list. */ +const char* wolfSSL_OpenSSL_version(int type) +{ + WOLFSSL_ENTER("wolfSSL_OpenSSL_version"); + switch (type) { + case OPENSSL_VERSION: + return "wolfSSL " LIBWOLFSSL_VERSION_STRING; + case OPENSSL_CFLAGS: + return "compiler: information not available"; + case OPENSSL_BUILT_ON: + /* Kernel module builds compile with -Werror=date-time. */ +#if defined(HAVE_REPRODUCIBLE_BUILD) || defined(WOLFSSL_LINUXKM) + return "built on: date not available"; #else -const char* wolfSSL_OpenSSL_version(void) -{ - return "wolfSSL " LIBWOLFSSL_VERSION_STRING; + return "built on: " __DATE__ " " __TIME__; +#endif + case OPENSSL_PLATFORM: + return "platform: information not available"; + case OPENSSL_DIR: + return "OPENSSLDIR: N/A"; + case OPENSSL_ENGINES_DIR: + return "ENGINESDIR: N/A"; + default: + return "not available"; + } } -#endif /* WOLFSSL_QT */ -#endif +#endif /* OPENSSL_EXTRA */ /* current library version in hex */ diff --git a/tests/api.c b/tests/api.c index 14f10ca8745..0d8d281c598 100644 --- a/tests/api.c +++ b/tests/api.c @@ -20119,6 +20119,73 @@ defined(OPENSSL_EXTRA) && defined(WOLFSSL_DH_EXTRA) return EXPECT_RESULT(); } +static int test_wolfSSL_i2d_PUBKEY_bio(void) +{ + EXPECT_DECLS; +/* Guards must match wolfSSL_i2d_PUBKEY_bio() in wolfcrypt/src/evp_pk.c. */ +#if defined(OPENSSL_EXTRA) && !defined(WOLFCRYPT_ONLY) && \ + !defined(NO_CERTS) && !defined(NO_BIO) && !defined(NO_ASN) && \ + !defined(NO_PWDBASED) + BIO* bio = NULL; + EVP_PKEY* pkey = NULL; + EVP_PKEY* pkey2 = NULL; + + /* NULL parameter tests */ + ExpectIntEQ(wolfSSL_i2d_PUBKEY_bio(NULL, NULL), WOLFSSL_FAILURE); + +#if defined(USE_CERT_BUFFERS_2048) && !defined(NO_RSA) + { + const unsigned char* p = client_keypub_der_2048; + /* Load an RSA public key from DER buffer */ + ExpectNotNull(pkey = d2i_PUBKEY(NULL, &p, + sizeof_client_keypub_der_2048)); + + /* Write it to BIO */ + ExpectNotNull(bio = BIO_new(BIO_s_mem())); + ExpectIntEQ(i2d_PUBKEY_bio(bio, pkey), WOLFSSL_SUCCESS); + + /* Read it back and verify round-trip */ + ExpectNotNull(pkey2 = d2i_PUBKEY_bio(bio, NULL)); + + EVP_PKEY_free(pkey2); + pkey2 = NULL; + EVP_PKEY_free(pkey); + pkey = NULL; + BIO_free(bio); + bio = NULL; + } +#endif + +#if defined(USE_CERT_BUFFERS_256) && defined(HAVE_ECC) + { + const unsigned char* p = ecc_clikeypub_der_256; + /* Load an ECC public key from DER buffer */ + ExpectNotNull(pkey = d2i_PUBKEY(NULL, &p, + sizeof_ecc_clikeypub_der_256)); + + /* Write it to BIO */ + ExpectNotNull(bio = BIO_new(BIO_s_mem())); + ExpectIntEQ(i2d_PUBKEY_bio(bio, pkey), WOLFSSL_SUCCESS); + + /* Read it back and verify round-trip */ + ExpectNotNull(pkey2 = d2i_PUBKEY_bio(bio, NULL)); + + EVP_PKEY_free(pkey2); + pkey2 = NULL; + EVP_PKEY_free(pkey); + pkey = NULL; + BIO_free(bio); + bio = NULL; + } +#endif + + (void)pkey; + (void)pkey2; + (void)bio; +#endif + return EXPECT_RESULT(); +} + #if (defined(OPENSSL_ALL) || defined(WOLFSSL_ASIO)) && !defined(NO_RSA) && \ !defined(NO_TLS) static int test_wolfSSL_d2i_PrivateKeys_bio(void) @@ -30232,16 +30299,41 @@ static int test_wolfSSL_CTX_set_timeout(void) static int test_wolfSSL_OpenSSL_version(void) { EXPECT_DECLS; -#if defined(OPENSSL_EXTRA) +#if defined(OPENSSL_EXTRA) && !defined(WOLFCRYPT_ONLY) const char* ver; -#if defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x10100000L - ExpectNotNull(ver = OpenSSL_version(0)); + ExpectNotNull(ver = OpenSSL_version(OPENSSL_VERSION)); + ExpectStrEQ(ver, "wolfSSL " LIBWOLFSSL_VERSION_STRING); + + /* Test OPENSSL_CFLAGS type */ + ExpectNotNull(ver = OpenSSL_version(OPENSSL_CFLAGS)); + ExpectStrEQ(ver, "compiler: information not available"); + + /* Test OPENSSL_BUILT_ON type */ + ExpectNotNull(ver = OpenSSL_version(OPENSSL_BUILT_ON)); +#ifdef HAVE_REPRODUCIBLE_BUILD + ExpectStrEQ(ver, "built on: date not available"); #else - ExpectNotNull(ver = OpenSSL_version()); + /* __DATE__/__TIME__ differ between translation units, so just check + * the prefix is present. */ + ExpectNotNull(XSTRSTR(ver, "built on: ")); #endif - ExpectIntEQ(XMEMCMP(ver, "wolfSSL " LIBWOLFSSL_VERSION_STRING, - XSTRLEN("wolfSSL " LIBWOLFSSL_VERSION_STRING)), 0); + + /* Test OPENSSL_PLATFORM type */ + ExpectNotNull(ver = OpenSSL_version(OPENSSL_PLATFORM)); + ExpectStrEQ(ver, "platform: information not available"); + + /* Test OPENSSL_DIR type */ + ExpectNotNull(ver = OpenSSL_version(OPENSSL_DIR)); + ExpectStrEQ(ver, "OPENSSLDIR: N/A"); + + /* Test OPENSSL_ENGINES_DIR type */ + ExpectNotNull(ver = OpenSSL_version(OPENSSL_ENGINES_DIR)); + ExpectStrEQ(ver, "ENGINESDIR: N/A"); + + /* Unknown selector returns the OpenSSL fallback string. */ + ExpectNotNull(ver = OpenSSL_version(99)); + ExpectStrEQ(ver, "not available"); #endif return EXPECT_RESULT(); } @@ -38210,6 +38302,7 @@ TEST_CASE testCases[] = { TEST_DECL(test_wolfSSL_d2i_and_i2d_PublicKey_ecc), #ifndef NO_BIO TEST_DECL(test_wolfSSL_d2i_PUBKEY), + TEST_DECL(test_wolfSSL_i2d_PUBKEY_bio), #if defined(OPENSSL_EXTRA) && defined(WOLFSSL_HAVE_MLDSA) && \ defined(WOLFSSL_MLDSA_NO_ASN1) && !defined(WOLFSSL_NO_ML_DSA_44) && \ !defined(WOLFSSL_NO_ML_DSA_65) && !defined(WOLFSSL_MLDSA_NO_VERIFY) diff --git a/tests/api/test_ossl_bio.c b/tests/api/test_ossl_bio.c index 6223ee8f932..e197fc549e6 100644 --- a/tests/api/test_ossl_bio.c +++ b/tests/api/test_ossl_bio.c @@ -1899,5 +1899,45 @@ int test_wolfSSL_BIO_get_init(void) return EXPECT_RESULT(); } +int test_wolfSSL_BIO_get_new_index(void) +{ + EXPECT_DECLS; +#if defined(OPENSSL_EXTRA) + int idx1, idx2, idx3; + BIO_METHOD* meth = NULL; + BIO* bio = NULL; + + /* Get three consecutive indices - should be unique and in valid range */ + idx1 = BIO_get_new_index(); + idx2 = BIO_get_new_index(); + idx3 = BIO_get_new_index(); + + ExpectIntGE(idx1, BIO_TYPE_START); + ExpectIntLE(idx1, WOLFSSL_BIO_TYPE_MAX); + ExpectIntGE(idx2, BIO_TYPE_START); + ExpectIntLE(idx2, WOLFSSL_BIO_TYPE_MAX); + ExpectIntGE(idx3, BIO_TYPE_START); + ExpectIntLE(idx3, WOLFSSL_BIO_TYPE_MAX); + + /* Each index must be unique */ + ExpectIntNE(idx1, idx2); + ExpectIntNE(idx2, idx3); + ExpectIntNE(idx1, idx3); + + /* Each consecutive call must return a strictly increasing value */ + ExpectIntGT(idx2, idx1); + ExpectIntGT(idx3, idx2); + + /* Use returned index with BIO_meth_new */ + ExpectNotNull(meth = BIO_meth_new(idx1, "custom_test")); + ExpectNotNull(bio = BIO_new(meth)); + ExpectIntEQ(BIO_method_type(bio), idx1); + + BIO_free(bio); + BIO_meth_free(meth); +#endif + return EXPECT_RESULT(); +} + #endif /* !NO_BIO */ diff --git a/tests/api/test_ossl_bio.h b/tests/api/test_ossl_bio.h index 7aac4f4addf..de1140ad115 100644 --- a/tests/api/test_ossl_bio.h +++ b/tests/api/test_ossl_bio.h @@ -49,6 +49,7 @@ int test_wolfSSL_BIO_set_conn_hostname(void); int test_wolfSSL_BIO_ctrl_pending_chain(void); int test_wolfSSL_BIO_meth_type_large(void); int test_wolfSSL_BIO_get_init(void); +int test_wolfSSL_BIO_get_new_index(void); #define TEST_OSSL_BIO_DECLS \ TEST_DECL_GROUP("ossl_bio", test_wolfSSL_BIO_gets), \ @@ -70,7 +71,8 @@ int test_wolfSSL_BIO_get_init(void); TEST_DECL_GROUP("ossl_bio", test_wolfSSL_BIO_set_conn_hostname), \ TEST_DECL_GROUP("ossl_bio", test_wolfSSL_BIO_ctrl_pending_chain), \ TEST_DECL_GROUP("ossl_bio", test_wolfSSL_BIO_meth_type_large), \ - TEST_DECL_GROUP("ossl_bio", test_wolfSSL_BIO_get_init) + TEST_DECL_GROUP("ossl_bio", test_wolfSSL_BIO_get_init), \ + TEST_DECL_GROUP("ossl_bio", test_wolfSSL_BIO_get_new_index) #define TEST_OSSL_BIO_TLS_DECLS \ TEST_DECL_GROUP("ossl_bio_tls", test_wolfSSL_BIO_connect), \ diff --git a/wolfcrypt/src/evp_pk.c b/wolfcrypt/src/evp_pk.c index 73b9ddc3f6a..b1cf7cbe0d3 100644 --- a/wolfcrypt/src/evp_pk.c +++ b/wolfcrypt/src/evp_pk.c @@ -2452,6 +2452,59 @@ int wolfSSL_i2d_PUBKEY(const WOLFSSL_EVP_PKEY *key, unsigned char **der) { return wolfSSL_i2d_PublicKey(key, der); } + +#ifndef NO_BIO +/* Encode public key as DER data and write to BIO. + * + * @param [in] bio BIO to write data to. + * @param [in] key Public key to encode. + * @return WOLFSSL_SUCCESS on success. + * @return WOLFSSL_FAILURE on failure. + */ +int wolfSSL_i2d_PUBKEY_bio(WOLFSSL_BIO* bio, WOLFSSL_EVP_PKEY* key) +{ + int ret = WC_NO_ERR_TRACE(WOLFSSL_FAILURE); + int derSz = 0; + byte* der = NULL; + byte* derPtr = NULL; + + WOLFSSL_ENTER("wolfSSL_i2d_PUBKEY_bio"); + + if (bio == NULL || key == NULL) { + return WOLFSSL_FAILURE; + } + + derSz = wolfSSL_i2d_PUBKEY(key, NULL); + if (derSz <= 0) { + WOLFSSL_MSG("wolfSSL_i2d_PUBKEY size query failed"); + return WOLFSSL_FAILURE; + } + + der = (byte*)XMALLOC((size_t)derSz, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (der == NULL) { + WOLFSSL_MSG("XMALLOC failed"); + return WOLFSSL_FAILURE; + } + + derPtr = der; + derSz = wolfSSL_i2d_PUBKEY(key, &derPtr); + if (derSz <= 0) { + WOLFSSL_MSG("wolfSSL_i2d_PUBKEY failed"); + goto cleanup; + } + + if (wolfSSL_BIO_write(bio, der, derSz) != derSz) { + goto cleanup; + } + + ret = WOLFSSL_SUCCESS; + +cleanup: + XFREE(der, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return ret; +} +#endif /* !NO_BIO */ + #endif /* !NO_ASN && !NO_PWDBASED */ #endif /* OPENSSL_EXTRA */ diff --git a/wolfssl/openssl/bio.h b/wolfssl/openssl/bio.h index f797d94ab58..f34bc1450cf 100644 --- a/wolfssl/openssl/bio.h +++ b/wolfssl/openssl/bio.h @@ -138,6 +138,8 @@ #define BIO_TYPE_BIO WOLFSSL_BIO_BIO #define BIO_TYPE_MEM WOLFSSL_BIO_MEMORY #define BIO_TYPE_BASE64 WOLFSSL_BIO_BASE64 +#define BIO_TYPE_START WOLFSSL_BIO_TYPE_START +#define BIO_get_new_index wolfSSL_BIO_get_new_index #define BIO_vprintf wolfSSL_BIO_vprintf #define BIO_printf wolfSSL_BIO_printf diff --git a/wolfssl/openssl/opensslv.h b/wolfssl/openssl/opensslv.h index df75d9e0d43..a11284c9c34 100644 --- a/wolfssl/openssl/opensslv.h +++ b/wolfssl/openssl/opensslv.h @@ -68,6 +68,21 @@ #ifndef OPENSSL_VERSION #define OPENSSL_VERSION 0 #endif +#ifndef OPENSSL_CFLAGS + #define OPENSSL_CFLAGS 1 +#endif +#ifndef OPENSSL_BUILT_ON + #define OPENSSL_BUILT_ON 2 +#endif +#ifndef OPENSSL_PLATFORM + #define OPENSSL_PLATFORM 3 +#endif +#ifndef OPENSSL_DIR + #define OPENSSL_DIR 4 +#endif +#ifndef OPENSSL_ENGINES_DIR + #define OPENSSL_ENGINES_DIR 5 +#endif #ifndef OPENSSL_IS_WOLFSSL #define OPENSSL_IS_WOLFSSL diff --git a/wolfssl/openssl/ssl.h b/wolfssl/openssl/ssl.h index 5c95da71316..1b28b695780 100644 --- a/wolfssl/openssl/ssl.h +++ b/wolfssl/openssl/ssl.h @@ -273,6 +273,7 @@ typedef STACK_OF(ACCESS_DESCRIPTION) AUTHORITY_INFO_ACCESS; #define SSL_CTX_set_ecdh_auto wolfSSL_CTX_set_ecdh_auto #define i2d_PUBKEY wolfSSL_i2d_PUBKEY +#define i2d_PUBKEY_bio wolfSSL_i2d_PUBKEY_bio #define i2d_X509_PUBKEY wolfSSL_i2d_X509_PUBKEY #define d2i_PUBKEY wolfSSL_d2i_PUBKEY #define d2i_PUBKEY_bio wolfSSL_d2i_PUBKEY_bio @@ -1877,11 +1878,7 @@ typedef WOLFSSL_SRTP_PROTECTION_PROFILE SRTP_PROTECTION_PROFILE; #define X509_OBJECT_new wolfSSL_X509_OBJECT_new #define X509_OBJECT_free wolfSSL_X509_OBJECT_free #define X509_OBJECT_get_type wolfSSL_X509_OBJECT_get_type -#if defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x10100000L #define OpenSSL_version(x) wolfSSL_OpenSSL_version(x) -#else -#define OpenSSL_version(x) wolfSSL_OpenSSL_version() -#endif #define X509_OBJECT_retrieve_by_subject wolfSSL_X509_OBJECT_retrieve_by_subject diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index 423f027c740..1dbf226b0b2 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -782,6 +782,11 @@ enum BIO_TYPE { WOLFSSL_BIO_NULL = 10 }; +/* Starting index for custom BIO types returned by wolfSSL_BIO_get_new_index. + * Matches OpenSSL BIO_TYPE_START (128). */ +#define WOLFSSL_BIO_TYPE_START 128 +#define WOLFSSL_BIO_TYPE_MAX 255 + enum BIO_FLAGS { WOLFSSL_BIO_FLAG_BASE64_NO_NL = 0x01, WOLFSSL_BIO_FLAG_READ = 0x02, @@ -2193,6 +2198,7 @@ WOLFSSL_API int wolfSSL_BIO_should_retry(WOLFSSL_BIO *bio); WOLFSSL_API int wolfSSL_BIO_should_read(WOLFSSL_BIO *bio); WOLFSSL_API int wolfSSL_BIO_should_write(WOLFSSL_BIO *bio); +WOLFSSL_API int wolfSSL_BIO_get_new_index(void); WOLFSSL_API WOLFSSL_BIO_METHOD *wolfSSL_BIO_meth_new(int type, const char* name); WOLFSSL_API void wolfSSL_BIO_meth_free(WOLFSSL_BIO_METHOD* biom); WOLFSSL_API int wolfSSL_BIO_meth_set_write(WOLFSSL_BIO_METHOD* biom, wolfSSL_BIO_meth_write_cb biom_write); @@ -2489,6 +2495,7 @@ WOLFSSL_API WOLFSSL_EVP_PKEY* wolfSSL_d2i_PUBKEY_bio(WOLFSSL_BIO* bio, WOLFSSL_API WOLFSSL_EVP_PKEY* wolfSSL_d2i_PUBKEY(WOLFSSL_EVP_PKEY** key, const unsigned char** in, long inSz); WOLFSSL_API int wolfSSL_i2d_PUBKEY(const WOLFSSL_EVP_PKEY *key, unsigned char **der); +WOLFSSL_API int wolfSSL_i2d_PUBKEY_bio(WOLFSSL_BIO* bio, WOLFSSL_EVP_PKEY* key); WOLFSSL_API int wolfSSL_i2d_X509_PUBKEY(WOLFSSL_X509_PUBKEY* x509_PubKey, unsigned char** der); WOLFSSL_API WOLFSSL_EVP_PKEY* wolfSSL_d2i_PublicKey(int type, WOLFSSL_EVP_PKEY** pkey, @@ -3532,11 +3539,7 @@ WOLFSSL_API void wolfSSL_set_security_level(WOLFSSL * ssl, int level); /* which library version do we have */ WOLFSSL_API const char* wolfSSL_lib_version(void); -#if defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x10100000L -WOLFSSL_API const char* wolfSSL_OpenSSL_version(int a); -#else -WOLFSSL_API const char* wolfSSL_OpenSSL_version(void); -#endif +WOLFSSL_API const char* wolfSSL_OpenSSL_version(int type); /* which library version do we have in hex */ WOLFSSL_API word32 wolfSSL_lib_version_hex(void);