@@ -1877,7 +1877,51 @@ static int test_ec_import_priv(void)
18771877 err = EVP_PKEY_fromdata (ctx2 , & pkey2 , EVP_PKEY_KEYPAIR , params ) != 1 ;
18781878 }
18791879
1880- /* For imported private only keys, get bn params should fail */
1880+ /* For imported private only keys, public key params behavior depends on OpenSSL version */
1881+ #if OPENSSL_VERSION_NUMBER > 0x30600000L
1882+ /* OpenSSL 3.6.0+ auto-derives public keys from private keys */
1883+ if (err == 0 ) {
1884+ err = EVP_PKEY_get_bn_param (pkey1 , OSSL_PKEY_PARAM_EC_PUB_X , & x1 ) != 1 ;
1885+ }
1886+ if (err == 0 ) {
1887+ err = EVP_PKEY_get_bn_param (pkey2 , OSSL_PKEY_PARAM_EC_PUB_X , & x2 ) != 1 ;
1888+ }
1889+ if (err == 0 ) {
1890+ err = EVP_PKEY_get_bn_param (pkey1 , OSSL_PKEY_PARAM_EC_PUB_Y , & y1 ) != 1 ;
1891+ }
1892+ if (err == 0 ) {
1893+ err = EVP_PKEY_get_bn_param (pkey2 , OSSL_PKEY_PARAM_EC_PUB_Y , & y2 ) != 1 ;
1894+ }
1895+
1896+ /* Verify public key is available */
1897+ if (err == 0 ) {
1898+ if (EVP_PKEY_get_octet_string_param (pkey1 ,
1899+ OSSL_PKEY_PARAM_PUB_KEY , NULL , 0 , (size_t * )& len ) != 1 ) {
1900+ err = 1 ;
1901+ }
1902+ }
1903+ if (err == 0 ) {
1904+ if (EVP_PKEY_get_octet_string_param (pkey2 ,
1905+ OSSL_PKEY_PARAM_PUB_KEY , NULL , 0 , (size_t * )& len ) != 1 ) {
1906+ err = 1 ;
1907+ }
1908+ }
1909+
1910+ /* Verify encoded public key is available */
1911+ if (err == 0 ) {
1912+ if (EVP_PKEY_get_octet_string_param (pkey1 ,
1913+ OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY , NULL , 0 , (size_t * )& len ) != 1 ) {
1914+ err = 1 ;
1915+ }
1916+ }
1917+ if (err == 0 ) {
1918+ if (EVP_PKEY_get_octet_string_param (pkey2 ,
1919+ OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY , NULL , 0 , (size_t * )& len ) != 1 ) {
1920+ err = 1 ;
1921+ }
1922+ }
1923+ #else
1924+ /* OpenSSL < 3.6.0: private-only keys should not have public components */
18811925 if (err == 0 ) {
18821926 err = EVP_PKEY_get_bn_param (pkey1 , OSSL_PKEY_PARAM_EC_PUB_X , & x1 ) == 1 ;
18831927 }
@@ -1918,7 +1962,8 @@ static int test_ec_import_priv(void)
19181962 err = 1 ;
19191963 }
19201964 }
1921- #endif
1965+ #endif /* OPENSSL_VERSION_NUMBER >= 0x30006000L 3.0.6+ */
1966+ #endif /* OPENSSL_VERSION_NUMBER > 0x30600000L 3.6.0+ */
19221967
19231968 EVP_PKEY_free (pkey1 );
19241969 EVP_PKEY_free (pkey2 );
@@ -2060,4 +2105,105 @@ int test_ec_null_init(void* data)
20602105 return err ;
20612106}
20622107
2108+ #if OPENSSL_VERSION_NUMBER > 0x30600000L
2109+ static int test_ec_auto_derive_pub (void )
2110+ {
2111+ int err = 0 ;
2112+ EVP_PKEY_CTX * ctx = NULL ;
2113+ EVP_PKEY * pkey = NULL ;
2114+ OSSL_PARAM * params = NULL ;
2115+ OSSL_PARAM_BLD * bld = NULL ;
2116+ BIGNUM * priv = NULL ;
2117+ BIGNUM * pub_x = NULL ;
2118+ BIGNUM * pub_y = NULL ;
2119+ unsigned char pub_key [65 ] = {0 };
2120+ size_t pub_key_len = sizeof (pub_key );
2121+
2122+ /* Build params with private key only (no public key) */
2123+ err = (bld = OSSL_PARAM_BLD_new ()) == NULL ;
2124+ if (err == 0 ) {
2125+ err = OSSL_PARAM_BLD_push_utf8_string (bld , OSSL_PKEY_PARAM_GROUP_NAME ,
2126+ ecc_p256_group_str , 0 ) != 1 ;
2127+ }
2128+ if (err == 0 ) {
2129+ err = (priv = BN_bin2bn (ecc_p256_priv , sizeof (ecc_p256_priv ), NULL )) == NULL ;
2130+ }
2131+ if (err == 0 ) {
2132+ err = OSSL_PARAM_BLD_push_BN (bld , OSSL_PKEY_PARAM_PRIV_KEY , priv ) != 1 ;
2133+ }
2134+ if (err == 0 ) {
2135+ err = (params = OSSL_PARAM_BLD_to_param (bld )) == NULL ;
2136+ }
2137+ /* Import key using wolfProvider */
2138+ if (err == 0 ) {
2139+ err = (ctx = EVP_PKEY_CTX_new_from_name (wpLibCtx , "EC" , NULL )) == NULL ;
2140+ }
2141+ if (err == 0 ) {
2142+ err = EVP_PKEY_fromdata_init (ctx ) != 1 ;
2143+ }
2144+ if (err == 0 ) {
2145+ err = EVP_PKEY_fromdata (ctx , & pkey , EVP_PKEY_KEYPAIR , params ) != 1 ;
2146+ }
2147+ /* Verify public X coordinate is available (auto-derived) */
2148+ if (err == 0 ) {
2149+ err = EVP_PKEY_get_bn_param (pkey , OSSL_PKEY_PARAM_EC_PUB_X , & pub_x ) != 1 ;
2150+ }
2151+ /* Verify public Y coordinate is available (auto-derived) */
2152+ if (err == 0 ) {
2153+ err = EVP_PKEY_get_bn_param (pkey , OSSL_PKEY_PARAM_EC_PUB_Y , & pub_y ) != 1 ;
2154+ }
2155+ /* Verify public key octet string is available */
2156+ if (err == 0 ) {
2157+ err = EVP_PKEY_get_octet_string_param (pkey , OSSL_PKEY_PARAM_PUB_KEY ,
2158+ pub_key , pub_key_len , & pub_key_len ) != 1 ;
2159+ }
2160+ if (err == 0 ) {
2161+ if (pub_key_len == 0 || pub_key_len > sizeof (pub_key )) {
2162+ err = 1 ;
2163+ }
2164+ }
2165+ /* Verify encoded public key is available */
2166+ if (err == 0 ) {
2167+ pub_key_len = sizeof (pub_key );
2168+ err = EVP_PKEY_get_octet_string_param (pkey , OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY ,
2169+ pub_key , pub_key_len , & pub_key_len ) != 1 ;
2170+ }
2171+ if (err == 0 ) {
2172+ if (pub_key_len == 0 || pub_key_len > sizeof (pub_key )) {
2173+ err = 1 ;
2174+ }
2175+ }
2176+ /* Verify the derived public key is valid (non-zero coordinates) */
2177+ if (err == 0 ) {
2178+ if (BN_is_zero (pub_x ) || BN_is_zero (pub_y )) {
2179+ err = 1 ;
2180+ }
2181+ }
2182+
2183+ EVP_PKEY_free (pkey );
2184+ EVP_PKEY_CTX_free (ctx );
2185+ OSSL_PARAM_free (params );
2186+ OSSL_PARAM_BLD_free (bld );
2187+ BN_clear_free (priv );
2188+ BN_free (pub_x );
2189+ BN_free (pub_y );
2190+
2191+ return err ;
2192+ }
2193+ #endif /* OPENSSL_VERSION_NUMBER > 0x30600000L */
2194+
2195+ int test_ec_auto_derive_pubkey (void * data )
2196+ {
2197+ int err = 0 ;
2198+ (void )data ;
2199+
2200+ #if OPENSSL_VERSION_NUMBER > 0x30600000L
2201+ err = test_ec_auto_derive_pub ();
2202+ #else
2203+ err = 0 ;
2204+ #endif
2205+
2206+ return err ;
2207+ }
2208+
20632209#endif /* WP_HAVE_ECC */
0 commit comments