File openssl-CVE-2022-40735.patch of Package openssl-3.29247

From 14e7c6b7945ec2a9201c1ac29a9e3042363b5102 Mon Sep 17 00:00:00 2001
From: Tomas Mraz <tomas@openssl.org>
Date: Wed, 13 Jul 2022 15:06:00 +0200
Subject: [PATCH 1/4] For known safe primes use the minimum key length
 according to RFC 7919

Longer private key sizes unnecessarily raise the cycles needed to
compute the shared secret without any increase of the real security.

This fixes a regression from 1.1.1 where these shorter keys
were generated for the known safe primes.
---
 crypto/dh/dh_group_params.c                               |    5 -
 crypto/ffc/ffc_backend.c                                  |    2 
 crypto/ffc/ffc_dh.c                                       |   49 +++++++++-----
 crypto/ffc/ffc_key_generate.c                             |    8 +-
 crypto/ffc/ffc_params.c                                   |    1 
 include/internal/ffc.h                                    |    5 +
 providers/implementations/encode_decode/encode_key2text.c |    6 +
 test/evp_extra_test2.c                                    |   10 ++
 test/ffc_internal_test.c                                  |   45 ++++++++++++
 test/recipes/30-test_evp_pkey_provided/DH.priv.txt        |    1 
 test/recipes/30-test_evp_pkey_provided/DH.pub.txt         |    1 
 11 files changed, 106 insertions(+), 27 deletions(-)

--- a/crypto/dh/dh_group_params.c
+++ b/crypto/dh/dh_group_params.c
@@ -32,7 +32,7 @@ static DH *dh_param_init(OSSL_LIB_CTX *l
     if (dh == NULL)
         return NULL;
 
-    ossl_ffc_named_group_set_pqg(&dh->params, group);
+    ossl_ffc_named_group_set(&dh->params, group);
     dh->params.nid = ossl_ffc_named_group_get_uid(group);
     dh->dirty_cnt++;
     return dh;
@@ -73,8 +73,9 @@ void ossl_dh_cache_named_group(DH *dh)
                                                     dh->params.g)) != NULL) {
         if (dh->params.q == NULL)
             dh->params.q = (BIGNUM *)ossl_ffc_named_group_get_q(group);
-        /* cache the nid */
+        /* cache the nid and default key length */
         dh->params.nid = ossl_ffc_named_group_get_uid(group);
+        dh->params.keylength = ossl_ffc_named_group_get_keylength(group);
         dh->dirty_cnt++;
     }
 }
--- a/crypto/ffc/ffc_backend.c
+++ b/crypto/ffc/ffc_backend.c
@@ -38,7 +38,7 @@ int ossl_ffc_params_fromdata(FFC_PARAMS
 
         if (prm->data_type != OSSL_PARAM_UTF8_STRING
             || (group = ossl_ffc_name_to_dh_named_group(prm->data)) == NULL
-            || !ossl_ffc_named_group_set_pqg(ffc, group))
+            || !ossl_ffc_named_group_set(ffc, group))
 #endif
             goto err;
     }
--- a/crypto/ffc/ffc_dh.c
+++ b/crypto/ffc/ffc_dh.c
@@ -14,16 +14,18 @@
 
 #ifndef OPENSSL_NO_DH
 
-# define FFDHE(sz) {                                                        \
+# define FFDHE(sz, keylength) {                                             \
         SN_ffdhe##sz, NID_ffdhe##sz,                                        \
         sz,                                                                 \
+        keylength,                                                          \
         &ossl_bignum_ffdhe##sz##_p, &ossl_bignum_ffdhe##sz##_q,             \
         &ossl_bignum_const_2,                                               \
     }
 
-# define MODP(sz)  {                                                        \
+# define MODP(sz, keylength)  {                                             \
         SN_modp_##sz, NID_modp_##sz,                                        \
         sz,                                                                 \
+        keylength,                                                          \
         &ossl_bignum_modp_##sz##_p, &ossl_bignum_modp_##sz##_q,             \
         &ossl_bignum_const_2                                                \
     }
@@ -31,14 +33,15 @@
 # define RFC5114(name, uid, sz, tag) {                                      \
         name, uid,                                                          \
         sz,                                                                 \
+        0,                                                                  \
         &ossl_bignum_dh##tag##_p, &ossl_bignum_dh##tag##_q,                 \
         &ossl_bignum_dh##tag##_g                                            \
     }
 
 #else
 
-# define FFDHE(sz)                      { SN_ffdhe##sz, NID_ffdhe##sz }
-# define MODP(sz)                       { SN_modp_##sz, NID_modp_##sz }
+# define FFDHE(sz, keylength)           { SN_ffdhe##sz, NID_ffdhe##sz }
+# define MODP(sz, keylength)            { SN_modp_##sz, NID_modp_##sz }
 # define RFC5114(name, uid, sz, tag)    { name, uid }
 
 #endif
@@ -48,26 +51,32 @@ struct dh_named_group_st {
     int uid;
 #ifndef OPENSSL_NO_DH
     int32_t nbits;
+    int keylength;
     const BIGNUM *p;
     const BIGNUM *q;
     const BIGNUM *g;
 #endif
 };
 
+/*
+ * The private key length values are taken from RFC7919 with the values for
+ * MODP primes given the same lengths as the equivalent FFDHE.
+ * The MODP 1536 value is approximated.
+ */
 static const DH_NAMED_GROUP dh_named_groups[] = {
-    FFDHE(2048),
-    FFDHE(3072),
-    FFDHE(4096),
-    FFDHE(6144),
-    FFDHE(8192),
+    FFDHE(2048, 225),
+    FFDHE(3072, 275),
+    FFDHE(4096, 325),
+    FFDHE(6144, 375),
+    FFDHE(8192, 400),
 #ifndef FIPS_MODULE
-    MODP(1536),
+    MODP(1536, 200),
 #endif
-    MODP(2048),
-    MODP(3072),
-    MODP(4096),
-    MODP(6144),
-    MODP(8192),
+    MODP(2048, 225),
+    MODP(3072, 275),
+    MODP(4096, 325),
+    MODP(6144, 375),
+    MODP(8192, 400),
     /*
      * Additional dh named groups from RFC 5114 that have a different g.
      * The uid can be any unique identifier.
@@ -135,6 +144,13 @@ const char *ossl_ffc_named_group_get_nam
 }
 
 #ifndef OPENSSL_NO_DH
+int ossl_ffc_named_group_get_keylength(const DH_NAMED_GROUP *group)
+{
+    if (group == NULL)
+        return 0;
+    return group->keylength;
+}
+
 const BIGNUM *ossl_ffc_named_group_get_q(const DH_NAMED_GROUP *group)
 {
     if (group == NULL)
@@ -142,13 +158,14 @@ const BIGNUM *ossl_ffc_named_group_get_q
     return group->q;
 }
 
-int ossl_ffc_named_group_set_pqg(FFC_PARAMS *ffc, const DH_NAMED_GROUP *group)
+int ossl_ffc_named_group_set(FFC_PARAMS *ffc, const DH_NAMED_GROUP *group)
 {
     if (ffc == NULL || group == NULL)
         return 0;
 
     ossl_ffc_params_set0_pqg(ffc, (BIGNUM *)group->p, (BIGNUM *)group->q,
                              (BIGNUM *)group->g);
+    ffc->keylength = group->keylength;
 
     /* flush the cached nid, The DH layer is responsible for caching */
     ffc->nid = NID_undef;
--- a/crypto/ffc/ffc_key_generate.c
+++ b/crypto/ffc/ffc_key_generate.c
@@ -25,11 +25,11 @@ int ossl_ffc_generate_private_key(BN_CTX
     int ret = 0, qbits = BN_num_bits(params->q);
     BIGNUM *m, *two_powN = NULL;
 
-    /* Deal with the edge case where the value of N is not set */
-    if (N == 0)
-        N = qbits;
+    /* Deal with the edge cases where the value of N and/or s is not set */
     if (s == 0)
-        s = N / 2;
+        goto err;
+    if (N == 0)
+        N = params->keylength ? params->keylength : 2 * s;
 
     /* Step (2) : check range of N */
     if (N < 2 * s || N > qbits)
--- a/crypto/ffc/ffc_params.c
+++ b/crypto/ffc/ffc_params.c
@@ -197,6 +197,7 @@ int ossl_ffc_params_copy(FFC_PARAMS *dst
     dst->h = src->h;
     dst->gindex = src->gindex;
     dst->flags = src->flags;
+    dst->keylength = src->keylength;
     return 1;
 }
 
--- a/include/internal/ffc.h
+++ b/include/internal/ffc.h
@@ -113,6 +113,8 @@ typedef struct ffc_params_st {
      */
     const char *mdname;
     const char *mdprops;
+    /* Default key length for known named groups according to RFC7919 */
+    int keylength;
 } FFC_PARAMS;
 
 void ossl_ffc_params_init(FFC_PARAMS *params);
@@ -206,8 +208,9 @@ const DH_NAMED_GROUP *ossl_ffc_numbers_t
 int ossl_ffc_named_group_get_uid(const DH_NAMED_GROUP *group);
 const char *ossl_ffc_named_group_get_name(const DH_NAMED_GROUP *);
 #ifndef OPENSSL_NO_DH
+int ossl_ffc_named_group_get_keylength(const DH_NAMED_GROUP *group);
 const BIGNUM *ossl_ffc_named_group_get_q(const DH_NAMED_GROUP *group);
-int ossl_ffc_named_group_set_pqg(FFC_PARAMS *ffc, const DH_NAMED_GROUP *group);
+int ossl_ffc_named_group_set(FFC_PARAMS *ffc, const DH_NAMED_GROUP *group);
 #endif
 
 #endif /* OSSL_INTERNAL_FFC_H */
--- a/providers/implementations/encode_decode/encode_key2text.c
+++ b/providers/implementations/encode_decode/encode_key2text.c
@@ -217,6 +217,7 @@ static int dh_to_text(BIO *out, const vo
     const BIGNUM *priv_key = NULL, *pub_key = NULL;
     const FFC_PARAMS *params = NULL;
     const BIGNUM *p = NULL;
+    long length;
 
     if (out == NULL || dh == NULL) {
         ERR_raise(ERR_LIB_PROV, ERR_R_PASSED_NULL_PARAMETER);
@@ -269,6 +270,11 @@ static int dh_to_text(BIO *out, const vo
     if (params != NULL
         && !ffc_params_to_text(out, params))
         return 0;
+    length = DH_get_length(dh);
+    if (length > 0
+        && BIO_printf(out, "recommended-private-length: %ld bits\n",
+                      length) <= 0)
+        return 0;
 
     return 1;
 }
--- a/test/evp_extra_test2.c
+++ b/test/evp_extra_test2.c
@@ -333,6 +333,10 @@ static int test_dh_tofrom_data_select(vo
     OSSL_PARAM params[2];
     EVP_PKEY *key = NULL;
     EVP_PKEY_CTX *gctx = NULL;
+# ifndef OPENSSL_NO_DEPRECATED_3_0
+    const DH *dhkey;
+    const BIGNUM *privkey;
+# endif
 
     params[0] = OSSL_PARAM_construct_utf8_string("group", "ffdhe2048", 0);
     params[1] = OSSL_PARAM_construct_end();
@@ -341,6 +345,12 @@ static int test_dh_tofrom_data_select(vo
           && TEST_true(EVP_PKEY_CTX_set_params(gctx, params))
           && TEST_int_gt(EVP_PKEY_generate(gctx, &key), 0)
           && TEST_true(do_pkey_tofrom_data_select(key, "DHX"));
+# ifndef OPENSSL_NO_DEPRECATED_3_0
+    dhkey = EVP_PKEY_get0_DH(key);
+    ret = ret && TEST_ptr(dhkey);
+    ret = ret && TEST_ptr(privkey = DH_get0_priv_key(dhkey))
+              && TEST_int_le(BN_num_bits(privkey), 225);
+# endif
     EVP_PKEY_free(key);
     EVP_PKEY_CTX_free(gctx);
     return ret;
--- a/test/ffc_internal_test.c
+++ b/test/ffc_internal_test.c
@@ -27,6 +27,7 @@
 #include "testutil.h"
 
 #include "internal/ffc.h"
+#include "crypto/security_bits.h"
 
 #ifndef OPENSSL_NO_DSA
 static const unsigned char dsa_2048_224_sha224_p[] = {
@@ -629,6 +630,9 @@ static int ffc_private_gen_test(int inde
     /* fail since N > len(q) */
     if (!TEST_false(ossl_ffc_generate_private_key(ctx, params, N + 1, 112, priv)))
         goto err;
+    /* s must be always set */
+    if (!TEST_false(ossl_ffc_generate_private_key(ctx, params, N, 0, priv)))
+        goto err;
     /* pass since 2s <= N <= len(q) */
     if (!TEST_true(ossl_ffc_generate_private_key(ctx, params, N, 112, priv)))
         goto err;
@@ -640,9 +644,12 @@ static int ffc_private_gen_test(int inde
         goto err;
     if (!TEST_true(ossl_ffc_validate_private_key(params->q, priv, &res)))
         goto err;
-
-    /* N and s are ignored in this case */
-    if (!TEST_true(ossl_ffc_generate_private_key(ctx, params, 0, 0, priv)))
+    /* N is ignored in this case */
+    if (!TEST_true(ossl_ffc_generate_private_key(ctx, params, 0,
+                                                 ossl_ifc_ffc_compute_security_bits(BN_num_bits(params->p)),
+                                                 priv)))
+        goto err;
+    if (!TEST_int_le(BN_num_bits(priv), 225))
         goto err;
     if (!TEST_true(ossl_ffc_validate_private_key(params->q, priv, &res)))
         goto err;
@@ -654,6 +661,37 @@ err:
     BN_CTX_free(ctx);
     return ret;
 }
+
+static int ffc_params_copy_test(void)
+{
+    int ret = 0;
+    DH *dh = NULL;
+    FFC_PARAMS *params, copy;
+
+    ossl_ffc_params_init(&copy);
+
+    if (!TEST_ptr(dh = DH_new_by_nid(NID_ffdhe3072)))
+        goto err;
+    params = ossl_dh_get0_params(dh);
+
+    if (!TEST_int_eq(params->keylength, 275))
+        goto err;
+
+    if (!TEST_true(ossl_ffc_params_copy(&copy, params)))
+        goto err;
+
+    if (!TEST_int_eq(copy.keylength, 275))
+        goto err;
+
+    if (!TEST_true(ossl_ffc_params_cmp(&copy, params, 0)))
+        goto err;
+
+    ret = 1;
+err:
+    ossl_ffc_params_cleanup(&copy);
+    DH_free(dh);
+    return ret;
+}
 #endif /* OPENSSL_NO_DH */
 
 int setup_tests(void)
@@ -669,6 +707,7 @@ int setup_tests(void)
     ADD_TEST(ffc_public_validate_test);
     ADD_TEST(ffc_private_validate_test);
     ADD_ALL_TESTS(ffc_private_gen_test, 10);
+    ADD_TEST(ffc_params_copy_test);
 #endif /* OPENSSL_NO_DH */
     return 1;
 }
--- a/test/recipes/30-test_evp_pkey_provided/DH.priv.txt
+++ b/test/recipes/30-test_evp_pkey_provided/DH.priv.txt
@@ -22,3 +22,4 @@ public-key:
     a8:ee:72:13:45:65:15:42:17:aa:d8:ab:cf:33:42:
     83:42
 GROUP: ffdhe2048
+recommended-private-length: 224 bits
--- a/test/recipes/30-test_evp_pkey_provided/DH.pub.txt
+++ b/test/recipes/30-test_evp_pkey_provided/DH.pub.txt
@@ -19,3 +19,4 @@ public-key:
     a8:ee:72:13:45:65:15:42:17:aa:d8:ab:cf:33:42:
     83:42
 GROUP: ffdhe2048
+recommended-private-length: 224 bits
openSUSE Build Service is sponsored by