dsa_check: Perform simple parameter check if seed is not available
authorTomas Mraz <tomas@openssl.org>
Wed, 10 Feb 2021 17:44:00 +0000 (18:44 +0100)
committerTomas Mraz <tomas@openssl.org>
Thu, 18 Feb 2021 10:02:26 +0000 (11:02 +0100)
Added primality check on p and q in the ossl_ffc_params_simple_validate().
Checking for p and q sizes in the default provider is made more
lenient.
Added two testcases for invalid parameters.

Fixes #13950

Reviewed-by: Shane Lontis <shane.lontis@oracle.com>
(Merged from https://github.com/openssl/openssl/pull/14148)

14 files changed:
crypto/dh/dh_key.c
crypto/dsa/dsa_check.c
crypto/dsa/dsa_err.c
crypto/dsa/dsa_key.c
crypto/err/openssl.txt
crypto/ffc/ffc_params_generate.c
crypto/ffc/ffc_params_validate.c
include/crypto/dsa.h
include/internal/ffc.h
include/openssl/dsaerr.h
providers/implementations/keymgmt/dsa_kmgmt.c
test/recipes/15-test_dsaparam.t
test/recipes/15-test_dsaparam_data/invalid/p2048_q256_bad_q.pem [new file with mode: 0644]
test/recipes/15-test_dsaparam_data/invalid/p768_q160_too_small.pem [new file with mode: 0644]

index be940456cdd53d4cd298a74fb587ca4908afbcb6..f8cbbd593b9b97762b34546c1883ac1217b76b95 100644 (file)
@@ -328,7 +328,7 @@ static int generate_key(DH *dh)
             {
                 /* Do a partial check for invalid p, q, g */
                 if (!ossl_ffc_params_simple_validate(dh->libctx, &dh->params,
-                                                     FFC_PARAM_TYPE_DH))
+                                                     FFC_PARAM_TYPE_DH, NULL))
                     goto err;
                 /*
                  * For FFC FIPS 186-4 keygen
index 9a1b129df8966e85b5a789312d0eea42001a53d8..7f56a785ab4dc80e00c17078035598f55a539d57 100644 (file)
 #include "dsa_local.h"
 #include "crypto/dsa.h"
 
-int dsa_check_params(const DSA *dsa, int *ret)
+int dsa_check_params(const DSA *dsa, int checktype, int *ret)
 {
-    /*
-     * (2b) FFC domain params conform to FIPS-186-4 explicit domain param
-     * validity tests.
-     */
-    return ossl_ffc_params_FIPS186_4_validate(dsa->libctx, &dsa->params,
-                                              FFC_PARAM_TYPE_DSA, ret, NULL);
+    if (checktype == OSSL_KEYMGMT_VALIDATE_QUICK_CHECK)
+        return ossl_ffc_params_simple_validate(dsa->libctx, &dsa->params,
+                                               FFC_PARAM_TYPE_DSA, ret);
+    else
+        /*
+         * Do full FFC domain params validation according to FIPS-186-4
+         *  - always in FIPS_MODULE
+         *  - only if possible (i.e., seed is set) in default provider
+         */
+        return ossl_ffc_params_full_validate(dsa->libctx, &dsa->params,
+                                             FFC_PARAM_TYPE_DSA, ret);
 }
 
 /*
index 99fc0e80fba30b4b2a65ec430752add3809c6bfd..6481e2dc587422c22387672c630100f8f807cc07 100644 (file)
@@ -32,6 +32,7 @@ static const ERR_STRING_DATA DSA_str_reasons[] = {
     {ERR_PACK(ERR_LIB_DSA, 0, DSA_R_NO_PARAMETERS_SET), "no parameters set"},
     {ERR_PACK(ERR_LIB_DSA, 0, DSA_R_PARAMETER_ENCODING_ERROR),
     "parameter encoding error"},
+    {ERR_PACK(ERR_LIB_DSA, 0, DSA_R_P_NOT_PRIME), "p not prime"},
     {ERR_PACK(ERR_LIB_DSA, 0, DSA_R_Q_NOT_PRIME), "q not prime"},
     {ERR_PACK(ERR_LIB_DSA, 0, DSA_R_SEED_LEN_SMALL),
     "seed_len is less than the length of q"},
index 899663353f40498dcc329934174b40d2df984a12..8646d01957f1ab8a661bc282e481ccc9d386ee49 100644 (file)
@@ -77,7 +77,7 @@ static int dsa_keygen(DSA *dsa, int pairwise_test)
 
     /* Do a partial check for invalid p, q, g */
     if (!ossl_ffc_params_simple_validate(dsa->libctx, &dsa->params,
-                                         FFC_PARAM_TYPE_DSA))
+                                         FFC_PARAM_TYPE_DSA, NULL))
         goto err;
 
     /*
index 002a7a0f108a386a1a753c9d0262890554b49f6d..530e3217e417281a708f830062d4600136d527de 100644 (file)
@@ -502,6 +502,7 @@ DSA_R_MISSING_PRIVATE_KEY:111:missing private key
 DSA_R_MODULUS_TOO_LARGE:103:modulus too large
 DSA_R_NO_PARAMETERS_SET:107:no parameters set
 DSA_R_PARAMETER_ENCODING_ERROR:105:parameter encoding error
+DSA_R_P_NOT_PRIME:115:p not prime
 DSA_R_Q_NOT_PRIME:113:q not prime
 DSA_R_SEED_LEN_SMALL:110:seed_len is less than the length of q
 DSO_R_CTRL_FAILED:100:control command failed
index 9285f93c05521a1fb2e7f4fdc06ec922a36163d7..2e50c2b80193bf14b5bba11ffb6f2e4d68404f3e 100644 (file)
@@ -77,12 +77,12 @@ static int ffc_validate_LN(size_t L, size_t N, int type, int verify)
         ERR_raise(ERR_LIB_DH, DH_R_BAD_FFC_PARAMETERS);
 # endif
     } else if (type == FFC_PARAM_TYPE_DSA) {
-        if (L == 1024 && N == 160)
-            return 80;
-        if (L == 2048 && (N == 224 || N == 256))
-            return 112;
-        if (L == 3072 && N == 256)
+        if (L >= 3072 && N >= 256)
             return 128;
+        if (L >= 2048 && N >= 224)
+            return 112;
+        if (L >= 1024 && N >= 160)
+            return 80;
 # ifndef OPENSSL_NO_DSA
         ERR_raise(ERR_LIB_DSA, DSA_R_BAD_FFC_PARAMETERS);
 # endif
index 22983d62ef05904dec22b046549e659b2c1d3426..a2bfe22da2682e45a1d025cb4c580e8b1267a6a5 100644 (file)
  * It calls the same functions as the generation as the code is very similar.
  */
 
+#include <openssl/err.h>
+#include <openssl/bn.h>
+#include <openssl/dsaerr.h>
+#include <openssl/dherr.h>
 #include "internal/ffc.h"
 
 /* FIPS186-4 A.2.2 Unverifiable partial validation of Generator g */
@@ -88,30 +92,92 @@ int ossl_ffc_params_FIPS186_2_validate(OSSL_LIB_CTX *libctx,
  * extra parameters such as the digest and seed, which may not be available for
  * this test.
  */
-int ossl_ffc_params_simple_validate(OSSL_LIB_CTX *libctx, FFC_PARAMS *params,
-                                    int type)
+int ossl_ffc_params_simple_validate(OSSL_LIB_CTX *libctx, const FFC_PARAMS *params,
+                                    int paramstype, int *res)
 {
-    int ret, res = 0;
-    int save_gindex;
-    unsigned int save_flags;
+    int ret;
+    int tmpres = 0;
+    FFC_PARAMS tmpparams = {0};
 
     if (params == NULL)
         return 0;
 
-    save_flags = params->flags;
-    save_gindex = params->gindex;
-    params->flags = FFC_PARAM_FLAG_VALIDATE_G;
-    params->gindex = FFC_UNVERIFIABLE_GINDEX;
+    if (res == NULL)
+        res = &tmpres;
+
+    if (!ossl_ffc_params_copy(&tmpparams, params))
+        return 0;
+
+    tmpparams.flags = FFC_PARAM_FLAG_VALIDATE_G;
+    tmpparams.gindex = FFC_UNVERIFIABLE_GINDEX;
 
 #ifndef FIPS_MODULE
-    if (save_flags & FFC_PARAM_FLAG_VALIDATE_LEGACY)
-        ret = ossl_ffc_params_FIPS186_2_validate(libctx, params, type, &res,
-                                                 NULL);
+    if (params->flags & FFC_PARAM_FLAG_VALIDATE_LEGACY)
+        ret = ossl_ffc_params_FIPS186_2_validate(libctx, &tmpparams, paramstype,
+                                                 res, NULL);
     else
 #endif
-        ret = ossl_ffc_params_FIPS186_4_validate(libctx, params, type, &res,
-                                                 NULL);
-    params->flags = save_flags;
-    params->gindex = save_gindex;
+        ret = ossl_ffc_params_FIPS186_4_validate(libctx, &tmpparams, paramstype,
+                                                 res, NULL);
+#ifndef OPENSSL_NO_DH
+    if (ret == FFC_PARAM_RET_STATUS_FAILED
+        && (*res & FFC_ERROR_NOT_SUITABLE_GENERATOR) != 0) {
+        ERR_raise(ERR_LIB_DH, DH_R_NOT_SUITABLE_GENERATOR);
+    }
+#endif
+
+    ossl_ffc_params_cleanup(&tmpparams);
+
     return ret != FFC_PARAM_RET_STATUS_FAILED;
 }
+
+/*
+ * If possible (or always in FIPS_MODULE) do full FIPS 186-4 validation.
+ * Otherwise do simple check but in addition also check the primality of the
+ * p and q.
+ */
+int ossl_ffc_params_full_validate(OSSL_LIB_CTX *libctx, const FFC_PARAMS *params,
+                                  int paramstype, int *res)
+{
+    int tmpres = 0;
+
+    if (params == NULL)
+        return 0;
+
+    if (res == NULL)
+        res = &tmpres;
+
+#ifdef FIPS_MODULE
+    return ossl_ffc_params_FIPS186_4_validate(libctx, params, paramstype,
+                                              res, NULL);
+#else
+    if (params->seed != NULL) {
+        return ossl_ffc_params_FIPS186_4_validate(libctx, params, paramstype,
+                                                  res, NULL);
+    } else {
+        int ret = 0;
+
+        ret = ossl_ffc_params_simple_validate(libctx, params, paramstype, res);
+        if (ret) {
+            BN_CTX *ctx;
+
+            if ((ctx = BN_CTX_new_ex(libctx)) == NULL)
+                return 0;
+            if (BN_check_prime(params->q, ctx, NULL) != 1) {
+# ifndef OPENSSL_NO_DSA
+                ERR_raise(ERR_LIB_DSA, DSA_R_Q_NOT_PRIME);
+# endif
+                ret = 0;
+            }
+            if (ret && BN_check_prime(params->p, ctx, NULL) != 1) {
+# ifndef OPENSSL_NO_DSA
+                ERR_raise(ERR_LIB_DSA, DSA_R_P_NOT_PRIME);
+# endif
+                ret = 0;
+            }
+            BN_CTX_free(ctx);
+        }
+        return ret;
+    }
+#endif
+}
index 8d282ab188b7d82f7520346f8044fb9cbe239317..3da569679526ad69cd6c0fe8b5fff8095e47583a 100644 (file)
@@ -33,7 +33,7 @@ int dsa_key_fromdata(DSA *dsa, const OSSL_PARAM params[]);
 
 int dsa_generate_public_key(BN_CTX *ctx, const DSA *dsa, const BIGNUM *priv_key,
                             BIGNUM *pub_key);
-int dsa_check_params(const DSA *dsa, int *ret);
+int dsa_check_params(const DSA *dsa, int checktype, int *ret);
 int dsa_check_pub_key(const DSA *dsa, const BIGNUM *pub_key, int *ret);
 int dsa_check_pub_key_partial(const DSA *dsa, const BIGNUM *pub_key, int *ret);
 int dsa_check_priv_key(const DSA *dsa, const BIGNUM *priv_key, int *ret);
index 7653b6e2fa6e8bbcbf2e7001013da43a6b348678..4cffc720a65d786ce6f86c3c557a9858a25b578c 100644 (file)
@@ -162,8 +162,12 @@ int ossl_ffc_params_FIPS186_2_gen_verify(OSSL_LIB_CTX *libctx,
                                          size_t L, size_t N, int *res,
                                          BN_GENCB *cb);
 
-int ossl_ffc_params_simple_validate(OSSL_LIB_CTX *libctx, FFC_PARAMS *params,
-                                    int type);
+int ossl_ffc_params_simple_validate(OSSL_LIB_CTX *libctx,
+                                    const FFC_PARAMS *params,
+                                    int paramstype, int *res);
+int ossl_ffc_params_full_validate(OSSL_LIB_CTX *libctx,
+                                  const FFC_PARAMS *params,
+                                  int paramstype, int *res);
 int ossl_ffc_params_FIPS186_4_validate(OSSL_LIB_CTX *libctx,
                                        const FFC_PARAMS *params,
                                        int type, int *res, BN_GENCB *cb);
index 49dabbf575232580bc99e764564bfb5febfe4216..669cd6c87fdffaefad6ed924f857dc40070349aa 100644 (file)
@@ -35,6 +35,7 @@
 #  define DSA_R_MODULUS_TOO_LARGE                          103
 #  define DSA_R_NO_PARAMETERS_SET                          107
 #  define DSA_R_PARAMETER_ENCODING_ERROR                   105
+#  define DSA_R_P_NOT_PRIME                                115
 #  define DSA_R_Q_NOT_PRIME                                113
 #  define DSA_R_SEED_LEN_SMALL                             110
 
index 28e8409aa22d906491f0a118abec2880534a6cdc..467f75bb553cec6715a29f9e04e37590353e45f4 100644 (file)
@@ -309,11 +309,11 @@ static const OSSL_PARAM *dsa_gettable_params(void *provctx)
     return dsa_params;
 }
 
-static int dsa_validate_domparams(const DSA *dsa)
+static int dsa_validate_domparams(const DSA *dsa, int checktype)
 {
     int status = 0;
 
-    return dsa_check_params(dsa, &status);
+    return dsa_check_params(dsa, checktype, &status);
 }
 
 static int dsa_validate_public(const DSA *dsa)
@@ -350,7 +350,7 @@ static int dsa_validate(const void *keydata, int selection, int checktype)
         ok = 1;
 
     if ((selection & OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) != 0)
-        ok = ok && dsa_validate_domparams(dsa);
+        ok = ok && dsa_validate_domparams(dsa, checktype);
 
     if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0)
         ok = ok && dsa_validate_public(dsa);
index c0c73841bd23aa3bf875f31c5d4e9780cb7fe845..c34d8ec9cd46ab178926f4327be004faccfee728 100644 (file)
@@ -64,15 +64,15 @@ plan skip_all => "DSA isn't supported in this build"
     if disabled("dsa");
 
 my @valid = glob(data_file("valid", "*.pem"));
-#my @invalid = glob(data_file("invalid", "*.pem"));
+my @invalid = glob(data_file("invalid", "*.pem"));
 
-my $num_tests = scalar @valid;
+my $num_tests = scalar @valid + scalar @invalid;
 plan tests => $num_tests;
 
 foreach (@valid) {
     ok(run(app([qw{openssl pkeyparam -noout -check -in}, $_])));
 }
 
-#foreach (@invalid) {
-#    ok(!run(app([qw{openssl pkeyparam -noout -check -in}, $_])));
-#}
+foreach (@invalid) {
+    ok(!run(app([qw{openssl pkeyparam -noout -check -in}, $_])));
+}
diff --git a/test/recipes/15-test_dsaparam_data/invalid/p2048_q256_bad_q.pem b/test/recipes/15-test_dsaparam_data/invalid/p2048_q256_bad_q.pem
new file mode 100644 (file)
index 0000000..6f7d98d
--- /dev/null
@@ -0,0 +1,14 @@
+-----BEGIN DSA PARAMETERS-----
+MIICLAKCAQEAwmWp4Y+deYlczoQUPiioJt6Qxthrk6L1CAVpGH2uRRlHfTl41WUX
+JHIJyCMBgRDtVVQdyAQ7AZ+CxOl1wpazvGJddyQVynhmIFsaUwHF2fYIT00MvBRL
+9VA5PQqUmX2Tnog5ezu35CTsEqlBTOYcGqkQ7ctNVjfvjYCkwzvTxJS/Qsvki+dA
+fE7NDWe+9r5QjSGEFZtH45alIM4qUnBS1mcN2Az5+S8JxPiivY5Jkt0pXoRQnvCM
+In4bHjM8ZOVmLxFCIrpB0dNgKDg+2zEjRjmL7B4aZRcO7wDyrtDPc7jiYPH/rlt/
+wU1o/Y1fnzN9+R3f0AMeWR44bqf5Ol9jVQIhAKDEbXZJcYLbvkUYWBr8TKsVu2hc
+H57M3PwkTsq+v2/dAoIBADKkGYUe9qsp4mqxkBKaEdpcjmjfLrvtE+3ikipPPGHh
+tbAX7NwZc9WCyhniKYskEbJBWsuAZJXDgIRNaSpCVLK7dd9fx8ZnIKJESO6Htv1z
+JfSIST57xW8L6m78Lq2kxpr5dVcm7I4pelTfL5jscTURm/1Ua+2skI9YlZU/Vgux
+Wrr30H8bp4fUgWjcgPJbeirSY7xVI8FKrQaES0s4NRFbgGMFUrEGddBF0bgaGkwd
+mFEpcXAEQDTJV7SPJp3rbjFug3CF4Atw3RmkV2T/sHAbplyr9YsQDmAQDhPsaWjQ
+eSsoRUq0aQ4aa2V4X/gSzSj9It3Q4ngQwkGGOPJEo44=
+-----END DSA PARAMETERS-----
diff --git a/test/recipes/15-test_dsaparam_data/invalid/p768_q160_too_small.pem b/test/recipes/15-test_dsaparam_data/invalid/p768_q160_too_small.pem
new file mode 100644 (file)
index 0000000..c717c91
--- /dev/null
@@ -0,0 +1,7 @@
+-----BEGIN DSA PARAMETERS-----
+MIHcAmEA702xO4DjQl4WxLId1FR8Q0tZ+FQDEqyhzfYheBnLra8Uaf3gLp7V0g52
+aQqDTeY1TK76ZmNo/SvESDcYTHjlgKphYCKLRxAhvuyGfX1RRPWa80BrM76wYtJD
+mwB9KSBnAhUArp9BUvskZ9/K8Bzo0MVejsHC6AkCYEugdq5OD0HjCrxt3hFMD3sJ
+ZQ7VAZa+Fnu9SJNjCeMYLEww4/A6fktqokDWITjSQpdJAAxwc+r8OlDRwBb0q7jT
+w1IDvvbF/xGex5VzHHBZmQU1G1jH+Lq3h7dQ6d4l+g==
+-----END DSA PARAMETERS-----