diff --git a/cipher/dsa.c b/cipher/dsa.c
index 22d8d78..55c966c 100644
--- a/cipher/dsa.c
+++ b/cipher/dsa.c
@@ -457,11 +457,22 @@ generate_fips186 (DSA_secret_key *sk, unsigned int nbits, unsigned int qbits,
&prime_q, &prime_p,
r_counter,
r_seed, r_seedlen);
- else
- ec = _gcry_generate_fips186_3_prime (nbits, qbits, NULL, 0,
+ else if (!domain->p || !domain->q)
+ ec = _gcry_generate_fips186_3_prime (nbits, qbits,
+ initial_seed.seed,
+ initial_seed.seedlen,
&prime_q, &prime_p,
r_counter,
r_seed, r_seedlen, NULL);
+ else
+ {
+ /* Domain parameters p and q are given; use them. */
+ prime_p = mpi_copy (domain->p);
+ prime_q = mpi_copy (domain->q);
+ gcry_assert (mpi_get_nbits (prime_p) == nbits);
+ gcry_assert (mpi_get_nbits (prime_q) == qbits);
+ ec = 0;
+ }
sexp_release (initial_seed.sexp);
if (ec)
goto leave;
@@ -855,13 +866,12 @@ dsa_generate (const gcry_sexp_t genparms, gcry_sexp_t *r_skey)
sexp_release (l1);
sexp_release (domainsexp);
- /* Check that all domain parameters are available. */
- if (!domain.p || !domain.q || !domain.g)
+ /* Check that p and q domain parameters are available. */
+ if (!domain.p || !domain.q || (!domain.g && !(flags & PUBKEY_FLAG_USE_FIPS186)))
{
_gcry_mpi_release (domain.p);
_gcry_mpi_release (domain.q);
_gcry_mpi_release (domain.g);
- sexp_release (deriveparms);
return GPG_ERR_MISSING_VALUE;
}
diff --git a/cipher/dsa.c.tests b/cipher/dsa.c.tests
new file mode 100644
index 0000000..22d8d78
--- /dev/null
+++ b/cipher/dsa.c.tests
@@ -0,0 +1,1390 @@
+/* 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. Not anymore
+ * used, kept only for reference. */
+#if 0
+static const char sample_secret_key_1024[] =
+"(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_1024[] =
+"(public-key"
+" (dsa"
+" (p #00AD7C0025BA1A15F775F3F2D673718391D00456978D347B33D7B49E7F32EDAB"
+" 96273899DD8B2BB46CD6ECA263FAF04A28903503D59062A8865D2AE8ADFB5191"
+" CF36FFB562D0E2F5809801A1F675DAE59698A9E01EFE8D7DCFCA084F4C6F5A44"
+" 44D499A06FFAEA5E8EF5E01F2FD20A7B7EF3F6968AFBA1FB8D91F1559D52D8777B#)"
+" (q #00EB7B5751D25EBBB7BD59D920315FD840E19AEBF9#)"
+" (g #1574363387FDFD1DDF38F4FBE135BB20C7EE4772FB94C337AF86EA8E49666503"
+" AE04B6BE81A2F8DD095311E0217ACA698A11E6C5D33CCDAE71498ED35D13991E"
+" B02F09AB40BD8F4C5ED8C75DA779D0AE104BC34C960B002377068AB4B5A1F984"
+" 3FBA91F537F1B7CAC4D8DD6D89B0D863AF7025D549F9C765D2FC07EE208F8D15#)"
+" (y #64B11EF8871BE4AB572AA810D5D3CA11A6CDBC637A8014602C72960DB135BF46"
+" A1816A724C34F87330FC9E187C5D66897A04535CC2AC9164A7150ABFA8179827"
+" 6E45831AB811EEE848EBB24D9F5F2883B6E5DDC4C659DEF944DCFD80BF4D0A20"
+" 42CAA7DC289F0C5A9D155F02D3D551DB741A81695B74D4C8F477F9C7838EB0FB#)))";
+#endif /*0*/
+
+/* 2048 DSA key from RFC 6979 A.2.2 */
+static const char sample_public_key_2048[] =
+"(public-key"
+" (dsa"
+" (p #9DB6FB5951B66BB6FE1E140F1D2CE5502374161FD6538DF1648218642F0B5C48C8F7A41AADFA187324B87674FA1822B00F1ECF8136943D7C55757264E5A1A44FFE012E9936E00C1D3E9310B01C7D179805D3058B2A9F4BB6F9716BFE6117C6B5B3CC4D9BE341104AD4A80AD6C94E005F4B993E14F091EB51743BF33050C38DE235567E1B34C3D6A5C0CEAA1A0F368213C3D19843D0B4B09DCB9FC72D39C8DE41F1BF14D4BB4563CA28371621CAD3324B6A2D392145BEBFAC748805236F5CA2FE92B871CD8F9C36D3292B5509CA8CAA77A2ADFC7BFD77DDA6F71125A7456FEA153E433256A2261C6A06ED3693797E7995FAD5AABBCFBE3EDA2741E375404AE25B#)"
+" (q #F2C3119374CE76C9356990B465374A17F23F9ED35089BD969F61C6DDE9998C1F#)"
+" (g #5C7FF6B06F8F143FE8288433493E4769C4D988ACE5BE25A0E24809670716C613D7B0CEE6932F8FAA7C44D2CB24523DA53FBE4F6EC3595892D1AA58C4328A06C46A15662E7EAA703A1DECF8BBB2D05DBE2EB956C142A338661D10461C0D135472085057F3494309FFA73C611F78B32ADBB5740C361C9F35BE90997DB2014E2EF5AA61782F52ABEB8BD6432C4DD097BC5423B285DAFB60DC364E8161F4A2A35ACA3A10B1C4D203CC76A470A33AFDCBDD92959859ABD8B56E1725252D78EAC66E71BA9AE3F1DD2487199874393CD4D832186800654760E1E34C09E4D155179F9EC0DC4473F996BDCE6EED1CABED8B6F116F7AD9CF505DF0F998E34AB27514B0FFE7#)"
+" (y #667098C654426C78D7F8201EAC6C203EF030D43605032C2F1FA937E5237DBD949F34A0A2564FE126DC8B715C5141802CE0979C8246463C40E6B6BDAA2513FA611728716C2E4FD53BC95B89E69949D96512E873B9C8F8DFD499CC312882561ADECB31F658E934C0C197F2C4D96B05CBAD67381E7B768891E4DA3843D24D94CDFB5126E9B8BF21E8358EE0E0A30EF13FD6A664C0DCE3731F7FB49A4845A4FD8254687972A2D382599C9BAC4E0ED7998193078913032558134976410B89D2C171D123AC35FD977219597AA7D15C1A9A428E59194F75C721EBCBCFAE44696A499AFA74E04299F132026601638CB87AB79190D4A0986315DA8EEC6561C938996BEADF#)))";
+
+static const char sample_secret_key_2048[] =
+"(private-key"
+" (dsa"
+" (p #9DB6FB5951B66BB6FE1E140F1D2CE5502374161FD6538DF1648218642F0B5C48C8F7A41AADFA187324B87674FA1822B00F1ECF8136943D7C55757264E5A1A44FFE012E9936E00C1D3E9310B01C7D179805D3058B2A9F4BB6F9716BFE6117C6B5B3CC4D9BE341104AD4A80AD6C94E005F4B993E14F091EB51743BF33050C38DE235567E1B34C3D6A5C0CEAA1A0F368213C3D19843D0B4B09DCB9FC72D39C8DE41F1BF14D4BB4563CA28371621CAD3324B6A2D392145BEBFAC748805236F5CA2FE92B871CD8F9C36D3292B5509CA8CAA77A2ADFC7BFD77DDA6F71125A7456FEA153E433256A2261C6A06ED3693797E7995FAD5AABBCFBE3EDA2741E375404AE25B#)"
+" (q #F2C3119374CE76C9356990B465374A17F23F9ED35089BD969F61C6DDE9998C1F#)"
+" (g #5C7FF6B06F8F143FE8288433493E4769C4D988ACE5BE25A0E24809670716C613D7B0CEE6932F8FAA7C44D2CB24523DA53FBE4F6EC3595892D1AA58C4328A06C46A15662E7EAA703A1DECF8BBB2D05DBE2EB956C142A338661D10461C0D135472085057F3494309FFA73C611F78B32ADBB5740C361C9F35BE90997DB2014E2EF5AA61782F52ABEB8BD6432C4DD097BC5423B285DAFB60DC364E8161F4A2A35ACA3A10B1C4D203CC76A470A33AFDCBDD92959859ABD8B56E1725252D78EAC66E71BA9AE3F1DD2487199874393CD4D832186800654760E1E34C09E4D155179F9EC0DC4473F996BDCE6EED1CABED8B6F116F7AD9CF505DF0F998E34AB27514B0FFE7#)"
+" (y #667098C654426C78D7F8201EAC6C203EF030D43605032C2F1FA937E5237DBD949F34A0A2564FE126DC8B715C5141802CE0979C8246463C40E6B6BDAA2513FA611728716C2E4FD53BC95B89E69949D96512E873B9C8F8DFD499CC312882561ADECB31F658E934C0C197F2C4D96B05CBAD67381E7B768891E4DA3843D24D94CDFB5126E9B8BF21E8358EE0E0A30EF13FD6A664C0DCE3731F7FB49A4845A4FD8254687972A2D382599C9BAC4E0ED7998193078913032558134976410B89D2C171D123AC35FD977219597AA7D15C1A9A428E59194F75C721EBCBCFAE44696A499AFA74E04299F132026601638CB87AB79190D4A0986315DA8EEC6561C938996BEADF#)"
+" (x #69C7548C21D0DFEA6B9A51C9EAD4E27C33D3B3F180316E5BCAB92C933F0E4DBC#)))";
+
+
+
+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 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) )
+ 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) )
+ 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 )
+{
+ gpg_err_code_t rc;
+ 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. */
+ rc = _gcry_generate_elg_prime (1, nbits, qbits, NULL, &p, ret_factors);
+ if (rc)
+ return rc;
+
+ /* 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. */
+ gcry_mpi_t value_c = NULL; /* helper for x */
+ gcry_mpi_t value_qm2 = NULL; /* q - 2 */
+
+ /* 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 && use_fips186_2)
+ ; /* Allowed in FIPS 186-2 mode. */
+ 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);
+ }
+
+ if (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. */
+ }
+
+ value_c = mpi_snew (qbits);
+ value_x = mpi_snew (qbits);
+ value_qm2 = mpi_snew (qbits);
+ mpi_sub_ui (value_qm2, prime_q, 2);
+
+ /* FIPS 186-4 B.1.2 steps 4-6 */
+ do
+ {
+ if( DBG_CIPHER )
+ progress('.');
+ _gcry_mpi_randomize (value_c, qbits, GCRY_VERY_STRONG_RANDOM);
+ mpi_clear_highbit (value_c, qbits+1);
+ }
+ while (!(mpi_cmp_ui (value_c, 0) > 0 && mpi_cmp (value_c, value_qm2) < 0));
+ /* while (mpi_cmp (value_c, value_qm2) > 0); */
+
+ /* x = c + 1 */
+ mpi_add_ui(value_x, value_c, 1);
+
+ /* 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);
+ _gcry_mpi_release (value_c);
+ _gcry_mpi_release (value_qm2);
+
+ /* 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. */
+ 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 gpg_err_code_t
+verify (gcry_mpi_t r, gcry_mpi_t s, gcry_mpi_t input, DSA_public_key *pkey )
+{
+ 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 GPG_ERR_BAD_SIGNATURE; /* Assertion 0 < r < n failed. */
+ if( !(mpi_cmp_ui( s, 0 ) > 0 && mpi_cmp( s, pkey->q ) < 0) )
+ 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 );
+
+ 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. */
+ 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 (gcry_sexp_t pkey, gcry_sexp_t skey)
+{
+ /* Sample data from RFC 6979 section A.2.2, hash is of message "sample" */
+ static const char sample_data[] =
+ "(data (flags rfc6979)"
+ " (hash sha256 #af2bdbe1aa9b6ec1e2ade1d694f41fc71a831d0268e9891562113d8a62add1bf#))";
+ static const char sample_data_bad[] =
+ "(data (flags rfc6979)"
+ " (hash sha256 #bf2bdbe1aa9b6ec1e2ade1d694f41fc71a831d0268e9891562113d8a62add1bf#))";
+ static const char signature_r[] =
+ "eace8bdbbe353c432a795d9ec556c6d021f7a03f42c36e9bc87e4ac7932cc809";
+ static const char signature_s[] =
+ "7081e175455f9247b812b74583e9e94f9ea79bd640dc962533b0680793a38d53";
+
+ const char *errtxt = NULL;
+ gcry_error_t err;
+ gcry_sexp_t data = NULL;
+ gcry_sexp_t data_bad = NULL;
+ gcry_sexp_t sig = NULL;
+ gcry_sexp_t l1 = NULL;
+ gcry_sexp_t l2 = NULL;
+ gcry_mpi_t r = NULL;
+ gcry_mpi_t s = NULL;
+ gcry_mpi_t calculated_r = NULL;
+ gcry_mpi_t calculated_s = NULL;
+ int cmp;
+
+ 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)
+ err = _gcry_mpi_scan (&r, GCRYMPI_FMT_HEX, signature_r, 0, NULL);
+ if (!err)
+ err = _gcry_mpi_scan (&s, GCRYMPI_FMT_HEX, signature_s, 0, NULL);
+
+ if (err)
+ {
+ errtxt = "converting data failed";
+ goto leave;
+ }
+
+ err = _gcry_pk_sign (&sig, data, skey);
+ if (err)
+ {
+ errtxt = "signing failed";
+ goto leave;
+ }
+
+ /* check against known signature */
+ errtxt = "signature validity failed";
+ l1 = _gcry_sexp_find_token (sig, "sig-val", 0);
+ if (!l1)
+ goto leave;
+ l2 = _gcry_sexp_find_token (l1, "dsa", 0);
+ if (!l2)
+ goto leave;
+
+ sexp_release (l1);
+ l1 = l2;
+
+ l2 = _gcry_sexp_find_token (l1, "r", 0);
+ if (!l2)
+ goto leave;
+ calculated_r = _gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG);
+ if (!calculated_r)
+ goto leave;
+
+ sexp_release (l2);
+ l2 = _gcry_sexp_find_token (l1, "s", 0);
+ if (!l2)
+ goto leave;
+ calculated_s = _gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG);
+ if (!calculated_s)
+ goto leave;
+
+ errtxt = "known sig check failed";
+
+ cmp = _gcry_mpi_cmp (r, calculated_r);
+ if (cmp)
+ goto leave;
+ cmp = _gcry_mpi_cmp (s, calculated_s);
+ if (cmp)
+ goto leave;
+
+ errtxt = NULL;
+
+
+ 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:
+ _gcry_mpi_release (calculated_s);
+ _gcry_mpi_release (calculated_r);
+ _gcry_mpi_release (s);
+ _gcry_mpi_release (r);
+ sexp_release (l2);
+ sexp_release (l1);
+ sexp_release (sig);
+ sexp_release (data_bad);
+ sexp_release (data);
+ return errtxt;
+}
+
+
+static gpg_err_code_t
+selftests_dsa_2048 (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_2048, strlen (sample_secret_key_2048));
+ if (!err)
+ err = sexp_sscan (&pkey, NULL,
+ sample_public_key_2048, strlen (sample_public_key_2048));
+ 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 (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_2048 (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/rsa.c b/cipher/rsa.c
index 575ea94..c226909 100644
--- a/cipher/rsa.c
+++ b/cipher/rsa.c
@@ -696,7 +696,7 @@ generate_x931 (RSA_secret_key *sk, unsigned int nbits, unsigned long e_value,
*swapped = 0;
- if (e_value == 1) /* Alias for a secure value. */
+ if (e_value == 1 || e_value == 0) /* Alias for a secure value. */
e_value = 65537;
/* Point 1 of section 4.1: k = 1024 + 256s with S >= 0 */
diff --git a/cipher/rsa.c.tests b/cipher/rsa.c.tests
new file mode 100644
index 0000000..575ea94
--- /dev/null
+++ b/cipher/rsa.c.tests
@@ -0,0 +1,2035 @@
+/* rsa.c - RSA implementation
+ * Copyright (C) 1997, 1998, 1999 by Werner Koch (dd9jn)
+ * Copyright (C) 2000, 2001, 2002, 2003, 2008 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 .
+ */
+
+/* This code uses an algorithm protected by U.S. Patent #4,405,829
+ which expired on September 20, 2000. The patent holder placed that
+ patent into the public domain on Sep 6th, 2000.
+*/
+
+#include
+#include
+#include
+#include
+#include
+
+#include "g10lib.h"
+#include "mpi.h"
+#include "cipher.h"
+#include "pubkey-internal.h"
+
+
+typedef struct
+{
+ gcry_mpi_t n; /* modulus */
+ gcry_mpi_t e; /* exponent */
+} RSA_public_key;
+
+
+typedef struct
+{
+ gcry_mpi_t n; /* public modulus */
+ gcry_mpi_t e; /* public exponent */
+ gcry_mpi_t d; /* exponent */
+ gcry_mpi_t p; /* prime p. */
+ gcry_mpi_t q; /* prime q. */
+ gcry_mpi_t u; /* inverse of p mod q. */
+} RSA_secret_key;
+
+
+static const char *rsa_names[] =
+ {
+ "rsa",
+ "openpgp-rsa",
+ "oid.1.2.840.113549.1.1.1",
+ NULL,
+ };
+
+
+/* A sample 2048 bit RSA key used for the selftests. */
+static const char sample_secret_key[] =
+" (private-key"
+" (rsa"
+" (n #009F56231A3D82E3E7D613D59D53E9AB921BEF9F08A782AED0B6E46ADBC853EC"
+" 7C71C422435A3CD8FA0DB9EFD55CD3295BADC4E8E2E2B94E15AE82866AB8ADE8"
+" 7E469FAE76DC3577DE87F1F419C4EB41123DFAF8D16922D5EDBAD6E9076D5A1C"
+" 958106F0AE5E2E9193C6B49124C64C2A241C4075D4AF16299EB87A6585BAE917"
+" DEF27FCDD165764D069BC18D16527B29DAAB549F7BBED4A7C6A842D203ED6613"
+" 6E2411744E432CD26D940132F25874483DCAEECDFD95744819CBCF1EA810681C"
+" 42907EBCB1C7EAFBE75C87EC32C5413EA10476545D3FC7B2ADB1B66B7F200918"
+" 664B0E5261C2895AA28B0DE321E921B3F877172CCCAB81F43EF98002916156F6CB#)"
+" (e #010001#)"
+" (d #07EF82500C403899934FE993AC5A36F14FF2DF38CF1EF315F205EE4C83EDAA19"
+" 8890FC23DE9AA933CAFB37B6A8A8DBA675411958337287310D3FF2F1DDC0CB93"
+" 7E70F57F75F833C021852B631D2B9A520E4431A03C5C3FCB5742DCD841D9FB12"
+" 771AA1620DCEC3F1583426066ED9DC3F7028C5B59202C88FDF20396E2FA0EC4F"
+" 5A22D9008F3043673931BC14A5046D6327398327900867E39CC61B2D1AFE2F48"
+" EC8E1E3861C68D257D7425F4E6F99ABD77D61F10CA100EFC14389071831B33DD"
+" 69CC8EABEF860D1DC2AAA84ABEAE5DFC91BC124DAF0F4C8EF5BBEA436751DE84"
+" 3A8063E827A024466F44C28614F93B0732A100D4A0D86D532FE1E22C7725E401#)"
+" (p #00C29D438F115825779631CD665A5739367F3E128ADC29766483A46CA80897E0"
+" 79B32881860B8F9A6A04C2614A904F6F2578DAE13EA67CD60AE3D0AA00A1FF9B"
+" 441485E44B2DC3D0B60260FBFE073B5AC72FAF67964DE15C8212C389D20DB9CF"
+" 54AF6AEF5C4196EAA56495DD30CF709F499D5AB30CA35E086C2A1589D6283F1783#)"
+" (q #00D1984135231CB243FE959C0CBEF551EDD986AD7BEDF71EDF447BE3DA27AF46"
+" 79C974A6FA69E4D52FE796650623DE70622862713932AA2FD9F2EC856EAEAA77"
+" 88B4EA6084DC81C902F014829B18EA8B2666EC41586818E0589E18876065F97E"
+" 8D22CE2DA53A05951EC132DCEF41E70A9C35F4ACC268FFAC2ADF54FA1DA110B919#)"
+" (u #67CF0FD7635205DD80FA814EE9E9C267C17376BF3209FB5D1BC42890D2822A04"
+" 479DAF4D5B6ED69D0F8D1AF94164D07F8CD52ECEFE880641FA0F41DDAB1785E4"
+" A37A32F997A516480B4CD4F6482B9466A1765093ED95023CA32D5EDC1E34CEE9"
+" AF595BC51FE43C4BF810FA225AF697FB473B83815966188A4312C048B885E3F7#)))";
+
+/* A sample 2048 bit RSA key used for the selftests (public only). */
+static const char sample_public_key[] =
+" (public-key"
+" (rsa"
+" (n #009F56231A3D82E3E7D613D59D53E9AB921BEF9F08A782AED0B6E46ADBC853EC"
+" 7C71C422435A3CD8FA0DB9EFD55CD3295BADC4E8E2E2B94E15AE82866AB8ADE8"
+" 7E469FAE76DC3577DE87F1F419C4EB41123DFAF8D16922D5EDBAD6E9076D5A1C"
+" 958106F0AE5E2E9193C6B49124C64C2A241C4075D4AF16299EB87A6585BAE917"
+" DEF27FCDD165764D069BC18D16527B29DAAB549F7BBED4A7C6A842D203ED6613"
+" 6E2411744E432CD26D940132F25874483DCAEECDFD95744819CBCF1EA810681C"
+" 42907EBCB1C7EAFBE75C87EC32C5413EA10476545D3FC7B2ADB1B66B7F200918"
+" 664B0E5261C2895AA28B0DE321E921B3F877172CCCAB81F43EF98002916156F6CB#)"
+" (e #010001#)))";
+
+
+static int test_keys (RSA_secret_key *sk, unsigned nbits);
+static int check_secret_key (RSA_secret_key *sk);
+static void public (gcry_mpi_t output, gcry_mpi_t input, RSA_public_key *skey);
+static void secret (gcry_mpi_t output, gcry_mpi_t input, RSA_secret_key *skey);
+static unsigned int rsa_get_nbits (gcry_sexp_t parms);
+
+
+/* Check that a freshly generated key actually works. Returns 0 on success. */
+static int
+test_keys (RSA_secret_key *sk, unsigned int nbits)
+{
+ int result = -1; /* Default to failure. */
+ RSA_public_key pk;
+ gcry_mpi_t plaintext = mpi_new (nbits);
+ gcry_mpi_t ciphertext = mpi_new (nbits);
+ gcry_mpi_t decr_plaintext = mpi_new (nbits);
+ gcry_mpi_t signature = mpi_new (nbits);
+
+ /* Put the relevant parameters into a public key structure. */
+ pk.n = sk->n;
+ pk.e = sk->e;
+
+ /* Create a random plaintext. */
+ _gcry_mpi_randomize (plaintext, nbits, GCRY_WEAK_RANDOM);
+
+ /* Encrypt using the public key. */
+ public (ciphertext, plaintext, &pk);
+
+ /* Check that the cipher text does not match the plaintext. */
+ if (!mpi_cmp (ciphertext, plaintext))
+ goto leave; /* Ciphertext is identical to the plaintext. */
+
+ /* Decrypt using the secret key. */
+ secret (decr_plaintext, ciphertext, sk);
+
+ /* Check that the decrypted plaintext matches the original plaintext. */
+ if (mpi_cmp (decr_plaintext, plaintext))
+ goto leave; /* Plaintext does not match. */
+
+ /* Create another random plaintext as data for signature checking. */
+ _gcry_mpi_randomize (plaintext, nbits, GCRY_WEAK_RANDOM);
+
+ /* Use the RSA secret function to create a signature of the plaintext. */
+ secret (signature, plaintext, sk);
+
+ /* Use the RSA public function to verify this signature. */
+ public (decr_plaintext, signature, &pk);
+ if (mpi_cmp (decr_plaintext, plaintext))
+ goto leave; /* Signature does not match. */
+
+ /* Modify the signature and check that the signing fails. */
+ mpi_add_ui (signature, signature, 1);
+ public (decr_plaintext, signature, &pk);
+ if (!mpi_cmp (decr_plaintext, plaintext))
+ goto leave; /* Signature matches but should not. */
+
+ result = 0; /* All tests succeeded. */
+
+ leave:
+ _gcry_mpi_release (signature);
+ _gcry_mpi_release (decr_plaintext);
+ _gcry_mpi_release (ciphertext);
+ _gcry_mpi_release (plaintext);
+ return result;
+}
+
+
+/* Callback used by the prime generation to test whether the exponent
+ is suitable. Returns 0 if the test has been passed. */
+static int
+check_exponent (void *arg, gcry_mpi_t a)
+{
+ gcry_mpi_t e = arg;
+ gcry_mpi_t tmp;
+ int result;
+
+ mpi_sub_ui (a, a, 1);
+ tmp = _gcry_mpi_alloc_like (a);
+ result = !mpi_gcd(tmp, e, a); /* GCD is not 1. */
+ _gcry_mpi_release (tmp);
+ mpi_add_ui (a, a, 1);
+ return result;
+}
+
+/****************
+ * Generate a key pair with a key of size NBITS.
+ * USE_E = 0 let Libcgrypt decide what exponent to use.
+ * = 1 request the use of a "secure" exponent; this is required by some
+ * specification to be 65537.
+ * > 2 Use this public exponent. If the given exponent
+ * is not odd one is internally added to it.
+ * TRANSIENT_KEY: If true, generate the primes using the standard RNG.
+ * Returns: 2 structures filled with all needed values
+ */
+static gpg_err_code_t
+generate_std (RSA_secret_key *sk, unsigned int nbits, unsigned long use_e,
+ int transient_key)
+{
+ gcry_mpi_t p, q; /* the two primes */
+ gcry_mpi_t d; /* the private key */
+ gcry_mpi_t u;
+ gcry_mpi_t t1, t2;
+ gcry_mpi_t n; /* the public key */
+ gcry_mpi_t e; /* the exponent */
+ gcry_mpi_t phi; /* helper: (p-1)(q-1) */
+ gcry_mpi_t g;
+ gcry_mpi_t f;
+ gcry_random_level_t random_level;
+
+ if (fips_mode ())
+ {
+ if (nbits < 1024)
+ return GPG_ERR_INV_VALUE;
+ if (transient_key)
+ return GPG_ERR_INV_VALUE;
+ }
+
+ /* The random quality depends on the transient_key flag. */
+ random_level = transient_key ? GCRY_STRONG_RANDOM : GCRY_VERY_STRONG_RANDOM;
+
+ /* Make sure that nbits is even so that we generate p, q of equal size. */
+ if ( (nbits&1) )
+ nbits++;
+
+ if (use_e == 1) /* Alias for a secure value */
+ use_e = 65537; /* as demanded by Sphinx. */
+
+ /* Public exponent:
+ In general we use 41 as this is quite fast and more secure than the
+ commonly used 17. Benchmarking the RSA verify function
+ with a 1024 bit key yields (2001-11-08):
+ e=17 0.54 ms
+ e=41 0.75 ms
+ e=257 0.95 ms
+ e=65537 1.80 ms
+ */
+ e = mpi_alloc( (32+BITS_PER_MPI_LIMB-1)/BITS_PER_MPI_LIMB );
+ if (!use_e)
+ mpi_set_ui (e, 41); /* This is a reasonable secure and fast value */
+ else
+ {
+ use_e |= 1; /* make sure this is odd */
+ mpi_set_ui (e, use_e);
+ }
+
+ n = mpi_new (nbits);
+
+ p = q = NULL;
+ do
+ {
+ /* select two (very secret) primes */
+ if (p)
+ _gcry_mpi_release (p);
+ if (q)
+ _gcry_mpi_release (q);
+ if (use_e)
+ { /* Do an extra test to ensure that the given exponent is
+ suitable. */
+ p = _gcry_generate_secret_prime (nbits/2, random_level,
+ check_exponent, e);
+ q = _gcry_generate_secret_prime (nbits/2, random_level,
+ check_exponent, e);
+ }
+ else
+ { /* We check the exponent later. */
+ p = _gcry_generate_secret_prime (nbits/2, random_level, NULL, NULL);
+ q = _gcry_generate_secret_prime (nbits/2, random_level, NULL, NULL);
+ }
+ if (mpi_cmp (p, q) > 0 ) /* p shall be smaller than q (for calc of u)*/
+ mpi_swap(p,q);
+ /* calculate the modulus */
+ mpi_mul( n, p, q );
+ }
+ while ( mpi_get_nbits(n) != nbits );
+
+ /* calculate Euler totient: phi = (p-1)(q-1) */
+ t1 = mpi_alloc_secure( mpi_get_nlimbs(p) );
+ t2 = mpi_alloc_secure( mpi_get_nlimbs(p) );
+ phi = mpi_snew ( nbits );
+ g = mpi_snew ( nbits );
+ f = mpi_snew ( nbits );
+ mpi_sub_ui( t1, p, 1 );
+ mpi_sub_ui( t2, q, 1 );
+ mpi_mul( phi, t1, t2 );
+ mpi_gcd (g, t1, t2);
+ mpi_fdiv_q(f, phi, g);
+
+ while (!mpi_gcd(t1, e, phi)) /* (while gcd is not 1) */
+ {
+ if (use_e)
+ BUG (); /* The prime generator already made sure that we
+ never can get to here. */
+ mpi_add_ui (e, e, 2);
+ }
+
+ /* calculate the secret key d = e^-1 mod phi */
+ d = mpi_snew ( nbits );
+ mpi_invm (d, e, f );
+ /* calculate the inverse of p and q (used for chinese remainder theorem)*/
+ u = mpi_snew ( nbits );
+ mpi_invm(u, p, q );
+
+ if( DBG_CIPHER )
+ {
+ log_mpidump(" p= ", p );
+ log_mpidump(" q= ", q );
+ log_mpidump("phi= ", phi );
+ log_mpidump(" g= ", g );
+ log_mpidump(" f= ", f );
+ log_mpidump(" n= ", n );
+ log_mpidump(" e= ", e );
+ log_mpidump(" d= ", d );
+ log_mpidump(" u= ", u );
+ }
+
+ _gcry_mpi_release (t1);
+ _gcry_mpi_release (t2);
+ _gcry_mpi_release (phi);
+ _gcry_mpi_release (f);
+ _gcry_mpi_release (g);
+
+ sk->n = n;
+ sk->e = e;
+ sk->p = p;
+ sk->q = q;
+ sk->d = d;
+ sk->u = u;
+
+ /* Now we can test our keys. */
+ if (test_keys (sk, nbits - 64))
+ {
+ _gcry_mpi_release (sk->n); sk->n = NULL;
+ _gcry_mpi_release (sk->e); sk->e = NULL;
+ _gcry_mpi_release (sk->p); sk->p = NULL;
+ _gcry_mpi_release (sk->q); sk->q = NULL;
+ _gcry_mpi_release (sk->d); sk->d = NULL;
+ _gcry_mpi_release (sk->u); sk->u = NULL;
+ fips_signal_error ("self-test after key generation failed");
+ return GPG_ERR_SELFTEST_FAILED;
+ }
+
+ return 0;
+}
+
+
+/****************
+ * Generate a key pair with a key of size NBITS.
+ * USE_E = 0 let Libcgrypt decide what exponent to use.
+ * = 1 request the use of a "secure" exponent; this is required by some
+ * specification to be 65537.
+ * > 2 Use this public exponent. If the given exponent
+ * is not odd one is internally added to it.
+ * TESTPARMS: If set, do not generate but test whether the p,q is probably prime
+ * Returns key with zeroes to not break code calling this function.
+ * TRANSIENT_KEY: If true, generate the primes using the standard RNG.
+ * Returns: 2 structures filled with all needed values
+ */
+static gpg_err_code_t
+generate_fips (RSA_secret_key *sk, unsigned int nbits, unsigned long use_e,
+ gcry_sexp_t testparms, int transient_key)
+{
+ gcry_mpi_t p, q; /* the two primes */
+ gcry_mpi_t d; /* the private key */
+ gcry_mpi_t u;
+ gcry_mpi_t p1, q1;
+ gcry_mpi_t n; /* the public key */
+ gcry_mpi_t e; /* the exponent */
+ gcry_mpi_t g;
+ gcry_mpi_t minp;
+ gcry_mpi_t diff, mindiff;
+ gcry_random_level_t random_level;
+ unsigned int pbits = nbits/2;
+ unsigned int i;
+ int pqswitch;
+ gpg_err_code_t ec = GPG_ERR_NO_PRIME;
+
+ if (nbits < 1024 || (nbits & 0x1FF))
+ return GPG_ERR_INV_VALUE;
+ if (_gcry_enforced_fips_mode() && nbits != 2048 && nbits != 3072)
+ return GPG_ERR_INV_VALUE;
+
+ /* The random quality depends on the transient_key flag. */
+ random_level = transient_key ? GCRY_STRONG_RANDOM : GCRY_VERY_STRONG_RANDOM;
+
+ if (testparms)
+ {
+ /* Parameters to derive the key are given. */
+ /* Note that we explicitly need to setup the values of tbl
+ because some compilers (e.g. OpenWatcom, IRIX) don't allow to
+ initialize a structure with automatic variables. */
+ struct { const char *name; gcry_mpi_t *value; } tbl[] = {
+ { "e" },
+ { "p" },
+ { "q" },
+ { NULL }
+ };
+ int idx;
+ gcry_sexp_t oneparm;
+
+ tbl[0].value = &e;
+ tbl[1].value = &p;
+ tbl[2].value = &q;
+
+ for (idx=0; tbl[idx].name; idx++)
+ {
+ oneparm = sexp_find_token (testparms, tbl[idx].name, 0);
+ if (oneparm)
+ {
+ *tbl[idx].value = sexp_nth_mpi (oneparm, 1, GCRYMPI_FMT_USG);
+ sexp_release (oneparm);
+ }
+ }
+ for (idx=0; tbl[idx].name; idx++)
+ if (!*tbl[idx].value)
+ break;
+ if (tbl[idx].name)
+ {
+ /* At least one parameter is missing. */
+ for (idx=0; tbl[idx].name; idx++)
+ _gcry_mpi_release (*tbl[idx].value);
+ return GPG_ERR_MISSING_VALUE;
+ }
+ }
+ else
+ {
+ if (use_e < 65537)
+ use_e = 65537; /* This is the smallest value allowed by FIPS */
+
+ e = mpi_alloc ((32+BITS_PER_MPI_LIMB-1)/BITS_PER_MPI_LIMB);
+
+ use_e |= 1; /* make sure this is odd */
+ mpi_set_ui (e, use_e);
+
+ p = mpi_snew (pbits);
+ q = mpi_snew (pbits);
+ }
+
+ n = mpi_new (nbits);
+ d = mpi_snew (nbits);
+ u = mpi_snew (nbits);
+
+ /* prepare approximate minimum p and q */
+ minp = mpi_new (pbits);
+ mpi_set_ui (minp, 0xB504F334);
+ mpi_lshift (minp, minp, pbits - 32);
+
+ /* prepare minimum p and q difference */
+ diff = mpi_new (pbits);
+ mindiff = mpi_new (pbits - 99);
+ mpi_set_ui (mindiff, 1);
+ mpi_lshift (mindiff, mindiff, pbits - 100);
+
+ p1 = mpi_snew (pbits);
+ q1 = mpi_snew (pbits);
+ g = mpi_snew (pbits);
+
+ retry:
+ /* generate p and q */
+ for (i = 0; i < 5 * pbits; i++)
+ {
+ ploop:
+ if (!testparms)
+ {
+ _gcry_mpi_randomize (p, pbits, random_level);
+ }
+ if (mpi_cmp (p, minp) < 0)
+ {
+ if (testparms)
+ goto err;
+ goto ploop;
+ }
+
+ mpi_sub_ui (p1, p, 1);
+ if (mpi_gcd (g, p1, e))
+ {
+ if (_gcry_fips186_4_prime_check (p, pbits) != GPG_ERR_NO_ERROR)
+ {
+ /* not a prime */
+ if (testparms)
+ goto err;
+ }
+ else
+ break;
+ }
+ else if (testparms)
+ goto err;
+ }
+ if (i >= 5 * pbits)
+ goto err;
+
+ for (i = 0; i < 5 * pbits; i++)
+ {
+ qloop:
+ if (!testparms)
+ {
+ _gcry_mpi_randomize (q, pbits, random_level);
+ }
+ if (mpi_cmp (q, minp) < 0)
+ {
+ if (testparms)
+ goto err;
+ goto qloop;
+ }
+ if (mpi_cmp (p, q) > 0)
+ {
+ pqswitch = 1;
+ mpi_sub (diff, p, q);
+ }
+ else
+ {
+ pqswitch = 0;
+ mpi_sub (diff, q, p);
+ }
+ if (mpi_cmp (diff, mindiff) < 0)
+ {
+ if (testparms)
+ goto err;
+ goto qloop;
+ }
+
+ mpi_sub_ui (q1, q, 1);
+ if (mpi_gcd (g, q1, e))
+ {
+ if (_gcry_fips186_4_prime_check (q, pbits) != GPG_ERR_NO_ERROR)
+ {
+ /* not a prime */
+ if (testparms)
+ goto err;
+ }
+ else
+ break;
+ }
+ else if (testparms)
+ goto err;
+ }
+ if (i >= 5 * pbits)
+ goto err;
+
+ if (testparms)
+ {
+ mpi_clear (p);
+ mpi_clear (q);
+ }
+ else
+ {
+ gcry_mpi_t f;
+
+ if (pqswitch)
+ {
+ gcry_mpi_t tmp;
+
+ tmp = p;
+ p = q;
+ q = tmp;
+ }
+
+ f = mpi_snew (nbits);
+
+ /* calculate the modulus */
+ mpi_mul (n, p, q);
+
+ /* calculate the secret key d = e^1 mod phi */
+ mpi_gcd (g, p1, q1);
+ mpi_fdiv_q (f, p1, g);
+ mpi_mul (f, f, q1);
+
+ mpi_invm (d, e, f);
+
+ _gcry_mpi_release (f);
+
+ if (mpi_get_nbits (d) < pbits)
+ goto retry;
+
+ /* calculate the inverse of p and q (used for chinese remainder theorem)*/
+ mpi_invm (u, p, q );
+ }
+
+ ec = 0;
+
+ if (DBG_CIPHER)
+ {
+ log_mpidump(" p= ", p );
+ log_mpidump(" q= ", q );
+ log_mpidump(" n= ", n );
+ log_mpidump(" e= ", e );
+ log_mpidump(" d= ", d );
+ log_mpidump(" u= ", u );
+ }
+
+ err:
+
+ _gcry_mpi_release (p1);
+ _gcry_mpi_release (q1);
+ _gcry_mpi_release (g);
+ _gcry_mpi_release (minp);
+ _gcry_mpi_release (mindiff);
+ _gcry_mpi_release (diff);
+
+ sk->n = n;
+ sk->e = e;
+ sk->p = p;
+ sk->q = q;
+ sk->d = d;
+ sk->u = u;
+
+ /* Now we can test our keys. */
+ if (ec || (!testparms && test_keys (sk, nbits - 64)))
+ {
+ _gcry_mpi_release (sk->n); sk->n = NULL;
+ _gcry_mpi_release (sk->e); sk->e = NULL;
+ _gcry_mpi_release (sk->p); sk->p = NULL;
+ _gcry_mpi_release (sk->q); sk->q = NULL;
+ _gcry_mpi_release (sk->d); sk->d = NULL;
+ _gcry_mpi_release (sk->u); sk->u = NULL;
+ if (!ec)
+ {
+ fips_signal_error ("self-test after key generation failed");
+ return GPG_ERR_SELFTEST_FAILED;
+ }
+ }
+
+ return ec;
+}
+
+
+/* Helper for generate_x931. */
+static gcry_mpi_t
+gen_x931_parm_xp (unsigned int nbits)
+{
+ gcry_mpi_t xp;
+
+ xp = mpi_snew (nbits);
+ _gcry_mpi_randomize (xp, nbits, GCRY_VERY_STRONG_RANDOM);
+
+ /* The requirement for Xp is:
+
+ sqrt{2}*2^{nbits-1} <= xp <= 2^{nbits} - 1
+
+ We set the two high order bits to 1 to satisfy the lower bound.
+ By using mpi_set_highbit we make sure that the upper bound is
+ satisfied as well. */
+ mpi_set_highbit (xp, nbits-1);
+ mpi_set_bit (xp, nbits-2);
+ gcry_assert ( mpi_get_nbits (xp) == nbits );
+
+ return xp;
+}
+
+
+/* Helper for generate_x931. */
+static gcry_mpi_t
+gen_x931_parm_xi (void)
+{
+ gcry_mpi_t xi;
+
+ xi = mpi_snew (101);
+ _gcry_mpi_randomize (xi, 101, GCRY_VERY_STRONG_RANDOM);
+ mpi_set_highbit (xi, 100);
+ gcry_assert ( mpi_get_nbits (xi) == 101 );
+
+ return xi;
+}
+
+
+
+/* Variant of the standard key generation code using the algorithm
+ from X9.31. Using this algorithm has the advantage that the
+ generation can be made deterministic which is required for CAVS
+ testing. */
+static gpg_err_code_t
+generate_x931 (RSA_secret_key *sk, unsigned int nbits, unsigned long e_value,
+ gcry_sexp_t deriveparms, int *swapped)
+{
+ gcry_mpi_t p, q; /* The two primes. */
+ gcry_mpi_t e; /* The public exponent. */
+ gcry_mpi_t n; /* The public key. */
+ gcry_mpi_t d; /* The private key */
+ gcry_mpi_t u; /* The inverse of p and q. */
+ gcry_mpi_t pm1; /* p - 1 */
+ gcry_mpi_t qm1; /* q - 1 */
+ gcry_mpi_t phi; /* Euler totient. */
+ gcry_mpi_t f, g; /* Helper. */
+
+ *swapped = 0;
+
+ if (e_value == 1) /* Alias for a secure value. */
+ e_value = 65537;
+
+ /* Point 1 of section 4.1: k = 1024 + 256s with S >= 0 */
+ if (nbits < 1024 || (nbits % 256))
+ return GPG_ERR_INV_VALUE;
+
+ /* Point 2: 2 <= bitlength(e) < 2^{k-2}
+ Note that we do not need to check the upper bound because we use
+ an unsigned long for E and thus there is no way for E to reach
+ that limit. */
+ if (e_value < 3)
+ return GPG_ERR_INV_VALUE;
+
+ /* Our implementation requires E to be odd. */
+ if (!(e_value & 1))
+ return GPG_ERR_INV_VALUE;
+
+ /* Point 3: e > 0 or e 0 if it is to be randomly generated.
+ We support only a fixed E and thus there is no need for an extra test. */
+
+
+ /* Compute or extract the derive parameters. */
+ {
+ gcry_mpi_t xp1 = NULL;
+ gcry_mpi_t xp2 = NULL;
+ gcry_mpi_t xp = NULL;
+ gcry_mpi_t xq1 = NULL;
+ gcry_mpi_t xq2 = NULL;
+ gcry_mpi_t xq = NULL;
+ gcry_mpi_t tmpval;
+
+ if (!deriveparms)
+ {
+ /* Not given: Generate them. */
+ xp = gen_x931_parm_xp (nbits/2);
+ /* Make sure that |xp - xq| > 2^{nbits - 100} holds. */
+ tmpval = mpi_snew (nbits/2);
+ do
+ {
+ _gcry_mpi_release (xq);
+ xq = gen_x931_parm_xp (nbits/2);
+ mpi_sub (tmpval, xp, xq);
+ }
+ while (mpi_get_nbits (tmpval) <= (nbits/2 - 100));
+ _gcry_mpi_release (tmpval);
+
+ xp1 = gen_x931_parm_xi ();
+ xp2 = gen_x931_parm_xi ();
+ xq1 = gen_x931_parm_xi ();
+ xq2 = gen_x931_parm_xi ();
+
+ }
+ else
+ {
+ /* Parameters to derive the key are given. */
+ /* Note that we explicitly need to setup the values of tbl
+ because some compilers (e.g. OpenWatcom, IRIX) don't allow
+ to initialize a structure with automatic variables. */
+ struct { const char *name; gcry_mpi_t *value; } tbl[] = {
+ { "Xp1" },
+ { "Xp2" },
+ { "Xp" },
+ { "Xq1" },
+ { "Xq2" },
+ { "Xq" },
+ { NULL }
+ };
+ int idx;
+ gcry_sexp_t oneparm;
+
+ tbl[0].value = &xp1;
+ tbl[1].value = &xp2;
+ tbl[2].value = &xp;
+ tbl[3].value = &xq1;
+ tbl[4].value = &xq2;
+ tbl[5].value = &xq;
+
+ for (idx=0; tbl[idx].name; idx++)
+ {
+ oneparm = sexp_find_token (deriveparms, tbl[idx].name, 0);
+ if (oneparm)
+ {
+ *tbl[idx].value = sexp_nth_mpi (oneparm, 1, GCRYMPI_FMT_USG);
+ sexp_release (oneparm);
+ }
+ }
+ for (idx=0; tbl[idx].name; idx++)
+ if (!*tbl[idx].value)
+ break;
+ if (tbl[idx].name)
+ {
+ /* At least one parameter is missing. */
+ for (idx=0; tbl[idx].name; idx++)
+ _gcry_mpi_release (*tbl[idx].value);
+ return GPG_ERR_MISSING_VALUE;
+ }
+ }
+
+ e = mpi_alloc_set_ui (e_value);
+
+ /* Find two prime numbers. */
+ p = _gcry_derive_x931_prime (xp, xp1, xp2, e, NULL, NULL);
+ q = _gcry_derive_x931_prime (xq, xq1, xq2, e, NULL, NULL);
+ _gcry_mpi_release (xp); xp = NULL;
+ _gcry_mpi_release (xp1); xp1 = NULL;
+ _gcry_mpi_release (xp2); xp2 = NULL;
+ _gcry_mpi_release (xq); xq = NULL;
+ _gcry_mpi_release (xq1); xq1 = NULL;
+ _gcry_mpi_release (xq2); xq2 = NULL;
+ if (!p || !q)
+ {
+ _gcry_mpi_release (p);
+ _gcry_mpi_release (q);
+ _gcry_mpi_release (e);
+ return GPG_ERR_NO_PRIME;
+ }
+ }
+
+
+ /* Compute the public modulus. We make sure that p is smaller than
+ q to allow the use of the CRT. */
+ if (mpi_cmp (p, q) > 0 )
+ {
+ mpi_swap (p, q);
+ *swapped = 1;
+ }
+ n = mpi_new (nbits);
+ mpi_mul (n, p, q);
+
+ /* Compute the Euler totient: phi = (p-1)(q-1) */
+ pm1 = mpi_snew (nbits/2);
+ qm1 = mpi_snew (nbits/2);
+ phi = mpi_snew (nbits);
+ mpi_sub_ui (pm1, p, 1);
+ mpi_sub_ui (qm1, q, 1);
+ mpi_mul (phi, pm1, qm1);
+
+ g = mpi_snew (nbits);
+ gcry_assert (mpi_gcd (g, e, phi));
+
+ /* Compute: f = lcm(p-1,q-1) = phi / gcd(p-1,q-1) */
+ mpi_gcd (g, pm1, qm1);
+ f = pm1; pm1 = NULL;
+ _gcry_mpi_release (qm1); qm1 = NULL;
+ mpi_fdiv_q (f, phi, g);
+ _gcry_mpi_release (phi); phi = NULL;
+ d = g; g = NULL;
+ /* Compute the secret key: d = e^{-1} mod lcm(p-1,q-1) */
+ mpi_invm (d, e, f);
+
+ /* Compute the inverse of p and q. */
+ u = f; f = NULL;
+ mpi_invm (u, p, q );
+
+ if( DBG_CIPHER )
+ {
+ if (*swapped)
+ log_debug ("p and q are swapped\n");
+ log_mpidump(" p", p );
+ log_mpidump(" q", q );
+ log_mpidump(" n", n );
+ log_mpidump(" e", e );
+ log_mpidump(" d", d );
+ log_mpidump(" u", u );
+ }
+
+
+ sk->n = n;
+ sk->e = e;
+ sk->p = p;
+ sk->q = q;
+ sk->d = d;
+ sk->u = u;
+
+ /* Now we can test our keys. */
+ if (test_keys (sk, nbits - 64))
+ {
+ _gcry_mpi_release (sk->n); sk->n = NULL;
+ _gcry_mpi_release (sk->e); sk->e = NULL;
+ _gcry_mpi_release (sk->p); sk->p = NULL;
+ _gcry_mpi_release (sk->q); sk->q = NULL;
+ _gcry_mpi_release (sk->d); sk->d = NULL;
+ _gcry_mpi_release (sk->u); sk->u = NULL;
+ fips_signal_error ("self-test after key generation failed");
+ return GPG_ERR_SELFTEST_FAILED;
+ }
+
+ return 0;
+}
+
+
+/****************
+ * Test whether the secret key is valid.
+ * Returns: true if this is a valid key.
+ */
+static int
+check_secret_key( RSA_secret_key *sk )
+{
+ int rc;
+ gcry_mpi_t temp = mpi_alloc( mpi_get_nlimbs(sk->p)*2 );
+
+ mpi_mul(temp, sk->p, sk->q );
+ rc = mpi_cmp( temp, sk->n );
+ mpi_free(temp);
+ return !rc;
+}
+
+
+
+/****************
+ * Public key operation. Encrypt INPUT with PKEY and put result into OUTPUT.
+ *
+ * c = m^e mod n
+ *
+ * Where c is OUTPUT, m is INPUT and e,n are elements of PKEY.
+ */
+static void
+public(gcry_mpi_t output, gcry_mpi_t input, RSA_public_key *pkey )
+{
+ if( output == input ) /* powm doesn't like output and input the same */
+ {
+ gcry_mpi_t x = mpi_alloc( mpi_get_nlimbs(input)*2 );
+ mpi_powm( x, input, pkey->e, pkey->n );
+ mpi_set(output, x);
+ mpi_free(x);
+ }
+ else
+ mpi_powm( output, input, pkey->e, pkey->n );
+}
+
+#if 0
+static void
+stronger_key_check ( RSA_secret_key *skey )
+{
+ gcry_mpi_t t = mpi_alloc_secure ( 0 );
+ gcry_mpi_t t1 = mpi_alloc_secure ( 0 );
+ gcry_mpi_t t2 = mpi_alloc_secure ( 0 );
+ gcry_mpi_t phi = mpi_alloc_secure ( 0 );
+
+ /* check that n == p * q */
+ mpi_mul( t, skey->p, skey->q);
+ if (mpi_cmp( t, skey->n) )
+ log_info ( "RSA Oops: n != p * q\n" );
+
+ /* check that p is less than q */
+ if( mpi_cmp( skey->p, skey->q ) > 0 )
+ {
+ log_info ("RSA Oops: p >= q - fixed\n");
+ _gcry_mpi_swap ( skey->p, skey->q);
+ }
+
+ /* check that e divides neither p-1 nor q-1 */
+ mpi_sub_ui(t, skey->p, 1 );
+ mpi_fdiv_r(t, t, skey->e );
+ if ( !mpi_cmp_ui( t, 0) )
+ log_info ( "RSA Oops: e divides p-1\n" );
+ mpi_sub_ui(t, skey->q, 1 );
+ mpi_fdiv_r(t, t, skey->e );
+ if ( !mpi_cmp_ui( t, 0) )
+ log_info ( "RSA Oops: e divides q-1\n" );
+
+ /* check that d is correct */
+ mpi_sub_ui( t1, skey->p, 1 );
+ mpi_sub_ui( t2, skey->q, 1 );
+ mpi_mul( phi, t1, t2 );
+ gcry_mpi_gcd(t, t1, t2);
+ mpi_fdiv_q(t, phi, t);
+ mpi_invm(t, skey->e, t );
+ if ( mpi_cmp(t, skey->d ) )
+ {
+ log_info ( "RSA Oops: d is wrong - fixed\n");
+ mpi_set (skey->d, t);
+ log_printmpi (" fixed d", skey->d);
+ }
+
+ /* check for correctness of u */
+ mpi_invm(t, skey->p, skey->q );
+ if ( mpi_cmp(t, skey->u ) )
+ {
+ log_info ( "RSA Oops: u is wrong - fixed\n");
+ mpi_set (skey->u, t);
+ log_printmpi (" fixed u", skey->u);
+ }
+
+ log_info ( "RSA secret key check finished\n");
+
+ mpi_free (t);
+ mpi_free (t1);
+ mpi_free (t2);
+ mpi_free (phi);
+}
+#endif
+
+
+
+/* Secret key operation - standard version.
+ *
+ * m = c^d mod n
+ */
+static void
+secret_core_std (gcry_mpi_t M, gcry_mpi_t C,
+ gcry_mpi_t D, gcry_mpi_t N)
+{
+ mpi_powm (M, C, D, N);
+}
+
+
+/* Secret key operation - using the CRT.
+ *
+ * m1 = c ^ (d mod (p-1)) mod p
+ * m2 = c ^ (d mod (q-1)) mod q
+ * h = u * (m2 - m1) mod q
+ * m = m1 + h * p
+ */
+static void
+secret_core_crt (gcry_mpi_t M, gcry_mpi_t C,
+ gcry_mpi_t D, unsigned int Nlimbs,
+ gcry_mpi_t P, gcry_mpi_t Q, gcry_mpi_t U)
+{
+ gcry_mpi_t m1 = mpi_alloc_secure ( Nlimbs + 1 );
+ gcry_mpi_t m2 = mpi_alloc_secure ( Nlimbs + 1 );
+ gcry_mpi_t h = mpi_alloc_secure ( Nlimbs + 1 );
+ gcry_mpi_t D_blind = mpi_alloc_secure ( Nlimbs + 1 );
+ gcry_mpi_t r;
+ unsigned int r_nbits;
+
+ r_nbits = mpi_get_nbits (P) / 4;
+ if (r_nbits < 96)
+ r_nbits = 96;
+ r = mpi_secure_new (r_nbits);
+
+ /* d_blind = (d mod (p-1)) + (p-1) * r */
+ /* m1 = c ^ d_blind mod p */
+ _gcry_mpi_randomize (r, r_nbits, GCRY_WEAK_RANDOM);
+ mpi_set_highbit (r, r_nbits - 1);
+ mpi_sub_ui ( h, P, 1 );
+ mpi_mul ( D_blind, h, r );
+ mpi_fdiv_r ( h, D, h );
+ mpi_add ( D_blind, D_blind, h );
+ mpi_powm ( m1, C, D_blind, P );
+
+ /* d_blind = (d mod (q-1)) + (q-1) * r */
+ /* m2 = c ^ d_blind mod q */
+ _gcry_mpi_randomize (r, r_nbits, GCRY_WEAK_RANDOM);
+ mpi_set_highbit (r, r_nbits - 1);
+ mpi_sub_ui ( h, Q, 1 );
+ mpi_mul ( D_blind, h, r );
+ mpi_fdiv_r ( h, D, h );
+ mpi_add ( D_blind, D_blind, h );
+ mpi_powm ( m2, C, D_blind, Q );
+
+ mpi_free ( r );
+ mpi_free ( D_blind );
+
+ /* h = u * ( m2 - m1 ) mod q */
+ mpi_sub ( h, m2, m1 );
+ if ( mpi_has_sign ( h ) )
+ mpi_add ( h, h, Q );
+ mpi_mulm ( h, U, h, Q );
+
+ /* m = m1 + h * p */
+ mpi_mul ( h, h, P );
+ mpi_add ( M, m1, h );
+
+ mpi_free ( h );
+ mpi_free ( m1 );
+ mpi_free ( m2 );
+}
+
+
+/* Secret key operation.
+ * Encrypt INPUT with SKEY and put result into
+ * OUTPUT. SKEY has the secret key parameters.
+ */
+static void
+secret (gcry_mpi_t output, gcry_mpi_t input, RSA_secret_key *skey )
+{
+ /* Remove superfluous leading zeroes from INPUT. */
+ mpi_normalize (input);
+
+ if (!skey->p || !skey->q || !skey->u)
+ {
+ secret_core_std (output, input, skey->d, skey->n);
+ }
+ else
+ {
+ secret_core_crt (output, input, skey->d, mpi_get_nlimbs (skey->n),
+ skey->p, skey->q, skey->u);
+ }
+}
+
+
+static void
+secret_blinded (gcry_mpi_t output, gcry_mpi_t input,
+ RSA_secret_key *sk, unsigned int nbits)
+{
+ gcry_mpi_t r; /* Random number needed for blinding. */
+ gcry_mpi_t ri; /* Modular multiplicative inverse of r. */
+ gcry_mpi_t bldata; /* Blinded data to decrypt. */
+
+ /* First, we need a random number r between 0 and n - 1, which is
+ * relatively prime to n (i.e. it is neither p nor q). The random
+ * number needs to be only unpredictable, thus we employ the
+ * gcry_create_nonce function by using GCRY_WEAK_RANDOM with
+ * gcry_mpi_randomize. */
+ r = mpi_snew (nbits);
+ ri = mpi_snew (nbits);
+ bldata = mpi_snew (nbits);
+
+ do
+ {
+ _gcry_mpi_randomize (r, nbits, GCRY_WEAK_RANDOM);
+ mpi_mod (r, r, sk->n);
+ }
+ while (!mpi_invm (ri, r, sk->n));
+
+ /* Do blinding. We calculate: y = (x * r^e) mod n, where r is the
+ * random number, e is the public exponent, x is the non-blinded
+ * input data and n is the RSA modulus. */
+ mpi_powm (bldata, r, sk->e, sk->n);
+ mpi_mulm (bldata, bldata, input, sk->n);
+
+ /* Perform decryption. */
+ secret (output, bldata, sk);
+ _gcry_mpi_release (bldata);
+
+ /* Undo blinding. Here we calculate: y = (x * r^-1) mod n, where x
+ * is the blinded decrypted data, ri is the modular multiplicative
+ * inverse of r and n is the RSA modulus. */
+ mpi_mulm (output, output, ri, sk->n);
+
+ _gcry_mpi_release (r);
+ _gcry_mpi_release (ri);
+}
+
+
+/*********************************************
+ ************** interface ******************
+ *********************************************/
+
+static gcry_err_code_t
+rsa_generate (const gcry_sexp_t genparms, gcry_sexp_t *r_skey)
+{
+ gpg_err_code_t ec;
+ unsigned int nbits;
+ unsigned long evalue;
+ RSA_secret_key sk;
+ gcry_sexp_t deriveparms;
+ int flags = 0;
+ gcry_sexp_t l1;
+ gcry_sexp_t swap_info = NULL;
+
+ memset (&sk, 0, sizeof sk);
+
+ ec = _gcry_pk_util_get_nbits (genparms, &nbits);
+ if (ec)
+ return ec;
+
+ ec = _gcry_pk_util_get_rsa_use_e (genparms, &evalue);
+ if (ec)
+ return ec;
+
+ /* Parse the optional flags list. */
+ l1 = sexp_find_token (genparms, "flags", 0);
+ if (l1)
+ {
+ ec = _gcry_pk_util_parse_flaglist (l1, &flags, NULL);
+ sexp_release (l1);
+ if (ec)
+ return ec;
+ }
+
+ deriveparms = (genparms?
+ sexp_find_token (genparms, "derive-parms", 0) : NULL);
+ if (!deriveparms)
+ {
+ /* Parse the optional "use-x931" flag. */
+ l1 = sexp_find_token (genparms, "use-x931", 0);
+ if (l1)
+ {
+ flags |= PUBKEY_FLAG_USE_X931;
+ sexp_release (l1);
+ }
+ }
+
+ if (deriveparms || (flags & PUBKEY_FLAG_USE_X931))
+ {
+ int swapped;
+ ec = generate_x931 (&sk, nbits, evalue, deriveparms, &swapped);
+ sexp_release (deriveparms);
+ if (!ec && swapped)
+ ec = sexp_new (&swap_info, "(misc-key-info(p-q-swapped))", 0, 1);
+ }
+ else
+ {
+ /* 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);
+ }
+ }
+ deriveparms = (genparms? sexp_find_token (genparms, "test-parms", 0)
+ /**/ : NULL);
+
+ /* Generate. */
+ if (deriveparms || fips_mode())
+ {
+ ec = generate_fips (&sk, nbits, evalue, deriveparms,
+ !!(flags & PUBKEY_FLAG_TRANSIENT_KEY));
+ }
+ else
+ {
+ ec = generate_std (&sk, nbits, evalue,
+ !!(flags & PUBKEY_FLAG_TRANSIENT_KEY));
+ }
+ sexp_release (deriveparms);
+ }
+
+ if (!ec)
+ {
+ ec = sexp_build (r_skey, NULL,
+ "(key-data"
+ " (public-key"
+ " (rsa(n%m)(e%m)))"
+ " (private-key"
+ " (rsa(n%m)(e%m)(d%m)(p%m)(q%m)(u%m)))"
+ " %S)",
+ sk.n, sk.e,
+ sk.n, sk.e, sk.d, sk.p, sk.q, sk.u,
+ swap_info);
+ }
+
+ mpi_free (sk.n);
+ mpi_free (sk.e);
+ mpi_free (sk.p);
+ mpi_free (sk.q);
+ mpi_free (sk.d);
+ mpi_free (sk.u);
+ sexp_release (swap_info);
+
+ return ec;
+}
+
+
+static gcry_err_code_t
+rsa_check_secret_key (gcry_sexp_t keyparms)
+{
+ gcry_err_code_t rc;
+ RSA_secret_key sk = {NULL, NULL, NULL, NULL, NULL, NULL};
+
+ /* To check the key we need the optional parameters. */
+ rc = sexp_extract_param (keyparms, NULL, "nedpqu",
+ &sk.n, &sk.e, &sk.d, &sk.p, &sk.q, &sk.u,
+ NULL);
+ if (rc)
+ goto leave;
+
+ if (!check_secret_key (&sk))
+ rc = GPG_ERR_BAD_SECKEY;
+
+ leave:
+ _gcry_mpi_release (sk.n);
+ _gcry_mpi_release (sk.e);
+ _gcry_mpi_release (sk.d);
+ _gcry_mpi_release (sk.p);
+ _gcry_mpi_release (sk.q);
+ _gcry_mpi_release (sk.u);
+ if (DBG_CIPHER)
+ log_debug ("rsa_testkey => %s\n", gpg_strerror (rc));
+ return rc;
+}
+
+
+static gcry_err_code_t
+rsa_encrypt (gcry_sexp_t *r_ciph, gcry_sexp_t s_data, gcry_sexp_t keyparms)
+{
+ gcry_err_code_t rc;
+ struct pk_encoding_ctx ctx;
+ gcry_mpi_t data = NULL;
+ RSA_public_key pk = {NULL, NULL};
+ gcry_mpi_t ciph = NULL;
+
+ _gcry_pk_util_init_encoding_ctx (&ctx, PUBKEY_OP_ENCRYPT,
+ rsa_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 ("rsa_encrypt data", data);
+ if (!data || mpi_is_opaque (data))
+ {
+ rc = GPG_ERR_INV_DATA;
+ goto leave;
+ }
+
+ /* Extract the key. */
+ rc = sexp_extract_param (keyparms, NULL, "ne", &pk.n, &pk.e, NULL);
+ if (rc)
+ goto leave;
+ if (DBG_CIPHER)
+ {
+ log_mpidump ("rsa_encrypt n", pk.n);
+ log_mpidump ("rsa_encrypt e", pk.e);
+ }
+
+ /* Do RSA computation and build result. */
+ ciph = mpi_new (0);
+ public (ciph, data, &pk);
+ if (DBG_CIPHER)
+ log_mpidump ("rsa_encrypt res", ciph);
+ if ((ctx.flags & PUBKEY_FLAG_FIXEDLEN))
+ {
+ /* We need to make sure to return the correct length to avoid
+ problems with missing leading zeroes. */
+ unsigned char *em;
+ size_t emlen = (mpi_get_nbits (pk.n)+7)/8;
+
+ rc = _gcry_mpi_to_octet_string (&em, NULL, ciph, emlen);
+ if (!rc)
+ {
+ rc = sexp_build (r_ciph, NULL, "(enc-val(rsa(a%b)))", (int)emlen, em);
+ xfree (em);
+ }
+ }
+ else
+ rc = sexp_build (r_ciph, NULL, "(enc-val(rsa(a%m)))", ciph);
+
+ leave:
+ _gcry_mpi_release (ciph);
+ _gcry_mpi_release (pk.n);
+ _gcry_mpi_release (pk.e);
+ _gcry_mpi_release (data);
+ _gcry_pk_util_free_encoding_ctx (&ctx);
+ if (DBG_CIPHER)
+ log_debug ("rsa_encrypt => %s\n", gpg_strerror (rc));
+ return rc;
+}
+
+
+static gcry_err_code_t
+rsa_decrypt (gcry_sexp_t *r_plain, gcry_sexp_t s_data, gcry_sexp_t keyparms)
+
+{
+ gpg_err_code_t rc;
+ struct pk_encoding_ctx ctx;
+ gcry_sexp_t l1 = NULL;
+ gcry_mpi_t data = NULL;
+ RSA_secret_key sk = {NULL, NULL, NULL, NULL, NULL, NULL};
+ gcry_mpi_t plain = NULL;
+ unsigned char *unpad = NULL;
+ size_t unpadlen = 0;
+
+ _gcry_pk_util_init_encoding_ctx (&ctx, PUBKEY_OP_DECRYPT,
+ rsa_get_nbits (keyparms));
+
+ /* Extract the data. */
+ rc = _gcry_pk_util_preparse_encval (s_data, rsa_names, &l1, &ctx);
+ if (rc)
+ goto leave;
+ rc = sexp_extract_param (l1, NULL, "a", &data, NULL);
+ if (rc)
+ goto leave;
+ if (DBG_CIPHER)
+ log_printmpi ("rsa_decrypt data", data);
+ if (mpi_is_opaque (data))
+ {
+ rc = GPG_ERR_INV_DATA;
+ goto leave;
+ }
+
+ /* Extract the key. */
+ rc = sexp_extract_param (keyparms, NULL, "nedp?q?u?",
+ &sk.n, &sk.e, &sk.d, &sk.p, &sk.q, &sk.u,
+ NULL);
+ if (rc)
+ goto leave;
+ if (DBG_CIPHER)
+ {
+ log_printmpi ("rsa_decrypt n", sk.n);
+ log_printmpi ("rsa_decrypt e", sk.e);
+ if (!fips_mode ())
+ {
+ log_printmpi ("rsa_decrypt d", sk.d);
+ log_printmpi ("rsa_decrypt p", sk.p);
+ log_printmpi ("rsa_decrypt q", sk.q);
+ log_printmpi ("rsa_decrypt u", sk.u);
+ }
+ }
+
+ /* Better make sure that there are no superfluous leading zeroes in
+ the input and it has not been "padded" using multiples of N.
+ This mitigates side-channel attacks (CVE-2013-4576). */
+ mpi_normalize (data);
+ mpi_fdiv_r (data, data, sk.n);
+
+ /* Allocate MPI for the plaintext. */
+ plain = mpi_snew (ctx.nbits);
+
+ /* We use blinding by default to mitigate timing attacks which can
+ be practically mounted over the network as shown by Brumley and
+ Boney in 2003. */
+ if ((ctx.flags & PUBKEY_FLAG_NO_BLINDING))
+ secret (plain, data, &sk);
+ else
+ secret_blinded (plain, data, &sk, ctx.nbits);
+
+ if (DBG_CIPHER)
+ log_printmpi ("rsa_decrypt res", plain);
+
+ /* Reverse the encoding and build the s-expression. */
+ switch (ctx.encoding)
+ {
+ case PUBKEY_ENC_PKCS1:
+ rc = _gcry_rsa_pkcs1_decode_for_enc (&unpad, &unpadlen, ctx.nbits, plain);
+ mpi_free (plain);
+ plain = NULL;
+ if (!rc)
+ rc = sexp_build (r_plain, NULL, "(value %b)", (int)unpadlen, unpad);
+ break;
+
+ case PUBKEY_ENC_OAEP:
+ rc = _gcry_rsa_oaep_decode (&unpad, &unpadlen,
+ ctx.nbits, ctx.hash_algo,
+ plain, ctx.label, ctx.labellen);
+ mpi_free (plain);
+ plain = NULL;
+ if (!rc)
+ rc = sexp_build (r_plain, NULL, "(value %b)", (int)unpadlen, unpad);
+ break;
+
+ default:
+ /* Raw format. For backward compatibility we need to assume a
+ signed mpi by using the sexp format string "%m". */
+ rc = sexp_build (r_plain, NULL,
+ (ctx.flags & PUBKEY_FLAG_LEGACYRESULT)
+ ? "%m":"(value %m)", plain);
+ break;
+ }
+
+ leave:
+ xfree (unpad);
+ _gcry_mpi_release (plain);
+ _gcry_mpi_release (sk.n);
+ _gcry_mpi_release (sk.e);
+ _gcry_mpi_release (sk.d);
+ _gcry_mpi_release (sk.p);
+ _gcry_mpi_release (sk.q);
+ _gcry_mpi_release (sk.u);
+ _gcry_mpi_release (data);
+ sexp_release (l1);
+ _gcry_pk_util_free_encoding_ctx (&ctx);
+ if (DBG_CIPHER)
+ log_debug ("rsa_decrypt => %s\n", gpg_strerror (rc));
+ return rc;
+}
+
+
+static gcry_err_code_t
+rsa_sign (gcry_sexp_t *r_sig, gcry_sexp_t s_data, gcry_sexp_t keyparms)
+{
+ gpg_err_code_t rc;
+ struct pk_encoding_ctx ctx;
+ gcry_mpi_t data = NULL;
+ RSA_secret_key sk = {NULL, NULL, NULL, NULL, NULL, NULL};
+ RSA_public_key pk;
+ gcry_mpi_t sig = NULL;
+ gcry_mpi_t result = NULL;
+
+ _gcry_pk_util_init_encoding_ctx (&ctx, PUBKEY_OP_SIGN,
+ rsa_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_printmpi ("rsa_sign data", data);
+ if (mpi_is_opaque (data))
+ {
+ rc = GPG_ERR_INV_DATA;
+ goto leave;
+ }
+
+ /* Extract the key. */
+ rc = sexp_extract_param (keyparms, NULL, "nedp?q?u?",
+ &sk.n, &sk.e, &sk.d, &sk.p, &sk.q, &sk.u,
+ NULL);
+ if (rc)
+ goto leave;
+ if (DBG_CIPHER)
+ {
+ log_printmpi ("rsa_sign n", sk.n);
+ log_printmpi ("rsa_sign e", sk.e);
+ if (!fips_mode ())
+ {
+ log_printmpi ("rsa_sign d", sk.d);
+ log_printmpi ("rsa_sign p", sk.p);
+ log_printmpi ("rsa_sign q", sk.q);
+ log_printmpi ("rsa_sign u", sk.u);
+ }
+ }
+
+ /* Do RSA computation. */
+ sig = mpi_new (0);
+ if ((ctx.flags & PUBKEY_FLAG_NO_BLINDING))
+ secret (sig, data, &sk);
+ else
+ secret_blinded (sig, data, &sk, ctx.nbits);
+ if (DBG_CIPHER)
+ log_printmpi ("rsa_sign res", sig);
+
+ /* Check that the created signature is good. This detects a failure
+ of the CRT algorithm (Lenstra's attack on RSA's use of the CRT). */
+ result = mpi_new (0);
+ pk.n = sk.n;
+ pk.e = sk.e;
+ public (result, sig, &pk);
+ if (mpi_cmp (result, data))
+ {
+ rc = GPG_ERR_BAD_SIGNATURE;
+ goto leave;
+ }
+
+ /* Convert the result. */
+ if ((ctx.flags & PUBKEY_FLAG_FIXEDLEN))
+ {
+ /* We need to make sure to return the correct length to avoid
+ problems with missing leading zeroes. */
+ unsigned char *em;
+ size_t emlen = (mpi_get_nbits (sk.n)+7)/8;
+
+ rc = _gcry_mpi_to_octet_string (&em, NULL, sig, emlen);
+ if (!rc)
+ {
+ rc = sexp_build (r_sig, NULL, "(sig-val(rsa(s%b)))", (int)emlen, em);
+ xfree (em);
+ }
+ }
+ else
+ rc = sexp_build (r_sig, NULL, "(sig-val(rsa(s%M)))", sig);
+
+
+ leave:
+ _gcry_mpi_release (result);
+ _gcry_mpi_release (sig);
+ _gcry_mpi_release (sk.n);
+ _gcry_mpi_release (sk.e);
+ _gcry_mpi_release (sk.d);
+ _gcry_mpi_release (sk.p);
+ _gcry_mpi_release (sk.q);
+ _gcry_mpi_release (sk.u);
+ _gcry_mpi_release (data);
+ _gcry_pk_util_free_encoding_ctx (&ctx);
+ if (DBG_CIPHER)
+ log_debug ("rsa_sign => %s\n", gpg_strerror (rc));
+ return rc;
+}
+
+
+static gcry_err_code_t
+rsa_verify (gcry_sexp_t s_sig, gcry_sexp_t s_data, gcry_sexp_t keyparms)
+{
+ gcry_err_code_t rc;
+ struct pk_encoding_ctx ctx;
+ gcry_sexp_t l1 = NULL;
+ gcry_mpi_t sig = NULL;
+ gcry_mpi_t data = NULL;
+ RSA_public_key pk = { NULL, NULL };
+ gcry_mpi_t result = NULL;
+
+ _gcry_pk_util_init_encoding_ctx (&ctx, PUBKEY_OP_VERIFY,
+ rsa_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_printmpi ("rsa_verify data", data);
+ if (mpi_is_opaque (data))
+ {
+ rc = GPG_ERR_INV_DATA;
+ goto leave;
+ }
+
+ /* Extract the signature value. */
+ rc = _gcry_pk_util_preparse_sigval (s_sig, rsa_names, &l1, NULL);
+ if (rc)
+ goto leave;
+ rc = sexp_extract_param (l1, NULL, "s", &sig, NULL);
+ if (rc)
+ goto leave;
+ if (DBG_CIPHER)
+ log_printmpi ("rsa_verify sig", sig);
+
+ /* Extract the key. */
+ rc = sexp_extract_param (keyparms, NULL, "ne", &pk.n, &pk.e, NULL);
+ if (rc)
+ goto leave;
+ if (DBG_CIPHER)
+ {
+ log_printmpi ("rsa_verify n", pk.n);
+ log_printmpi ("rsa_verify e", pk.e);
+ }
+
+ /* Do RSA computation and compare. */
+ result = mpi_new (0);
+ public (result, sig, &pk);
+ if (DBG_CIPHER)
+ log_printmpi ("rsa_verify cmp", result);
+ if (ctx.verify_cmp)
+ rc = ctx.verify_cmp (&ctx, result);
+ else
+ rc = mpi_cmp (result, data) ? GPG_ERR_BAD_SIGNATURE : 0;
+
+ leave:
+ _gcry_mpi_release (result);
+ _gcry_mpi_release (pk.n);
+ _gcry_mpi_release (pk.e);
+ _gcry_mpi_release (data);
+ _gcry_mpi_release (sig);
+ sexp_release (l1);
+ _gcry_pk_util_free_encoding_ctx (&ctx);
+ if (DBG_CIPHER)
+ log_debug ("rsa_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:
+ *
+ * (rsa
+ * (n )
+ * (e ))
+ *
+ * More parameters may be given but we only need N here.
+ */
+static unsigned int
+rsa_get_nbits (gcry_sexp_t parms)
+{
+ gcry_sexp_t l1;
+ gcry_mpi_t n;
+ unsigned int nbits;
+
+ l1 = sexp_find_token (parms, "n", 1);
+ if (!l1)
+ return 0; /* Parameter N not found. */
+
+ n = sexp_nth_mpi (l1, 1, GCRYMPI_FMT_USG);
+ sexp_release (l1);
+ nbits = n? mpi_get_nbits (n) : 0;
+ _gcry_mpi_release (n);
+ return nbits;
+}
+
+
+/* Compute a keygrip. MD is the hash context which we are going to
+ update. KEYPARAM is an S-expression with the key parameters, this
+ is usually a public key but may also be a secret key. An example
+ of such an S-expression is:
+
+ (rsa
+ (n #00B...#)
+ (e #010001#))
+
+ PKCS-15 says that for RSA only the modulus should be hashed -
+ however, it is not clear whether this is meant to use the raw bytes
+ (assuming this is an unsigned integer) or whether the DER required
+ 0 should be prefixed. We hash the raw bytes. */
+static gpg_err_code_t
+compute_keygrip (gcry_md_hd_t md, gcry_sexp_t keyparam)
+{
+ gcry_sexp_t l1;
+ const char *data;
+ size_t datalen;
+
+ l1 = sexp_find_token (keyparam, "n", 1);
+ if (!l1)
+ return GPG_ERR_NO_OBJ;
+
+ data = sexp_nth_data (l1, 1, &datalen);
+ if (!data)
+ {
+ sexp_release (l1);
+ return GPG_ERR_NO_OBJ;
+ }
+
+ _gcry_md_write (md, data, datalen);
+ sexp_release (l1);
+
+ return 0;
+}
+
+
+
+
+/*
+ Self-test section.
+ */
+
+static const char *
+selftest_sign_2048 (gcry_sexp_t pkey, gcry_sexp_t skey)
+{
+ static const char sample_data[] =
+ "(data (flags pkcs1)"
+ " (hash sha256 #11223344556677889900aabbccddeeff"
+ /**/ "102030405060708090a0b0c0d0f01121#))";
+ static const char sample_data_bad[] =
+ "(data (flags pkcs1)"
+ " (hash sha256 #11223344556677889900aabbccddeeff"
+ /**/ "802030405060708090a0b0c0d0f01121#))";
+
+ const char *errtxt = NULL;
+ gcry_error_t err;
+ gcry_sexp_t data = NULL;
+ gcry_sexp_t data_bad = NULL;
+ gcry_sexp_t sig = NULL;
+ /* raw signature data reference */
+ const char ref_data[] =
+ "6252a19a11e1d5155ed9376036277193d644fa239397fff03e9b92d6f86415d6"
+ "d30da9273775f290e580d038295ff8ff89522becccfa6ae870bf76b76df402a8"
+ "54f69347e3db3de8e1e7d4dada281ec556810c7a8ecd0b5f51f9b1c0e7aa7557"
+ "61aa2b8ba5f811304acc6af0eca41fe49baf33bf34eddaf44e21e036ac7f0b68"
+ "03cdef1c60021fb7b5b97ebacdd88ab755ce29af568dbc5728cc6e6eff42618d"
+ "62a0386ca8beed46402bdeeef29b6a3feded906bace411a06a39192bf516ae10"
+ "67e4320fa8ea113968525f4574d022a3ceeaafdc41079efe1f22cc94bf59d8d3"
+ "328085da9674857db56de5978a62394aab48aa3b72e23a1b16260cfd9daafe65";
+ gcry_mpi_t ref_mpi = NULL;
+ gcry_mpi_t sig_mpi = 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_mpi_scan(&ref_mpi, GCRYMPI_FMT_HEX, ref_data, 0, NULL);
+ if (err)
+ {
+ errtxt = "converting ref_data to mpi failed";
+ goto leave;
+ }
+
+ err = _gcry_sexp_extract_param(sig, "sig-val!rsa", "s", &sig_mpi, NULL);
+ if (err)
+ {
+ errtxt = "extracting signature data failed";
+ goto leave;
+ }
+
+ if (mpi_cmp (sig_mpi, ref_mpi))
+ {
+ errtxt = "signature does not match reference data";
+ 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);
+ _gcry_mpi_release (ref_mpi);
+ _gcry_mpi_release (sig_mpi);
+ return errtxt;
+}
+
+
+
+/* Given an S-expression ENCR_DATA of the form:
+
+ (enc-val
+ (rsa
+ (a a-value)))
+
+ as returned by gcry_pk_decrypt, return the the A-VALUE. On error,
+ return NULL. */
+static gcry_mpi_t
+extract_a_from_sexp (gcry_sexp_t encr_data)
+{
+ gcry_sexp_t l1, l2, l3;
+ gcry_mpi_t a_value;
+
+ l1 = sexp_find_token (encr_data, "enc-val", 0);
+ if (!l1)
+ return NULL;
+ l2 = sexp_find_token (l1, "rsa", 0);
+ sexp_release (l1);
+ if (!l2)
+ return NULL;
+ l3 = sexp_find_token (l2, "a", 0);
+ sexp_release (l2);
+ if (!l3)
+ return NULL;
+ a_value = sexp_nth_mpi (l3, 1, 0);
+ sexp_release (l3);
+
+ return a_value;
+}
+
+
+static const char *
+selftest_encr_2048 (gcry_sexp_t pkey, gcry_sexp_t skey)
+{
+ const char *errtxt = NULL;
+ gcry_error_t err;
+ static const char plaintext[] =
+ "Jim quickly realized that the beautiful gowns are expensive.";
+ gcry_sexp_t plain = NULL;
+ gcry_sexp_t encr = NULL;
+ gcry_mpi_t ciphertext = NULL;
+ gcry_sexp_t decr = NULL;
+ char *decr_plaintext = NULL;
+ gcry_sexp_t tmplist = NULL;
+ /* expected result of encrypting the plaintext with sample_secret_key */
+ static const char ref_data[] =
+ "18022e2593a402a737caaa93b4c7e750e20ca265452980e1d6b7710fbd3e"
+ "7dce72be5c2110fb47691cb38f42170ee3b4a37f2498d4a51567d762585e"
+ "4cb81d04fbc7df4144f8e5eac2d4b8688521b64011f11d7ad53f4c874004"
+ "819856f2e2a6f83d1c9c4e73ac26089789c14482b0b8d44139133c88c4a5"
+ "2dba9dd6d6ffc622666b7d129168333d999706af30a2d7d272db7734e5ed"
+ "fb8c64ea3018af3ad20f4a013a5060cb0f5e72753967bebe294280a6ed0d"
+ "dbd3c4f11d0a8696e9d32a0dc03deb0b5e49b2cbd1503392642d4e1211f3"
+ "e8e2ee38abaa3671ccd57fcde8ca76e85fd2cb77c35706a970a213a27352"
+ "cec92a9604d543ddb5fc478ff50e0622";
+ gcry_mpi_t ref_mpi = NULL;
+
+ /* Put the plaintext into an S-expression. */
+ err = sexp_build (&plain, NULL, "(data (flags raw) (value %s))", plaintext);
+ if (err)
+ {
+ errtxt = "converting data failed";
+ goto leave;
+ }
+
+ /* Encrypt. */
+ err = _gcry_pk_encrypt (&encr, plain, pkey);
+ if (err)
+ {
+ errtxt = "encrypt failed";
+ goto leave;
+ }
+
+ err = _gcry_mpi_scan(&ref_mpi, GCRYMPI_FMT_HEX, ref_data, 0, NULL);
+ if (err)
+ {
+ errtxt = "converting encrydata to mpi failed";
+ goto leave;
+ }
+
+ /* Extraxt the ciphertext from the returned S-expression. */
+ /*sexp_dump (encr);*/
+ ciphertext = extract_a_from_sexp (encr);
+ if (!ciphertext)
+ {
+ errtxt = "gcry_pk_decrypt returned garbage";
+ goto leave;
+ }
+
+ /* Check that the ciphertext does no match the plaintext. */
+ /* _gcry_log_printmpi ("plaintext", plaintext); */
+ /* _gcry_log_printmpi ("ciphertxt", ciphertext); */
+ if (mpi_cmp (ref_mpi, ciphertext))
+ {
+ errtxt = "ciphertext doesn't match reference data";
+ goto leave;
+ }
+
+ /* Decrypt. */
+ err = _gcry_pk_decrypt (&decr, encr, skey);
+ if (err)
+ {
+ errtxt = "decrypt failed";
+ goto leave;
+ }
+
+ /* Extract the decrypted data from the S-expression. Note that the
+ output of gcry_pk_decrypt depends on whether a flags lists occurs
+ in its input data. Because we passed the output of
+ gcry_pk_encrypt directly to gcry_pk_decrypt, such a flag value
+ won't be there as of today. To be prepared for future changes we
+ take care of it anyway. */
+ tmplist = sexp_find_token (decr, "value", 0);
+ if (tmplist)
+ decr_plaintext = sexp_nth_string (tmplist, 1);
+ else
+ decr_plaintext = sexp_nth_string (decr, 0);
+ if (!decr_plaintext)
+ {
+ errtxt = "decrypt returned no plaintext";
+ goto leave;
+ }
+
+ /* Check that the decrypted plaintext matches the original plaintext. */
+ if (strcmp (plaintext, decr_plaintext))
+ {
+ errtxt = "mismatch";
+ goto leave;
+ }
+
+ leave:
+ sexp_release (tmplist);
+ xfree (decr_plaintext);
+ sexp_release (decr);
+ _gcry_mpi_release (ciphertext);
+ _gcry_mpi_release (ref_mpi);
+ sexp_release (encr);
+ sexp_release (plain);
+ return errtxt;
+}
+
+
+static gpg_err_code_t
+selftests_rsa (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_2048 (pkey, skey);
+ if (errtxt)
+ goto failed;
+
+ what = "encrypt";
+ errtxt = selftest_encr_2048 (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_RSA, 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_RSA:
+ ec = selftests_rsa (report);
+ break;
+ default:
+ ec = GPG_ERR_PUBKEY_ALGO;
+ break;
+
+ }
+ return ec;
+}
+
+
+
+
+gcry_pk_spec_t _gcry_pubkey_spec_rsa =
+ {
+ GCRY_PK_RSA, { 0, 1 },
+ (GCRY_PK_USAGE_SIGN | GCRY_PK_USAGE_ENCR),
+ "RSA", rsa_names,
+ "ne", "nedpqu", "a", "s", "n",
+ rsa_generate,
+ rsa_check_secret_key,
+ rsa_encrypt,
+ rsa_decrypt,
+ rsa_sign,
+ rsa_verify,
+ rsa_get_nbits,
+ run_selftests,
+ compute_keygrip
+ };
diff --git a/tests/keygen.c b/tests/keygen.c
index 6b6a60a..81cefb1 100644
--- a/tests/keygen.c
+++ b/tests/keygen.c
@@ -200,11 +200,11 @@ check_rsa_keys (void)
if (verbose)
- info ("creating 512 bit RSA key with e=257\n");
+ info ("creating 1024 bit RSA key with e=257\n");
rc = gcry_sexp_new (&keyparm,
"(genkey\n"
" (rsa\n"
- " (nbits 3:512)\n"
+ " (nbits 4:1024)\n"
" (rsa-use-e 3:257)\n"
" ))", 0, 1);
if (rc)
@@ -225,11 +225,11 @@ check_rsa_keys (void)
gcry_sexp_release (key);
if (verbose)
- info ("creating 512 bit RSA key with default e\n");
+ info ("creating 1024 bit RSA key with default e\n");
rc = gcry_sexp_new (&keyparm,
"(genkey\n"
" (rsa\n"
- " (nbits 3:512)\n"
+ " (nbits 4:1024)\n"
" (rsa-use-e 1:0)\n"
" ))", 0, 1);
if (rc)
@@ -309,12 +309,12 @@ check_dsa_keys (void)
}
if (verbose)
- info ("creating 1536 bit DSA key\n");
+ info ("creating 2048 bit DSA key\n");
rc = gcry_sexp_new (&keyparm,
"(genkey\n"
" (dsa\n"
- " (nbits 4:1536)\n"
- " (qbits 3:224)\n"
+ " (nbits 4:2048)\n"
+ " (qbits 3:256)\n"
" ))", 0, 1);
if (rc)
die ("error creating S-expression: %s\n", gpg_strerror (rc));
diff --git a/tests/keygen.c.tests b/tests/keygen.c.tests
new file mode 100644
index 0000000..6b6a60a
--- /dev/null
+++ b/tests/keygen.c.tests
@@ -0,0 +1,787 @@
+/* keygen.c - key generation regression tests
+ * Copyright (C) 2003, 2005, 2012 Free Software Foundation, Inc.
+ * Copyright (C) 2013, 2015 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 .
+ */
+
+#ifdef HAVE_CONFIG_H
+#include
+#endif
+#include
+#include
+#include
+#include
+#include "../src/gcrypt-int.h"
+
+
+#define PGM "keygen"
+#include "t-common.h"
+
+static int in_fips_mode;
+
+
+/* static void */
+/* show_note (const char *format, ...) */
+/* { */
+/* va_list arg_ptr; */
+
+/* if (!verbose && getenv ("srcdir")) */
+/* fputs (" ", stderr); /\* To align above "PASS: ". *\/ */
+/* else */
+/* fprintf (stderr, "%s: ", PGM); */
+/* va_start (arg_ptr, format); */
+/* vfprintf (stderr, format, arg_ptr); */
+/* if (*format && format[strlen(format)-1] != '\n') */
+/* putc ('\n', stderr); */
+/* va_end (arg_ptr); */
+/* } */
+
+
+static void
+show_sexp (const char *prefix, gcry_sexp_t a)
+{
+ char *buf;
+ size_t size;
+
+ fprintf (stderr, "%s: ", PGM);
+ if (prefix)
+ fputs (prefix, stderr);
+ size = gcry_sexp_sprint (a, GCRYSEXP_FMT_ADVANCED, NULL, 0);
+ buf = xmalloc (size);
+
+ gcry_sexp_sprint (a, GCRYSEXP_FMT_ADVANCED, buf, size);
+ fprintf (stderr, "%.*s", (int)size, buf);
+ gcry_free (buf);
+}
+
+
+static void
+show_mpi (const char *prefix, gcry_mpi_t a)
+{
+ char *buf;
+ void *bufaddr = &buf;
+ gcry_error_t rc;
+
+ fprintf (stderr, "%s: ", PGM);
+ if (prefix)
+ fputs (prefix, stderr);
+ rc = gcry_mpi_aprint (GCRYMPI_FMT_HEX, bufaddr, NULL, a);
+ if (rc)
+ fprintf (stderr, "[error printing number: %s]\n", gpg_strerror (rc));
+ else
+ {
+ fprintf (stderr, "%s\n", buf);
+ gcry_free (buf);
+ }
+}
+
+
+static void
+check_generated_rsa_key (gcry_sexp_t key, unsigned long expected_e)
+{
+ gcry_sexp_t skey, pkey, list;
+
+ pkey = gcry_sexp_find_token (key, "public-key", 0);
+ if (!pkey)
+ fail ("public part missing in return value\n");
+ else
+ {
+ gcry_mpi_t e = NULL;
+
+ list = gcry_sexp_find_token (pkey, "e", 0);
+ if (!list || !(e=gcry_sexp_nth_mpi (list, 1, 0)) )
+ fail ("public exponent not found\n");
+ else if (!expected_e)
+ {
+ if (verbose)
+ show_mpi ("public exponent: ", e);
+ }
+ else if ( gcry_mpi_cmp_ui (e, expected_e))
+ {
+ show_mpi ("public exponent: ", e);
+ fail ("public exponent is not %lu\n", expected_e);
+ }
+ gcry_sexp_release (list);
+ gcry_mpi_release (e);
+ gcry_sexp_release (pkey);
+ }
+
+ skey = gcry_sexp_find_token (key, "private-key", 0);
+ if (!skey)
+ fail ("private part missing in return value\n");
+ else
+ {
+ int rc = gcry_pk_testkey (skey);
+ if (rc)
+ fail ("gcry_pk_testkey failed: %s\n", gpg_strerror (rc));
+ gcry_sexp_release (skey);
+ }
+}
+
+
+static void
+check_rsa_keys (void)
+{
+ gcry_sexp_t keyparm, key;
+ int rc;
+
+ if (verbose)
+ info ("creating 2048 bit RSA key\n");
+ rc = gcry_sexp_new (&keyparm,
+ "(genkey\n"
+ " (rsa\n"
+ " (nbits 4:2048)\n"
+ " ))", 0, 1);
+ if (rc)
+ die ("error creating S-expression: %s\n", gpg_strerror (rc));
+ rc = gcry_pk_genkey (&key, keyparm);
+ gcry_sexp_release (keyparm);
+ if (rc)
+ die ("error generating RSA key: %s\n", gpg_strerror (rc));
+
+ if (verbose)
+ info ("creating 1024 bit RSA key\n");
+ rc = gcry_sexp_new (&keyparm,
+ "(genkey\n"
+ " (rsa\n"
+ " (nbits 4:1024)\n"
+ " ))", 0, 1);
+ if (rc)
+ die ("error creating S-expression: %s\n", gpg_strerror (rc));
+
+ gcry_sexp_release (key);
+ rc = gcry_pk_genkey (&key, keyparm);
+ gcry_sexp_release (keyparm);
+ if (rc && !in_fips_mode)
+ fail ("error generating RSA key: %s\n", gpg_strerror (rc));
+ else if (!rc && in_fips_mode)
+ fail ("generating 1024 bit RSA key must not work!");
+
+ if (!rc)
+ {
+ if (verbose > 1)
+ show_sexp ("1024 bit RSA key:\n", key);
+ check_generated_rsa_key (key, 65537);
+ }
+ gcry_sexp_release (key);
+
+ if (verbose)
+ info ("creating 2048 bit RSA key with e=65539\n");
+ rc = gcry_sexp_new (&keyparm,
+ "(genkey\n"
+ " (rsa\n"
+ " (nbits 4:2048)\n"
+ " (rsa-use-e 5:65539)\n"
+ " ))", 0, 1);
+ if (rc)
+ die ("error creating S-expression: %s\n", gpg_strerror (rc));
+ rc = gcry_pk_genkey (&key, keyparm);
+ gcry_sexp_release (keyparm);
+ if (rc)
+ fail ("error generating RSA key: %s\n", gpg_strerror (rc));
+
+ if (!rc)
+ check_generated_rsa_key (key, 65539);
+ gcry_sexp_release (key);
+
+
+ if (verbose)
+ info ("creating 512 bit RSA key with e=257\n");
+ rc = gcry_sexp_new (&keyparm,
+ "(genkey\n"
+ " (rsa\n"
+ " (nbits 3:512)\n"
+ " (rsa-use-e 3:257)\n"
+ " ))", 0, 1);
+ if (rc)
+ die ("error creating S-expression: %s\n", gpg_strerror (rc));
+ rc = gcry_pk_genkey (&key, keyparm);
+ gcry_sexp_release (keyparm);
+ if (rc && !in_fips_mode)
+ fail ("error generating RSA key: %s\n", gpg_strerror (rc));
+ else if (!rc && in_fips_mode)
+ fail ("generating 512 bit RSA key must not work!");
+
+ if (verbose && rc && in_fips_mode)
+ info ("... correctly rejected key creation in FIPS mode (%s)\n",
+ gpg_strerror (rc));
+
+ if (!rc)
+ check_generated_rsa_key (key, 257);
+ gcry_sexp_release (key);
+
+ if (verbose)
+ info ("creating 512 bit RSA key with default e\n");
+ rc = gcry_sexp_new (&keyparm,
+ "(genkey\n"
+ " (rsa\n"
+ " (nbits 3:512)\n"
+ " (rsa-use-e 1:0)\n"
+ " ))", 0, 1);
+ if (rc)
+ die ("error creating S-expression: %s\n", gpg_strerror (rc));
+ rc = gcry_pk_genkey (&key, keyparm);
+ gcry_sexp_release (keyparm);
+ if (rc && !in_fips_mode)
+ fail ("error generating RSA key: %s\n", gpg_strerror (rc));
+ else if (!rc && in_fips_mode)
+ fail ("generating 512 bit RSA key must not work!");
+
+ if (verbose && rc && in_fips_mode)
+ info ("... correctly rejected key creation in FIPS mode (%s)\n",
+ gpg_strerror (rc));
+
+
+ if (!rc)
+ check_generated_rsa_key (key, 0); /* We don't expect a constant exponent. */
+ gcry_sexp_release (key);
+}
+
+
+static void
+check_elg_keys (void)
+{
+ gcry_sexp_t keyparm, key;
+ int rc;
+
+ if (verbose)
+ info ("creating 1024 bit Elgamal key\n");
+ rc = gcry_sexp_new (&keyparm,
+ "(genkey\n"
+ " (elg\n"
+ " (nbits 4:1024)\n"
+ " ))", 0, 1);
+ if (rc)
+ die ("error creating S-expression: %s\n", gpg_strerror (rc));
+ rc = gcry_pk_genkey (&key, keyparm);
+ gcry_sexp_release (keyparm);
+ if (rc)
+ die ("error generating Elgamal key: %s\n", gpg_strerror (rc));
+ if (verbose > 1)
+ show_sexp ("1024 bit Elgamal key:\n", key);
+ gcry_sexp_release (key);
+}
+
+
+static void
+check_dsa_keys (void)
+{
+ gcry_sexp_t keyparm, key;
+ int rc;
+ int i;
+
+ /* Check that DSA generation works and that it can grok the qbits
+ argument. */
+ if (verbose)
+ info ("creating 5 1024 bit DSA keys\n");
+ for (i=0; i < 5; i++)
+ {
+ rc = gcry_sexp_new (&keyparm,
+ "(genkey\n"
+ " (dsa\n"
+ " (nbits 4:1024)\n"
+ " ))", 0, 1);
+ if (rc)
+ die ("error creating S-expression: %s\n", gpg_strerror (rc));
+ rc = gcry_pk_genkey (&key, keyparm);
+ gcry_sexp_release (keyparm);
+ if (rc && !in_fips_mode)
+ die ("error generating DSA key: %s\n", gpg_strerror (rc));
+ else if (!rc && in_fips_mode)
+ die ("generating 1024 bit DSA key must not work!");
+ if (!i && verbose > 1)
+ show_sexp ("1024 bit DSA key:\n", key);
+ gcry_sexp_release (key);
+ }
+
+ if (verbose)
+ info ("creating 1536 bit DSA key\n");
+ rc = gcry_sexp_new (&keyparm,
+ "(genkey\n"
+ " (dsa\n"
+ " (nbits 4:1536)\n"
+ " (qbits 3:224)\n"
+ " ))", 0, 1);
+ if (rc)
+ die ("error creating S-expression: %s\n", gpg_strerror (rc));
+ rc = gcry_pk_genkey (&key, keyparm);
+ gcry_sexp_release (keyparm);
+ if (rc && !in_fips_mode)
+ die ("error generating DSA key: %s\n", gpg_strerror (rc));
+ else if (!rc && in_fips_mode)
+ die ("generating 1536 bit DSA key must not work!");
+ if (verbose > 1)
+ show_sexp ("1536 bit DSA key:\n", key);
+ gcry_sexp_release (key);
+
+ if (verbose)
+ info ("creating 3072 bit DSA key\n");
+ rc = gcry_sexp_new (&keyparm,
+ "(genkey\n"
+ " (dsa\n"
+ " (nbits 4:3072)\n"
+ " (qbits 3:256)\n"
+ " ))", 0, 1);
+ if (rc)
+ die ("error creating S-expression: %s\n", gpg_strerror (rc));
+ rc = gcry_pk_genkey (&key, keyparm);
+ gcry_sexp_release (keyparm);
+ if (rc)
+ die ("error generating DSA key: %s\n", gpg_strerror (rc));
+ if (verbose > 1)
+ show_sexp ("3072 bit DSA key:\n", key);
+ gcry_sexp_release (key);
+
+ if (verbose)
+ info ("creating 2048/256 bit DSA key\n");
+ rc = gcry_sexp_new (&keyparm,
+ "(genkey\n"
+ " (dsa\n"
+ " (nbits 4:2048)\n"
+ " (qbits 3:256)\n"
+ " ))", 0, 1);
+ if (rc)
+ die ("error creating S-expression: %s\n", gpg_strerror (rc));
+ rc = gcry_pk_genkey (&key, keyparm);
+ gcry_sexp_release (keyparm);
+ if (rc)
+ die ("error generating DSA key: %s\n", gpg_strerror (rc));
+ if (verbose > 1)
+ show_sexp ("2048 bit DSA key:\n", key);
+ gcry_sexp_release (key);
+
+ if (verbose)
+ info ("creating 2048/224 bit DSA key\n");
+ rc = gcry_sexp_new (&keyparm,
+ "(genkey\n"
+ " (dsa\n"
+ " (nbits 4:2048)\n"
+ " (qbits 3:224)\n"
+ " ))", 0, 1);
+ if (rc)
+ die ("error creating S-expression: %s\n", gpg_strerror (rc));
+ rc = gcry_pk_genkey (&key, keyparm);
+ gcry_sexp_release (keyparm);
+ if (rc)
+ die ("error generating DSA key: %s\n", gpg_strerror (rc));
+ if (verbose > 1)
+ show_sexp ("2048 bit DSA key:\n", key);
+ gcry_sexp_release (key);
+}
+
+
+static void
+check_generated_ecc_key (gcry_sexp_t key)
+{
+ gcry_sexp_t skey, pkey;
+
+ pkey = gcry_sexp_find_token (key, "public-key", 0);
+ if (!pkey)
+ fail ("public part missing in return value\n");
+ else
+ {
+ /* Fixme: Check more stuff. */
+ gcry_sexp_release (pkey);
+ }
+
+ skey = gcry_sexp_find_token (key, "private-key", 0);
+ if (!skey)
+ fail ("private part missing in return value\n");
+ else
+ {
+ int rc = gcry_pk_testkey (skey);
+ if (rc)
+ fail ("gcry_pk_testkey failed: %s\n", gpg_strerror (rc));
+ gcry_sexp_release (skey);
+ }
+
+ /* Finally check that gcry_pk_testkey also works on the entire
+ S-expression. */
+ {
+ int rc = gcry_pk_testkey (key);
+ if (rc)
+ fail ("gcry_pk_testkey failed on key pair: %s\n", gpg_strerror (rc));
+ }
+}
+
+
+static void
+check_ecc_keys (void)
+{
+ const char *curves[] = { "NIST P-521", "NIST P-384", "NIST P-256",
+ "Ed25519", NULL };
+ int testno;
+ gcry_sexp_t keyparm, key;
+ int rc;
+
+ for (testno=0; curves[testno]; testno++)
+ {
+ if (verbose)
+ info ("creating ECC key using curve %s\n", curves[testno]);
+ if (!strcmp (curves[testno], "Ed25519"))
+ {
+ /* Ed25519 isn't allowed in fips mode */
+ if (in_fips_mode)
+ continue;
+ rc = gcry_sexp_build (&keyparm, NULL,
+ "(genkey(ecc(curve %s)(flags param eddsa)))",
+ curves[testno]);
+ }
+ else
+ rc = gcry_sexp_build (&keyparm, NULL,
+ "(genkey(ecc(curve %s)(flags param)))",
+ curves[testno]);
+ if (rc)
+ die ("error creating S-expression: %s\n", gpg_strerror (rc));
+ rc = gcry_pk_genkey (&key, keyparm);
+ gcry_sexp_release (keyparm);
+ if (rc)
+ die ("error generating ECC key using curve %s: %s\n",
+ curves[testno], gpg_strerror (rc));
+
+ if (verbose > 1)
+ show_sexp ("ECC key:\n", key);
+
+ check_generated_ecc_key (key);
+
+ gcry_sexp_release (key);
+ }
+
+ if (verbose)
+ info ("creating ECC key using curve Ed25519 for ECDSA\n");
+ rc = gcry_sexp_build (&keyparm, NULL, "(genkey(ecc(curve Ed25519)))");
+ if (rc)
+ die ("error creating S-expression: %s\n", gpg_strerror (rc));
+ rc = gcry_pk_genkey (&key, keyparm);
+ gcry_sexp_release (keyparm);
+ if (rc && !in_fips_mode)
+ die ("error generating ECC key using curve Ed25519 for ECDSA: %s\n",
+ gpg_strerror (rc));
+ else if (!rc && in_fips_mode)
+ fail ("generating Ed25519 key must not work!");
+
+ if (verbose && rc && in_fips_mode)
+ info ("... correctly rejected key creation in FIPS mode (%s)\n",
+ gpg_strerror (rc));
+
+ if (!rc)
+ {
+ if (verbose > 1)
+ show_sexp ("ECC key:\n", key);
+
+ check_generated_ecc_key (key);
+ }
+ gcry_sexp_release (key);
+
+ if (verbose)
+ info ("creating ECC key using curve Ed25519 for ECDSA (nocomp)\n");
+ rc = gcry_sexp_build (&keyparm, NULL,
+ "(genkey(ecc(curve Ed25519)(flags nocomp)))");
+ if (rc)
+ die ("error creating S-expression: %s\n", gpg_strerror (rc));
+ rc = gcry_pk_genkey (&key, keyparm);
+ gcry_sexp_release (keyparm);
+ if (rc && !in_fips_mode)
+ die ("error generating ECC key using curve Ed25519 for ECDSA"
+ " (nocomp): %s\n",
+ gpg_strerror (rc));
+ else if (!rc && in_fips_mode)
+ fail ("generating Ed25519 key must not work in FIPS mode!");
+
+ if (verbose && rc && in_fips_mode)
+ info ("... correctly rejected key creation in FIPS mode (%s)\n",
+ gpg_strerror (rc));
+ gcry_sexp_release (key);
+
+ if (verbose)
+ info ("creating ECC key using curve NIST P-384 for ECDSA\n");
+
+ /* Must be specified as nistp384 (one word), because ecc_generate
+ * uses _gcry_sexp_nth_string which takes the first word of the name
+ * and thus libgcrypt can't find it later in its curves table. */
+ rc = gcry_sexp_build (&keyparm, NULL, "(genkey(ecc(curve nistp384)))");
+ if (rc)
+ die ("error creating S-expression: %s\n", gpg_strerror (rc));
+ rc = gcry_pk_genkey (&key, keyparm);
+ gcry_sexp_release (keyparm);
+ if (rc)
+ die ("error generating ECC key using curve NIST P-384 for ECDSA: %s\n",
+ gpg_strerror (rc));
+
+ if (verbose > 1)
+ show_sexp ("ECC key:\n", key);
+
+ check_generated_ecc_key (key);
+ gcry_sexp_release (key);
+
+ if (verbose)
+ info ("creating ECC key using curve NIST P-384 for ECDSA (nocomp)\n");
+ rc = gcry_sexp_build (&keyparm, NULL,
+ "(genkey(ecc(curve nistp384)(flags nocomp)))");
+ if (rc)
+ die ("error creating S-expression: %s\n", gpg_strerror (rc));
+ rc = gcry_pk_genkey (&key, keyparm);
+ gcry_sexp_release (keyparm);
+ if (rc)
+ die ("error generating ECC key using curve NIST P-384 for ECDSA"
+ " (nocomp): %s\n",
+ gpg_strerror (rc));
+
+ if (verbose > 1)
+ show_sexp ("ECC key:\n", key);
+
+ check_generated_ecc_key (key);
+ gcry_sexp_release (key);
+
+
+ if (verbose)
+ info ("creating ECC key using curve Ed25519 for ECDSA (transient-key)\n");
+ rc = gcry_sexp_build (&keyparm, NULL,
+ "(genkey(ecc(curve Ed25519)(flags transient-key)))");
+ if (rc)
+ die ("error creating S-expression: %s\n", gpg_strerror (rc));
+ rc = gcry_pk_genkey (&key, keyparm);
+ gcry_sexp_release (keyparm);
+ if (rc && !in_fips_mode)
+ die ("error generating ECC key using curve Ed25519 for ECDSA"
+ " (transient-key): %s\n",
+ gpg_strerror (rc));
+ else if (!rc && in_fips_mode)
+ fail ("generating Ed25519 key must not work in FIPS mode!");
+
+ if (verbose && rc && in_fips_mode)
+ info ("... correctly rejected key creation in FIPS mode (%s)\n",
+ gpg_strerror (rc));
+
+ if (!rc)
+ {
+ if (verbose > 1)
+ show_sexp ("ECC key:\n", key);
+ check_generated_ecc_key (key);
+ }
+ gcry_sexp_release (key);
+
+ if (verbose)
+ info ("creating ECC key using curve Ed25519 for ECDSA "
+ "(transient-key no-keytest)\n");
+ rc = gcry_sexp_build (&keyparm, NULL,
+ "(genkey(ecc(curve Ed25519)"
+ "(flags transient-key no-keytest)))");
+ if (rc)
+ die ("error creating S-expression: %s\n", gpg_strerror (rc));
+ rc = gcry_pk_genkey (&key, keyparm);
+ gcry_sexp_release (keyparm);
+ if (rc && !in_fips_mode)
+ die ("error generating ECC key using curve Ed25519 for ECDSA"
+ " (transient-key no-keytest): %s\n",
+ gpg_strerror (rc));
+ else if (!rc && in_fips_mode)
+ fail ("generating Ed25519 key must not work in FIPS mode!");
+
+ if (verbose && rc && in_fips_mode)
+ info ("... correctly rejected key creation in FIPS mode (%s)\n",
+ gpg_strerror (rc));
+
+ if (!rc)
+ {
+ if (verbose > 1)
+ show_sexp ("ECC key:\n", key);
+ check_generated_ecc_key (key);
+ }
+ gcry_sexp_release (key);
+}
+
+
+static void
+check_nonce (void)
+{
+ char a[32], b[32];
+ int i,j;
+ int oops=0;
+
+ if (verbose)
+ info ("checking gcry_create_nonce\n");
+
+ gcry_create_nonce (a, sizeof a);
+ for (i=0; i < 10; i++)
+ {
+ gcry_create_nonce (b, sizeof b);
+ if (!memcmp (a, b, sizeof a))
+ die ("identical nonce found\n");
+ }
+ for (i=0; i < 10; i++)
+ {
+ gcry_create_nonce (a, sizeof a);
+ if (!memcmp (a, b, sizeof a))
+ die ("identical nonce found\n");
+ }
+
+ again:
+ for (i=1,j=0; i < sizeof a; i++)
+ if (a[0] == a[i])
+ j++;
+ if (j+1 == sizeof (a))
+ {
+ if (oops)
+ die ("impossible nonce found\n");
+ oops++;
+ gcry_create_nonce (a, sizeof a);
+ goto again;
+ }
+}
+
+
+static void
+progress_cb (void *cb_data, const char *what, int printchar,
+ int current, int total)
+{
+ (void)cb_data;
+ (void)what;
+ (void)current;
+ (void)total;
+
+ if (printchar == '\n')
+ fputs ( "", stdout);
+ else
+ putchar (printchar);
+ fflush (stdout);
+}
+
+
+static void
+usage (int mode)
+{
+ fputs ("usage: " PGM " [options] [{rsa|elg|dsa|ecc|nonce}]\n"
+ "Options:\n"
+ " --verbose be verbose\n"
+ " --debug flyswatter\n"
+ " --fips run in FIPS mode\n"
+ " --no-quick To not use the quick RNG hack\n"
+ " --progress print progress indicators\n",
+ mode? stderr : stdout);
+ if (mode)
+ exit (1);
+}
+
+int
+main (int argc, char **argv)
+{
+ int last_argc = -1;
+ int opt_fips = 0;
+ int with_progress = 0;
+ int no_quick = 0;
+
+ if (argc)
+ { argc--; argv++; }
+
+ while (argc && last_argc != argc )
+ {
+ last_argc = argc;
+ if (!strcmp (*argv, "--"))
+ {
+ argc--; argv++;
+ break;
+ }
+ else if (!strcmp (*argv, "--help"))
+ {
+ usage (0);
+ exit (0);
+ }
+ else if (!strcmp (*argv, "--verbose"))
+ {
+ verbose++;
+ argc--; argv++;
+ }
+ else if (!strcmp (*argv, "--debug"))
+ {
+ verbose += 2;
+ debug++;
+ argc--; argv++;
+ }
+ else if (!strcmp (*argv, "--fips"))
+ {
+ argc--; argv++;
+ opt_fips = 1;
+ }
+ else if (!strcmp (*argv, "--progress"))
+ {
+ argc--; argv++;
+ with_progress = 1;
+ }
+ else if (!strcmp (*argv, "--no-quick"))
+ {
+ argc--; argv++;
+ no_quick = 1;
+ }
+ else if (!strncmp (*argv, "--", 2))
+ die ("unknown option '%s'", *argv);
+ else
+ break;
+ }
+
+ xgcry_control (GCRYCTL_SET_VERBOSITY, (int)verbose);
+ if (opt_fips)
+ xgcry_control (GCRYCTL_FORCE_FIPS_MODE, 0);
+
+ if (!gcry_check_version (GCRYPT_VERSION))
+ die ("version mismatch\n");
+
+ if (!opt_fips)
+ xgcry_control (GCRYCTL_DISABLE_SECMEM, 0);
+
+ xgcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
+ if (debug)
+ xgcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1u , 0);
+ /* No valuable keys are create, so we can speed up our RNG. */
+ if (!no_quick)
+ xgcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
+ if (with_progress)
+ gcry_set_progress_handler (progress_cb, NULL);
+
+ if ( gcry_fips_mode_active () )
+ in_fips_mode = 1;
+
+ if (opt_fips && !in_fips_mode)
+ die ("failed to switch into FIPS mode\n");
+
+ if (!argc)
+ {
+ check_rsa_keys ();
+ check_elg_keys ();
+ check_dsa_keys ();
+ check_ecc_keys ();
+ check_nonce ();
+ }
+ else
+ {
+ for (; argc; argc--, argv++)
+ if (!strcmp (*argv, "rsa"))
+ check_rsa_keys ();
+ else if (!strcmp (*argv, "elg"))
+ check_elg_keys ();
+ else if (!strcmp (*argv, "dsa"))
+ check_dsa_keys ();
+ else if (!strcmp (*argv, "ecc"))
+ check_ecc_keys ();
+ else if (!strcmp (*argv, "nonce"))
+ check_nonce ();
+ else
+ usage (1);
+ }
+
+ return error_count? 1:0;
+}
diff --git a/tests/pubkey.c b/tests/pubkey.c
index fbb7bbb..a49f903 100644
--- a/tests/pubkey.c
+++ b/tests/pubkey.c
@@ -595,7 +595,7 @@ get_dsa_key_fips186_with_seed_new (gcry_sexp_t *pkey, gcry_sexp_t *skey)
" (use-fips186)"
" (transient-key)"
" (derive-parms"
- " (seed #0cb1990c1fd3626055d7a0096f8fa99807399871#))))",
+ " (seed #8b4c4d671fff82e8ed932260206d0571e3a1c2cee8cd94cb73fe58f9b67488fa#))))",
0, 1);
if (rc)
die ("error creating S-expression: %s\n", gcry_strerror (rc));
diff --git a/tests/pubkey.c.tests b/tests/pubkey.c.tests
new file mode 100644
index 0000000..fbb7bbb
--- /dev/null
+++ b/tests/pubkey.c.tests
@@ -0,0 +1,1202 @@
+/* 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
+
+
+#define PGM "pubkey"
+#include "t-common.h"
+
+
+/* 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 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);
+}
+
+/* from ../cipher/pubkey-util.c */
+static gpg_err_code_t
+_gcry_pk_util_get_nbits (gcry_sexp_t list, unsigned int *r_nbits)
+{
+ char buf[50];
+ const char *s;
+ size_t n;
+
+ *r_nbits = 0;
+
+ list = gcry_sexp_find_token (list, "nbits", 0);
+ if (!list)
+ return 0; /* No NBITS found. */
+
+ s = gcry_sexp_nth_data (list, 1, &n);
+ if (!s || n >= DIM (buf) - 1 )
+ {
+ /* NBITS given without a cdr. */
+ gcry_sexp_release (list);
+ return GPG_ERR_INV_OBJ;
+ }
+ memcpy (buf, s, n);
+ buf[n] = 0;
+ *r_nbits = (unsigned int)strtoul (buf, NULL, 0);
+ gcry_sexp_release (list);
+ return 0;
+}
+
+/* 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:2048)))", 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:2048)(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:2048)(transient-key)))"
+ : "(genkey (dsa (nbits 4:2048)))",
+ 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:2048)(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;
+}
+
+#if 0
+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;
+}
+#endif /*0*/
+
+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:2048)"
+ " (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);
+
+ /* We need new test vectors for get_dsa_key_fips186_with_domain_new. */
+ if (verbose)
+ fprintf (stderr, "Generating DSA key with given domain (FIPS 186)"
+ " - skipped.\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 = NULL, key = NULL, pub_key = NULL, sec_key = NULL;
+ gcry_mpi_t d_expected = NULL, d_have = NULL;
+
+ 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));
+
+ {
+ unsigned nbits;
+ err = _gcry_pk_util_get_nbits(key_spec, &nbits);
+ if (err)
+ die ("nbits not found\n");
+ if (gcry_fips_mode_active() && nbits < 2048)
+ {
+ info("RSA key test with %d bits skipped in fips mode\n", nbits);
+ goto leave;
+ }
+ }
+
+ err = gcry_pk_genkey (&key, key_spec);
+ gcry_sexp_release (key_spec);
+ if (err)
+ {
+ fail ("error generating RSA key [%d]: %s\n", what, gpg_strerror (err));
+ goto leave;
+ }
+
+ 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);
+ }
+leave:
+ 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, 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 i;
+
+ if (argc > 1 && !strcmp (argv[1], "--verbose"))
+ verbose = 1;
+ else if (argc > 1 && !strcmp (argv[1], "--debug"))
+ {
+ verbose = 2;
+ debug = 1;
+ }
+
+ xgcry_control (GCRYCTL_DISABLE_SECMEM, 0);
+ if (!gcry_check_version (GCRYPT_VERSION))
+ die ("version mismatch\n");
+ xgcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
+ if (debug)
+ xgcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1u , 0);
+ /* No valuable keys are create, so we can speed up our RNG. */
+ xgcry_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 ();
+ if (!gcry_fips_mode_active ())
+ check_ed25519ecdsa_sample_key ();
+
+ return !!error_count;
+}