Commit 7e57092596 for openssl.org

commit 7e57092596c97683cea16ab2f712ac48138fece9
Author: Viktor Dukhovni <viktor@openssl.org>
Date:   Wed Apr 22 22:46:18 2026 +1000

    Handle NULL-buffer size probe in ossl_param_build_set_bn_pad()

    ossl_param_build_set_bn_pad() is reached by two distinct caller
    populations.  When an OSSL_PARAM_BLD template is supplied
    (bld != NULL), the template allocates backing storage internally and
    no caller-side sizing is required.  When an explicit OSSL_PARAM[]
    array is supplied (bld == NULL), the caller follows the standard
    OSSL_PARAM size-probe contract: invoke the primitive once with
    p->data == NULL to learn the required size via p->return_size, then
    allocate a buffer of that size and invoke again with the real
    storage.

    The bld == NULL branch did not honour the size-probe contract: with
    p->data == NULL and a non-zero sz it fell through to
    OSSL_PARAM_set_BN() and raised CRYPTO_R_TOO_SMALL_BUFFER, so callers
    could never discover the required size.

    The defect has been latent across several releases.  This primitive
    is the *padded* BN setter: it emits a fixed-width encoding regardless
    of the BN's actual magnitude, which is needed for the private key --
    a minimal encoding would leak its bit-length through timing or
    allocation side channels.  In practice the private key is the only
    provider parameter that reaches this primitive.  Callers that want
    private-key material have historically done so through
    EVP_PKEY_todata() and its OSSL_PARAM_BLD template path, where the
    bug is invisible.  EVP_PKEY_get_params() callers exist but have not
    previously needed the private-key BN.  Any caller that does request
    it on the explicit-params path -- whether by name or as part of
    iterating a provider's full gettable list -- now sees the probe
    behave as it does elsewhere.

    Reviewed-by: Eugene Syromiatnikov <esyr@openssl.org>
    Reviewed-by: Frederik Wedel-Heinen <fwh.openssl@gmail.com>
    MergeDate: Sun Apr 26 13:35:32 2026
    (Merged from https://github.com/openssl/openssl/pull/30942)

diff --git a/crypto/param_build_set.c b/crypto/param_build_set.c
index db49683ed9..51a2678350 100644
--- a/crypto/param_build_set.c
+++ b/crypto/param_build_set.c
@@ -73,6 +73,11 @@ int ossl_param_build_set_bn_pad(OSSL_PARAM_BLD *bld, OSSL_PARAM *p,
         return OSSL_PARAM_BLD_push_BN_pad(bld, key, bn, sz);
     p = OSSL_PARAM_locate(p, key);
     if (p != NULL) {
+        /* Size probe: NULL data means "report the required size". */
+        if (p->data == NULL) {
+            p->return_size = sz;
+            return 1;
+        }
         if (sz > p->data_size) {
             ERR_raise(ERR_LIB_CRYPTO, CRYPTO_R_TOO_SMALL_BUFFER);
             return 0;
diff --git a/test/evp_pkey_provided_test.c b/test/evp_pkey_provided_test.c
index f96b6e43ee..fbb418ab6b 100644
--- a/test/evp_pkey_provided_test.c
+++ b/test/evp_pkey_provided_test.c
@@ -1654,6 +1654,11 @@ static int test_fromdata_ec(void)
     BIGNUM *a = NULL;
     BIGNUM *b = NULL;
     BIGNUM *p = NULL;
+    OSSL_PARAM probe[2] = {
+        OSSL_PARAM_DEFN(OSSL_PKEY_PARAM_PRIV_KEY, OSSL_PARAM_UNSIGNED_INTEGER,
+            NULL, 0),
+        OSSL_PARAM_END
+    };

     if (!TEST_ptr(bld = OSSL_PARAM_BLD_new()))
         goto err;
@@ -1742,6 +1747,18 @@ static int test_fromdata_ec(void)
             || !TEST_BN_eq(group_b, b))
             goto err;

+        /*
+         * Probe the EC private-key BN length via the explicit-params
+         * path; with NULL data, return_size receives the required
+         * (padded) buffer size, which equals the byte length of the
+         * group order.
+         */
+        probe[0].return_size = OSSL_PARAM_UNMODIFIED;
+        if (!TEST_true(EVP_PKEY_get_params(pk, probe))
+            || !TEST_size_t_eq(probe[0].return_size,
+                BN_num_bytes(EC_GROUP_get0_order(group))))
+            goto err;
+
         EC_GROUP_free(group);
         group = NULL;
         BN_free(group_p);