isaacpittman-hitachi / rpms / openssl

Forked from rpms/openssl 2 years ago
Clone

Blame SOURCES/0106-CVE-2023-0217-dsa.patch

3da501
From 23985bac83fd50c8e29431009302b5442f985096 Mon Sep 17 00:00:00 2001
3da501
From: slontis <shane.lontis@oracle.com>
3da501
Date: Wed, 11 Jan 2023 11:05:04 +1000
3da501
Subject: [PATCH 10/18] Fix NULL deference when validating FFC public key.
3da501
3da501
Fixes CVE-2023-0217
3da501
3da501
When attempting to do a BN_Copy of params->p there was no NULL check.
3da501
Since BN_copy does not check for NULL this is a NULL reference.
3da501
3da501
As an aside BN_cmp() does do a NULL check, so there are other checks
3da501
that fail because a NULL is passed. A more general check for NULL params
3da501
has been added for both FFC public and private key validation instead.
3da501
3da501
Reviewed-by: Matt Caswell <matt@openssl.org>
3da501
Reviewed-by: Paul Dale <pauli@openssl.org>
3da501
Reviewed-by: Tomas Mraz <tomas@openssl.org>
3da501
---
3da501
 crypto/ffc/ffc_key_validate.c |  9 +++++++++
3da501
 include/internal/ffc.h        |  1 +
3da501
 test/ffc_internal_test.c      | 31 +++++++++++++++++++++++++++++++
3da501
 3 files changed, 41 insertions(+)
3da501
3da501
diff --git a/crypto/ffc/ffc_key_validate.c b/crypto/ffc/ffc_key_validate.c
3da501
index 9f6525a2c8..442303e4b3 100644
3da501
--- a/crypto/ffc/ffc_key_validate.c
3da501
+++ b/crypto/ffc/ffc_key_validate.c
3da501
@@ -24,6 +24,11 @@ int ossl_ffc_validate_public_key_partial(const FFC_PARAMS *params,
3da501
     BN_CTX *ctx = NULL;
3da501
 
3da501
     *ret = 0;
3da501
+    if (params == NULL || pub_key == NULL || params->p == NULL) {
3da501
+        *ret = FFC_ERROR_PASSED_NULL_PARAM;
3da501
+        return 0;
3da501
+    }
3da501
+
3da501
     ctx = BN_CTX_new_ex(NULL);
3da501
     if (ctx == NULL)
3da501
         goto err;
3da501
@@ -107,6 +112,10 @@ int ossl_ffc_validate_private_key(const BIGNUM *upper, const BIGNUM *priv,
3da501
 
3da501
     *ret = 0;
3da501
 
3da501
+    if (priv == NULL || upper == NULL) {
3da501
+        *ret = FFC_ERROR_PASSED_NULL_PARAM;
3da501
+        goto err;
3da501
+    }
3da501
     if (BN_cmp(priv, BN_value_one()) < 0) {
3da501
         *ret |= FFC_ERROR_PRIVKEY_TOO_SMALL;
3da501
         goto err;
3da501
diff --git a/include/internal/ffc.h b/include/internal/ffc.h
3da501
index 732514a6c2..b8b7140857 100644
3da501
--- a/include/internal/ffc.h
3da501
+++ b/include/internal/ffc.h
3da501
@@ -76,6 +76,7 @@
3da501
 # define FFC_ERROR_NOT_SUITABLE_GENERATOR 0x08
3da501
 # define FFC_ERROR_PRIVKEY_TOO_SMALL      0x10
3da501
 # define FFC_ERROR_PRIVKEY_TOO_LARGE      0x20
3da501
+# define FFC_ERROR_PASSED_NULL_PARAM      0x40
3da501
 
3da501
 /*
3da501
  * Finite field cryptography (FFC) domain parameters are used by DH and DSA.
3da501
diff --git a/test/ffc_internal_test.c b/test/ffc_internal_test.c
3da501
index 2c97293573..9f67bd29b9 100644
3da501
--- a/test/ffc_internal_test.c
3da501
+++ b/test/ffc_internal_test.c
3da501
@@ -510,6 +510,27 @@ static int ffc_public_validate_test(void)
3da501
     if (!TEST_true(ossl_ffc_validate_public_key(params, pub, &res)))
3da501
         goto err;
3da501
 
3da501
+    /* Fail if params is NULL */
3da501
+    if (!TEST_false(ossl_ffc_validate_public_key(NULL, pub, &res)))
3da501
+        goto err;
3da501
+    if (!TEST_int_eq(FFC_ERROR_PASSED_NULL_PARAM, res))
3da501
+        goto err;
3da501
+    res = -1;
3da501
+    /* Fail if pubkey is NULL */
3da501
+    if (!TEST_false(ossl_ffc_validate_public_key(params, NULL, &res)))
3da501
+        goto err;
3da501
+    if (!TEST_int_eq(FFC_ERROR_PASSED_NULL_PARAM, res))
3da501
+        goto err;
3da501
+    res = -1;
3da501
+
3da501
+    BN_free(params->p);
3da501
+    params->p = NULL;
3da501
+    /* Fail if params->p is NULL */
3da501
+    if (!TEST_false(ossl_ffc_validate_public_key(params, pub, &res)))
3da501
+        goto err;
3da501
+    if (!TEST_int_eq(FFC_ERROR_PASSED_NULL_PARAM, res))
3da501
+        goto err;
3da501
+
3da501
     ret = 1;
3da501
 err:
3da501
     DH_free(dh);
3da501
@@ -567,6 +588,16 @@ static int ffc_private_validate_test(void)
3da501
     if (!TEST_true(ossl_ffc_validate_private_key(params->q, priv, &res)))
3da501
         goto err;
3da501
 
3da501
+    if (!TEST_false(ossl_ffc_validate_private_key(NULL, priv, &res)))
3da501
+        goto err;
3da501
+    if (!TEST_int_eq(FFC_ERROR_PASSED_NULL_PARAM, res))
3da501
+        goto err;
3da501
+    res = -1;
3da501
+    if (!TEST_false(ossl_ffc_validate_private_key(params->q, NULL, &res)))
3da501
+        goto err;
3da501
+    if (!TEST_int_eq(FFC_ERROR_PASSED_NULL_PARAM, res))
3da501
+        goto err;
3da501
+
3da501
     ret = 1;
3da501
 err:
3da501
     DH_free(dh);
3da501
-- 
3da501
2.39.1
3da501
3da501
From c1b4467a7cc129a74fc5205b80a5c47556b99416 Mon Sep 17 00:00:00 2001
3da501
From: Tomas Mraz <tomas@openssl.org>
3da501
Date: Fri, 13 Jan 2023 17:57:59 +0100
3da501
Subject: [PATCH 11/18] Prevent creating DSA and DH keys without parameters
3da501
 through import
3da501
3da501
Reviewed-by: Matt Caswell <matt@openssl.org>
3da501
Reviewed-by: Paul Dale <pauli@openssl.org>
3da501
---
3da501
 providers/implementations/keymgmt/dh_kmgmt.c  | 4 ++--
3da501
 providers/implementations/keymgmt/dsa_kmgmt.c | 5 +++--
3da501
 2 files changed, 5 insertions(+), 4 deletions(-)
3da501
3da501
diff --git a/providers/implementations/keymgmt/dh_kmgmt.c b/providers/implementations/keymgmt/dh_kmgmt.c
3da501
index 58a5fd009f..c2d87b4a7f 100644
3da501
--- a/providers/implementations/keymgmt/dh_kmgmt.c
3da501
+++ b/providers/implementations/keymgmt/dh_kmgmt.c
3da501
@@ -198,8 +198,8 @@ static int dh_import(void *keydata, int selection, const OSSL_PARAM params[])
3da501
     if ((selection & DH_POSSIBLE_SELECTIONS) == 0)
3da501
         return 0;
3da501
 
3da501
-    if ((selection & OSSL_KEYMGMT_SELECT_ALL_PARAMETERS) != 0)
3da501
-        ok = ok && ossl_dh_params_fromdata(dh, params);
3da501
+    /* a key without parameters is meaningless */
3da501
+    ok = ok && ossl_dh_params_fromdata(dh, params);
3da501
 
3da501
     if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != 0)
3da501
         ok = ok && ossl_dh_key_fromdata(dh, params);
3da501
diff --git a/providers/implementations/keymgmt/dsa_kmgmt.c b/providers/implementations/keymgmt/dsa_kmgmt.c
3da501
index 100e917167..881680c085 100644
3da501
--- a/providers/implementations/keymgmt/dsa_kmgmt.c
3da501
+++ b/providers/implementations/keymgmt/dsa_kmgmt.c
3da501
@@ -199,8 +199,9 @@ static int dsa_import(void *keydata, int selection, const OSSL_PARAM params[])
3da501
     if ((selection & DSA_POSSIBLE_SELECTIONS) == 0)
3da501
         return 0;
3da501
 
3da501
-    if ((selection & OSSL_KEYMGMT_SELECT_ALL_PARAMETERS) != 0)
3da501
-        ok = ok && ossl_dsa_ffc_params_fromdata(dsa, params);
3da501
+    /* a key without parameters is meaningless */
3da501
+    ok = ok && ossl_dsa_ffc_params_fromdata(dsa, params);
3da501
+
3da501
     if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != 0)
3da501
         ok = ok && ossl_dsa_key_fromdata(dsa, params);
3da501
 
3da501
-- 
3da501
2.39.1
3da501
3da501
From fab4973801bdc11c29c4c8ccf65cf39cbc63ce9b Mon Sep 17 00:00:00 2001
3da501
From: Tomas Mraz <tomas@openssl.org>
3da501
Date: Fri, 13 Jan 2023 17:59:52 +0100
3da501
Subject: [PATCH 12/18] Do not create DSA keys without parameters by decoder
3da501
3da501
Reviewed-by: Matt Caswell <matt@openssl.org>
3da501
Reviewed-by: Paul Dale <pauli@openssl.org>
3da501
---
3da501
 crypto/x509/x_pubkey.c                        | 24 +++++++++++++++++++
3da501
 include/crypto/x509.h                         |  3 +++
3da501
 .../encode_decode/decode_der2key.c            |  2 +-
3da501
 3 files changed, 28 insertions(+), 1 deletion(-)
3da501
3da501
diff --git a/crypto/x509/x_pubkey.c b/crypto/x509/x_pubkey.c
3da501
index bc90ddd89b..77790faa1f 100644
3da501
--- a/crypto/x509/x_pubkey.c
3da501
+++ b/crypto/x509/x_pubkey.c
3da501
@@ -745,6 +745,30 @@ DSA *d2i_DSA_PUBKEY(DSA **a, const unsigned char **pp, long length)
3da501
     return key;
3da501
 }
3da501
 
3da501
+/* Called from decoders; disallows provided DSA keys without parameters. */
3da501
+DSA *ossl_d2i_DSA_PUBKEY(DSA **a, const unsigned char **pp, long length)
3da501
+{
3da501
+    DSA *key = NULL;
3da501
+    const unsigned char *data;
3da501
+    const BIGNUM *p, *q, *g;
3da501
+
3da501
+    data = *pp;
3da501
+    key = d2i_DSA_PUBKEY(NULL, &data, length);
3da501
+    if (key == NULL)
3da501
+        return NULL;
3da501
+    DSA_get0_pqg(key, &p, &q, &g);
3da501
+    if (p == NULL || q == NULL || g == NULL) {
3da501
+        DSA_free(key);
3da501
+        return NULL;
3da501
+    }
3da501
+    *pp = data;
3da501
+    if (a != NULL) {
3da501
+        DSA_free(*a);
3da501
+        *a = key;
3da501
+    }
3da501
+    return key;
3da501
+}
3da501
+
3da501
 int i2d_DSA_PUBKEY(const DSA *a, unsigned char **pp)
3da501
 {
3da501
     EVP_PKEY *pktmp;
3da501
diff --git a/include/crypto/x509.h b/include/crypto/x509.h
3da501
index 1f00178e89..0c42730ee9 100644
3da501
--- a/include/crypto/x509.h
3da501
+++ b/include/crypto/x509.h
3da501
@@ -339,6 +339,9 @@ void ossl_X509_PUBKEY_INTERNAL_free(X509_PUBKEY *xpub);
3da501
 
3da501
 RSA *ossl_d2i_RSA_PSS_PUBKEY(RSA **a, const unsigned char **pp, long length);
3da501
 int ossl_i2d_RSA_PSS_PUBKEY(const RSA *a, unsigned char **pp);
3da501
+# ifndef OPENSSL_NO_DSA
3da501
+DSA *ossl_d2i_DSA_PUBKEY(DSA **a, const unsigned char **pp, long length);
3da501
+# endif /* OPENSSL_NO_DSA */
3da501
 # ifndef OPENSSL_NO_DH
3da501
 DH *ossl_d2i_DH_PUBKEY(DH **a, const unsigned char **pp, long length);
3da501
 int ossl_i2d_DH_PUBKEY(const DH *a, unsigned char **pp);
3da501
diff --git a/providers/implementations/encode_decode/decode_der2key.c b/providers/implementations/encode_decode/decode_der2key.c
3da501
index ebc2d24833..d6ad738ef3 100644
3da501
--- a/providers/implementations/encode_decode/decode_der2key.c
3da501
+++ b/providers/implementations/encode_decode/decode_der2key.c
3da501
@@ -374,7 +374,7 @@ static void *dsa_d2i_PKCS8(void **key, const unsigned char **der, long der_len,
3da501
                              (key_from_pkcs8_t *)ossl_dsa_key_from_pkcs8);
3da501
 }
3da501
 
3da501
-# define dsa_d2i_PUBKEY                 (d2i_of_void *)d2i_DSA_PUBKEY
3da501
+# define dsa_d2i_PUBKEY                 (d2i_of_void *)ossl_d2i_DSA_PUBKEY
3da501
 # define dsa_free                       (free_key_fn *)DSA_free
3da501
 # define dsa_check                      NULL
3da501
 
3da501
-- 
3da501
2.39.1
3da501
3da501
From 7e37185582995b35f885fec9dcc3670af9ffcbef Mon Sep 17 00:00:00 2001
3da501
From: Tomas Mraz <tomas@openssl.org>
3da501
Date: Fri, 13 Jan 2023 18:46:15 +0100
3da501
Subject: [PATCH 13/18] Add test for DSA pubkey without param import and check
3da501
3da501
Reviewed-by: Matt Caswell <matt@openssl.org>
3da501
Reviewed-by: Paul Dale <pauli@openssl.org>
3da501
---
3da501
 test/recipes/91-test_pkey_check.t             |  48 ++++++++++++++----
3da501
 .../91-test_pkey_check_data/dsapub.pem        |  12 +++++
3da501
 .../dsapub_noparam.der                        | Bin 0 -> 108 bytes
3da501
 3 files changed, 49 insertions(+), 11 deletions(-)
3da501
 create mode 100644 test/recipes/91-test_pkey_check_data/dsapub.pem
3da501
 create mode 100644 test/recipes/91-test_pkey_check_data/dsapub_noparam.der
3da501
3da501
--- openssl-3.0.1/test/recipes/91-test_pkey_check.t	2023-02-08 13:43:56.228487948 +0100
3da501
+++ openssl-3.0.7/test/recipes/91-test_pkey_check.t	2023-02-08 12:47:13.531027540 +0100
3da501
@@ -1,5 +1,5 @@
3da501
 #! /usr/bin/env perl
3da501
-# Copyright 2017-2021 The OpenSSL Project Authors. All Rights Reserved.
3da501
+# Copyright 2017-2022 The OpenSSL Project Authors. All Rights Reserved.
3da501
 #
3da501
 # Licensed under the Apache License 2.0 (the "License").  You may not use
3da501
 # this file except in compliance with the License.  You can obtain a copy
3da501
@@ -11,24 +11,37 @@
3da501
 use warnings;
3da501
 
3da501
 use File::Spec;
3da501
-use OpenSSL::Test qw/:DEFAULT data_file/;
3da501
+use OpenSSL::Test qw/:DEFAULT data_file with/;
3da501
 use OpenSSL::Test::Utils;
3da501
 
3da501
-sub check_key {
3da501
+sub pkey_check {
3da501
     my $f = shift;
3da501
+    my $pubcheck = shift;
3da501
+    my @checkopt = ('-check');
3da501
+
3da501
+    @checkopt = ('-pubcheck', '-pubin') if $pubcheck;
3da501
 
3da501
-    return run(app(['openssl', 'pkey', '-check', '-text',
3da501
+    return run(app(['openssl', 'pkey', @checkopt, '-text',
3da501
                     '-in', $f]));
3da501
 }
3da501
 
3da501
-sub check_key_notok {
3da501
+sub check_key {
3da501
     my $f = shift;
3da501
-    my $str = "$f should fail validation";
3da501
+    my $should_fail = shift;
3da501
+    my $pubcheck = shift;
3da501
+    my $str;
3da501
+
3da501
+
3da501
+    $str = "$f should fail validation" if $should_fail;
3da501
+    $str = "$f should pass validation" unless $should_fail;
3da501
 
3da501
     $f = data_file($f);
3da501
 
3da501
     if ( -s $f ) {
3da501
-        ok(!check_key($f), $str);
3da501
+        with({ exit_checker => sub { return shift == $should_fail; } },
3da501
+            sub {
3da501
+                ok(pkey_check($f, $pubcheck), $str);
3da501
+            });
3da501
     } else {
3da501
         fail("Missing file $f");
3da501
     }
3da501
@@ -36,26 +49,54 @@
3da501
 
3da501
 setup("test_pkey_check");
3da501
 
3da501
-my @tests = ();
3da501
+my @negative_tests = ();
3da501
 
3da501
-push(@tests, (
3da501
+push(@negative_tests, (
3da501
     # For EC keys the range for the secret scalar `k` is `1 <= k <= n-1`
3da501
     "ec_p256_bad_0.pem", # `k` set to `n` (equivalent to `0 mod n`, invalid)
3da501
     "ec_p256_bad_1.pem", # `k` set to `n+1` (equivalent to `1 mod n`, invalid)
3da501
     )) unless disabled("ec");
3da501
 
3da501
-push(@tests, (
3da501
+push(@negative_tests, (
3da501
     # For SM2 keys the range for the secret scalar `k` is `1 <= k < n-1`
3da501
     "sm2_bad_neg1.pem", # `k` set to `n-1` (invalid, because SM2 range)
3da501
     "sm2_bad_0.pem", # `k` set to `n` (equivalent to `0 mod n`, invalid)
3da501
     "sm2_bad_1.pem", # `k` set to `n+1` (equivalent to `1 mod n`, invalid)
3da501
     )) unless disabled("sm2");
3da501
 
3da501
+my @positive_tests = ();
3da501
+
3da501
+my @negative_pubtests = ();
3da501
+
3da501
+push(@negative_pubtests, (
3da501
+    "dsapub_noparam.der"
3da501
+    )) unless disabled("dsa");
3da501
+
3da501
+my @positive_pubtests = ();
3da501
+
3da501
+push(@positive_pubtests, (
3da501
+    "dsapub.pem"
3da501
+    )) unless disabled("dsa");
3da501
+
3da501
 plan skip_all => "No tests within the current enabled feature set"
3da501
-    unless @tests;
3da501
+    unless @negative_tests && @positive_tests
3da501
+           && @negative_pubtests && @positive_pubtests;
3da501
+
3da501
+plan tests => scalar(@negative_tests) + scalar(@positive_tests)
3da501
+              + scalar(@negative_pubtests) + scalar(@positive_pubtests);
3da501
+
3da501
+foreach my $t (@negative_tests) {
3da501
+    check_key($t, 1, 0);
3da501
+}
3da501
+
3da501
+foreach my $t (@positive_tests) {
3da501
+    check_key($t, 0, 0);
3da501
+}
3da501
 
3da501
-plan tests => scalar(@tests);
3da501
+foreach my $t (@negative_pubtests) {
3da501
+    check_key($t, 1, 1);
3da501
+}
3da501
 
3da501
-foreach my $t (@tests) {
3da501
-    check_key_notok($t);
3da501
+foreach my $t (@positive_pubtests) {
3da501
+    check_key($t, 0, 1);
3da501
 }
3da501
diff --git a/test/recipes/91-test_pkey_check_data/dsapub.pem b/test/recipes/91-test_pkey_check_data/dsapub.pem
3da501
new file mode 100644
3da501
index 0000000000..0ff4bd83ed
3da501
--- /dev/null
3da501
+++ b/test/recipes/91-test_pkey_check_data/dsapub.pem
3da501
@@ -0,0 +1,12 @@
3da501
+-----BEGIN PUBLIC KEY-----
3da501
+MIIBvzCCATQGByqGSM44BAEwggEnAoGBAIjbXpOVVciVNuagg26annKkghIIZFI4
3da501
+4WdMomnV+I/oXyxHbZTBBBpW9xy/E1+yMjbp4GmX+VxyDj3WxUWxXllzL+miEkzD
3da501
+9Xz638VzIBhjFbMvk1/N4kS4bKVUd9yk7HfvYzAdnRphk0WI+RoDiDrBNPPxSoQD
3da501
+CEWgvwgsLIDhAh0A6dbz1IQpQwGF4+Ca28x6OO+UfJJv3ggeZ++fNwKBgQCA9XKV
3da501
+lRrTY8ALBxS0KbZjpaIXuUj5nr3i1lIDyP3ISksDF0ekyLtn6eK9VijX6Pm65Np+
3da501
+4ic9Nr5WKLKhPaUSpLNRx1gDqo3sd92hYgiEUifzEuhLYfK/CsgFED+l2hDXtJUq
3da501
+bISNSHVwI5lsyNXLu7HI1Fk8F5UO3LqsboFAngOBhAACgYATxFY89nEYcUhgHGgr
3da501
+YDHhXBQfMKnTKYdvon4DN7WQ9ip+t4VUsLpTD1ZE9zrM2R/B04+8C6KGoViwyeER
3da501
+kS4dxWOkX71x4X2DlNpYevcR53tNcTDqmMD7YKfDDmrb0lftMyfW8aESaiymVMys
3da501
+DRjhKHBjdo0rZeSM8DAk3ctrXA==
3da501
+-----END PUBLIC KEY-----
3da501
diff --git a/test/recipes/91-test_pkey_check_data/dsapub_noparam.der b/test/recipes/91-test_pkey_check_data/dsapub_noparam.der
3da501
new file mode 100644
3da501
index 0000000000000000000000000000000000000000..b8135f1ca94da914b6829421e0c13f6daa731862
3da501
GIT binary patch
3da501
literal 108
3da501
zcmXpIGT>xm*J|@PXTieE%*wz71
3da501
U3o&W4F|x9<gY>|F5F-Nv0Bz9(=Kufz
3da501
3da501
literal 0
3da501
HcmV?d00001
3da501
3da501
-- 
3da501
2.39.1
3da501
3da501
From 2ad9928170768653d19d81881deabc5f9c1665c0 Mon Sep 17 00:00:00 2001
3da501
From: Tomas Mraz <tomas@openssl.org>
3da501
Date: Fri, 3 Feb 2023 14:57:04 +0100
3da501
Subject: [PATCH 18/18] Internaly declare the DSA type for no-deprecated builds
3da501
3da501
Reviewed-by: Hugo Landau <hlandau@openssl.org>
3da501
Reviewed-by: Richard Levitte <levitte@openssl.org>
3da501
(cherry picked from commit 7a21a1b5fa2dac438892cf3292d1f9c445d870d9)
3da501
---
3da501
 include/crypto/types.h | 3 +++
3da501
 1 file changed, 3 insertions(+)
3da501
3da501
diff --git a/include/crypto/types.h b/include/crypto/types.h
3da501
index 0d81404091..0a75f03a3f 100644
3da501
--- a/include/crypto/types.h
3da501
+++ b/include/crypto/types.h
3da501
@@ -20,6 +20,9 @@ typedef struct rsa_meth_st RSA_METHOD;
3da501
 typedef struct ec_key_st EC_KEY;
3da501
 typedef struct ec_key_method_st EC_KEY_METHOD;
3da501
 #  endif
3da501
+#  ifndef OPENSSL_NO_DSA
3da501
+typedef struct dsa_st DSA;
3da501
+#  endif
3da501
 # endif
3da501
 
3da501
 # ifndef OPENSSL_NO_EC
3da501
-- 
3da501
2.39.1
3da501