|  | /* keygen.c  -  key generation regression tests | 
|  | * Copyright (C) 2003, 2005, 2012 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, write to the Free Software | 
|  | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA | 
|  | */ | 
|  |  | 
|  | #ifdef HAVE_CONFIG_H | 
|  | #include <config.h> | 
|  | #endif | 
|  | #include <stdio.h> | 
|  | #include <stdlib.h> | 
|  | #include <string.h> | 
|  | #include <stdarg.h> | 
|  | #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); | 
|  | } | 
|  |  | 
|  |  | 
|  | 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 ( "<LF>", 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; | 
|  | } |