/* 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"
#define xmalloc(a) gcry_xmalloc ((a))
#define xcalloc(a,b) gcry_xcalloc ((a),(b))
#define xstrdup(a) gcry_xstrdup ((a))
#define xfree(a) gcry_free ((a))
#define pass() do { ; } while (0)
static int verbose;
static int debug;
static int error_count;
static void
die (const char *format, ...)
{
va_list arg_ptr ;
fflush (stdout);
fprintf (stderr, "%s: ", PGM);
va_start( arg_ptr, format ) ;
vfprintf (stderr, format, arg_ptr );
va_end(arg_ptr);
if (*format && format[strlen(format)-1] != '\n')
putc ('\n', stderr);
exit (1);
}
static void
fail (const char *format, ...)
{
va_list arg_ptr;
fflush (stdout);
fprintf (stderr, "%s: ", PGM);
/* if (wherestr) */
/* fprintf (stderr, "%s: ", wherestr); */
va_start (arg_ptr, format);
vfprintf (stderr, format, arg_ptr);
va_end (arg_ptr);
if (*format && format[strlen(format)-1] != '\n')
putc ('\n', stderr);
error_count++;
if (error_count >= 50)
die ("stopped after 50 errors.");
}
static void
show (const char *format, ...)
{
va_list arg_ptr;
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_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)
show ("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));
rc = gcry_pk_genkey (&key, keyparm);
gcry_sexp_release (keyparm);
if (rc)
die ("error generating RSA key: %s\n", gpg_strerror (rc));
if (verbose > 1)
show_sexp ("1024 bit RSA key:\n", key);
check_generated_rsa_key (key, 65537);
gcry_sexp_release (key);
if (verbose)
show ("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)
die ("error generating RSA key: %s\n", gpg_strerror (rc));
check_generated_rsa_key (key, 257);
gcry_sexp_release (key);
if (verbose)
show ("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)
die ("error generating RSA key: %s\n", gpg_strerror (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)
show ("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)
show ("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)
die ("error generating DSA key: %s\n", gpg_strerror (rc));
if (!i && verbose > 1)
show_sexp ("1024 bit DSA key:\n", key);
gcry_sexp_release (key);
}
if (verbose)
show ("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)
die ("error generating DSA key: %s\n", gpg_strerror (rc));
if (verbose > 1)
show_sexp ("1536 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)
show ("creating ECC key using curve %s\n", curves[testno]);
if (!strcmp (curves[testno], "Ed25519"))
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)
show ("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)
die ("error generating ECC key using curve Ed25519 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)
show ("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)
die ("error generating ECC key using curve Ed25519 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)
show ("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)
die ("error generating ECC key using curve Ed25519 for ECDSA"
" (transient-key): %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)
show ("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)
die ("error generating ECC key using curve Ed25519 for ECDSA"
" (transient-key no-keytest): %s\n",
gpg_strerror (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)
show ("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"
" --progress print progress indicators\n",
mode? stderr : stdout);
if (mode)
exit (1);
}
int
main (int argc, char **argv)
{
int last_argc = -1;
int with_progress = 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, "--progress"))
{
argc--; argv++;
with_progress = 1;
}
else if (!strncmp (*argv, "--", 2))
die ("unknown option '%s'", *argv);
else
break;
}
if (!gcry_check_version (GCRYPT_VERSION))
die ("version mismatch\n");
gcry_control (GCRYCTL_DISABLE_SECMEM, 0);
gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
if (debug)
gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1u , 0);
/* No valuable keys are create, so we can speed up our RNG. */
gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
if (with_progress)
gcry_set_progress_handler (progress_cb, NULL);
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;
}