]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
algorithms: properly calculate hash strength for Ed448
authorDaiki Ueno <dueno@redhat.com>
Mon, 16 Mar 2020 10:03:41 +0000 (11:03 +0100)
committerDaiki Ueno <dueno@redhat.com>
Mon, 16 Mar 2020 11:36:21 +0000 (12:36 +0100)
The Ed448 signature scheme internally uses XOF (SHAKE256) as the hash
function with 114-octet output.  According to FIPS-202, the strength
against collisions is calculated as:

  min(114*8/2, 256) = 256

Reported by Peter Dettman in:
https://gitlab.com/gnutls/gnutls/-/issues/128#note_304892538

Signed-off-by: Daiki Ueno <dueno@redhat.com>
lib/algorithms.h
lib/algorithms/sign.c
lib/x509/verify.c
tests/test-chains.h

index c68a266cc99f7a447df1a2dfc110ac1e0d94f1d5..9cdb3abf7a8984cdafe3c0281c9f2f45ae17a7fa 100644 (file)
@@ -367,6 +367,10 @@ struct gnutls_sign_entry_st {
           for values to use in aid struct. */
        const sign_algorithm_st aid;
        hash_security_level_t slevel;   /* contains values of hash_security_level_t */
+
+       /* 0 if it matches the predefined hash output size, otherwise
+        * it is truncated or expanded (with XOF) */
+       unsigned hash_output_size;
 };
 typedef struct gnutls_sign_entry_st gnutls_sign_entry_st;
 
@@ -521,4 +525,6 @@ static inline int _sig_is_ecdsa(gnutls_sign_algorithm_t sig)
 
 bool _gnutls_pk_are_compat(gnutls_pk_algorithm_t pk1, gnutls_pk_algorithm_t pk2);
 
+unsigned _gnutls_sign_get_hash_strength(gnutls_sign_algorithm_t sign);
+
 #endif /* GNUTLS_LIB_ALGORITHMS_H */
index 9c95e388aef98b1882e0f5f381d65cc1bcc465b4..0d8d1a89c98de4d514951a500af007f79a044ad2 100644 (file)
@@ -134,7 +134,8 @@ gnutls_sign_entry_st sign_algorithms[] = {
         .pk = GNUTLS_PK_EDDSA_ED448,
         .hash = GNUTLS_DIG_SHAKE_256,
         .flags = GNUTLS_SIGN_FLAG_TLS13_OK,
-        .aid = {{8, 8}, SIG_SEM_DEFAULT}},
+        .aid = {{8, 8}, SIG_SEM_DEFAULT},
+        .hash_output_size = 114},
 
         /* ECDSA */
         /* The following three signature algorithms
@@ -785,3 +786,30 @@ _gnutls13_sign_get_compatible_with_privkey(gnutls_privkey_t privkey)
 
        return NULL;
 }
+
+unsigned
+_gnutls_sign_get_hash_strength(gnutls_sign_algorithm_t sign)
+{
+       const gnutls_sign_entry_st *se = _gnutls_sign_to_entry(sign);
+       const mac_entry_st *me;
+       unsigned hash_output_size;
+
+       if (unlikely(se == NULL))
+               return 0;
+
+       me = mac_to_entry(se->hash);
+       if (unlikely(me == NULL))
+               return 0;
+
+       if (se->hash_output_size > 0)
+               hash_output_size = se->hash_output_size;
+       else
+               hash_output_size = _gnutls_mac_get_algo_len(me);
+
+       if (me->id == GNUTLS_MAC_SHAKE_128)
+               return MIN(hash_output_size*8/2, 128);
+       else if (me->id == GNUTLS_MAC_SHAKE_256)
+               return MIN(hash_output_size*8/2, 256);
+
+       return hash_output_size*8/2;
+}
index d381b4ee87a290e6b0348fc642a2ffd7e59a8ff9..d202670198a2b08020e1545742bc7ddd9546bb5e 100644 (file)
@@ -421,9 +421,9 @@ unsigned _gnutls_is_broken_sig_allowed(const gnutls_sign_entry_st *se, unsigned
                        _gnutls_debug_log(#level": certificate's signature hash is unknown\n"); \
                        return gnutls_assert_val(0); \
                } \
-               if (entry->output_size*8/2 < sym_bits) { \
+               if (_gnutls_sign_get_hash_strength(sigalg) < sym_bits) { \
                        _gnutls_cert_log("cert", crt); \
-                       _gnutls_debug_log(#level": certificate's signature hash strength is unacceptable (is %u bits, needed %u)\n", entry->output_size*8/2, sym_bits); \
+                       _gnutls_debug_log(#level": certificate's signature hash strength is unacceptable (is %u bits, needed %u)\n", _gnutls_sign_get_hash_strength(sigalg), sym_bits); \
                        return gnutls_assert_val(0); \
                } \
                sp = gnutls_pk_bits_to_sec_param(pkalg, bits); \
index fe118717d4442f3de7f24eac956e41fb632f8e2d..dd19e6a815fffc89ce7b3fa2212a49261b94a9ef 100644 (file)
@@ -3995,6 +3995,21 @@ static const char *rsa_512[] = {
        NULL
 };
 
+static const char *ed448[] = {
+       "-----BEGIN CERTIFICATE-----\n"
+       "MIIBhDCCAQSgAwIBAgIUIWKQV5hisum31Z2Fw+PeZ80wqnkwBQYDK2VxMBkxFzAV\n"
+       "BgNVBAMTDkdudVRMUyB0ZXN0IENBMCAXDTIwMDMxNjA5MTY1M1oYDzk5OTkxMjMx\n"
+       "MjM1OTU5WjAZMRcwFQYDVQQDEw5HbnVUTFMgdGVzdCBDQTBDMAUGAytlcQM6AFsM\n"
+       "fQUL5TonNaVrBB7H4UtwnVlolZatMXceHZiWnzMKXOZXlIabi0nTGkvSFu9ed6JJ\n"
+       "L7EWarjRAKNDMEEwDwYDVR0TAQH/BAUwAwEB/zAPBgNVHQ8BAf8EBQMDBwQAMB0G\n"
+       "A1UdDgQWBBRMwtFQ9T9Ndw63UP2QGAuIFoYb6TAFBgMrZXEDcwB8hbYLw7KMlb3a\n"
+       "Q2YAXiugWt2WcAMtvKgqzjXzUt2jilaDA72d3MCAWQQsMmQfRNSthDIao5CksoDk\n"
+       "Xc8qFzckmdBiF7W+UNT3OMisE9yIxF4iA1Sxsji3C0WDUq2jen5Uv9E99H+r47L8\n"
+       "U955wKxWJAA=\n"
+       "-----END CERTIFICATE-----\n",
+       NULL
+};
+
 #if defined __clang__ || __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)
 #  pragma GCC diagnostic push
 #  pragma GCC diagnostic ignored "-Wunused-variable"
@@ -4161,6 +4176,8 @@ static struct
 #endif
   { "rsa-512 - not ok (due to profile)", rsa_512, &rsa_512[0], GNUTLS_PROFILE_TO_VFLAGS(GNUTLS_PROFILE_MEDIUM),
     GNUTLS_CERT_INSECURE_ALGORITHM | GNUTLS_CERT_INVALID, NULL, 1576759855, 1},
+  { "ed448 - ok", ed448, &ed448[0], GNUTLS_PROFILE_TO_VFLAGS(GNUTLS_PROFILE_ULTRA),
+    0, NULL, 1584352960, 1},
   { NULL, NULL, NULL, 0, 0}
 };