]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
fips: fix checking on hash algorithm used in ECDSA
authorDaiki Ueno <ueno@gnu.org>
Tue, 20 Sep 2022 07:06:13 +0000 (16:06 +0900)
committerDaiki Ueno <ueno@gnu.org>
Thu, 29 Sep 2022 08:25:55 +0000 (17:25 +0900)
Previously we checked against the "preferred" hash algorithm based on
the curve, instead of the one actually used.

Signed-off-by: Daiki Ueno <ueno@gnu.org>
lib/crypto-backend.h
lib/nettle/pk.c
lib/pubkey.c
tests/fips-test.c

index f0f68c337e9ad6c2a9db09e792855403e40a8c0c..4dd1ae26edb2b042e3788d838b41233a9a3726cd 100644 (file)
@@ -247,11 +247,13 @@ typedef enum {
        GNUTLS_PK_FLAG_RSA_PSS_FIXED_SALT_LENGTH = 4
 } gnutls_pk_flag_t;
 
-#define FIX_SIGN_PARAMS(params, flags, dig) do {               \
-       if ((flags) & GNUTLS_PRIVKEY_FLAG_REPRODUCIBLE) {       \
-               (params).flags |= GNUTLS_PK_FLAG_REPRODUCIBLE;  \
-               (params).dsa_dig = (dig);                       \
-       }                                                       \
+#define FIX_SIGN_PARAMS(params, flags, dig) do {                       \
+       if ((flags) & GNUTLS_PRIVKEY_FLAG_REPRODUCIBLE) {               \
+               (params).flags |= GNUTLS_PK_FLAG_REPRODUCIBLE;          \
+       }                                                               \
+       if ((params).pk == GNUTLS_PK_DSA || (params).pk == GNUTLS_PK_ECDSA) { \
+               (params).dsa_dig = (dig);                               \
+       }                                                               \
 } while (0)
 
 void gnutls_pk_params_release(gnutls_pk_params_st * p);
index f38016b19a325b472591b245517016fcda29ae4a..c098e2aa452b38b0fa7c1b0ff5739eab6e3b7bfa 100644 (file)
@@ -1104,8 +1104,16 @@ _wrap_nettle_pk_sign(gnutls_pk_algorithm_t algo,
                        me = _gnutls_dsa_q_to_hash(pk_params,
                                                   &hash_len);
 
+                       if (hash_len > vdata->size) {
+                               gnutls_assert();
+                               _gnutls_debug_log
+                                   ("Security level of algorithm requires hash %s(%d) or better\n",
+                                    _gnutls_mac_get_name(me), hash_len);
+                               hash_len = vdata->size;
+                       }
+
                        /* Only SHA-2 is allowed in FIPS 140-3 */
-                       switch (me->id) {
+                       switch (DIG_TO_MAC(sign_params->dsa_dig)) {
                        case GNUTLS_MAC_SHA256:
                        case GNUTLS_MAC_SHA384:
                        case GNUTLS_MAC_SHA512:
@@ -1115,14 +1123,6 @@ _wrap_nettle_pk_sign(gnutls_pk_algorithm_t algo,
                                not_approved = true;
                        }
 
-                       if (hash_len > vdata->size) {
-                               gnutls_assert();
-                               _gnutls_debug_log
-                                   ("Security level of algorithm requires hash %s(%d) or better\n",
-                                    _gnutls_mac_get_name(me), hash_len);
-                               hash_len = vdata->size;
-                       }
-
                        mpz_init(k);
                        if (_gnutls_get_lib_state() == LIB_STATE_SELFTEST ||
                            (sign_params->flags & GNUTLS_PK_FLAG_REPRODUCIBLE)) {
@@ -1545,7 +1545,6 @@ _wrap_nettle_pk_verify(gnutls_pk_algorithm_t algo,
                        struct dsa_signature sig;
                        int curve_id = pk_params->curve;
                        const struct ecc_curve *curve;
-                       const mac_entry_st *me;
 
                        curve = get_supported_nist_curve(curve_id);
                        if (curve == NULL) {
@@ -1571,11 +1570,14 @@ _wrap_nettle_pk_verify(gnutls_pk_algorithm_t algo,
                        memcpy(sig.r, tmp[0], SIZEOF_MPZT);
                        memcpy(sig.s, tmp[1], SIZEOF_MPZT);
 
-                       me = _gnutls_dsa_q_to_hash(pk_params, &hash_len);
+                       (void)_gnutls_dsa_q_to_hash(pk_params, &hash_len);
+
+                       if (hash_len > vdata->size)
+                               hash_len = vdata->size;
 
                        /* SHA-1 is allowed for SigVer in FIPS 140-3 in legacy
                         * mode */
-                       switch (me->id) {
+                       switch (DIG_TO_MAC(sign_params->dsa_dig)) {
                        case GNUTLS_MAC_SHA1:
                        case GNUTLS_MAC_SHA256:
                        case GNUTLS_MAC_SHA384:
@@ -1586,9 +1588,6 @@ _wrap_nettle_pk_verify(gnutls_pk_algorithm_t algo,
                                not_approved = true;
                        }
 
-                       if (hash_len > vdata->size)
-                               hash_len = vdata->size;
-
                        ret =
                            ecdsa_verify(&pub, hash_len, vdata->data,
                                         &sig);
@@ -2390,8 +2389,10 @@ static int pct_test(gnutls_pk_algorithm_t algo, const gnutls_pk_params_st* param
 
        if (algo == GNUTLS_PK_DSA || algo == GNUTLS_PK_EC) {
                unsigned hash_len;
+               const mac_entry_st *me;
 
-               _gnutls_dsa_q_to_hash(params, &hash_len);
+               me = _gnutls_dsa_q_to_hash(params, &hash_len);
+               spki.dsa_dig = MAC_TO_DIG(me->id);
                gen_data = gnutls_malloc(hash_len);
                gnutls_rnd(GNUTLS_RND_NONCE, gen_data, hash_len);
 
index a0e5bc94566ab1db09e8acec3e078ad152a02150..be1b045fa72107805c5efb488513721e885dbdc8 100644 (file)
@@ -1985,7 +1985,7 @@ gnutls_pubkey_import_dsa_raw(gnutls_pubkey_t key,
  * parameters (if any) with the signature algorithm */
 static
 int fixup_spki_params(const gnutls_pk_params_st *key_params, const gnutls_sign_entry_st *se,
-                      const mac_entry_st *me, gnutls_x509_spki_st *params)
+                     const mac_entry_st *me, gnutls_x509_spki_st *params)
 {
        unsigned bits;
 
@@ -2018,6 +2018,9 @@ int fixup_spki_params(const gnutls_pk_params_st *key_params, const gnutls_sign_e
 
                if (params->rsa_pss_dig != se->hash)
                        return gnutls_assert_val(GNUTLS_E_CONSTRAINT_ERROR);
+       } else if (params->pk == GNUTLS_PK_DSA ||
+                  params->pk == GNUTLS_PK_ECDSA) {
+               params->dsa_dig = se->hash;
        }
 
        return 0;
index 475b7391979adcbcbde6c6f2aadb9b837f9b6077..bde0704f9f9f5b108e1a75a0b6228acf74d944d1 100644 (file)
@@ -80,8 +80,22 @@ static const gnutls_datum_t rsa2342_sha1_sig = {
        .size = sizeof(rsa2342_sha1_sig_data),
 };
 
+static const uint8_t ecc256_sha1_sig_data[] = {
+       0x30, 0x45, 0x02, 0x21, 0x00, 0x9a, 0x28, 0xc9, 0xbf, 0xc8, 0x70, 0x4f, 
+       0x27, 0x2d, 0xe1, 0x66, 0xc4, 0xa5, 0xc6, 0xf2, 0xdc, 0x33, 0xb9, 0x41, 
+       0xdf, 0x78, 0x98, 0x8a, 0x22, 0x4d, 0x29, 0x37, 0xa0, 0x0f, 0x6f, 0xd4, 
+       0xed, 0x02, 0x20, 0x0b, 0x15, 0xca, 0x30, 0x09, 0x2d, 0x55, 0x44, 0xb4, 
+       0x1d, 0x3f, 0x48, 0x7a, 0xc3, 0xd1, 0x2a, 0xc1, 0x0e, 0x47, 0xfa, 0xe6, 
+       0xe9, 0x0f, 0x03, 0xe2, 0x01, 0x4e, 0xe4, 0x73, 0x37, 0xa7, 0x90, 
+};
+
+static const gnutls_datum_t ecc256_sha1_sig = {
+       .data = (unsigned char *)ecc256_sha1_sig_data,
+       .size = sizeof(ecc256_sha1_sig_data),
+};
+
 static void
-rsa_import_keypair(gnutls_privkey_t *privkey, gnutls_pubkey_t *pubkey,
+import_keypair(gnutls_privkey_t *privkey, gnutls_pubkey_t *pubkey,
                   const char *filename)
 {
        const char *srcdir;
@@ -424,7 +438,7 @@ void doit(void)
 
        /* Import 2432-bit RSA key; not a security function */
        FIPS_PUSH_CONTEXT();
-       rsa_import_keypair(&privkey, &pubkey, "rsa-2432.pem");
+       import_keypair(&privkey, &pubkey, "rsa-2432.pem");
        FIPS_POP_CONTEXT(INITIAL);
 
        /* Create a signature with 2432-bit RSA and SHA256; approved */
@@ -470,7 +484,7 @@ void doit(void)
 
        /* Import 512-bit RSA key; not a security function */
        FIPS_PUSH_CONTEXT();
-       rsa_import_keypair(&privkey, &pubkey, "rsa-512.pem");
+       import_keypair(&privkey, &pubkey, "rsa-512.pem");
        FIPS_POP_CONTEXT(INITIAL);
 
        /* Create a signature with 512-bit RSA and SHA256; not approved */
@@ -494,6 +508,72 @@ void doit(void)
        gnutls_pubkey_deinit(pubkey);
        gnutls_privkey_deinit(privkey);
 
+       /* Import ECDSA key; not a security function */
+       FIPS_PUSH_CONTEXT();
+       import_keypair(&privkey, &pubkey, "ecc256.pem");
+       FIPS_POP_CONTEXT(INITIAL);
+
+       /* Create a signature with ECDSA and SHA256; approved */
+       FIPS_PUSH_CONTEXT();
+       ret = gnutls_privkey_sign_data2(privkey, GNUTLS_SIGN_ECDSA_SHA256, 0,
+                                       &data, &signature);
+       if (ret < 0) {
+               fail("gnutls_privkey_sign_data2 failed\n");
+       }
+       FIPS_POP_CONTEXT(APPROVED);
+
+       /* Verify a signature with ECDSA and SHA256; approved */
+       FIPS_PUSH_CONTEXT();
+       ret = gnutls_pubkey_verify_data2(pubkey, GNUTLS_SIGN_ECDSA_SHA256, 0,
+                                        &data, &signature);
+       if (ret < 0) {
+               fail("gnutls_pubkey_verify_data2 failed\n");
+       }
+       FIPS_POP_CONTEXT(APPROVED);
+       gnutls_free(signature.data);
+
+       /* Create a signature with ECDSA and SHA256 (old API); approved */
+       FIPS_PUSH_CONTEXT();
+       ret = gnutls_privkey_sign_data(privkey, GNUTLS_DIG_SHA256, 0,
+                                      &data, &signature);
+       if (ret < 0) {
+               fail("gnutls_privkey_sign_data failed\n");
+       }
+       FIPS_POP_CONTEXT(APPROVED);
+       gnutls_free(signature.data);
+
+       /* Create a signature with ECDSA and SHA-1; not approved */
+       FIPS_PUSH_CONTEXT();
+       ret = gnutls_privkey_sign_data2(privkey, GNUTLS_SIGN_ECDSA_SHA1, 0,
+                                       &data, &signature);
+       if (ret < 0) {
+               fail("gnutls_privkey_sign_data2 failed\n");
+       }
+       FIPS_POP_CONTEXT(NOT_APPROVED);
+
+       /* Verify a signature created with ECDSA and SHA-1; approved */
+       FIPS_PUSH_CONTEXT();
+       ret = gnutls_pubkey_verify_data2(pubkey, GNUTLS_SIGN_ECDSA_SHA1,
+                                        GNUTLS_VERIFY_ALLOW_SIGN_WITH_SHA1, &data,
+                                        &ecc256_sha1_sig);
+       if (ret < 0) {
+               fail("gnutls_pubkey_verify_data2 failed\n");
+       }
+       FIPS_POP_CONTEXT(APPROVED);
+       gnutls_free(signature.data);
+
+       /* Create a signature with ECDSA and SHA-1 (old API); not approved */
+       FIPS_PUSH_CONTEXT();
+       ret = gnutls_privkey_sign_data(privkey, GNUTLS_DIG_SHA1, 0,
+                                       &data, &signature);
+       if (ret < 0) {
+               fail("gnutls_privkey_sign_data failed\n");
+       }
+       FIPS_POP_CONTEXT(NOT_APPROVED);
+       gnutls_free(signature.data);
+       gnutls_pubkey_deinit(pubkey);
+       gnutls_privkey_deinit(privkey);
+
         /* Test RND functions */
        FIPS_PUSH_CONTEXT();
        ret = gnutls_rnd(GNUTLS_RND_RANDOM, key16, sizeof(key16));