diff --git a/cipher/dsa-common.c b/cipher/dsa-common.c index d251eae8..a5e42a21 100644 --- a/cipher/dsa-common.c +++ b/cipher/dsa-common.c @@ -1,361 +1,394 @@ /* dsa-common.c - Common code for DSA * Copyright (C) 1998, 1999 Free Software Foundation, Inc. * Copyright (C) 2013 g10 Code GmbH * * This file is part of Libgcrypt. * * Libgcrypt is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * Libgcrypt is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, see . */ #include #include #include #include #include "g10lib.h" #include "mpi.h" #include "cipher.h" #include "pubkey-internal.h" /* * Generate a random secret exponent K less than Q. * Note that ECDSA uses this code also to generate D. */ gcry_mpi_t _gcry_dsa_gen_k (gcry_mpi_t q, int security_level) { gcry_mpi_t k = mpi_alloc_secure (mpi_get_nlimbs (q)); unsigned int nbits = mpi_get_nbits (q); unsigned int nbytes = (nbits+7)/8; char *rndbuf = NULL; /* To learn why we don't use mpi_mod to get the requested bit size, read the paper: "The Insecurity of the Digital Signature Algorithm with Partially Known Nonces" by Nguyen and Shparlinski. Journal of Cryptology, New York. Vol 15, nr 3 (2003) */ if (DBG_CIPHER) log_debug ("choosing a random k of %u bits at seclevel %d\n", nbits, security_level); for (;;) { if ( !rndbuf || nbits < 32 ) { xfree (rndbuf); rndbuf = _gcry_random_bytes_secure (nbytes, security_level); } else { /* Change only some of the higher bits. We could improve this by directly requesting more memory at the first call to get_random_bytes() and use these extra bytes here. However the required management code is more complex and thus we better use this simple method. */ char *pp = _gcry_random_bytes_secure (4, security_level); memcpy (rndbuf, pp, 4); xfree (pp); } _gcry_mpi_set_buffer (k, rndbuf, nbytes, 0); /* Make sure we have the requested number of bits. This code looks a bit funny but it is easy to understand if you consider that mpi_set_highbit clears all higher bits. We don't have a clear_highbit, thus we first set the high bit and then clear it again. */ if (mpi_test_bit (k, nbits-1)) mpi_set_highbit (k, nbits-1); else { mpi_set_highbit (k, nbits-1); mpi_clear_bit (k, nbits-1); } if (!(mpi_cmp (k, q) < 0)) /* check: k < q */ { if (DBG_CIPHER) log_debug ("\tk too large - again\n"); continue; /* no */ } if (!(mpi_cmp_ui (k, 0) > 0)) /* check: k > 0 */ { if (DBG_CIPHER) log_debug ("\tk is zero - again\n"); continue; /* no */ } break; /* okay */ } xfree (rndbuf); return k; } /* Turn VALUE into an octet string and store it in an allocated buffer at R_FRAME. If the resulting octet string is shorter than NBYTES the result will be left padded with zeroes. If VALUE does not fit into NBYTES an error code is returned. */ static gpg_err_code_t int2octets (unsigned char **r_frame, gcry_mpi_t value, size_t nbytes) { gpg_err_code_t rc; size_t nframe, noff, n; unsigned char *frame; rc = _gcry_mpi_print (GCRYMPI_FMT_USG, NULL, 0, &nframe, value); if (rc) return rc; if (nframe > nbytes) return GPG_ERR_TOO_LARGE; /* Value too long to fit into NBYTES. */ noff = (nframe < nbytes)? nbytes - nframe : 0; n = nframe + noff; frame = mpi_is_secure (value)? xtrymalloc_secure (n) : xtrymalloc (n); if (!frame) return gpg_err_code_from_syserror (); if (noff) memset (frame, 0, noff); nframe += noff; rc = _gcry_mpi_print (GCRYMPI_FMT_USG, frame+noff, nframe-noff, NULL, value); if (rc) { xfree (frame); return rc; } *r_frame = frame; return 0; } /* Connert the bit string BITS of length NBITS into an octet string with a length of (QBITS+7)/8 bytes. On success store the result at R_FRAME. */ static gpg_err_code_t bits2octets (unsigned char **r_frame, const void *bits, unsigned int nbits, gcry_mpi_t q, unsigned int qbits) { gpg_err_code_t rc; gcry_mpi_t z1; /* z1 = bits2int (b) */ rc = _gcry_mpi_scan (&z1, GCRYMPI_FMT_USG, bits, (nbits+7)/8, NULL); if (rc) return rc; if (nbits > qbits) mpi_rshift (z1, z1, nbits - qbits); /* z2 - z1 mod q */ if (mpi_cmp (z1, q) >= 0) mpi_sub (z1, z1, q); /* Convert to an octet string. */ rc = int2octets (r_frame, z1, (qbits+7)/8); mpi_free (z1); return rc; } /* * Generate a deterministic secret exponent K less than DSA_Q. H1 is * the to be signed digest with a length of HLEN bytes. HALGO is the * algorithm used to create the hash. On success the value for K is * stored at R_K. */ gpg_err_code_t _gcry_dsa_gen_rfc6979_k (gcry_mpi_t *r_k, gcry_mpi_t dsa_q, gcry_mpi_t dsa_x, const unsigned char *h1, unsigned int hlen, int halgo, unsigned int extraloops) { gpg_err_code_t rc; unsigned char *V = NULL; unsigned char *K = NULL; unsigned char *x_buf = NULL; unsigned char *h1_buf = NULL; gcry_md_hd_t hd = NULL; unsigned char *t = NULL; gcry_mpi_t k = NULL; unsigned int tbits, qbits; int i; qbits = mpi_get_nbits (dsa_q); if (!qbits || !h1 || !hlen) return GPG_ERR_EINVAL; if (_gcry_md_get_algo_dlen (halgo) != hlen) return GPG_ERR_DIGEST_ALGO; /* Step b: V = 0x01 0x01 0x01 ... 0x01 */ V = xtrymalloc (hlen); if (!V) { rc = gpg_err_code_from_syserror (); goto leave; } for (i=0; i < hlen; i++) V[i] = 1; /* Step c: K = 0x00 0x00 0x00 ... 0x00 */ K = xtrycalloc (1, hlen); if (!K) { rc = gpg_err_code_from_syserror (); goto leave; } rc = int2octets (&x_buf, dsa_x, (qbits+7)/8); if (rc) goto leave; rc = bits2octets (&h1_buf, h1, hlen*8, dsa_q, qbits); if (rc) goto leave; /* Create a handle to compute the HMACs. */ rc = _gcry_md_open (&hd, halgo, (GCRY_MD_FLAG_SECURE | GCRY_MD_FLAG_HMAC)); if (rc) goto leave; /* Step d: K = HMAC_K(V || 0x00 || int2octets(x) || bits2octets(h1) */ rc = _gcry_md_setkey (hd, K, hlen); if (rc) goto leave; _gcry_md_write (hd, V, hlen); _gcry_md_write (hd, "", 1); _gcry_md_write (hd, x_buf, (qbits+7)/8); _gcry_md_write (hd, h1_buf, (qbits+7)/8); memcpy (K, _gcry_md_read (hd, 0), hlen); /* Step e: V = HMAC_K(V) */ rc = _gcry_md_setkey (hd, K, hlen); if (rc) goto leave; _gcry_md_write (hd, V, hlen); memcpy (V, _gcry_md_read (hd, 0), hlen); /* Step f: K = HMAC_K(V || 0x01 || int2octets(x) || bits2octets(h1) */ rc = _gcry_md_setkey (hd, K, hlen); if (rc) goto leave; _gcry_md_write (hd, V, hlen); _gcry_md_write (hd, "\x01", 1); _gcry_md_write (hd, x_buf, (qbits+7)/8); _gcry_md_write (hd, h1_buf, (qbits+7)/8); memcpy (K, _gcry_md_read (hd, 0), hlen); /* Step g: V = HMAC_K(V) */ rc = _gcry_md_setkey (hd, K, hlen); if (rc) goto leave; _gcry_md_write (hd, V, hlen); memcpy (V, _gcry_md_read (hd, 0), hlen); /* Step h. */ t = xtrymalloc ((qbits+7)/8+hlen); if (!t) { rc = gpg_err_code_from_syserror (); goto leave; } again: for (tbits = 0; tbits < qbits;) { /* V = HMAC_K(V) */ rc = _gcry_md_setkey (hd, K, hlen); if (rc) goto leave; _gcry_md_write (hd, V, hlen); memcpy (V, _gcry_md_read (hd, 0), hlen); /* T = T || V */ memcpy (t+(tbits+7)/8, V, hlen); tbits += 8*hlen; } /* k = bits2int (T) */ mpi_free (k); k = NULL; rc = _gcry_mpi_scan (&k, GCRYMPI_FMT_USG, t, (tbits+7)/8, NULL); if (rc) goto leave; if (tbits > qbits) mpi_rshift (k, k, tbits - qbits); /* Check: k < q and k > 1 */ if (!(mpi_cmp (k, dsa_q) < 0 && mpi_cmp_ui (k, 0) > 0)) { /* K = HMAC_K(V || 0x00) */ rc = _gcry_md_setkey (hd, K, hlen); if (rc) goto leave; _gcry_md_write (hd, V, hlen); _gcry_md_write (hd, "", 1); memcpy (K, _gcry_md_read (hd, 0), hlen); /* V = HMAC_K(V) */ rc = _gcry_md_setkey (hd, K, hlen); if (rc) goto leave; _gcry_md_write (hd, V, hlen); memcpy (V, _gcry_md_read (hd, 0), hlen); goto again; } /* The caller may have requested that we introduce some extra loops. This is for example useful if the caller wants another value for K because the last returned one yielded an R of 0. Becuase this is very unlikely we implement it in a straightforward way. */ if (extraloops) { extraloops--; /* K = HMAC_K(V || 0x00) */ rc = _gcry_md_setkey (hd, K, hlen); if (rc) goto leave; _gcry_md_write (hd, V, hlen); _gcry_md_write (hd, "", 1); memcpy (K, _gcry_md_read (hd, 0), hlen); /* V = HMAC_K(V) */ rc = _gcry_md_setkey (hd, K, hlen); if (rc) goto leave; _gcry_md_write (hd, V, hlen); memcpy (V, _gcry_md_read (hd, 0), hlen); goto again; } /* log_mpidump (" k", k); */ leave: xfree (t); _gcry_md_close (hd); xfree (h1_buf); xfree (x_buf); xfree (K); xfree (V); if (rc) mpi_free (k); else *r_k = k; return rc; } + +/* + * Truncate opaque hash value to qbits for DSA. + * Non-opaque input is not truncated, in hope that user + * knows what is passed. It is not possible to correctly + * trucate non-opaque inputs. + */ +gpg_err_code_t +_gcry_dsa_normalize_hash (gcry_mpi_t input, + gcry_mpi_t *out, + unsigned int qbits) +{ + gpg_err_code_t rc = 0; + const void *abuf; + unsigned int abits; + gcry_mpi_t hash; + + if (mpi_is_opaque (input)) + { + abuf = mpi_get_opaque (input, &abits); + rc = _gcry_mpi_scan (&hash, GCRYMPI_FMT_USG, abuf, (abits+7)/8, NULL); + if (rc) + return rc; + if (abits > qbits) + mpi_rshift (hash, hash, abits - qbits); + } + else + hash = input; + + *out = hash; + + return rc; +} diff --git a/cipher/dsa.c b/cipher/dsa.c index 50bdab16..1707d8cf 100644 --- a/cipher/dsa.c +++ b/cipher/dsa.c @@ -1,1310 +1,1295 @@ /* dsa.c - DSA signature algorithm * Copyright (C) 1998, 2000, 2001, 2002, 2003, * 2006, 2008 Free Software Foundation, Inc. * Copyright (C) 2013 g10 Code GmbH. * * This file is part of Libgcrypt. * * Libgcrypt is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * Libgcrypt is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, see . */ #include #include #include #include #include "g10lib.h" #include "mpi.h" #include "cipher.h" #include "pubkey-internal.h" typedef struct { gcry_mpi_t p; /* prime */ gcry_mpi_t q; /* group order */ gcry_mpi_t g; /* group generator */ gcry_mpi_t y; /* g^x mod p */ } DSA_public_key; typedef struct { gcry_mpi_t p; /* prime */ gcry_mpi_t q; /* group order */ gcry_mpi_t g; /* group generator */ gcry_mpi_t y; /* g^x mod p */ gcry_mpi_t x; /* secret exponent */ } DSA_secret_key; /* A structure used to hold domain parameters. */ typedef struct { gcry_mpi_t p; /* prime */ gcry_mpi_t q; /* group order */ gcry_mpi_t g; /* group generator */ } dsa_domain_t; static const char *dsa_names[] = { "dsa", "openpgp-dsa", NULL, }; /* A sample 1024 bit DSA key used for the selftests. */ static const char sample_secret_key[] = "(private-key" " (dsa" " (p #00AD7C0025BA1A15F775F3F2D673718391D00456978D347B33D7B49E7F32EDAB" " 96273899DD8B2BB46CD6ECA263FAF04A28903503D59062A8865D2AE8ADFB5191" " CF36FFB562D0E2F5809801A1F675DAE59698A9E01EFE8D7DCFCA084F4C6F5A44" " 44D499A06FFAEA5E8EF5E01F2FD20A7B7EF3F6968AFBA1FB8D91F1559D52D8777B#)" " (q #00EB7B5751D25EBBB7BD59D920315FD840E19AEBF9#)" " (g #1574363387FDFD1DDF38F4FBE135BB20C7EE4772FB94C337AF86EA8E49666503" " AE04B6BE81A2F8DD095311E0217ACA698A11E6C5D33CCDAE71498ED35D13991E" " B02F09AB40BD8F4C5ED8C75DA779D0AE104BC34C960B002377068AB4B5A1F984" " 3FBA91F537F1B7CAC4D8DD6D89B0D863AF7025D549F9C765D2FC07EE208F8D15#)" " (y #64B11EF8871BE4AB572AA810D5D3CA11A6CDBC637A8014602C72960DB135BF46" " A1816A724C34F87330FC9E187C5D66897A04535CC2AC9164A7150ABFA8179827" " 6E45831AB811EEE848EBB24D9F5F2883B6E5DDC4C659DEF944DCFD80BF4D0A20" " 42CAA7DC289F0C5A9D155F02D3D551DB741A81695B74D4C8F477F9C7838EB0FB#)" " (x #11D54E4ADBD3034160F2CED4B7CD292A4EBF3EC0#)))"; /* A sample 1024 bit DSA key used for the selftests (public only). */ static const char sample_public_key[] = "(public-key" " (dsa" " (p #00AD7C0025BA1A15F775F3F2D673718391D00456978D347B33D7B49E7F32EDAB" " 96273899DD8B2BB46CD6ECA263FAF04A28903503D59062A8865D2AE8ADFB5191" " CF36FFB562D0E2F5809801A1F675DAE59698A9E01EFE8D7DCFCA084F4C6F5A44" " 44D499A06FFAEA5E8EF5E01F2FD20A7B7EF3F6968AFBA1FB8D91F1559D52D8777B#)" " (q #00EB7B5751D25EBBB7BD59D920315FD840E19AEBF9#)" " (g #1574363387FDFD1DDF38F4FBE135BB20C7EE4772FB94C337AF86EA8E49666503" " AE04B6BE81A2F8DD095311E0217ACA698A11E6C5D33CCDAE71498ED35D13991E" " B02F09AB40BD8F4C5ED8C75DA779D0AE104BC34C960B002377068AB4B5A1F984" " 3FBA91F537F1B7CAC4D8DD6D89B0D863AF7025D549F9C765D2FC07EE208F8D15#)" " (y #64B11EF8871BE4AB572AA810D5D3CA11A6CDBC637A8014602C72960DB135BF46" " A1816A724C34F87330FC9E187C5D66897A04535CC2AC9164A7150ABFA8179827" " 6E45831AB811EEE848EBB24D9F5F2883B6E5DDC4C659DEF944DCFD80BF4D0A20" " 42CAA7DC289F0C5A9D155F02D3D551DB741A81695B74D4C8F477F9C7838EB0FB#)))"; static int test_keys (DSA_secret_key *sk, unsigned int qbits); static int check_secret_key (DSA_secret_key *sk); static gpg_err_code_t generate (DSA_secret_key *sk, unsigned int nbits, unsigned int qbits, int transient_key, dsa_domain_t *domain, gcry_mpi_t **ret_factors); static gpg_err_code_t sign (gcry_mpi_t r, gcry_mpi_t s, gcry_mpi_t input, DSA_secret_key *skey, int flags, int hashalgo); -static int verify (gcry_mpi_t r, gcry_mpi_t s, gcry_mpi_t input, +static gpg_err_code_t verify (gcry_mpi_t r, gcry_mpi_t s, gcry_mpi_t input, DSA_public_key *pkey); static unsigned int dsa_get_nbits (gcry_sexp_t parms); static void (*progress_cb) (void *,const char *, int, int, int ); static void *progress_cb_data; void _gcry_register_pk_dsa_progress (void (*cb) (void *, const char *, int, int, int), void *cb_data) { progress_cb = cb; progress_cb_data = cb_data; } static void progress (int c) { if (progress_cb) progress_cb (progress_cb_data, "pk_dsa", c, 0, 0); } /* Check that a freshly generated key actually works. Returns 0 on success. */ static int test_keys (DSA_secret_key *sk, unsigned int qbits) { int result = -1; /* Default to failure. */ DSA_public_key pk; gcry_mpi_t data = mpi_new (qbits); gcry_mpi_t sig_a = mpi_new (qbits); gcry_mpi_t sig_b = mpi_new (qbits); /* Put the relevant parameters into a public key structure. */ pk.p = sk->p; pk.q = sk->q; pk.g = sk->g; pk.y = sk->y; /* Create a random plaintext. */ _gcry_mpi_randomize (data, qbits, GCRY_WEAK_RANDOM); /* Sign DATA using the secret key. */ sign (sig_a, sig_b, data, sk, 0, 0); /* Verify the signature using the public key. */ - if ( !verify (sig_a, sig_b, data, &pk) ) + if ( verify (sig_a, sig_b, data, &pk) ) goto leave; /* Signature does not match. */ /* Modify the data and check that the signing fails. */ mpi_add_ui (data, data, 1); - if ( verify (sig_a, sig_b, data, &pk) ) + if ( !verify (sig_a, sig_b, data, &pk) ) goto leave; /* Signature matches but should not. */ result = 0; /* The test succeeded. */ leave: _gcry_mpi_release (sig_b); _gcry_mpi_release (sig_a); _gcry_mpi_release (data); return result; } /* Generate a DSA key pair with a key of size NBITS. If transient_key is true the key is generated using the standard RNG and not the very secure one. Returns: 2 structures filled with all needed values and an array with the n-1 factors of (p-1) */ static gpg_err_code_t generate (DSA_secret_key *sk, unsigned int nbits, unsigned int qbits, int transient_key, dsa_domain_t *domain, gcry_mpi_t **ret_factors ) { gcry_mpi_t p; /* the prime */ gcry_mpi_t q; /* the 160 bit prime factor */ gcry_mpi_t g; /* the generator */ gcry_mpi_t y; /* g^x mod p */ gcry_mpi_t x; /* the secret exponent */ gcry_mpi_t h, e; /* helper */ unsigned char *rndbuf; gcry_random_level_t random_level; if (qbits) ; /* Caller supplied qbits. Use this value. */ else if ( nbits >= 512 && nbits <= 1024 ) qbits = 160; else if ( nbits == 2048 ) qbits = 224; else if ( nbits == 3072 ) qbits = 256; else if ( nbits == 7680 ) qbits = 384; else if ( nbits == 15360 ) qbits = 512; else return GPG_ERR_INV_VALUE; if (qbits < 160 || qbits > 512 || (qbits%8) ) return GPG_ERR_INV_VALUE; if (nbits < 2*qbits || nbits > 15360) return GPG_ERR_INV_VALUE; if (fips_mode ()) { if (nbits < 1024) return GPG_ERR_INV_VALUE; if (transient_key) return GPG_ERR_INV_VALUE; } if (domain->p && domain->q && domain->g) { /* Domain parameters are given; use them. */ p = mpi_copy (domain->p); q = mpi_copy (domain->q); g = mpi_copy (domain->g); gcry_assert (mpi_get_nbits (p) == nbits); gcry_assert (mpi_get_nbits (q) == qbits); h = mpi_alloc (0); e = NULL; } else { /* Generate new domain parameters. */ p = _gcry_generate_elg_prime (1, nbits, qbits, NULL, ret_factors); /* Get q out of factors. */ q = mpi_copy ((*ret_factors)[0]); gcry_assert (mpi_get_nbits (q) == qbits); /* Find a generator g (h and e are helpers). e = (p-1)/q */ e = mpi_alloc (mpi_get_nlimbs (p)); mpi_sub_ui (e, p, 1); mpi_fdiv_q (e, e, q); g = mpi_alloc (mpi_get_nlimbs (p)); h = mpi_alloc_set_ui (1); /* (We start with 2.) */ do { mpi_add_ui (h, h, 1); /* g = h^e mod p */ mpi_powm (g, h, e, p); } while (!mpi_cmp_ui (g, 1)); /* Continue until g != 1. */ } /* Select a random number X with the property: * 0 < x < q-1 * * FIXME: Why do we use the requirement x < q-1 ? It should be * sufficient to test for x < q. FIPS-186-3 check x < q-1 but it * does not check for 0 < x because it makes sure that Q is unsigned * and finally adds one to the result so that 0 will never be * returned. We should replace the code below with _gcry_dsa_gen_k. * * This must be a very good random number because this is the secret * part. The random quality depends on the transient_key flag. */ random_level = transient_key ? GCRY_STRONG_RANDOM : GCRY_VERY_STRONG_RANDOM; if (DBG_CIPHER) log_debug("choosing a random x%s\n", transient_key? " (transient-key)":""); gcry_assert( qbits >= 160 ); x = mpi_alloc_secure( mpi_get_nlimbs(q) ); mpi_sub_ui( h, q, 1 ); /* put q-1 into h */ rndbuf = NULL; do { if( DBG_CIPHER ) progress('.'); if( !rndbuf ) rndbuf = _gcry_random_bytes_secure ((qbits+7)/8, random_level); else { /* Change only some of the higher bits (= 2 bytes)*/ char *r = _gcry_random_bytes_secure (2, random_level); memcpy(rndbuf, r, 2 ); xfree(r); } _gcry_mpi_set_buffer( x, rndbuf, (qbits+7)/8, 0 ); mpi_clear_highbit( x, qbits+1 ); } while ( !( mpi_cmp_ui( x, 0 )>0 && mpi_cmp( x, h )<0 ) ); xfree(rndbuf); mpi_free( e ); mpi_free( h ); /* y = g^x mod p */ y = mpi_alloc( mpi_get_nlimbs(p) ); mpi_powm (y, g, x, p); if( DBG_CIPHER ) { progress('\n'); log_mpidump("dsa p", p ); log_mpidump("dsa q", q ); log_mpidump("dsa g", g ); log_mpidump("dsa y", y ); log_mpidump("dsa x", x ); } /* Copy the stuff to the key structures. */ sk->p = p; sk->q = q; sk->g = g; sk->y = y; sk->x = x; /* Now we can test our keys (this should never fail!). */ if ( test_keys (sk, qbits) ) { _gcry_mpi_release (sk->p); sk->p = NULL; _gcry_mpi_release (sk->q); sk->q = NULL; _gcry_mpi_release (sk->g); sk->g = NULL; _gcry_mpi_release (sk->y); sk->y = NULL; _gcry_mpi_release (sk->x); sk->x = NULL; fips_signal_error ("self-test after key generation failed"); return GPG_ERR_SELFTEST_FAILED; } return 0; } /* Generate a DSA key pair with a key of size NBITS using the algorithm given in FIPS-186-3. If USE_FIPS186_2 is true, FIPS-186-2 is used and thus the length is restricted to 1024/160. If DERIVEPARMS is not NULL it may contain a seed value. If domain parameters are specified in DOMAIN, DERIVEPARMS may not be given and NBITS and QBITS must match the specified domain parameters. */ static gpg_err_code_t generate_fips186 (DSA_secret_key *sk, unsigned int nbits, unsigned int qbits, gcry_sexp_t deriveparms, int use_fips186_2, dsa_domain_t *domain, int *r_counter, void **r_seed, size_t *r_seedlen, gcry_mpi_t *r_h) { gpg_err_code_t ec; struct { gcry_sexp_t sexp; const void *seed; size_t seedlen; } initial_seed = { NULL, NULL, 0 }; gcry_mpi_t prime_q = NULL; gcry_mpi_t prime_p = NULL; gcry_mpi_t value_g = NULL; /* The generator. */ gcry_mpi_t value_y = NULL; /* g^x mod p */ gcry_mpi_t value_x = NULL; /* The secret exponent. */ gcry_mpi_t value_h = NULL; /* Helper. */ gcry_mpi_t value_e = NULL; /* Helper. */ /* Preset return values. */ *r_counter = 0; *r_seed = NULL; *r_seedlen = 0; *r_h = NULL; /* Derive QBITS from NBITS if requested */ if (!qbits) { if (nbits == 1024) qbits = 160; else if (nbits == 2048) qbits = 224; else if (nbits == 3072) qbits = 256; } /* Check that QBITS and NBITS match the standard. Note that FIPS 186-3 uses N for QBITS and L for NBITS. */ if (nbits == 1024 && qbits == 160) ; else if (nbits == 2048 && qbits == 224) ; else if (nbits == 2048 && qbits == 256) ; else if (nbits == 3072 && qbits == 256) ; else return GPG_ERR_INV_VALUE; if (domain->p && domain->q && domain->g) { /* Domain parameters are given; use them. */ prime_p = mpi_copy (domain->p); prime_q = mpi_copy (domain->q); value_g = mpi_copy (domain->g); gcry_assert (mpi_get_nbits (prime_p) == nbits); gcry_assert (mpi_get_nbits (prime_q) == qbits); gcry_assert (!deriveparms); ec = 0; } else { /* Generate new domain parameters. */ /* Get an initial seed value. */ if (deriveparms) { initial_seed.sexp = sexp_find_token (deriveparms, "seed", 0); if (initial_seed.sexp) initial_seed.seed = sexp_nth_data (initial_seed.sexp, 1, &initial_seed.seedlen); } /* Fixme: Enable 186-3 after it has been approved and after fixing the generation function. */ /* if (use_fips186_2) */ (void)use_fips186_2; ec = _gcry_generate_fips186_2_prime (nbits, qbits, initial_seed.seed, initial_seed.seedlen, &prime_q, &prime_p, r_counter, r_seed, r_seedlen); /* else */ /* ec = _gcry_generate_fips186_3_prime (nbits, qbits, NULL, 0, */ /* &prime_q, &prime_p, */ /* r_counter, */ /* r_seed, r_seedlen, NULL); */ sexp_release (initial_seed.sexp); if (ec) goto leave; /* Find a generator g (h and e are helpers). e = (p-1)/q */ value_e = mpi_alloc_like (prime_p); mpi_sub_ui (value_e, prime_p, 1); mpi_fdiv_q (value_e, value_e, prime_q ); value_g = mpi_alloc_like (prime_p); value_h = mpi_alloc_set_ui (1); do { mpi_add_ui (value_h, value_h, 1); /* g = h^e mod p */ mpi_powm (value_g, value_h, value_e, prime_p); } while (!mpi_cmp_ui (value_g, 1)); /* Continue until g != 1. */ } /* Select a random number x with: 0 < x < q */ value_x = mpi_snew (qbits); do { if( DBG_CIPHER ) progress('.'); _gcry_mpi_randomize (value_x, qbits, GCRY_VERY_STRONG_RANDOM); mpi_clear_highbit (value_x, qbits+1); } while (!(mpi_cmp_ui (value_x, 0) > 0 && mpi_cmp (value_x, prime_q) < 0)); /* y = g^x mod p */ value_y = mpi_alloc_like (prime_p); mpi_powm (value_y, value_g, value_x, prime_p); if (DBG_CIPHER) { progress('\n'); log_mpidump("dsa p", prime_p ); log_mpidump("dsa q", prime_q ); log_mpidump("dsa g", value_g ); log_mpidump("dsa y", value_y ); log_mpidump("dsa x", value_x ); log_mpidump("dsa h", value_h ); } /* Copy the stuff to the key structures. */ sk->p = prime_p; prime_p = NULL; sk->q = prime_q; prime_q = NULL; sk->g = value_g; value_g = NULL; sk->y = value_y; value_y = NULL; sk->x = value_x; value_x = NULL; *r_h = value_h; value_h = NULL; leave: _gcry_mpi_release (prime_p); _gcry_mpi_release (prime_q); _gcry_mpi_release (value_g); _gcry_mpi_release (value_y); _gcry_mpi_release (value_x); _gcry_mpi_release (value_h); _gcry_mpi_release (value_e); /* As a last step test this keys (this should never fail of course). */ if (!ec && test_keys (sk, qbits) ) { _gcry_mpi_release (sk->p); sk->p = NULL; _gcry_mpi_release (sk->q); sk->q = NULL; _gcry_mpi_release (sk->g); sk->g = NULL; _gcry_mpi_release (sk->y); sk->y = NULL; _gcry_mpi_release (sk->x); sk->x = NULL; fips_signal_error ("self-test after key generation failed"); ec = GPG_ERR_SELFTEST_FAILED; } if (ec) { *r_counter = 0; xfree (*r_seed); *r_seed = NULL; *r_seedlen = 0; _gcry_mpi_release (*r_h); *r_h = NULL; } return ec; } /* Test whether the secret key is valid. Returns: if this is a valid key. */ static int check_secret_key( DSA_secret_key *sk ) { int rc; gcry_mpi_t y = mpi_alloc( mpi_get_nlimbs(sk->y) ); mpi_powm( y, sk->g, sk->x, sk->p ); rc = !mpi_cmp( y, sk->y ); mpi_free( y ); return rc; } /* Make a DSA signature from INPUT and put it into r and s. INPUT may either be a plain MPI or an opaque MPI which is then internally converted to a plain MPI. FLAGS and HASHALGO may both be 0 for standard operation mode. The return value is 0 on success or an error code. Note that for backward compatibility the function will not return any error if FLAGS and HASHALGO are both 0 and INPUT is a plain MPI. */ static gpg_err_code_t sign (gcry_mpi_t r, gcry_mpi_t s, gcry_mpi_t input, DSA_secret_key *skey, int flags, int hashalgo) { gpg_err_code_t rc; gcry_mpi_t hash; gcry_mpi_t k; gcry_mpi_t kinv; gcry_mpi_t tmp; const void *abuf; unsigned int abits, qbits; int extraloops = 0; qbits = mpi_get_nbits (skey->q); /* Convert the INPUT into an MPI. */ - if (mpi_is_opaque (input)) - { - abuf = mpi_get_opaque (input, &abits); - rc = _gcry_mpi_scan (&hash, GCRYMPI_FMT_USG, abuf, (abits+7)/8, NULL); - if (rc) - return rc; - if (abits > qbits) - mpi_rshift (hash, hash, abits - qbits); - } - else - { - mpi_normalize (input); - hash = input; - } + rc = _gcry_dsa_normalize_hash (input, &hash, qbits); + if (rc) + return rc; again: /* Create the K value. */ if ((flags & PUBKEY_FLAG_RFC6979) && hashalgo) { /* Use Pornin's method for deterministic DSA. If this flag is set, it is expected that HASH is an opaque MPI with the to be signed hash. That hash is also used as h1 from 3.2.a. */ if (!mpi_is_opaque (input)) { rc = GPG_ERR_CONFLICT; goto leave; } abuf = mpi_get_opaque (input, &abits); rc = _gcry_dsa_gen_rfc6979_k (&k, skey->q, skey->x, abuf, (abits+7)/8, hashalgo, extraloops); if (rc) goto leave; } else { /* Select a random k with 0 < k < q */ k = _gcry_dsa_gen_k (skey->q, GCRY_STRONG_RANDOM); } /* r = (a^k mod p) mod q */ mpi_powm( r, skey->g, k, skey->p ); mpi_fdiv_r( r, r, skey->q ); /* kinv = k^(-1) mod q */ kinv = mpi_alloc( mpi_get_nlimbs(k) ); mpi_invm(kinv, k, skey->q ); /* s = (kinv * ( hash + x * r)) mod q */ tmp = mpi_alloc( mpi_get_nlimbs(skey->p) ); mpi_mul( tmp, skey->x, r ); mpi_add( tmp, tmp, hash ); mpi_mulm( s , kinv, tmp, skey->q ); mpi_free(k); mpi_free(kinv); mpi_free(tmp); if (!mpi_cmp_ui (r, 0)) { /* This is a highly unlikely code path. */ extraloops++; goto again; } rc = 0; leave: if (hash != input) mpi_free (hash); return rc; } /* Returns true if the signature composed from R and S is valid. */ -static int -verify (gcry_mpi_t r, gcry_mpi_t s, gcry_mpi_t hash, DSA_public_key *pkey ) +static gpg_err_code_t +verify (gcry_mpi_t r, gcry_mpi_t s, gcry_mpi_t input, DSA_public_key *pkey ) { - int rc; + gpg_err_code_t rc = 0; gcry_mpi_t w, u1, u2, v; gcry_mpi_t base[3]; gcry_mpi_t ex[3]; + gcry_mpi_t hash; + unsigned int nbits; if( !(mpi_cmp_ui( r, 0 ) > 0 && mpi_cmp( r, pkey->q ) < 0) ) - return 0; /* assertion 0 < r < q failed */ + return GPG_ERR_BAD_SIGNATURE; /* Assertion 0 < r < n failed. */ if( !(mpi_cmp_ui( s, 0 ) > 0 && mpi_cmp( s, pkey->q ) < 0) ) - return 0; /* assertion 0 < s < q failed */ + return GPG_ERR_BAD_SIGNATURE; /* Assertion 0 < s < n failed. */ + + nbits = mpi_get_nbits (pkey->q); + rc = _gcry_dsa_normalize_hash (input, &hash, nbits); + if (rc) + return rc; w = mpi_alloc( mpi_get_nlimbs(pkey->q) ); u1 = mpi_alloc( mpi_get_nlimbs(pkey->q) ); u2 = mpi_alloc( mpi_get_nlimbs(pkey->q) ); v = mpi_alloc( mpi_get_nlimbs(pkey->p) ); /* w = s^(-1) mod q */ mpi_invm( w, s, pkey->q ); /* u1 = (hash * w) mod q */ mpi_mulm( u1, hash, w, pkey->q ); /* u2 = r * w mod q */ mpi_mulm( u2, r, w, pkey->q ); /* v = g^u1 * y^u2 mod p mod q */ base[0] = pkey->g; ex[0] = u1; base[1] = pkey->y; ex[1] = u2; base[2] = NULL; ex[2] = NULL; mpi_mulpowm( v, base, ex, pkey->p ); mpi_fdiv_r( v, v, pkey->q ); - rc = !mpi_cmp( v, r ); + if (mpi_cmp( v, r )) + { + if (DBG_CIPHER) + { + log_mpidump (" i", input); + log_mpidump (" h", hash); + log_mpidump (" v", v); + log_mpidump (" r", r); + log_mpidump (" s", s); + } + rc = GPG_ERR_BAD_SIGNATURE; + } mpi_free(w); mpi_free(u1); mpi_free(u2); mpi_free(v); + if (hash != input) + mpi_free (hash); return rc; } /********************************************* ************** interface ****************** *********************************************/ static gcry_err_code_t dsa_generate (const gcry_sexp_t genparms, gcry_sexp_t *r_skey) { gpg_err_code_t rc; unsigned int nbits; gcry_sexp_t domainsexp; DSA_secret_key sk; gcry_sexp_t l1; unsigned int qbits = 0; gcry_sexp_t deriveparms = NULL; gcry_sexp_t seedinfo = NULL; gcry_sexp_t misc_info = NULL; int flags = 0; dsa_domain_t domain; gcry_mpi_t *factors = NULL; memset (&sk, 0, sizeof sk); memset (&domain, 0, sizeof domain); rc = _gcry_pk_util_get_nbits (genparms, &nbits); if (rc) return rc; /* Parse the optional flags list. */ l1 = sexp_find_token (genparms, "flags", 0); if (l1) { rc = _gcry_pk_util_parse_flaglist (l1, &flags, NULL); sexp_release (l1); if (rc) return rc;\ } /* Parse the optional qbits element. */ l1 = sexp_find_token (genparms, "qbits", 0); if (l1) { char buf[50]; const char *s; size_t n; s = sexp_nth_data (l1, 1, &n); if (!s || n >= DIM (buf) - 1 ) { sexp_release (l1); return GPG_ERR_INV_OBJ; /* No value or value too large. */ } memcpy (buf, s, n); buf[n] = 0; qbits = (unsigned int)strtoul (buf, NULL, 0); sexp_release (l1); } /* Parse the optional transient-key flag. */ if (!(flags & PUBKEY_FLAG_TRANSIENT_KEY)) { l1 = sexp_find_token (genparms, "transient-key", 0); if (l1) { flags |= PUBKEY_FLAG_TRANSIENT_KEY; sexp_release (l1); } } /* Get the optional derive parameters. */ deriveparms = sexp_find_token (genparms, "derive-parms", 0); /* Parse the optional "use-fips186" flags. */ if (!(flags & PUBKEY_FLAG_USE_FIPS186)) { l1 = sexp_find_token (genparms, "use-fips186", 0); if (l1) { flags |= PUBKEY_FLAG_USE_FIPS186; sexp_release (l1); } } if (!(flags & PUBKEY_FLAG_USE_FIPS186_2)) { l1 = sexp_find_token (genparms, "use-fips186-2", 0); if (l1) { flags |= PUBKEY_FLAG_USE_FIPS186_2; sexp_release (l1); } } /* Check whether domain parameters are given. */ domainsexp = sexp_find_token (genparms, "domain", 0); if (domainsexp) { /* DERIVEPARMS can't be used together with domain parameters. NBITS abnd QBITS may not be specified because there values are derived from the domain parameters. */ if (deriveparms || qbits || nbits) { sexp_release (domainsexp); sexp_release (deriveparms); return GPG_ERR_INV_VALUE; } /* Put all domain parameters into the domain object. */ l1 = sexp_find_token (domainsexp, "p", 0); domain.p = sexp_nth_mpi (l1, 1, GCRYMPI_FMT_USG); sexp_release (l1); l1 = sexp_find_token (domainsexp, "q", 0); domain.q = sexp_nth_mpi (l1, 1, GCRYMPI_FMT_USG); sexp_release (l1); l1 = sexp_find_token (domainsexp, "g", 0); domain.g = sexp_nth_mpi (l1, 1, GCRYMPI_FMT_USG); sexp_release (l1); sexp_release (domainsexp); /* Check that all domain parameters are available. */ if (!domain.p || !domain.q || !domain.g) { _gcry_mpi_release (domain.p); _gcry_mpi_release (domain.q); _gcry_mpi_release (domain.g); sexp_release (deriveparms); return GPG_ERR_MISSING_VALUE; } /* Get NBITS and QBITS from the domain parameters. */ nbits = mpi_get_nbits (domain.p); qbits = mpi_get_nbits (domain.q); } if (deriveparms || (flags & PUBKEY_FLAG_USE_FIPS186) || (flags & PUBKEY_FLAG_USE_FIPS186_2) || fips_mode ()) { int counter; void *seed; size_t seedlen; gcry_mpi_t h_value; rc = generate_fips186 (&sk, nbits, qbits, deriveparms, !!(flags & PUBKEY_FLAG_USE_FIPS186_2), &domain, &counter, &seed, &seedlen, &h_value); if (!rc && h_value) { /* Format the seed-values unless domain parameters are used for which a H_VALUE of NULL is an indication. */ rc = sexp_build (&seedinfo, NULL, "(seed-values(counter %d)(seed %b)(h %m))", counter, (int)seedlen, seed, h_value); xfree (seed); _gcry_mpi_release (h_value); } } else { rc = generate (&sk, nbits, qbits, !!(flags & PUBKEY_FLAG_TRANSIENT_KEY), &domain, &factors); } if (!rc) { /* Put the factors into MISC_INFO. Note that the factors are not confidential thus we can store them in standard memory. */ int nfactors, i, j; char *p; char *format = NULL; void **arg_list = NULL; for (nfactors=0; factors && factors[nfactors]; nfactors++) ; /* Allocate space for the format string: "(misc-key-info%S(pm1-factors%m))" with one "%m" for each factor and construct it. */ format = xtrymalloc (50 + 2*nfactors); if (!format) rc = gpg_err_code_from_syserror (); else { p = stpcpy (format, "(misc-key-info"); if (seedinfo) p = stpcpy (p, "%S"); if (nfactors) { p = stpcpy (p, "(pm1-factors"); for (i=0; i < nfactors; i++) p = stpcpy (p, "%m"); p = stpcpy (p, ")"); } p = stpcpy (p, ")"); /* Allocate space for the list of factors plus one for the seedinfo s-exp plus an extra NULL entry for safety and fill it with the factors. */ arg_list = xtrycalloc (nfactors+1+1, sizeof *arg_list); if (!arg_list) rc = gpg_err_code_from_syserror (); else { i = 0; if (seedinfo) arg_list[i++] = &seedinfo; for (j=0; j < nfactors; j++) arg_list[i++] = factors + j; arg_list[i] = NULL; rc = sexp_build_array (&misc_info, NULL, format, arg_list); } } xfree (arg_list); xfree (format); } if (!rc) rc = sexp_build (r_skey, NULL, "(key-data" " (public-key" " (dsa(p%m)(q%m)(g%m)(y%m)))" " (private-key" " (dsa(p%m)(q%m)(g%m)(y%m)(x%m)))" " %S)", sk.p, sk.q, sk.g, sk.y, sk.p, sk.q, sk.g, sk.y, sk.x, misc_info); _gcry_mpi_release (sk.p); _gcry_mpi_release (sk.q); _gcry_mpi_release (sk.g); _gcry_mpi_release (sk.y); _gcry_mpi_release (sk.x); _gcry_mpi_release (domain.p); _gcry_mpi_release (domain.q); _gcry_mpi_release (domain.g); sexp_release (seedinfo); sexp_release (misc_info); sexp_release (deriveparms); if (factors) { gcry_mpi_t *mp; for (mp = factors; *mp; mp++) mpi_free (*mp); xfree (factors); } return rc; } static gcry_err_code_t dsa_check_secret_key (gcry_sexp_t keyparms) { gcry_err_code_t rc; DSA_secret_key sk = {NULL, NULL, NULL, NULL, NULL}; rc = _gcry_sexp_extract_param (keyparms, NULL, "pqgyx", &sk.p, &sk.q, &sk.g, &sk.y, &sk.x, NULL); if (rc) goto leave; if (!check_secret_key (&sk)) rc = GPG_ERR_BAD_SECKEY; leave: _gcry_mpi_release (sk.p); _gcry_mpi_release (sk.q); _gcry_mpi_release (sk.g); _gcry_mpi_release (sk.y); _gcry_mpi_release (sk.x); if (DBG_CIPHER) log_debug ("dsa_testkey => %s\n", gpg_strerror (rc)); return rc; } static gcry_err_code_t dsa_sign (gcry_sexp_t *r_sig, gcry_sexp_t s_data, gcry_sexp_t keyparms) { gcry_err_code_t rc; struct pk_encoding_ctx ctx; gcry_mpi_t data = NULL; DSA_secret_key sk = {NULL, NULL, NULL, NULL, NULL}; gcry_mpi_t sig_r = NULL; gcry_mpi_t sig_s = NULL; _gcry_pk_util_init_encoding_ctx (&ctx, PUBKEY_OP_SIGN, dsa_get_nbits (keyparms)); /* Extract the data. */ rc = _gcry_pk_util_data_to_mpi (s_data, &data, &ctx); if (rc) goto leave; if (DBG_CIPHER) log_mpidump ("dsa_sign data", data); /* Extract the key. */ rc = _gcry_sexp_extract_param (keyparms, NULL, "pqgyx", &sk.p, &sk.q, &sk.g, &sk.y, &sk.x, NULL); if (rc) goto leave; if (DBG_CIPHER) { log_mpidump ("dsa_sign p", sk.p); log_mpidump ("dsa_sign q", sk.q); log_mpidump ("dsa_sign g", sk.g); log_mpidump ("dsa_sign y", sk.y); if (!fips_mode ()) log_mpidump ("dsa_sign x", sk.x); } sig_r = mpi_new (0); sig_s = mpi_new (0); rc = sign (sig_r, sig_s, data, &sk, ctx.flags, ctx.hash_algo); if (rc) goto leave; if (DBG_CIPHER) { log_mpidump ("dsa_sign sig_r", sig_r); log_mpidump ("dsa_sign sig_s", sig_s); } rc = sexp_build (r_sig, NULL, "(sig-val(dsa(r%M)(s%M)))", sig_r, sig_s); leave: _gcry_mpi_release (sig_r); _gcry_mpi_release (sig_s); _gcry_mpi_release (sk.p); _gcry_mpi_release (sk.q); _gcry_mpi_release (sk.g); _gcry_mpi_release (sk.y); _gcry_mpi_release (sk.x); _gcry_mpi_release (data); _gcry_pk_util_free_encoding_ctx (&ctx); if (DBG_CIPHER) log_debug ("dsa_sign => %s\n", gpg_strerror (rc)); return rc; } static gcry_err_code_t dsa_verify (gcry_sexp_t s_sig, gcry_sexp_t s_data, gcry_sexp_t s_keyparms) { gcry_err_code_t rc; struct pk_encoding_ctx ctx; gcry_sexp_t l1 = NULL; gcry_mpi_t sig_r = NULL; gcry_mpi_t sig_s = NULL; gcry_mpi_t data = NULL; DSA_public_key pk = { NULL, NULL, NULL, NULL }; _gcry_pk_util_init_encoding_ctx (&ctx, PUBKEY_OP_VERIFY, dsa_get_nbits (s_keyparms)); /* Extract the data. */ rc = _gcry_pk_util_data_to_mpi (s_data, &data, &ctx); if (rc) goto leave; if (DBG_CIPHER) log_mpidump ("dsa_verify data", data); /* Extract the signature value. */ rc = _gcry_pk_util_preparse_sigval (s_sig, dsa_names, &l1, NULL); if (rc) goto leave; rc = _gcry_sexp_extract_param (l1, NULL, "rs", &sig_r, &sig_s, NULL); if (rc) goto leave; if (DBG_CIPHER) { log_mpidump ("dsa_verify s_r", sig_r); log_mpidump ("dsa_verify s_s", sig_s); } /* Extract the key. */ rc = _gcry_sexp_extract_param (s_keyparms, NULL, "pqgy", &pk.p, &pk.q, &pk.g, &pk.y, NULL); if (rc) goto leave; if (DBG_CIPHER) { log_mpidump ("dsa_verify p", pk.p); log_mpidump ("dsa_verify q", pk.q); log_mpidump ("dsa_verify g", pk.g); log_mpidump ("dsa_verify y", pk.y); } /* Verify the signature. */ - if (mpi_is_opaque (data)) - { - const void *abuf; - unsigned int abits, qbits; - gcry_mpi_t a; - - qbits = mpi_get_nbits (pk.q); - - abuf = mpi_get_opaque (data, &abits); - rc = _gcry_mpi_scan (&a, GCRYMPI_FMT_USG, abuf, (abits+7)/8, NULL); - if (!rc) - { - if (abits > qbits) - mpi_rshift (a, a, abits - qbits); - - if (!verify (sig_r, sig_s, a, &pk)) - rc = GPG_ERR_BAD_SIGNATURE; - _gcry_mpi_release (a); - } - } - else - { - if (!verify (sig_r, sig_s, data, &pk)) - rc = GPG_ERR_BAD_SIGNATURE; - } + rc = verify (sig_r, sig_s, data, &pk); leave: _gcry_mpi_release (pk.p); _gcry_mpi_release (pk.q); _gcry_mpi_release (pk.g); _gcry_mpi_release (pk.y); _gcry_mpi_release (data); _gcry_mpi_release (sig_r); _gcry_mpi_release (sig_s); sexp_release (l1); _gcry_pk_util_free_encoding_ctx (&ctx); if (DBG_CIPHER) log_debug ("dsa_verify => %s\n", rc?gpg_strerror (rc):"Good"); return rc; } /* Return the number of bits for the key described by PARMS. On error * 0 is returned. The format of PARMS starts with the algorithm name; * for example: * * (dsa * (p ) * (q ) * (g ) * (y )) * * More parameters may be given but we only need P here. */ static unsigned int dsa_get_nbits (gcry_sexp_t parms) { gcry_sexp_t l1; gcry_mpi_t p; unsigned int nbits; l1 = sexp_find_token (parms, "p", 1); if (!l1) return 0; /* Parameter P not found. */ p = sexp_nth_mpi (l1, 1, GCRYMPI_FMT_USG); sexp_release (l1); nbits = p? mpi_get_nbits (p) : 0; _gcry_mpi_release (p); return nbits; } /* Self-test section. */ static const char * selftest_sign_1024 (gcry_sexp_t pkey, gcry_sexp_t skey) { static const char sample_data[] = "(data (flags raw)" " (value #a0b1c2d3e4f500102030405060708090a1b2c3d4#))"; static const char sample_data_bad[] = "(data (flags raw)" " (value #a0b1c2d3e4f510102030405060708090a1b2c3d4#))"; const char *errtxt = NULL; gcry_error_t err; gcry_sexp_t data = NULL; gcry_sexp_t data_bad = NULL; gcry_sexp_t sig = NULL; err = sexp_sscan (&data, NULL, sample_data, strlen (sample_data)); if (!err) err = sexp_sscan (&data_bad, NULL, sample_data_bad, strlen (sample_data_bad)); if (err) { errtxt = "converting data failed"; goto leave; } err = _gcry_pk_sign (&sig, data, skey); if (err) { errtxt = "signing failed"; goto leave; } err = _gcry_pk_verify (sig, data, pkey); if (err) { errtxt = "verify failed"; goto leave; } err = _gcry_pk_verify (sig, data_bad, pkey); if (gcry_err_code (err) != GPG_ERR_BAD_SIGNATURE) { errtxt = "bad signature not detected"; goto leave; } leave: sexp_release (sig); sexp_release (data_bad); sexp_release (data); return errtxt; } static gpg_err_code_t selftests_dsa (selftest_report_func_t report) { const char *what; const char *errtxt; gcry_error_t err; gcry_sexp_t skey = NULL; gcry_sexp_t pkey = NULL; /* Convert the S-expressions into the internal representation. */ what = "convert"; err = sexp_sscan (&skey, NULL, sample_secret_key, strlen (sample_secret_key)); if (!err) err = sexp_sscan (&pkey, NULL, sample_public_key, strlen (sample_public_key)); if (err) { errtxt = _gcry_strerror (err); goto failed; } what = "key consistency"; err = _gcry_pk_testkey (skey); if (err) { errtxt = _gcry_strerror (err); goto failed; } what = "sign"; errtxt = selftest_sign_1024 (pkey, skey); if (errtxt) goto failed; sexp_release (pkey); sexp_release (skey); return 0; /* Succeeded. */ failed: sexp_release (pkey); sexp_release (skey); if (report) report ("pubkey", GCRY_PK_DSA, what, errtxt); return GPG_ERR_SELFTEST_FAILED; } /* Run a full self-test for ALGO and return 0 on success. */ static gpg_err_code_t run_selftests (int algo, int extended, selftest_report_func_t report) { gpg_err_code_t ec; (void)extended; switch (algo) { case GCRY_PK_DSA: ec = selftests_dsa (report); break; default: ec = GPG_ERR_PUBKEY_ALGO; break; } return ec; } gcry_pk_spec_t _gcry_pubkey_spec_dsa = { GCRY_PK_DSA, { 0, 1 }, GCRY_PK_USAGE_SIGN, "DSA", dsa_names, "pqgy", "pqgyx", "", "rs", "pqgy", dsa_generate, dsa_check_secret_key, NULL, NULL, dsa_sign, dsa_verify, dsa_get_nbits, run_selftests }; diff --git a/cipher/ecc-ecdsa.c b/cipher/ecc-ecdsa.c index b4bbe2cc..1484830b 100644 --- a/cipher/ecc-ecdsa.c +++ b/cipher/ecc-ecdsa.c @@ -1,234 +1,234 @@ /* ecc-ecdsa.c - Elliptic Curve ECDSA signatures * Copyright (C) 2007, 2008, 2010, 2011 Free Software Foundation, Inc. * Copyright (C) 2013 g10 Code GmbH * * This file is part of Libgcrypt. * * Libgcrypt is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * Libgcrypt is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, see . */ #include #include #include #include #include #include "g10lib.h" #include "mpi.h" #include "cipher.h" #include "context.h" #include "ec-context.h" #include "pubkey-internal.h" #include "ecc-common.h" /* Compute an ECDSA signature. * Return the signature struct (r,s) from the message hash. The caller * must have allocated R and S. */ gpg_err_code_t _gcry_ecc_ecdsa_sign (gcry_mpi_t input, ECC_secret_key *skey, gcry_mpi_t r, gcry_mpi_t s, int flags, int hashalgo) { gpg_err_code_t rc = 0; int extraloops = 0; gcry_mpi_t k, dr, sum, k_1, x; mpi_point_struct I; gcry_mpi_t hash; const void *abuf; unsigned int abits, qbits; mpi_ec_t ctx; if (DBG_CIPHER) log_mpidump ("ecdsa sign hash ", input ); qbits = mpi_get_nbits (skey->E.n); /* Convert the INPUT into an MPI if needed. */ - if (mpi_is_opaque (input)) - { - abuf = mpi_get_opaque (input, &abits); - rc = _gcry_mpi_scan (&hash, GCRYMPI_FMT_USG, abuf, (abits+7)/8, NULL); - if (rc) - return rc; - if (abits > qbits) - mpi_rshift (hash, hash, abits - qbits); - } - else - hash = input; - + rc = _gcry_dsa_normalize_hash (input, &hash, qbits); + if (rc) + return rc; k = NULL; dr = mpi_alloc (0); sum = mpi_alloc (0); k_1 = mpi_alloc (0); x = mpi_alloc (0); point_init (&I); ctx = _gcry_mpi_ec_p_internal_new (skey->E.model, skey->E.dialect, 0, skey->E.p, skey->E.a, skey->E.b); /* Two loops to avoid R or S are zero. This is more of a joke than a real demand because the probability of them being zero is less than any hardware failure. Some specs however require it. */ do { do { mpi_free (k); k = NULL; if ((flags & PUBKEY_FLAG_RFC6979) && hashalgo) { /* Use Pornin's method for deterministic DSA. If this flag is set, it is expected that HASH is an opaque MPI with the to be signed hash. That hash is also used as h1 from 3.2.a. */ if (!mpi_is_opaque (input)) { rc = GPG_ERR_CONFLICT; goto leave; } abuf = mpi_get_opaque (input, &abits); rc = _gcry_dsa_gen_rfc6979_k (&k, skey->E.n, skey->d, abuf, (abits+7)/8, hashalgo, extraloops); if (rc) goto leave; extraloops++; } else k = _gcry_dsa_gen_k (skey->E.n, GCRY_STRONG_RANDOM); _gcry_mpi_ec_mul_point (&I, k, &skey->E.G, ctx); if (_gcry_mpi_ec_get_affine (x, NULL, &I, ctx)) { if (DBG_CIPHER) log_debug ("ecc sign: Failed to get affine coordinates\n"); rc = GPG_ERR_BAD_SIGNATURE; goto leave; } mpi_mod (r, x, skey->E.n); /* r = x mod n */ } while (!mpi_cmp_ui (r, 0)); mpi_mulm (dr, skey->d, r, skey->E.n); /* dr = d*r mod n */ mpi_addm (sum, hash, dr, skey->E.n); /* sum = hash + (d*r) mod n */ mpi_invm (k_1, k, skey->E.n); /* k_1 = k^(-1) mod n */ mpi_mulm (s, k_1, sum, skey->E.n); /* s = k^(-1)*(hash+(d*r)) mod n */ } while (!mpi_cmp_ui (s, 0)); if (DBG_CIPHER) { log_mpidump ("ecdsa sign result r ", r); log_mpidump ("ecdsa sign result s ", s); } leave: _gcry_mpi_ec_free (ctx); point_free (&I); mpi_free (x); mpi_free (k_1); mpi_free (sum); mpi_free (dr); mpi_free (k); if (hash != input) mpi_free (hash); return rc; } /* Verify an ECDSA signature. * Check if R and S verifies INPUT. */ gpg_err_code_t _gcry_ecc_ecdsa_verify (gcry_mpi_t input, ECC_public_key *pkey, gcry_mpi_t r, gcry_mpi_t s) { gpg_err_code_t err = 0; - gcry_mpi_t h, h1, h2, x; + gcry_mpi_t hash, h, h1, h2, x; mpi_point_struct Q, Q1, Q2; mpi_ec_t ctx; + unsigned int nbits; if( !(mpi_cmp_ui (r, 0) > 0 && mpi_cmp (r, pkey->E.n) < 0) ) return GPG_ERR_BAD_SIGNATURE; /* Assertion 0 < r < n failed. */ if( !(mpi_cmp_ui (s, 0) > 0 && mpi_cmp (s, pkey->E.n) < 0) ) return GPG_ERR_BAD_SIGNATURE; /* Assertion 0 < s < n failed. */ + nbits = mpi_get_nbits (pkey->E.n); + err = _gcry_dsa_normalize_hash (input, &hash, nbits); + if (err) + return err; + h = mpi_alloc (0); h1 = mpi_alloc (0); h2 = mpi_alloc (0); x = mpi_alloc (0); point_init (&Q); point_init (&Q1); point_init (&Q2); ctx = _gcry_mpi_ec_p_internal_new (pkey->E.model, pkey->E.dialect, 0, pkey->E.p, pkey->E.a, pkey->E.b); /* h = s^(-1) (mod n) */ mpi_invm (h, s, pkey->E.n); /* h1 = hash * s^(-1) (mod n) */ - mpi_mulm (h1, input, h, pkey->E.n); + mpi_mulm (h1, hash, h, pkey->E.n); /* Q1 = [ hash * s^(-1) ]G */ _gcry_mpi_ec_mul_point (&Q1, h1, &pkey->E.G, ctx); /* h2 = r * s^(-1) (mod n) */ mpi_mulm (h2, r, h, pkey->E.n); /* Q2 = [ r * s^(-1) ]Q */ _gcry_mpi_ec_mul_point (&Q2, h2, &pkey->Q, ctx); /* Q = ([hash * s^(-1)]G) + ([r * s^(-1)]Q) */ _gcry_mpi_ec_add_points (&Q, &Q1, &Q2, ctx); if (!mpi_cmp_ui (Q.z, 0)) { if (DBG_CIPHER) log_debug ("ecc verify: Rejected\n"); err = GPG_ERR_BAD_SIGNATURE; goto leave; } if (_gcry_mpi_ec_get_affine (x, NULL, &Q, ctx)) { if (DBG_CIPHER) log_debug ("ecc verify: Failed to get affine coordinates\n"); err = GPG_ERR_BAD_SIGNATURE; goto leave; } mpi_mod (x, x, pkey->E.n); /* x = x mod E_n */ if (mpi_cmp (x, r)) /* x != r */ { if (DBG_CIPHER) { log_mpidump (" x", x); log_mpidump (" r", r); log_mpidump (" s", s); } err = GPG_ERR_BAD_SIGNATURE; goto leave; } leave: _gcry_mpi_ec_free (ctx); point_free (&Q2); point_free (&Q1); point_free (&Q); mpi_free (x); mpi_free (h2); mpi_free (h1); mpi_free (h); + if (hash != input) + mpi_free (hash); + return err; } diff --git a/cipher/pubkey-internal.h b/cipher/pubkey-internal.h index db1399d2..193248c3 100644 --- a/cipher/pubkey-internal.h +++ b/cipher/pubkey-internal.h @@ -1,97 +1,100 @@ /* pubkey-internal.h - Internal defs for pubkey.c * Copyright (C) 2013 g10 code GmbH * * This file is part of Libgcrypt. * * Libgcrypt is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser general Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * Libgcrypt is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, see . */ #ifndef GCRY_PUBKEY_INTERNAL_H #define GCRY_PUBKEY_INTERNAL_H /*-- pubkey-util.c --*/ gpg_err_code_t _gcry_pk_util_parse_flaglist (gcry_sexp_t list, int *r_flags, enum pk_encoding *r_encoding); gpg_err_code_t _gcry_pk_util_get_nbits (gcry_sexp_t list, unsigned int *r_nbits); gpg_err_code_t _gcry_pk_util_get_rsa_use_e (gcry_sexp_t list, unsigned long *r_e); gpg_err_code_t _gcry_pk_util_preparse_sigval (gcry_sexp_t s_sig, const char **algo_names, gcry_sexp_t *r_parms, int *r_eccflags); gpg_err_code_t _gcry_pk_util_preparse_encval (gcry_sexp_t sexp, const char **algo_names, gcry_sexp_t *r_parms, struct pk_encoding_ctx *ctx); void _gcry_pk_util_init_encoding_ctx (struct pk_encoding_ctx *ctx, enum pk_operation op, unsigned int nbits); void _gcry_pk_util_free_encoding_ctx (struct pk_encoding_ctx *ctx); gcry_err_code_t _gcry_pk_util_data_to_mpi (gcry_sexp_t input, gcry_mpi_t *ret_mpi, struct pk_encoding_ctx *ctx); /*-- rsa-common.c --*/ gpg_err_code_t _gcry_rsa_pkcs1_encode_for_enc (gcry_mpi_t *r_result, unsigned int nbits, const unsigned char *value, size_t valuelen, const unsigned char *random_override, size_t random_override_len); gpg_err_code_t _gcry_rsa_pkcs1_decode_for_enc (unsigned char **r_result, size_t *r_resultlen, unsigned int nbits, gcry_mpi_t value); gpg_err_code_t _gcry_rsa_pkcs1_encode_for_sig (gcry_mpi_t *r_result, unsigned int nbits, const unsigned char *value, size_t valuelen, int algo); gpg_err_code_t _gcry_rsa_oaep_encode (gcry_mpi_t *r_result, unsigned int nbits, int algo, const unsigned char *value, size_t valuelen, const unsigned char *label, size_t labellen, const void *random_override, size_t random_override_len); gpg_err_code_t _gcry_rsa_oaep_decode (unsigned char **r_result, size_t *r_resultlen, unsigned int nbits, int algo, gcry_mpi_t value, const unsigned char *label, size_t labellen); gpg_err_code_t _gcry_rsa_pss_encode (gcry_mpi_t *r_result, unsigned int nbits, int algo, const unsigned char *value, size_t valuelen, int saltlen, const void *random_override, size_t random_override_len); gpg_err_code_t _gcry_rsa_pss_verify (gcry_mpi_t value, gcry_mpi_t encoded, unsigned int nbits, int algo, size_t saltlen); /*-- dsa-common.c --*/ gcry_mpi_t _gcry_dsa_gen_k (gcry_mpi_t q, int security_level); gpg_err_code_t _gcry_dsa_gen_rfc6979_k (gcry_mpi_t *r_k, gcry_mpi_t dsa_q, gcry_mpi_t dsa_x, const unsigned char *h1, unsigned int h1len, int halgo, unsigned int extraloops); +gpg_err_code_t _gcry_dsa_normalize_hash (gcry_mpi_t input, + gcry_mpi_t *out, + unsigned int qbits); /*-- ecc.c --*/ gpg_err_code_t _gcry_pk_ecc_get_sexp (gcry_sexp_t *r_sexp, int mode, mpi_ec_t ec); #endif /*GCRY_PUBKEY_INTERNAL_H*/ diff --git a/tests/pubkey.c b/tests/pubkey.c index 4e12dfd7..ae5eea2d 100644 --- a/tests/pubkey.c +++ b/tests/pubkey.c @@ -1,1158 +1,1203 @@ /* pubkey.c - Public key encryption/decryption tests * Copyright (C) 2001, 2002, 2003, 2005 Free Software Foundation, Inc. * * This file is part of Libgcrypt. * * Libgcrypt is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * Libgcrypt is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, see . */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include "../src/gcrypt-int.h" #define my_isascii(c) (!((c) & 0x80)) #define digitp(p) (*(p) >= '0' && *(p) <= '9') #define hexdigitp(a) (digitp (a) \ || (*(a) >= 'A' && *(a) <= 'F') \ || (*(a) >= 'a' && *(a) <= 'f')) #define xtoi_1(p) (*(p) <= '9'? (*(p)- '0'): \ *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10)) #define xtoi_2(p) ((xtoi_1(p) * 16) + xtoi_1((p)+1)) #define DIM(v) (sizeof(v)/sizeof((v)[0])) #define DIMof(type,member) DIM(((type *)0)->member) /* Sample RSA keys, taken from basic.c. */ static const char sample_private_key_1[] = "(private-key\n" " (openpgp-rsa\n" " (n #00e0ce96f90b6c9e02f3922beada93fe50a875eac6bcc18bb9a9cf2e84965caa" "2d1ff95a7f542465c6c0c19d276e4526ce048868a7a914fd343cc3a87dd74291" "ffc565506d5bbb25cbac6a0e2dd1f8bcaab0d4a29c2f37c950f363484bf269f7" "891440464baf79827e03a36e70b814938eebdc63e964247be75dc58b014b7ea251#)\n" " (e #010001#)\n" " (d #046129F2489D71579BE0A75FE029BD6CDB574EBF57EA8A5B0FDA942CAB943B11" "7D7BB95E5D28875E0F9FC5FCC06A72F6D502464DABDED78EF6B716177B83D5BD" "C543DC5D3FED932E59F5897E92E6F58A0F33424106A3B6FA2CBF877510E4AC21" "C3EE47851E97D12996222AC3566D4CCB0B83D164074ABF7DE655FC2446DA1781#)\n" " (p #00e861b700e17e8afe6837e7512e35b6ca11d0ae47d8b85161c67baf64377213" "fe52d772f2035b3ca830af41d8a4120e1c1c70d12cc22f00d28d31dd48a8d424f1#)\n" " (q #00f7a7ca5367c661f8e62df34f0d05c10c88e5492348dd7bddc942c9a8f369f9" "35a07785d2db805215ed786e4285df1658eed3ce84f469b81b50d358407b4ad361#)\n" " (u #304559a9ead56d2309d203811a641bb1a09626bc8eb36fffa23c968ec5bd891e" "ebbafc73ae666e01ba7c8990bae06cc2bbe10b75e69fcacb353a6473079d8e9b#)\n" " )\n" ")\n"; /* The same key as above but without p, q and u to test the non CRT case. */ static const char sample_private_key_1_1[] = "(private-key\n" " (openpgp-rsa\n" " (n #00e0ce96f90b6c9e02f3922beada93fe50a875eac6bcc18bb9a9cf2e84965caa" "2d1ff95a7f542465c6c0c19d276e4526ce048868a7a914fd343cc3a87dd74291" "ffc565506d5bbb25cbac6a0e2dd1f8bcaab0d4a29c2f37c950f363484bf269f7" "891440464baf79827e03a36e70b814938eebdc63e964247be75dc58b014b7ea251#)\n" " (e #010001#)\n" " (d #046129F2489D71579BE0A75FE029BD6CDB574EBF57EA8A5B0FDA942CAB943B11" "7D7BB95E5D28875E0F9FC5FCC06A72F6D502464DABDED78EF6B716177B83D5BD" "C543DC5D3FED932E59F5897E92E6F58A0F33424106A3B6FA2CBF877510E4AC21" "C3EE47851E97D12996222AC3566D4CCB0B83D164074ABF7DE655FC2446DA1781#)\n" " )\n" ")\n"; /* The same key as above but just without q to test the non CRT case. This should fail. */ static const char sample_private_key_1_2[] = "(private-key\n" " (openpgp-rsa\n" " (n #00e0ce96f90b6c9e02f3922beada93fe50a875eac6bcc18bb9a9cf2e84965caa" "2d1ff95a7f542465c6c0c19d276e4526ce048868a7a914fd343cc3a87dd74291" "ffc565506d5bbb25cbac6a0e2dd1f8bcaab0d4a29c2f37c950f363484bf269f7" "891440464baf79827e03a36e70b814938eebdc63e964247be75dc58b014b7ea251#)\n" " (e #010001#)\n" " (d #046129F2489D71579BE0A75FE029BD6CDB574EBF57EA8A5B0FDA942CAB943B11" "7D7BB95E5D28875E0F9FC5FCC06A72F6D502464DABDED78EF6B716177B83D5BD" "C543DC5D3FED932E59F5897E92E6F58A0F33424106A3B6FA2CBF877510E4AC21" "C3EE47851E97D12996222AC3566D4CCB0B83D164074ABF7DE655FC2446DA1781#)\n" " (p #00e861b700e17e8afe6837e7512e35b6ca11d0ae47d8b85161c67baf64377213" "fe52d772f2035b3ca830af41d8a4120e1c1c70d12cc22f00d28d31dd48a8d424f1#)\n" " (u #304559a9ead56d2309d203811a641bb1a09626bc8eb36fffa23c968ec5bd891e" "ebbafc73ae666e01ba7c8990bae06cc2bbe10b75e69fcacb353a6473079d8e9b#)\n" " )\n" ")\n"; static const char sample_public_key_1[] = "(public-key\n" " (rsa\n" " (n #00e0ce96f90b6c9e02f3922beada93fe50a875eac6bcc18bb9a9cf2e84965caa" "2d1ff95a7f542465c6c0c19d276e4526ce048868a7a914fd343cc3a87dd74291" "ffc565506d5bbb25cbac6a0e2dd1f8bcaab0d4a29c2f37c950f363484bf269f7" "891440464baf79827e03a36e70b814938eebdc63e964247be75dc58b014b7ea251#)\n" " (e #010001#)\n" " )\n" ")\n"; static int verbose; static int error_count; static void die (const char *format, ...) { va_list arg_ptr ; va_start( arg_ptr, format ) ; vfprintf (stderr, format, arg_ptr ); va_end(arg_ptr); if (*format && format[strlen(format)-1] != '\n') putc ('\n', stderr); exit (1); } static void fail (const char *format, ...) { va_list arg_ptr; va_start (arg_ptr, format); vfprintf (stderr, format, arg_ptr); va_end (arg_ptr); error_count++; } static void info (const char *format, ...) { va_list arg_ptr; va_start (arg_ptr, format); vfprintf (stderr, format, arg_ptr); va_end (arg_ptr); } static void show_sexp (const char *prefix, gcry_sexp_t a) { char *buf; size_t size; if (prefix) fputs (prefix, stderr); size = gcry_sexp_sprint (a, GCRYSEXP_FMT_ADVANCED, NULL, 0); buf = gcry_xmalloc (size); gcry_sexp_sprint (a, GCRYSEXP_FMT_ADVANCED, buf, size); fprintf (stderr, "%.*s", (int)size, buf); gcry_free (buf); } /* Convert STRING consisting of hex characters into its binary representation and return it as an allocated buffer. The valid length of the buffer is returned at R_LENGTH. The string is delimited by end of string. The function returns NULL on error. */ static void * data_from_hex (const char *string, size_t *r_length) { const char *s; unsigned char *buffer; size_t length; buffer = gcry_xmalloc (strlen(string)/2+1); length = 0; for (s=string; *s; s +=2 ) { if (!hexdigitp (s) || !hexdigitp (s+1)) die ("error parsing hex string `%s'\n", string); ((unsigned char*)buffer)[length++] = xtoi_2 (s); } *r_length = length; return buffer; } static void extract_cmp_data (gcry_sexp_t sexp, const char *name, const char *expected) { gcry_sexp_t l1; const void *a; size_t alen; void *b; size_t blen; l1 = gcry_sexp_find_token (sexp, name, 0); a = gcry_sexp_nth_data (l1, 1, &alen); b = data_from_hex (expected, &blen); if (!a) fail ("parameter \"%s\" missing in key\n", name); else if ( alen != blen || memcmp (a, b, alen) ) { fail ("parameter \"%s\" does not match expected value\n", name); if (verbose) { info ("expected: %s\n", expected); show_sexp ("sexp: ", sexp); } } gcry_free (b); gcry_sexp_release (l1); } static void check_keys_crypt (gcry_sexp_t pkey, gcry_sexp_t skey, gcry_sexp_t plain0, gpg_err_code_t decrypt_fail_code) { gcry_sexp_t plain1, cipher, l; gcry_mpi_t x0, x1; int rc; int have_flags; /* Extract data from plaintext. */ l = gcry_sexp_find_token (plain0, "value", 0); x0 = gcry_sexp_nth_mpi (l, 1, GCRYMPI_FMT_USG); gcry_sexp_release (l); /* Encrypt data. */ rc = gcry_pk_encrypt (&cipher, plain0, pkey); if (rc) die ("encryption failed: %s\n", gcry_strerror (rc)); l = gcry_sexp_find_token (cipher, "flags", 0); have_flags = !!l; gcry_sexp_release (l); /* Decrypt data. */ rc = gcry_pk_decrypt (&plain1, cipher, skey); gcry_sexp_release (cipher); if (rc) { if (decrypt_fail_code && gpg_err_code (rc) == decrypt_fail_code) { gcry_mpi_release (x0); return; /* This is the expected failure code. */ } die ("decryption failed: %s\n", gcry_strerror (rc)); } /* Extract decrypted data. Note that for compatibility reasons, the output of gcry_pk_decrypt depends on whether a flags lists (even if empty) occurs in its input data. Because we passed the output of encrypt directly to decrypt, such a flag value won't be there as of today. We check it anyway. */ l = gcry_sexp_find_token (plain1, "value", 0); if (l) { if (!have_flags) die ("compatibility mode of pk_decrypt broken\n"); gcry_sexp_release (plain1); x1 = gcry_sexp_nth_mpi (l, 1, GCRYMPI_FMT_USG); gcry_sexp_release (l); } else { if (have_flags) die ("compatibility mode of pk_decrypt broken\n"); x1 = gcry_sexp_nth_mpi (plain1, 0, GCRYMPI_FMT_USG); gcry_sexp_release (plain1); } /* Compare. */ if (gcry_mpi_cmp (x0, x1)) die ("data corrupted\n"); gcry_mpi_release (x0); gcry_mpi_release (x1); } static void check_keys (gcry_sexp_t pkey, gcry_sexp_t skey, unsigned int nbits_data, gpg_err_code_t decrypt_fail_code) { gcry_sexp_t plain; gcry_mpi_t x; int rc; /* Create plain text. */ x = gcry_mpi_new (nbits_data); gcry_mpi_randomize (x, nbits_data, GCRY_WEAK_RANDOM); rc = gcry_sexp_build (&plain, NULL, "(data (flags raw) (value %m))", x); if (rc) die ("converting data for encryption failed: %s\n", gcry_strerror (rc)); check_keys_crypt (pkey, skey, plain, decrypt_fail_code); gcry_sexp_release (plain); gcry_mpi_release (x); /* Create plain text. */ x = gcry_mpi_new (nbits_data); gcry_mpi_randomize (x, nbits_data, GCRY_WEAK_RANDOM); rc = gcry_sexp_build (&plain, NULL, "(data (flags raw no-blinding) (value %m))", x); gcry_mpi_release (x); if (rc) die ("converting data for encryption failed: %s\n", gcry_strerror (rc)); check_keys_crypt (pkey, skey, plain, decrypt_fail_code); gcry_sexp_release (plain); } static void get_keys_sample (gcry_sexp_t *pkey, gcry_sexp_t *skey, int secret_variant) { gcry_sexp_t pub_key, sec_key; int rc; static const char *secret; switch (secret_variant) { case 0: secret = sample_private_key_1; break; case 1: secret = sample_private_key_1_1; break; case 2: secret = sample_private_key_1_2; break; default: die ("BUG\n"); } rc = gcry_sexp_sscan (&pub_key, NULL, sample_public_key_1, strlen (sample_public_key_1)); if (!rc) rc = gcry_sexp_sscan (&sec_key, NULL, secret, strlen (secret)); if (rc) die ("converting sample keys failed: %s\n", gcry_strerror (rc)); *pkey = pub_key; *skey = sec_key; } static void get_keys_new (gcry_sexp_t *pkey, gcry_sexp_t *skey) { gcry_sexp_t key_spec, key, pub_key, sec_key; int rc; rc = gcry_sexp_new (&key_spec, "(genkey (rsa (nbits 4:1024)))", 0, 1); if (rc) die ("error creating S-expression: %s\n", gcry_strerror (rc)); rc = gcry_pk_genkey (&key, key_spec); gcry_sexp_release (key_spec); if (rc) die ("error generating RSA key: %s\n", gcry_strerror (rc)); if (verbose > 1) show_sexp ("generated RSA key:\n", key); pub_key = gcry_sexp_find_token (key, "public-key", 0); if (! pub_key) die ("public part missing in key\n"); sec_key = gcry_sexp_find_token (key, "private-key", 0); if (! sec_key) die ("private part missing in key\n"); gcry_sexp_release (key); *pkey = pub_key; *skey = sec_key; } static void get_keys_x931_new (gcry_sexp_t *pkey, gcry_sexp_t *skey) { gcry_sexp_t key_spec, key, pub_key, sec_key; int rc; rc = gcry_sexp_new (&key_spec, "(genkey (rsa (nbits 4:1024)(use-x931)))", 0, 1); if (rc) die ("error creating S-expression: %s\n", gcry_strerror (rc)); rc = gcry_pk_genkey (&key, key_spec); gcry_sexp_release (key_spec); if (rc) die ("error generating RSA key: %s\n", gcry_strerror (rc)); if (verbose > 1) show_sexp ("generated RSA (X9.31) key:\n", key); pub_key = gcry_sexp_find_token (key, "public-key", 0); if (!pub_key) die ("public part missing in key\n"); sec_key = gcry_sexp_find_token (key, "private-key", 0); if (!sec_key) die ("private part missing in key\n"); gcry_sexp_release (key); *pkey = pub_key; *skey = sec_key; } static void get_elg_key_new (gcry_sexp_t *pkey, gcry_sexp_t *skey, int fixed_x) { gcry_sexp_t key_spec, key, pub_key, sec_key; int rc; rc = gcry_sexp_new (&key_spec, (fixed_x ? "(genkey (elg (nbits 4:1024)(xvalue my.not-so-secret.key)))" : "(genkey (elg (nbits 3:512)))"), 0, 1); if (rc) die ("error creating S-expression: %s\n", gcry_strerror (rc)); rc = gcry_pk_genkey (&key, key_spec); gcry_sexp_release (key_spec); if (rc) die ("error generating Elgamal key: %s\n", gcry_strerror (rc)); if (verbose > 1) show_sexp ("generated ELG key:\n", key); pub_key = gcry_sexp_find_token (key, "public-key", 0); if (!pub_key) die ("public part missing in key\n"); sec_key = gcry_sexp_find_token (key, "private-key", 0); if (!sec_key) die ("private part missing in key\n"); gcry_sexp_release (key); *pkey = pub_key; *skey = sec_key; } static void get_dsa_key_new (gcry_sexp_t *pkey, gcry_sexp_t *skey, int transient_key) { gcry_sexp_t key_spec, key, pub_key, sec_key; int rc; rc = gcry_sexp_new (&key_spec, transient_key ? "(genkey (dsa (nbits 4:1024)(transient-key)))" : "(genkey (dsa (nbits 4:1024)))", 0, 1); if (rc) die ("error creating S-expression: %s\n", gcry_strerror (rc)); rc = gcry_pk_genkey (&key, key_spec); gcry_sexp_release (key_spec); if (rc) die ("error generating DSA key: %s\n", gcry_strerror (rc)); if (verbose > 1) show_sexp ("generated DSA key:\n", key); pub_key = gcry_sexp_find_token (key, "public-key", 0); if (!pub_key) die ("public part missing in key\n"); sec_key = gcry_sexp_find_token (key, "private-key", 0); if (!sec_key) die ("private part missing in key\n"); gcry_sexp_release (key); *pkey = pub_key; *skey = sec_key; } static void get_dsa_key_fips186_new (gcry_sexp_t *pkey, gcry_sexp_t *skey) { gcry_sexp_t key_spec, key, pub_key, sec_key; int rc; rc = gcry_sexp_new (&key_spec, "(genkey (dsa (nbits 4:1024)(use-fips186)))", 0, 1); if (rc) die ("error creating S-expression: %s\n", gcry_strerror (rc)); rc = gcry_pk_genkey (&key, key_spec); gcry_sexp_release (key_spec); if (rc) die ("error generating DSA key: %s\n", gcry_strerror (rc)); if (verbose > 1) show_sexp ("generated DSA key (fips 186):\n", key); pub_key = gcry_sexp_find_token (key, "public-key", 0); if (!pub_key) die ("public part missing in key\n"); sec_key = gcry_sexp_find_token (key, "private-key", 0); if (!sec_key) die ("private part missing in key\n"); gcry_sexp_release (key); *pkey = pub_key; *skey = sec_key; } static void get_dsa_key_with_domain_new (gcry_sexp_t *pkey, gcry_sexp_t *skey) { gcry_sexp_t key_spec, key, pub_key, sec_key; int rc; rc = gcry_sexp_new (&key_spec, "(genkey (dsa (transient-key)(domain" "(p #d3aed1876054db831d0c1348fbb1ada72507e5fbf9a62cbd47a63aeb7859d6921" "4adeb9146a6ec3f43520f0fd8e3125dd8bbc5d87405d1ac5f82073cd762a3f8d7" "74322657c9da88a7d2f0e1a9ceb84a39cb40876179e6a76e400498de4bb9379b0" "5f5feb7b91eb8fea97ee17a955a0a8a37587a272c4719d6feb6b54ba4ab69#)" "(q #9c916d121de9a03f71fb21bc2e1c0d116f065a4f#)" "(g #8157c5f68ca40b3ded11c353327ab9b8af3e186dd2e8dade98761a0996dda99ab" "0250d3409063ad99efae48b10c6ab2bba3ea9a67b12b911a372a2bba260176fad" "b4b93247d9712aad13aa70216c55da9858f7a298deb670a403eb1e7c91b847f1e" "ccfbd14bd806fd42cf45dbb69cd6d6b43add2a78f7d16928eaa04458dea44#)" ")))", 0, 1); if (rc) die ("error creating S-expression: %s\n", gcry_strerror (rc)); rc = gcry_pk_genkey (&key, key_spec); gcry_sexp_release (key_spec); if (rc) die ("error generating DSA key: %s\n", gcry_strerror (rc)); if (verbose > 1) show_sexp ("generated DSA key:\n", key); pub_key = gcry_sexp_find_token (key, "public-key", 0); if (!pub_key) die ("public part missing in key\n"); sec_key = gcry_sexp_find_token (key, "private-key", 0); if (!sec_key) die ("private part missing in key\n"); gcry_sexp_release (key); *pkey = pub_key; *skey = sec_key; } static void get_dsa_key_fips186_with_domain_new (gcry_sexp_t *pkey, gcry_sexp_t *skey) { gcry_sexp_t key_spec, key, pub_key, sec_key; int rc; rc = gcry_sexp_new (&key_spec, "(genkey (dsa (transient-key)(use-fips186)(domain" "(p #d3aed1876054db831d0c1348fbb1ada72507e5fbf9a62cbd47a63aeb7859d6921" "4adeb9146a6ec3f43520f0fd8e3125dd8bbc5d87405d1ac5f82073cd762a3f8d7" "74322657c9da88a7d2f0e1a9ceb84a39cb40876179e6a76e400498de4bb9379b0" "5f5feb7b91eb8fea97ee17a955a0a8a37587a272c4719d6feb6b54ba4ab69#)" "(q #9c916d121de9a03f71fb21bc2e1c0d116f065a4f#)" "(g #8157c5f68ca40b3ded11c353327ab9b8af3e186dd2e8dade98761a0996dda99ab" "0250d3409063ad99efae48b10c6ab2bba3ea9a67b12b911a372a2bba260176fad" "b4b93247d9712aad13aa70216c55da9858f7a298deb670a403eb1e7c91b847f1e" "ccfbd14bd806fd42cf45dbb69cd6d6b43add2a78f7d16928eaa04458dea44#)" ")))", 0, 1); if (rc) die ("error creating S-expression: %s\n", gcry_strerror (rc)); rc = gcry_pk_genkey (&key, key_spec); gcry_sexp_release (key_spec); if (rc) die ("error generating DSA key: %s\n", gcry_strerror (rc)); if (verbose > 1) show_sexp ("generated DSA key:\n", key); pub_key = gcry_sexp_find_token (key, "public-key", 0); if (!pub_key) die ("public part missing in key\n"); sec_key = gcry_sexp_find_token (key, "private-key", 0); if (!sec_key) die ("private part missing in key\n"); gcry_sexp_release (key); *pkey = pub_key; *skey = sec_key; } static void get_dsa_key_fips186_with_seed_new (gcry_sexp_t *pkey, gcry_sexp_t *skey) { gcry_sexp_t key_spec, key, pub_key, sec_key; int rc; rc = gcry_sexp_new (&key_spec, "(genkey" " (dsa" " (nbits 4:1024)" " (use-fips186)" " (transient-key)" " (derive-parms" " (seed #0cb1990c1fd3626055d7a0096f8fa99807399871#))))", 0, 1); if (rc) die ("error creating S-expression: %s\n", gcry_strerror (rc)); rc = gcry_pk_genkey (&key, key_spec); gcry_sexp_release (key_spec); if (rc) die ("error generating DSA key: %s\n", gcry_strerror (rc)); if (verbose > 1) show_sexp ("generated DSA key (fips 186 with seed):\n", key); pub_key = gcry_sexp_find_token (key, "public-key", 0); if (!pub_key) die ("public part missing in key\n"); sec_key = gcry_sexp_find_token (key, "private-key", 0); if (!sec_key) die ("private part missing in key\n"); gcry_sexp_release (key); *pkey = pub_key; *skey = sec_key; } static void check_run (void) { gpg_error_t err; gcry_sexp_t pkey, skey; int variant; for (variant=0; variant < 3; variant++) { if (verbose) fprintf (stderr, "Checking sample key (%d).\n", variant); get_keys_sample (&pkey, &skey, variant); /* Check gcry_pk_testkey which requires all elements. */ err = gcry_pk_testkey (skey); if ((variant == 0 && err) || (variant > 0 && gpg_err_code (err) != GPG_ERR_NO_OBJ)) die ("gcry_pk_testkey failed: %s\n", gpg_strerror (err)); /* Run the usual check but expect an error from variant 2. */ check_keys (pkey, skey, 800, variant == 2? GPG_ERR_NO_OBJ : 0); gcry_sexp_release (pkey); gcry_sexp_release (skey); } if (verbose) fprintf (stderr, "Checking generated RSA key.\n"); get_keys_new (&pkey, &skey); check_keys (pkey, skey, 800, 0); gcry_sexp_release (pkey); gcry_sexp_release (skey); if (verbose) fprintf (stderr, "Checking generated RSA key (X9.31).\n"); get_keys_x931_new (&pkey, &skey); check_keys (pkey, skey, 800, 0); gcry_sexp_release (pkey); gcry_sexp_release (skey); if (verbose) fprintf (stderr, "Checking generated Elgamal key.\n"); get_elg_key_new (&pkey, &skey, 0); check_keys (pkey, skey, 400, 0); gcry_sexp_release (pkey); gcry_sexp_release (skey); if (verbose) fprintf (stderr, "Checking passphrase generated Elgamal key.\n"); get_elg_key_new (&pkey, &skey, 1); check_keys (pkey, skey, 800, 0); gcry_sexp_release (pkey); gcry_sexp_release (skey); if (verbose) fprintf (stderr, "Generating DSA key.\n"); get_dsa_key_new (&pkey, &skey, 0); /* Fixme: Add a check function for DSA keys. */ gcry_sexp_release (pkey); gcry_sexp_release (skey); if (!gcry_fips_mode_active ()) { if (verbose) fprintf (stderr, "Generating transient DSA key.\n"); get_dsa_key_new (&pkey, &skey, 1); /* Fixme: Add a check function for DSA keys. */ gcry_sexp_release (pkey); gcry_sexp_release (skey); } if (verbose) fprintf (stderr, "Generating DSA key (FIPS 186).\n"); get_dsa_key_fips186_new (&pkey, &skey); /* Fixme: Add a check function for DSA keys. */ gcry_sexp_release (pkey); gcry_sexp_release (skey); if (verbose) fprintf (stderr, "Generating DSA key with given domain.\n"); get_dsa_key_with_domain_new (&pkey, &skey); /* Fixme: Add a check function for DSA keys. */ gcry_sexp_release (pkey); gcry_sexp_release (skey); if (verbose) fprintf (stderr, "Generating DSA key with given domain (FIPS 186).\n"); get_dsa_key_fips186_with_domain_new (&pkey, &skey); /* Fixme: Add a check function for DSA keys. */ gcry_sexp_release (pkey); gcry_sexp_release (skey); if (verbose) fprintf (stderr, "Generating DSA key with given seed (FIPS 186).\n"); get_dsa_key_fips186_with_seed_new (&pkey, &skey); /* Fixme: Add a check function for DSA keys. */ gcry_sexp_release (pkey); gcry_sexp_release (skey); } static gcry_mpi_t key_param_from_sexp (gcry_sexp_t sexp, const char *topname, const char *name) { gcry_sexp_t l1, l2; gcry_mpi_t result; l1 = gcry_sexp_find_token (sexp, topname, 0); if (!l1) return NULL; l2 = gcry_sexp_find_token (l1, name, 0); if (!l2) { gcry_sexp_release (l1); return NULL; } result = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG); gcry_sexp_release (l2); gcry_sexp_release (l1); return result; } static void check_x931_derived_key (int what) { static struct { const char *param; const char *expected_d; } testtable[] = { { /* First example from X9.31 (D.1.1). */ "(genkey\n" " (rsa\n" " (nbits 4:1024)\n" " (rsa-use-e 1:3)\n" " (derive-parms\n" " (Xp1 #1A1916DDB29B4EB7EB6732E128#)\n" " (Xp2 #192E8AAC41C576C822D93EA433#)\n" " (Xp #D8CD81F035EC57EFE822955149D3BFF70C53520D\n" " 769D6D76646C7A792E16EBD89FE6FC5B605A6493\n" " 39DFC925A86A4C6D150B71B9EEA02D68885F5009\n" " B98BD984#)\n" " (Xq1 #1A5CF72EE770DE50CB09ACCEA9#)\n" " (Xq2 #134E4CAA16D2350A21D775C404#)\n" " (Xq #CC1092495D867E64065DEE3E7955F2EBC7D47A2D\n" " 7C9953388F97DDDC3E1CA19C35CA659EDC2FC325\n" " 6D29C2627479C086A699A49C4C9CEE7EF7BD1B34\n" " 321DE34A#))))\n", "1CCDA20BCFFB8D517EE9666866621B11822C7950D55F4BB5BEE37989A7D173" "12E326718BE0D79546EAAE87A56623B919B1715FFBD7F16028FC4007741961" "C88C5D7B4DAAAC8D36A98C9EFBB26C8A4A0E6BC15B358E528A1AC9D0F042BE" "B93BCA16B541B33F80C933A3B769285C462ED5677BFE89DF07BED5C127FD13" "241D3C4B" }, { /* Second example from X9.31 (D.2.1). */ "(genkey\n" " (rsa\n" " (nbits 4:1536)\n" " (rsa-use-e 1:3)\n" " (derive-parms\n" " (Xp1 #18272558B61316348297EACA74#)\n" " (Xp2 #1E970E8C6C97CEF91F05B0FA80#)\n" " (Xp #F7E943C7EF2169E930DCF23FE389EF7507EE8265\n" " 0D42F4A0D3A3CEFABE367999BB30EE680B2FE064\n" " 60F707F46005F8AA7CBFCDDC4814BBE7F0F8BC09\n" " 318C8E51A48D134296E40D0BBDD282DCCBDDEE1D\n" " EC86F0B1C96EAFF5CDA70F9AEB6EE31E#)\n" " (Xq1 #11FDDA6E8128DC1629F75192BA#)\n" " (Xq2 #18AB178ECA907D72472F65E480#)\n" " (Xq #C47560011412D6E13E3E7D007B5C05DBF5FF0D0F\n" " CFF1FA2070D16C7ABA93EDFB35D8700567E5913D\n" " B734E3FBD15862EBC59FA0425DFA131E549136E8\n" " E52397A8ABE4705EC4877D4F82C4AAC651B33DA6\n" " EA14B9D5F2A263DC65626E4D6CEAC767#))))\n", "1FB56069985F18C4519694FB71055721A01F14422DC901C35B03A64D4A5BD1" "259D573305F5B056AC931B82EDB084E39A0FD1D1A86CC5B147A264F7EF4EB2" "0ED1E7FAAE5CAE4C30D5328B7F74C3CAA72C88B70DED8EDE207B8629DA2383" "B78C3CE1CA3F9F218D78C938B35763AF2A8714664CC57F5CECE2413841F5E9" "EDEC43B728E25A41BF3E1EF8D9EEE163286C9F8BF0F219D3B322C3E4B0389C" "2E8BB28DC04C47DA2BF38823731266D2CF6CC3FC181738157624EF051874D0" "BBCCB9F65C83" /* Note that this example in X9.31 gives this value for D: "7ED581A6617C6311465A53EDC4155C86807C5108B724070D6C0E9935296F44" "96755CCC17D6C15AB24C6E0BB6C2138E683F4746A1B316C51E8993DFBD3AC8" "3B479FEAB972B930C354CA2DFDD30F2A9CB222DC37B63B7881EE18A7688E0E" "DE30F38728FE7C8635E324E2CD5D8EBCAA1C51993315FD73B38904E107D7A7" "B7B10EDCA3896906FCF87BE367BB858CA1B27E2FC3C8674ECC8B0F92C0E270" "BA2ECA3701311F68AFCE208DCC499B4B3DB30FF0605CE055D893BC1461D342" "EF32E7D9720B" This is a bug in X9.31, obviously introduced by using d = e^{-1} mod (p-1)(q-1) instead of using the universal exponent as required by 4.1.3: d = e^{-1} mod lcm(p-1,q-1) The examples in X9.31 seem to be pretty buggy, see cipher/primegen.c for another bug. Not only that I had to spend 100 USD for the 66 pages of the document, it also took me several hours to figure out that the bugs are in the document and not in my code. */ }, { /* First example from NIST RSAVS (B.1.1). */ "(genkey\n" " (rsa\n" " (nbits 4:1024)\n" " (rsa-use-e 1:3)\n" " (derive-parms\n" " (Xp1 #1ed3d6368e101dab9124c92ac8#)\n" " (Xp2 #16e5457b8844967ce83cab8c11#)\n" " (Xp #b79f2c2493b4b76f329903d7555b7f5f06aaa5ea\n" " ab262da1dcda8194720672a4e02229a0c71f60ae\n" " c4f0d2ed8d49ef583ca7d5eeea907c10801c302a\n" " cab44595#)\n" " (Xq1 #1a5d9e3fa34fb479bedea412f6#)\n" " (Xq2 #1f9cca85f185341516d92e82fd#)\n" " (Xq #c8387fd38fa33ddcea6a9de1b2d55410663502db\n" " c225655a9310cceac9f4cf1bce653ec916d45788\n" " f8113c46bc0fa42bf5e8d0c41120c1612e2ea8bb\n" " 2f389eda#))))\n", "17ef7ad4fd96011b62d76dfb2261b4b3270ca8e07bc501be954f8719ef586b" "f237e8f693dd16c23e7adecc40279dc6877c62ab541df5849883a5254fccfd" "4072a657b7f4663953930346febd6bbd82f9a499038402cbf97fd5f068083a" "c81ad0335c4aab0da19cfebe060a1bac7482738efafea078e21df785e56ea0" "dc7e8feb" }, { /* Second example from NIST RSAVS (B.1.1). */ "(genkey\n" " (rsa\n" " (nbits 4:1536)\n" " (rsa-use-e 1:3)\n" " (derive-parms\n" " (Xp1 #1e64c1af460dff8842c22b64d0#)\n" " (Xp2 #1e948edcedba84039c81f2ac0c#)\n" " (Xp #c8c67df894c882045ede26a9008ab09ea0672077\n" " d7bc71d412511cd93981ddde8f91b967da404056\n" " c39f105f7f239abdaff92923859920f6299e82b9\n" " 5bd5b8c959948f4a034d81613d6235a3953b49ce\n" " 26974eb7bb1f14843841281b363b9cdb#)\n" " (Xq1 #1f3df0f017ddd05611a97b6adb#)\n" " (Xq2 #143edd7b22d828913abf24ca4d#)\n" " (Xq #f15147d0e7c04a1e3f37adde802cdc610999bf7a\n" " b0088434aaeda0c0ab3910b14d2ce56cb66bffd9\n" " 7552195fae8b061077e03920814d8b9cfb5a3958\n" " b3a82c2a7fc97e55db543948d3396289245336ec\n" " 9e3cb308cc655aebd766340da8921383#))))\n", "1f8b19f3f5f2ac9fc599f110cad403dcd9bdf5f7f00fb2790e78e820398184" "1f3fb3dd230fb223d898f45719d9b2d3525587ff2b8bcc7425e40550a5b536" "1c8e9c1d26e83fbd9c33c64029c0e878b829d55def12912b73d94fd758c461" "0f473e230c41b5e4c86e27c5a5029d82c811c88525d0269b95bd2ff272994a" "dbd80f2c2ecf69065feb8abd8b445b9c6d306b1585d7d3d7576d49842bc7e2" "8b4a2f88f4a47e71c3edd35fdf83f547ea5c2b532975c551ed5268f748b2c4" "2ccf8a84835b" } }; gpg_error_t err; gcry_sexp_t key_spec, key, pub_key, sec_key; gcry_mpi_t d_expected, d_have; if (what < 0 && what >= sizeof testtable) die ("invalid WHAT value\n"); err = gcry_sexp_new (&key_spec, testtable[what].param, 0, 1); if (err) die ("error creating S-expression [%d]: %s\n", what, gpg_strerror (err)); err = gcry_pk_genkey (&key, key_spec); gcry_sexp_release (key_spec); if (err) die ("error generating RSA key [%d]: %s\n", what, gpg_strerror (err)); pub_key = gcry_sexp_find_token (key, "public-key", 0); if (!pub_key) die ("public part missing in key [%d]\n", what); sec_key = gcry_sexp_find_token (key, "private-key", 0); if (!sec_key) die ("private part missing in key [%d]\n", what); err = gcry_mpi_scan (&d_expected, GCRYMPI_FMT_HEX, testtable[what].expected_d, 0, NULL); if (err) die ("error converting string [%d]\n", what); if (verbose > 1) show_sexp ("generated key:\n", key); d_have = key_param_from_sexp (sec_key, "rsa", "d"); if (!d_have) die ("parameter d not found in RSA secret key [%d]\n", what); if (gcry_mpi_cmp (d_expected, d_have)) { show_sexp (NULL, sec_key); die ("parameter d does match expected value [%d]\n", what); } gcry_mpi_release (d_expected); gcry_mpi_release (d_have); gcry_sexp_release (key); gcry_sexp_release (pub_key); gcry_sexp_release (sec_key); } static void check_ecc_sample_key (void) { static const char ecc_private_key[] = "(private-key\n" " (ecdsa\n" " (curve \"NIST P-256\")\n" " (q #04D4F6A6738D9B8D3A7075C1E4EE95015FC0C9B7E4272D2BEB6644D3609FC781" "B71F9A8072F58CB66AE2F89BB12451873ABF7D91F9E1FBF96BF2F70E73AAC9A283#)\n" " (d #5A1EF0035118F19F3110FB81813D3547BCE1E5BCE77D1F744715E1D5BBE70378#)" "))"; static const char ecc_private_key_wo_q[] = "(private-key\n" " (ecdsa\n" " (curve \"NIST P-256\")\n" " (d #5A1EF0035118F19F3110FB81813D3547BCE1E5BCE77D1F744715E1D5BBE70378#)" "))"; static const char ecc_public_key[] = "(public-key\n" " (ecdsa\n" " (curve \"NIST P-256\")\n" " (q #04D4F6A6738D9B8D3A7075C1E4EE95015FC0C9B7E4272D2BEB6644D3609FC781" "B71F9A8072F58CB66AE2F89BB12451873ABF7D91F9E1FBF96BF2F70E73AAC9A283#)" "))"; static const char hash_string[] = "(data (flags raw)\n" " (value #00112233445566778899AABBCCDDEEFF" /* */ "000102030405060708090A0B0C0D0E0F#))"; + static const char hash2_string[] = + "(data (flags raw)\n" + " (hash sha1 #00112233445566778899AABBCCDDEEFF" + /* */ "000102030405060708090A0B0C0D0E0F" + /* */ "000102030405060708090A0B0C0D0E0F" + /* */ "00112233445566778899AABBCCDDEEFF#))"; + /* hash2, but longer than curve length, so it will be truncated */ + static const char hash3_string[] = + "(data (flags raw)\n" + " (hash sha1 #00112233445566778899AABBCCDDEEFF" + /* */ "000102030405060708090A0B0C0D0E0F" + /* */ "000102030405060708090A0B0C0D0E0F" + /* */ "00112233445566778899AABBCCDDEEFF" + /* */ "000102030405060708090A0B0C0D0E0F#))"; gpg_error_t err; - gcry_sexp_t key, hash, sig; + gcry_sexp_t key, hash, hash2, hash3, sig, sig2; if (verbose) fprintf (stderr, "Checking sample ECC key.\n"); if ((err = gcry_sexp_new (&hash, hash_string, 0, 1))) die ("line %d: %s", __LINE__, gpg_strerror (err)); + if ((err = gcry_sexp_new (&hash2, hash2_string, 0, 1))) + die ("line %d: %s", __LINE__, gpg_strerror (err)); + + if ((err = gcry_sexp_new (&hash3, hash3_string, 0, 1))) + die ("line %d: %s", __LINE__, gpg_strerror (err)); + if ((err = gcry_sexp_new (&key, ecc_private_key, 0, 1))) die ("line %d: %s", __LINE__, gpg_strerror (err)); if ((err = gcry_pk_sign (&sig, hash, key))) die ("gcry_pk_sign failed: %s", gpg_strerror (err)); gcry_sexp_release (key); if ((err = gcry_sexp_new (&key, ecc_public_key, 0, 1))) die ("line %d: %s", __LINE__, gpg_strerror (err)); if ((err = gcry_pk_verify (sig, hash, key))) die ("gcry_pk_verify failed: %s", gpg_strerror (err)); + /* Verify hash truncation */ + gcry_sexp_release (key); + if ((err = gcry_sexp_new (&key, ecc_private_key, 0, 1))) + die ("line %d: %s", __LINE__, gpg_strerror (err)); + + if ((err = gcry_pk_sign (&sig2, hash2, key))) + die ("gcry_pk_sign failed: %s", gpg_strerror (err)); + + gcry_sexp_release (sig); + if ((err = gcry_pk_sign (&sig, hash3, key))) + die ("gcry_pk_sign failed: %s", gpg_strerror (err)); + + gcry_sexp_release (key); + if ((err = gcry_sexp_new (&key, ecc_public_key, 0, 1))) + die ("line %d: %s", __LINE__, gpg_strerror (err)); + + if ((err = gcry_pk_verify (sig, hash2, key))) + die ("gcry_pk_verify failed: %s", gpg_strerror (err)); + + if ((err = gcry_pk_verify (sig2, hash3, key))) + die ("gcry_pk_verify failed: %s", gpg_strerror (err)); + /* Now try signing without the Q parameter. */ gcry_sexp_release (key); if ((err = gcry_sexp_new (&key, ecc_private_key_wo_q, 0, 1))) die ("line %d: %s", __LINE__, gpg_strerror (err)); gcry_sexp_release (sig); if ((err = gcry_pk_sign (&sig, hash, key))) die ("gcry_pk_sign without Q failed: %s", gpg_strerror (err)); gcry_sexp_release (key); if ((err = gcry_sexp_new (&key, ecc_public_key, 0, 1))) die ("line %d: %s", __LINE__, gpg_strerror (err)); if ((err = gcry_pk_verify (sig, hash, key))) die ("gcry_pk_verify signed without Q failed: %s", gpg_strerror (err)); gcry_sexp_release (sig); + gcry_sexp_release (sig2); gcry_sexp_release (key); gcry_sexp_release (hash); + gcry_sexp_release (hash2); + gcry_sexp_release (hash3); } static void check_ed25519ecdsa_sample_key (void) { static const char ecc_private_key[] = "(private-key\n" " (ecc\n" " (curve \"Ed25519\")\n" " (q #044C056555BE4084BB3D8D8895FDF7C2893DFE0256251923053010977D12658321" " 156D1ADDC07987713A418783658B476358D48D582DB53233D9DED3C1C2577B04#)" " (d #09A0C38E0F1699073541447C19DA12E3A07A7BFDB0C186E4AC5BCE6F23D55252#)" "))"; static const char ecc_private_key_wo_q[] = "(private-key\n" " (ecc\n" " (curve \"Ed25519\")\n" " (d #09A0C38E0F1699073541447C19DA12E3A07A7BFDB0C186E4AC5BCE6F23D55252#)" "))"; static const char ecc_public_key[] = "(public-key\n" " (ecc\n" " (curve \"Ed25519\")\n" " (q #044C056555BE4084BB3D8D8895FDF7C2893DFE0256251923053010977D12658321" " 156D1ADDC07987713A418783658B476358D48D582DB53233D9DED3C1C2577B04#)" "))"; static const char ecc_public_key_comp[] = "(public-key\n" " (ecc\n" " (curve \"Ed25519\")\n" " (q #047b57c2c1d3ded93332b52d588dd45863478b658387413a718779c0dd1a6d95#)" "))"; static const char hash_string[] = "(data (flags rfc6979)\n" " (hash sha256 #00112233445566778899AABBCCDDEEFF" /* */ "000102030405060708090A0B0C0D0E0F#))"; gpg_error_t err; gcry_sexp_t key, hash, sig; if (verbose) fprintf (stderr, "Checking sample Ed25519/ECDSA key.\n"); /* Sign. */ if ((err = gcry_sexp_new (&hash, hash_string, 0, 1))) die ("line %d: %s", __LINE__, gpg_strerror (err)); if ((err = gcry_sexp_new (&key, ecc_private_key, 0, 1))) die ("line %d: %s", __LINE__, gpg_strerror (err)); if ((err = gcry_pk_sign (&sig, hash, key))) die ("gcry_pk_sign failed: %s", gpg_strerror (err)); /* Verify. */ gcry_sexp_release (key); if ((err = gcry_sexp_new (&key, ecc_public_key, 0, 1))) die ("line %d: %s", __LINE__, gpg_strerror (err)); if ((err = gcry_pk_verify (sig, hash, key))) die ("gcry_pk_verify failed: %s", gpg_strerror (err)); /* Verify again using a compressed public key. */ gcry_sexp_release (key); if ((err = gcry_sexp_new (&key, ecc_public_key_comp, 0, 1))) die ("line %d: %s", __LINE__, gpg_strerror (err)); if ((err = gcry_pk_verify (sig, hash, key))) die ("gcry_pk_verify failed (comp): %s", gpg_strerror (err)); /* Sign without a Q parameter. */ gcry_sexp_release (key); if ((err = gcry_sexp_new (&key, ecc_private_key_wo_q, 0, 1))) die ("line %d: %s", __LINE__, gpg_strerror (err)); gcry_sexp_release (sig); if ((err = gcry_pk_sign (&sig, hash, key))) die ("gcry_pk_sign w/o Q failed: %s", gpg_strerror (err)); /* Verify. */ gcry_sexp_release (key); if ((err = gcry_sexp_new (&key, ecc_public_key, 0, 1))) die ("line %d: %s", __LINE__, gpg_strerror (err)); if ((err = gcry_pk_verify (sig, hash, key))) die ("gcry_pk_verify signed w/o Q failed: %s", gpg_strerror (err)); /* Verify again using a compressed public key. */ gcry_sexp_release (key); if ((err = gcry_sexp_new (&key, ecc_public_key_comp, 0, 1))) die ("line %d: %s", __LINE__, gpg_strerror (err)); if ((err = gcry_pk_verify (sig, hash, key))) die ("gcry_pk_verify signed w/o Q failed (comp): %s", gpg_strerror (err)); extract_cmp_data (sig, "r", ("a63123a783ef29b8276e08987daca4" "655d0179e22199bf63691fd88eb64e15")); extract_cmp_data (sig, "s", ("0d9b45c696ab90b96b08812b485df185" "623ddaf5d02fa65ca5056cb6bd0f16f1")); gcry_sexp_release (sig); gcry_sexp_release (key); gcry_sexp_release (hash); } int main (int argc, char **argv) { int debug = 0; int i; if (argc > 1 && !strcmp (argv[1], "--verbose")) verbose = 1; else if (argc > 1 && !strcmp (argv[1], "--debug")) { verbose = 2; debug = 1; } gcry_control (GCRYCTL_DISABLE_SECMEM, 0); if (!gcry_check_version (GCRYPT_VERSION)) die ("version mismatch\n"); gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0); if (debug) gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1u , 0); /* No valuable keys are create, so we can speed up our RNG. */ gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0); for (i=0; i < 2; i++) check_run (); for (i=0; i < 4; i++) check_x931_derived_key (i); check_ecc_sample_key (); check_ed25519ecdsa_sample_key (); return !!error_count; }