diff options
-rw-r--r-- | AUTHORS | 5 | ||||
-rw-r--r-- | NEWS | 7 | ||||
-rw-r--r-- | cipher/rsa.c | 3 | ||||
-rw-r--r-- | configure.ac | 4 | ||||
-rw-r--r-- | doc/ChangeLog | 5 | ||||
-rw-r--r-- | doc/announce.txt | 10 | ||||
-rw-r--r-- | doc/fips-fsm.fig | 16 | ||||
-rw-r--r-- | doc/gcrypt.texi | 35 | ||||
-rw-r--r-- | src/ChangeLog | 17 | ||||
-rw-r--r-- | src/cipher-proto.h | 3 | ||||
-rw-r--r-- | src/cipher.h | 5 | ||||
-rw-r--r-- | src/dumpsexp.c | 2 | ||||
-rw-r--r-- | src/fips.c | 1 | ||||
-rw-r--r-- | src/gcrypt-module.h | 7 | ||||
-rw-r--r-- | src/gcrypt.h.in | 4 | ||||
-rw-r--r-- | src/module.c | 4 | ||||
-rw-r--r-- | tests/ChangeLog | 24 | ||||
-rw-r--r-- | tests/Makefile.am | 8 | ||||
-rw-r--r-- | tests/benchmark.c | 4 | ||||
-rwxr-xr-x[-rw-r--r--] | tests/cavs_driver.pl | 131 | ||||
-rwxr-xr-x | tests/cavs_tests.sh | 125 | ||||
-rw-r--r-- | tests/fipsdrv.c | 1458 | ||||
-rw-r--r-- | tests/fipsrngdrv.c | 9 |
23 files changed, 1832 insertions, 55 deletions
@@ -110,6 +110,11 @@ sergi at calcurco dot org. The implementation of the Camellia cipher has been been taken from the original NTT provided GPL source. +The CAVS testing program tests/cavs_driver.pl is not to be considered +a part of libgcrypt proper. We distribute it merely for convenience. +It has a permissive license and is copyright by atsec information +security corporation. See the file for details. + Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2006, 2007, 2008 Free Software Foundation, Inc. @@ -1,3 +1,10 @@ +Noteworthy changes in version 1.4.4 +------------------------------------------------ + + * Publish GCRY_MODULE_ID_USER and GCRY_MODULE_ID_USER_LAST constants. + This functionality is in Libgcrypt since 1.3.0. + + Noteworthy changes in version 1.4.3 (2008-09-18) ------------------------------------------------ diff --git a/cipher/rsa.c b/cipher/rsa.c index 72ee8a8b..434fd8ba 100644 --- a/cipher/rsa.c +++ b/cipher/rsa.c @@ -175,7 +175,8 @@ check_exponent (void *arg, gcry_mpi_t a) * 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 Try starting at this value until a working exponent is found. + * > 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 */ diff --git a/configure.ac b/configure.ac index 4b735991..de41ea5a 100644 --- a/configure.ac +++ b/configure.ac @@ -26,8 +26,8 @@ min_automake_version="1.10" # Remember to change the version number immediately *after* a release. # Set my_issvn to "yes" for non-released code. Remember to run an # "svn up" and "autogen.sh" right before creating a distribution. -m4_define([my_version], [1.4.3]) -m4_define([my_issvn], [no]) +m4_define([my_version], [1.4.4]) +m4_define([my_issvn], [yes]) m4_define([svn_revision], m4_esyscmd([printf "%d" $(svn info 2>/dev/null \ | sed -n '/^Revision:/ s/[^0-9]//gp'|head -1)])) diff --git a/doc/ChangeLog b/doc/ChangeLog index 903081ff..b619baa6 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -1,5 +1,10 @@ 2008-09-18 Werner Koch <wk@g10code.com> + * gcrypt.texi (FIPS Mode): Add state transition Error to Error. + * fips-fsm.fig: Ditto. + +2008-09-18 Werner Koch <wk@g10code.com> + * gcrypt.texi: Add a couple of index items. (FIPS Mode): Reflect recent changes. (Controlling the library): Describe gcry_fips_mode_active. diff --git a/doc/announce.txt b/doc/announce.txt index 6f2925f2..48c41bf4 100644 --- a/doc/announce.txt +++ b/doc/announce.txt @@ -39,21 +39,25 @@ Source code is hosted at the GnuPG FTP server and its mirrors as listed at http://www.gnupg.org/download/mirrors.html . On the primary server the source file and its digital signatures is: - ftp://ftp.gnupg.org/gcrypt/libgcrypt/libgcrypt-1.4.3.tar.bz2 (k) + ftp://ftp.gnupg.org/gcrypt/libgcrypt/libgcrypt-1.4.3.tar.bz2 (1062k) ftp://ftp.gnupg.org/gcrypt/libgcrypt/libgcrypt-1.4.3.tar.bz2.sig This file is bzip2 compressed. A gzip compressed version is also available: - ftp://ftp.gnupg.org/gcrypt/libgcrypt/libgcrypt-1.4.3.tar.gz (k) + ftp://ftp.gnupg.org/gcrypt/libgcrypt/libgcrypt-1.4.3.tar.gz (1325k) ftp://ftp.gnupg.org/gcrypt/libgcrypt/libgcrypt-1.4.3.tar.gz.sig Alternativley you may upgrade version 1.4.2 using this patch file: - ftp://ftp.gnupg.org/gcrypt/libgcrypt/libgcrypt-1.4.2-1.4.3.diff.bz2 (k) + ftp://ftp.gnupg.org/gcrypt/libgcrypt/libgcrypt-1.4.2-1.4.3.diff.bz2 (42k) The SHA-1 checksums are: +bdc67c1fdcec464a94dca691615f2335a12db5ce libgcrypt-1.4.3.tar.bz2 +3d9d583501ce951596fa7dd3667afd357ac7d056 libgcrypt-1.4.3.tar.gz +e28b74c5824364e20ae7f147f1b89925f5426669 libgcrypt-1.4.2-1.4.3.diff.bz2 + For help on developing with Libgcrypt you should read the included manual and optional ask on the gcrypt-devel mailing list [1]. diff --git a/doc/fips-fsm.fig b/doc/fips-fsm.fig index d3a307aa..a4f0aece 100644 --- a/doc/fips-fsm.fig +++ b/doc/fips-fsm.fig @@ -24,7 +24,9 @@ Single 1 1 2.00 120.00 240.00 5 1 0 2 0 7 50 -1 -1 0.000 1 1 1 0 3026.138 8399.825 4185 8370 3870 7605 2925 7245 1 1 2.00 120.00 240.00 -5 1 0 2 0 7 50 -1 -1 0.000 1 1 1 0 7708.125 -2028.750 2925 5175 4815 6120 6795 6570 +5 1 0 2 0 7 50 -1 -1 0.000 1 1 1 0 7663.125 -2028.750 2880 5175 4770 6120 6750 6570 + 1 1 2.00 120.00 240.00 +5 1 0 2 0 7 50 -1 -1 0.000 1 1 1 0 7717.500 7211.250 7155 7470 7740 7830 8280 7470 1 1 2.00 120.00 240.00 6 3096 1593 3380 1877 1 3 0 1 0 7 50 -1 -1 0.000 1 0.0000 3238 1735 142 142 3238 1735 3103 1690 @@ -134,14 +136,18 @@ Single 1 3 0 1 0 7 50 -1 -1 0.000 1 0.0000 4192 6338 142 142 4192 6338 4057 6293 4 0 0 50 -1 13 12 0.0000 4 105 210 4066 6399 17\001 -6 -6 3188 5033 3486 5331 -1 3 0 1 0 7 50 -1 -1 0.000 1 0.0000 3337 5182 142 142 3337 5182 3202 5137 -4 0 0 50 -1 13 12 0.0000 4 105 210 3211 5243 18\001 --6 6 3053 4358 3351 4656 1 3 0 1 0 7 50 -1 -1 0.000 1 0.0000 3202 4507 142 142 3202 4507 3067 4462 4 0 0 50 -1 13 12 0.0000 4 105 210 3076 4568 19\001 -6 +6 3032 5012 3330 5310 +1 3 0 1 0 7 50 -1 -1 0.000 1 0.0000 3181 5161 142 142 3181 5161 3046 5116 +4 0 0 50 -1 13 12 0.0000 4 105 210 3055 5222 18\001 +-6 +6 7560 7847 7858 8145 +1 3 0 1 0 7 50 -1 -1 0.000 1 0.0000 7709 7996 142 142 7709 7996 7574 7951 +4 0 0 50 -1 13 12 0.0000 4 105 210 7612 8047 20\001 +-6 2 1 0 2 0 7 50 -1 -1 0.000 0 1 -1 1 0 2 1 1 2.00 120.00 240.00 3420 1395 3420 2295 diff --git a/doc/gcrypt.texi b/doc/gcrypt.texi index f1a02bc4..a1bb696b 100644 --- a/doc/gcrypt.texi +++ b/doc/gcrypt.texi @@ -2612,7 +2612,7 @@ and @var{buflen} must have the value @code{sizeof (int)}. @c end gcry_pk_ctl @noindent -Libgcrypt also provides a function for generating public key +Libgcrypt also provides a function to generate public key pairs: @deftypefun gcry_error_t gcry_pk_genkey (@w{gcry_sexp_t *@var{r_key}}, @w{gcry_sexp_t @var{parms}}) @@ -2624,12 +2624,12 @@ an error, @var{r_key} is set to @code{NULL}. The return code is 0 for success or an error code otherwise. @noindent -Here is an example for @var{parms} for creating a 1024 bit RSA key: +Here is an example for @var{parms} to create an 2048 bit RSA key: @example (genkey (rsa - (nbits 4:1024))) + (nbits 4:2048))) @end example @noindent @@ -2660,10 +2660,12 @@ are special: @item 0 Use a secure and fast value. This is currently the number 41. @item 1 -Use a secure value as required by some specification. This is currently +Use a value as required by some crypto policies. This is currently the number 65537. @item 2 Reserved +@item > 2 +Use the given value. @end table @noindent @@ -2696,6 +2698,26 @@ given the RSA key is created using a faster and a somewhat less secure random number generator. This flag may be used for keys which are only used for a short time and do not require full cryptographic strength. +@item domain +This is only meaningful for DLP algorithms. If specified keys are +generated with domain parameters taken from this list. The exact +format of this parameter depends on the actual algorithm. It is +currently only implemented for DSA using this format: + +@example +(genkey + (dsa + (domain + (p @var{p-mpi}) + (q @var{q-mpi}) + (g @var{q-mpi}) + (seed @var{seed-mpi}) + (counter @var{counter-mpi}) + (h @var{h-mpi})))) +@end example + +The @code{seed}, @code{counter} and @code{h} domain parameters are +optional and currently not used. @end table @c end table of parameters @@ -5652,6 +5674,11 @@ Init to Error is triggered by errors in the initialization code. Init to Fatal-Error is triggered by non-recoverable errors in the initialization code. +@item 20 +Error to Error is triggered by errors while already in the Error +state. + + @end table @end float diff --git a/src/ChangeLog b/src/ChangeLog index 3371ca34..7759dbb8 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,20 @@ +2008-09-29 Werner Koch <wk@g10code.com> + + * gcrypt-module.h (GCRY_MODULE_ID_USER, GCRY_MODULE_ID_USER_LAST): + New. + * module.c (MODULE_ID_USER, MODULE_ID_USER_LAST): Define using new + macros. + +2008-09-20 Werner Koch <wk@g10code.com> + + * hmac256.c (finalize) [WORDS_BIGENDIAN]: Fix sigbus problem. + +2008-09-18 Werner Koch <wk@g10code.com> + + * cipher-proto.h (pk_ext_generate_t): Add args QBITS, NAME, DOMAIN. + + * fips.c (fips_new_state): Allow Error => Error transition. + 2008-09-18 Werner Koch <wk@g10code.com> * gcrypt.h.in (gcry_fips_mode_active): New. diff --git a/src/cipher-proto.h b/src/cipher-proto.h index 2382a68d..43ed0886 100644 --- a/src/cipher-proto.h +++ b/src/cipher-proto.h @@ -43,7 +43,10 @@ typedef gpg_err_code_t (*selftest_func_t) typedef gcry_err_code_t (*pk_ext_generate_t) (int algo, unsigned int nbits, + unsigned int qbits, unsigned long use_e, + const char *name, + gcry_sexp_t domain, unsigned int keygen_flags, gcry_mpi_t *skey, gcry_mpi_t **retfactors); diff --git a/src/cipher.h b/src/cipher.h index 8a4c2de1..3e0ba9d2 100644 --- a/src/cipher.h +++ b/src/cipher.h @@ -56,11 +56,6 @@ void _gcry_aes_cbc_dec (void *context, unsigned char *iv, /*-- dsa.c --*/ void _gcry_register_pk_dsa_progress (gcry_handler_progress_t cbc, void *cb_data); -gcry_err_code_t _gcry_dsa_generate2 (int algo, unsigned int nbits, - unsigned int qbits, - unsigned long dummy, - gcry_mpi_t *skey, - gcry_mpi_t **retfactors); /*-- elgamal.c --*/ void _gcry_register_pk_elg_progress (gcry_handler_progress_t cb, diff --git a/src/dumpsexp.c b/src/dumpsexp.c index 157c4105..8f5c0d30 100644 --- a/src/dumpsexp.c +++ b/src/dumpsexp.c @@ -263,11 +263,13 @@ printctl (const char *text) static void printchr (int c) { + (void)c; } static void printhex (int c) { + (void)c; } @@ -730,6 +730,7 @@ fips_new_state (enum module_states new_state) case STATE_ERROR: if (new_state == STATE_SHUTDOWN + || new_state == STATE_ERROR || new_state == STATE_FATALERROR || new_state == STATE_SELFTEST) ok = 1; diff --git a/src/gcrypt-module.h b/src/gcrypt-module.h index 39d39c86..e717b70c 100644 --- a/src/gcrypt-module.h +++ b/src/gcrypt-module.h @@ -32,6 +32,13 @@ extern "C" { #endif #endif +/* The interfaces using the module system reserve a certain range of + IDs for application use. These IDs are not valid within Libgcrypt + but Libgcrypt makes sure never to allocate such a module ID. */ +#define GCRY_MODULE_ID_USER 1024 +#define GCRY_MODULE_ID_USER_LAST 4095 + + /* This type represents a `module'. */ typedef struct gcry_module *gcry_module_t; diff --git a/src/gcrypt.h.in b/src/gcrypt.h.in index f040ed84..ae34d106 100644 --- a/src/gcrypt.h.in +++ b/src/gcrypt.h.in @@ -479,7 +479,7 @@ size_t gcry_sexp_canon_len (const unsigned char *buffer, size_t length, size_t gcry_sexp_sprint (gcry_sexp_t sexp, int mode, void *buffer, size_t maxlength); -/* Dumps the S-expression object A in a aformat suitable for debugging +/* Dumps the S-expression object A in a format suitable for debugging to Libgcrypt's logging stream. */ void gcry_sexp_dump (const gcry_sexp_t a); @@ -1165,7 +1165,7 @@ gcry_error_t gcry_md_algo_info (int algo, int what, void *buffer, size_t *nbytes); /* Map the digest algorithm id ALGO to a string representation of the - algorithm name. For unknown algorithms this functions returns + algorithm name. For unknown algorithms this function returns "?". */ const char *gcry_md_algo_name (int algo) _GCRY_GCC_ATTR_PURE; diff --git a/src/module.c b/src/module.c index f6a24209..c70a44c0 100644 --- a/src/module.c +++ b/src/module.c @@ -25,8 +25,8 @@ numbers. */ #define MODULE_ID_MIN 600 #define MODULE_ID_LAST 65500 -#define MODULE_ID_USER 1024 -#define MODULE_ID_USER_LAST 4095 +#define MODULE_ID_USER GCRY_MODULE_ID_USER +#define MODULE_ID_USER_LAST GCRY_MODULE_ID_USER_LAST #if MODULE_ID_MIN >= MODULE_ID_USER #error Need to implement a different search strategy diff --git a/tests/ChangeLog b/tests/ChangeLog index 6e6a3117..4a5c68b8 100644 --- a/tests/ChangeLog +++ b/tests/ChangeLog @@ -1,3 +1,25 @@ +2008-10-02 Werner Koch <wk@g10code.com> + + * fipsdrv.c (print_buffer): Add base64 printing code. + (base64_decode, read_key_file,parse_tag): New. + (run_rsa_gen, run_rsa_sign): New. + (main): Add mode rsa-gen and rsa-sign. + +2008-09-29 Werner Koch <wk@g10code.com> + + * fipsdrv.c: Merge code from fipsrngdrv.c + * fipsrngdrv.c: Remove. + +2008-09-26 Werner Koch <wk@g10code.com> + + * Makefile.am: Distribute cavs_driver.pl. + * cavs_tests.sh: New. + * fipsdrv.c: New. + +2008-09-18 Werner Koch <wk@g10code.com> + + * benchmark.c (main): Do not disable secure memory in FIPS mode. + 2008-09-18 Werner Koch <wk@g10code.com> * basic.c (main): Do not disable secure memory in FIPS mode. @@ -604,7 +626,7 @@ * tsexp.c: New. - Copyright 2001, 2002, 2003 Free Software Foundation, Inc. + Copyright 2001, 2002, 2003, 2008 Free Software Foundation, Inc. This file is free software; as a special exception the author gives unlimited permission to copy and/or distribute it, with or without diff --git a/tests/Makefile.am b/tests/Makefile.am index 21d5bd84..38901f66 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -39,10 +39,6 @@ AM_CFLAGS = $(GPG_ERROR_CFLAGS) LDADD = ../src/libgcrypt.la $(DL_LIBS) EXTRA_PROGRAMS = testapi pkbench -noinst_PROGRAMS = $(TESTS) fipsrngdrv +noinst_PROGRAMS = $(TESTS) fipsdrv -EXTRA_DIST = README rsa-16k.key - -# Note: There is a file cavs-driver.pl in the SVN but we do not -# distribute it because we have no configure tests for Perl and thus -# we can expect that people get it from the SVN instead. +EXTRA_DIST = README rsa-16k.key cavs_tests.sh cavs_driver.pl diff --git a/tests/benchmark.c b/tests/benchmark.c index 452bef91..a7a0b413 100644 --- a/tests/benchmark.c +++ b/tests/benchmark.c @@ -1054,7 +1054,9 @@ main( int argc, char **argv ) fprintf (stderr, PGM ": version mismatch\n"); exit (1); } - gcry_control (GCRYCTL_DISABLE_SECMEM, 0); + + if (!gcry_fips_mode_active ()) + gcry_control (GCRYCTL_DISABLE_SECMEM, 0); if (use_random_daemon) gcry_control (GCRYCTL_USE_RANDOM_DAEMON, 1); diff --git a/tests/cavs_driver.pl b/tests/cavs_driver.pl index 55c238f6..c4ab0a8b 100644..100755 --- a/tests/cavs_driver.pl +++ b/tests/cavs_driver.pl @@ -1,6 +1,6 @@ #!/usr/bin/env perl # -# $Id: cavs_driver.pl 1236 2008-09-17 13:00:06Z smueller $ +# Id: cavs_driver.pl 1236 2008-09-17 13:00:06Z smueller # # CAVS test driver (based on the OpenSSL driver) # Written by: Stephan Müller <sm@atsec.com> @@ -282,12 +282,87 @@ sub openssl_state_cipher($$$$$) { ########################################################### ###### libgcrypt implementation ########################################################### +sub libgcrypt_encdec($$$$$) { + my $key=shift; + my $iv=shift; + my $cipher=shift; + my $enc = (shift) ? "encrypt" : "decrypt"; + my $data=shift; + + my $program="fipsdrv --no-fips --key $key --iv $iv --algo $cipher $enc"; + + return pipe_through_program($data,$program); +} + + +sub libgcrypt_rsa_sign($$$) { + my $data = shift; + my $hashalgo = shift; + my $keyfile = shift; + + die "ARCFOUR not available for RSA" if $opt{'R'}; + return pipe_through_program($data, + "fipsdrv --verbose --algo $hashalgo --key $keyfile rsa-sign"); +} + + +sub libgcrypt_rsa_verify($$$$) { + my $data = shift; + my $cipher = shift; + my $keyfile = shift; + my $sigfile = shift; + + $data = hex2bin($data); + die "ARCFOUR not available for RSA" if $opt{'R'}; + $data = pipe_through_program($data, + "fipsdrv --key $keyfile rsa-verify"); + + # Parse through the OpenSSL output information + return ($data =~ /OK/); +} + + +sub libgcrypt_gen_rsakey($$) { + my $keylen = shift; + my $file = shift; + + die "ARCFOUR not available for RSA" if $opt{'R'}; + my @args = ("fipsdrv --keysize $keylen rsa-gen > $file"); + system(@args) == 0 + or die "system @args failed: $?"; + die "system @args failed: file $file not created" if (! -f $file); +} + + +sub libgcrypt_hash($$) { + my $pt = shift; + my $hashalgo = shift; + + my $program = "fipsdrv --no-fips --algo $hashalgo digest"; + die "ARCFOUR not available for hashes" if $opt{'R'}; + + return pipe_through_program($pt, $program); +} + + +sub libgcrypt_state_cipher($$$$$) { + my $cipher = shift; + my $enc = (shift) ? "encrypt": "decrypt"; + my $bufsize = shift; + my $key = shift; + my $iv = shift; + + my $program="fipsdrv --no-fips --binary --key ".bin2hex($key)." --iv ".bin2hex($iv)." --algo '$cipher' --chunk '$bufsize' $enc"; + return $program; +} + + sub libgcrypt_state_rng($$$) { my $key = shift; my $dt = shift; my $v = shift; - return "fipsrngdrv --binary --loop $key $v $dt"; + return "fipsdrv --binary --progress --loop --key $key --iv $v --dt $dt random"; } sub libgcrypt_hmac($$$$) { @@ -296,8 +371,8 @@ sub libgcrypt_hmac($$$$) { my $msg = shift; my $hashtype = shift; - die "libgcrypt HMAC test not yet implemented: key $key, maclen $maclen, msg $msg, hashtype $hashtype"; - + my $program = "fipsdrv --no-fips --key $key --algo $hashtype hmac-sha"; + return pipe_through_program($msg, $program); } ######### End of libgcrypt implementation ################ @@ -941,12 +1016,12 @@ sub crypto_mct($$$$$$$$) { $old_calc_data = $calc_data; # $calc_data = AES($key, $calc_data); - #print STDERR "source_data=", bin2hex($source_data), "\n"; + #print STDERR "source_data=", bin2hex($source_data), "\n"; syswrite $CI, $source_data or die; my $len = sysread $CO, $calc_data, $bufsize; - #print STDERR "len=$len, bufsize=$bufsize\n"; + #print STDERR "len=$len, bufsize=$bufsize\n"; die if $len ne $bufsize; - #print STDERR "calc_data=", bin2hex($calc_data), "\n"; + #print STDERR "calc_data=", bin2hex($calc_data), "\n"; if ( (!$enc && $ciph =~ /des/) || $ciph =~ /rc4/ ) { @@ -1158,10 +1233,12 @@ sub rngx931($$$$) { sub usage() { print STDERR "Usage: -$0 [-R] <CAVS-test vector file> - --R execution of ARCFOUR instead of OpenSSL"; +$0 [-R] [-I name] <CAVS-test vector file> +-R execution of ARCFOUR instead of OpenSSL +-I NAME Use interface style NAME: + openssl OpenSSL (default) + libgcrypt Libgcrypt"; } # Parser of CAVS test vector file @@ -1548,21 +1625,31 @@ sub main() { usage() unless @ARGV; - getopts("R", \%opt) or die "bad option"; + getopts("RI:", \%opt) or die "bad option"; ##### Set library - #print STDERR "Using OpenSSL interface functions\n"; - #$encdec = \&openssl_encdec; - #$rsa_sign = \&openssl_rsa_sign; - #$rsa_verify = \&openssl_rsa_verify; - #$gen_rsakey = \&openssl_gen_rsakey; - #$hash = \&openssl_hash; - #$state_cipher = \&openssl_state_cipher; - - print STDERR "Using libgcrypt interface functions\n"; - $state_rng = \&libgcrypt_state_rng; - $hmac = \&libgcrypt_hmac; + if ( ! defined $opt{'I'} || $opt{'I'} eq 'openssl' ) { + print STDERR "Using OpenSSL interface functions\n"; + $encdec = \&openssl_encdec; + $rsa_sign = \&openssl_rsa_sign; + $rsa_verify = \&openssl_rsa_verify; + $gen_rsakey = \&openssl_gen_rsakey; + $hash = \&openssl_hash; + $state_cipher = \&openssl_state_cipher; + } elsif ( $opt{'I'} eq 'libgcrypt' ) { + print STDERR "Using libgcrypt interface functions\n"; + $encdec = \&libgcrypt_encdec; + $rsa_sign = \&libgcrypt_rsa_sign; + $rsa_verify = \&libgcrypt_rsa_verify; + $gen_rsakey = \&libgcrypt_gen_rsakey; + $hash = \&libgcrypt_hash; + $state_cipher = \&libgcrypt_state_cipher; + $state_rng = \&libgcrypt_state_rng; + $hmac = \&libgcrypt_hmac; + } else { + die "Invalid interface option given"; + } my $infile=$ARGV[0]; die "Error: Test vector file $infile not found" if (! -f $infile); diff --git a/tests/cavs_tests.sh b/tests/cavs_tests.sh new file mode 100755 index 00000000..6ba2b085 --- /dev/null +++ b/tests/cavs_tests.sh @@ -0,0 +1,125 @@ +#!/bin/sh +# Run FIPS CAVS tests +# Copyright 2008 Free Software Foundation, Inc. +# +# This file is free software; as a special exception the author gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. +# +# This file is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Instructions: +# +# 1. Cd to the libgcrypt/tests directory +# +# 2. Unpack the test vector tarball into subdirectory named "cavs". +# An example directory layout after unpacking might be: +# libgcrypt/tests/cavs/AES/req/CBCGFSbox128.req +# libgcrypt/tests/cavs/AES/req/CFB128MCT128.req +# +# Note that below the "cavs" directory there should only be one +# directory part named "req". Further avoid directory part +# names "resp". +# +# 3. Run this script from the libgcrypt/tests directory: +# ./cavs_tests.sh +# +# 4. Send the result file cavs/CAVS_results-*.zip to the testing lab. +# + +# Stop script if something unexpected happens. +set -e + +# A global flag to keep track of errors. +errors_seen_file="$(pwd)/.#cavs_test.errors_seen.tmp" +[ -f "$errors_seen_file" ] && rm "$errors_seen_file" +continue_mode=no +[ "$1" = "--continue" ] && continue_mode=yes + + +# Function to run one test. +# The argument is the request file name. +function run_one_test () { + local reqfile="$1" + local rspfile + local tmprspfile + local respdir + + tmprspfile=$(echo "$reqfile" | sed 's,.req$,.rsp,') + rspfile=$(echo "$tmprspfile" | sed 's,/req/,/resp/,' ) + respdir=$(dirname "$rspfile") + [ -f "$tmprspfile" ] && rm "$tmprspfile" + [ -d "$respdir" ] || mkdir "$respdir" + [ -f "$rspfile" ] && rm "$rspfile" + + if ./cavs_driver.pl -I libgcrypt "$reqfile"; then + echo "failed test: $reqfile" >&2 + : >"$errors_seen_file" + elif [ -f "$tmprspfile" ]; then + mv "$tmprspfile" "$rspfile" + else + echo "failed test: $reqfile" >&2 + : >"$errors_seen_file" + fi +} + + + +# Save date and system architecure to construct the output archive name +DATE=$(date +%Y%m%d) +ARCH=$(arch || echo unknown) +result_file="CAVS_results-$ARCH-$DATE.zip" + +for f in fipsdrv fipsrngdrv cavs_driver.pl; do + if [ ! -f "./$f" ]; then + echo "required program \"$f\" missing in current directory" >&2 + exit 2 + fi +done +if [ ! -d cavs ]; then + echo "required directory \"cavs\" missing below current directory" >&2 + exit 2 +fi +if [ ! zip -h >/dev/null 2>&1 ]; then + echo "required program \"zip\" is not installed on this system" >&2 + exit 2 +fi + +# Set the PATH to this directory so that the perl script is able to +# find the test drivers. +PATH=.:$PATH + +# Check whether there are any stale response files +find cavs -type f -name "*.rsp" | ( while read f ; do + echo "Stale response file: $f" >&2 + any=yes +done +if [ "$any" = "yes" ]; then + echo "Stale response files found" >&2 + if [ "$continue_mode" != "yes" ]; then + echo "use option --continue if that is not a problem" >&2 + exit 1 + fi +fi +) || exit 1 + + +# Find all test files and run the tests. +find cavs -type f -name "*.req" | while read f ; do + echo "Running test file $f" >&2 + run_one_test "$f" +done + +if [ -f "$errors_seen_file" ]; then + rm "$errors_seen_file" + echo "Error enountered - not packing up response file" >&2 + exit 1 +fi + +echo "Packing up all response files" >&2 +cd cavs +find . -type f -name "*rsp" -print | zip -@ "$result_file" + +echo "Result file is: cavs/$result_file" >&2 diff --git a/tests/fipsdrv.c b/tests/fipsdrv.c new file mode 100644 index 00000000..25018808 --- /dev/null +++ b/tests/fipsdrv.c @@ -0,0 +1,1458 @@ +/* fipsdrv.c - A driver to help with FIPS CAVS tests. + Copyright (C) 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 <http://www.gnu.org/licenses/>. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> +#include <errno.h> +#include <ctype.h> +#ifndef HAVE_W32_SYSTEM +# include <signal.h> +#endif +#include <assert.h> +#include <unistd.h> + +#include <gcrypt.h> + +#define PGM "fipsdrv" + +#define my_isascii(c) (!((c) & 0x80)) +#define digitp(p) (*(p) >= '0' && *(p) <= '9') +#define hexdigitp(a) (digitp (a) \ + || (*(a) >= 'A' && *(a) <= 'F') \ + || (*(a) >= 'a' && *(a) <= 'f')) +#define xtoi_1(p) (*(p) <= '9'? (*(p)- '0'): \ + *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10)) +#define xtoi_2(p) ((xtoi_1(p) * 16) + xtoi_1((p)+1)) +#define DIM(v) (sizeof(v)/sizeof((v)[0])) +#define DIMof(type,member) DIM(((type *)0)->member) + + +/* Verbose mode flag. */ +static int verbose; + +/* Binary input flag. */ +static int binary_input; + +/* Binary output flag. */ +static int binary_output; + +/* Base64 output flag. */ +static int base64_output; + +/* We need to know whetehr we are in loop_mode. */ +static int loop_mode; + +/* ASN.1 classes. */ +enum +{ + UNIVERSAL = 0, + APPLICATION = 1, + ASNCONTEXT = 2, + PRIVATE = 3 +}; + + +/* ASN.1 tags. */ +enum +{ + TAG_NONE = 0, + TAG_BOOLEAN = 1, + TAG_INTEGER = 2, + TAG_BIT_STRING = 3, + TAG_OCTET_STRING = 4, + TAG_NULL = 5, + TAG_OBJECT_ID = 6, + TAG_OBJECT_DESCRIPTOR = 7, + TAG_EXTERNAL = 8, + TAG_REAL = 9, + TAG_ENUMERATED = 10, + TAG_EMBEDDED_PDV = 11, + TAG_UTF8_STRING = 12, + TAG_REALTIVE_OID = 13, + TAG_SEQUENCE = 16, + TAG_SET = 17, + TAG_NUMERIC_STRING = 18, + TAG_PRINTABLE_STRING = 19, + TAG_TELETEX_STRING = 20, + TAG_VIDEOTEX_STRING = 21, + TAG_IA5_STRING = 22, + TAG_UTC_TIME = 23, + TAG_GENERALIZED_TIME = 24, + TAG_GRAPHIC_STRING = 25, + TAG_VISIBLE_STRING = 26, + TAG_GENERAL_STRING = 27, + TAG_UNIVERSAL_STRING = 28, + TAG_CHARACTER_STRING = 29, + TAG_BMP_STRING = 30 +}; + +/* ASN.1 Parser object. */ +struct tag_info +{ + int class; /* Object class. */ + unsigned long tag; /* The tag of the object. */ + unsigned long length; /* Length of the values. */ + int nhdr; /* Length of the header (TL). */ + unsigned int ndef:1; /* The object has an indefinite length. */ + unsigned int cons:1; /* This is a constructed object. */ +}; + + + +/* Print a error message and exit the process with an error code. */ +static void +die (const char *format, ...) +{ + va_list arg_ptr; + + va_start (arg_ptr, format); + fputs (PGM ": ", stderr); + vfprintf (stderr, format, arg_ptr); + va_end (arg_ptr); + exit (1); +} + + +static void +showhex (const char *prefix, const void *buffer, size_t length) +{ + const unsigned char *p = buffer; + + if (prefix) + fprintf (stderr, PGM ": %s: ", prefix); + while (length-- ) + fprintf (stderr, "%02X", *p++); + if (prefix) + putc ('\n', stderr); +} + + +/* Convert STRING consisting of hex characters into its binary + representation and store that at BUFFER. BUFFER needs to be of + LENGTH bytes. The function checks that the STRING will convert + exactly to LENGTH bytes. The string is delimited by either end of + string or a white space character. The function returns -1 on + error or the length of the parsed string. */ +static int +hex2bin (const char *string, void *buffer, size_t length) +{ + int i; + const char *s = string; + + for (i=0; i < length; ) + { + if (!hexdigitp (s) || !hexdigitp (s+1)) + return -1; /* Invalid hex digits. */ + ((unsigned char*)buffer)[i++] = xtoi_2 (s); + s += 2; + } + if (*s && (!my_isascii (*s) || !isspace (*s)) ) + return -1; /* Not followed by Nul or white space. */ + if (i != length) + return -1; /* Not of expected length. */ + if (*s) + s++; /* Skip the delimiter. */ + return s - string; +} + + +/* 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 * +hex2buffer (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)) + return NULL; /* Invalid hex digits. */ + ((unsigned char*)buffer)[length++] = xtoi_2 (s); + } + *r_length = length; + return buffer; +} + +/* Read a file from stream FP into a newly allocated buffer and return + that buffer. The valid length of the buffer is stored at R_LENGTH. + Returns NULL on failure. If decode is set, the file is assumed to + be hex encoded and the decoded content is returned. */ +static void * +read_file (FILE *fp, int decode, size_t *r_length) +{ + char *buffer; + size_t buflen; + size_t nread, bufsize = 0; + + *r_length = 0; +#define NCHUNK 8192 +#ifdef HAVE_DOSISH_SYSTEM + setmode (fileno(fp), O_BINARY); +#endif + buffer = NULL; + buflen = 0; + do + { + bufsize += NCHUNK; + if (!buffer) + buffer = gcry_xmalloc (bufsize); + else + buffer = gcry_xrealloc (buffer, bufsize); + + nread = fread (buffer + buflen, 1, NCHUNK, fp); + if (nread < NCHUNK && ferror (fp)) + { + gcry_free (buffer); + return NULL; + } + buflen += nread; + } + while (nread == NCHUNK); +#undef NCHUNK + if (decode) + { + const char *s; + char *p; + + for (s=buffer,p=buffer,nread=0; nread+1 < buflen; s += 2, nread +=2 ) + { + if (!hexdigitp (s) || !hexdigitp (s+1)) + { + gcry_free (buffer); + return NULL; /* Invalid hex digits. */ + } + *(unsigned char*)p++ = xtoi_2 (s); + } + if (nread != buflen) + { + gcry_free (buffer); + return NULL; /* Odd number of hex digits. */ + } + buflen = p - buffer; + } + + *r_length = buflen; + return buffer; +} + +/* Do in-place decoding of base-64 data of LENGTH in BUFFER. Returns + the new length of the buffer. Dies on error. */ +static size_t +base64_decode (char *buffer, size_t length) +{ + static unsigned char const asctobin[128] = + { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, + 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, + 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, + 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, + 0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff + }; + + int idx = 0; + unsigned char val = 0; + int c = 0; + char *d, *s; + int lfseen = 1; + + /* Find BEGIN line. */ + for (s=buffer; length; length--, s++) + { + if (lfseen && *s == '-' && length > 11 && !memcmp (s, "-----BEGIN ", 11)) + { + for (; length && *s != '\n'; length--, s++) + ; + break; + } + lfseen = (*s == '\n'); + } + + /* Decode until pad character or END line. */ + for (d=buffer; length; length--, s++) + { + if (lfseen && *s == '-' && length > 9 && !memcmp (s, "-----END ", 9)) + break; + if ((lfseen = (*s == '\n')) || *s == ' ' || *s == '\r' || *s == '\t') + continue; + if (*s == '=') + { + /* Pad character: stop */ + if (idx == 1) + *d++ = val; + break; + } + + if ( (*s & 0x80) || (c = asctobin[*(unsigned char *)s]) == 0xff) + die ("invalid base64 character %02X at pos %d detected\n", + *(unsigned char*)s, (int)(s-buffer)); + + switch (idx) + { + case 0: + val = c << 2; + break; + case 1: + val |= (c>>4)&3; + *d++ = val; + val = (c<<4)&0xf0; + break; + case 2: + val |= (c>>2)&15; + *d++ = val; + val = (c<<6)&0xc0; + break; + case 3: + val |= c&0x3f; + *d++ = val; + break; + } + idx = (idx+1) % 4; + } + + return d - buffer; +} + + +/* Parse the buffer at the address BUFFER which consists of the number + of octets as stored at BUFLEN. Return the tag and the length part + from the TLV triplet. Update BUFFER and BUFLEN on success. Checks + that the encoded length does not exhaust the length of the provided + buffer. */ +static int +parse_tag (unsigned char const **buffer, size_t *buflen, struct tag_info *ti) +{ + int c; + unsigned long tag; + const unsigned char *buf = *buffer; + size_t length = *buflen; + + ti->length = 0; + ti->ndef = 0; + ti->nhdr = 0; + + /* Get the tag */ + if (!length) + return -1; /* Premature EOF. */ + c = *buf++; length--; + ti->nhdr++; + + ti->class = (c & 0xc0) >> 6; + ti->cons = !!(c & 0x20); + tag = (c & 0x1f); + + if (tag == 0x1f) + { + tag = 0; + do + { + tag <<= 7; + if (!length) + return -1; /* Premature EOF. */ + c = *buf++; length--; + ti->nhdr++; + tag |= (c & 0x7f); + } + while ( (c & 0x80) ); + } + ti->tag = tag; + + /* Get the length */ + if (!length) + return -1; /* Premature EOF. */ + c = *buf++; length--; + ti->nhdr++; + + if ( !(c & 0x80) ) + ti->length = c; + else if (c == 0x80) + ti->ndef = 1; + else if (c == 0xff) + return -1; /* Forbidden length value. */ + else + { + unsigned long len = 0; + int count = c & 0x7f; + + for (; count; count--) + { + len <<= 8; + if (!length) + return -1; /* Premature EOF. */ + c = *buf++; length--; + ti->nhdr++; + len |= (c & 0xff); + } + ti->length = len; + } + + if (ti->class == UNIVERSAL && !ti->tag) + ti->length = 0; + + if (ti->length > length) + return -1; /* Data larger than buffer. */ + + *buffer = buf; + *buflen = length; + return 0; +} + + +/* Read the file FNAME assuming it is a PEM encoded private key file + and return an S-expression. With SHOW set, the key parameters are + printed. */ +static gcry_sexp_t +read_key_file (const char *fname, int show) +{ + gcry_error_t err; + FILE *fp; + char *buffer; + size_t buflen; + const unsigned char *der; + size_t derlen; + struct tag_info ti; + gcry_mpi_t keyparms[8]; + int idx; + gcry_sexp_t s_key; + + fp = fopen (fname, binary_input?"rb":"r"); + if (!fp) + die ("can't open `%s': %s\n", fname, strerror (errno)); + buffer = read_file (fp, 0, &buflen); + if (!buffer) + die ("error reading `%s'\n", fname); + fclose (fp); + + buflen = base64_decode (buffer, buflen); + + /* Parse the ASN.1 structure. */ + der = (const unsigned char*)buffer; + derlen = buflen; + if ( parse_tag (&der, &derlen, &ti) + || ti.tag != TAG_SEQUENCE || ti.class || !ti.cons || ti.ndef) + goto bad_asn1; + if ( parse_tag (&der, &derlen, &ti) + || ti.tag != TAG_INTEGER || ti.class || ti.cons || ti.ndef) + goto bad_asn1; + if (ti.length != 1 || *der) + goto bad_asn1; /* The value of the first integer is no 0. */ + der += ti.length; derlen += ti.length; + + for (idx=0; idx < DIM(keyparms); idx++) + { + if ( parse_tag (&der, &derlen, &ti) + || ti.tag != TAG_INTEGER || ti.class || ti.cons || ti.ndef) + goto bad_asn1; + if (show) + { + char prefix[2]; + + prefix[0] = idx < 8? "nedpq12u"[idx] : '?'; + prefix[1] = 0; + showhex (prefix, der, ti.length); + } + err = gcry_mpi_scan (keyparms+idx, GCRYMPI_FMT_USG, der, ti.length,NULL); + if (err) + die ("error scanning RSA parameter %d: %s\n", idx, gpg_strerror (err)); + der += ti.length; derlen += ti.length; + } + if (idx != DIM(keyparms)) + die ("not enough RSA key parameters\n"); + + gcry_free (buffer); + + /* Convert from OpenSSL parameter ordering to the OpenPGP order. */ + /* First check that p < q; if not swap p and q and recompute u. */ + if (gcry_mpi_cmp (keyparms[3], keyparms[4]) > 0) + { + gcry_mpi_swap (keyparms[3], keyparms[4]); + gcry_mpi_invm (keyparms[7], keyparms[3], keyparms[4]); + } + + /* Build the S-expression. */ + err = gcry_sexp_build (&s_key, NULL, + "(private-key(rsa(n%m)(e%m)(d%m)(p%m)(q%m)(u%m)))", + keyparms[0], keyparms[1], keyparms[2], + keyparms[3], keyparms[4], keyparms[7] ); + if (err) + die ("error building S-expression: %s\n", gpg_strerror (err)); + + for (idx=0; idx < DIM(keyparms); idx++) + gcry_mpi_release (keyparms[idx]); + + return s_key; + + bad_asn1: + die ("invalid ASN.1 structure in `%s'\n", fname); + return NULL; /*NOTREACHED*/ +} + + +static void +print_buffer (const void *buffer, size_t length) +{ + int writerr = 0; + + if (base64_output) + { + static const unsigned char bintoasc[64+1] = + ("ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/"); + const unsigned char *p; + unsigned char inbuf[4]; + char outbuf[4]; + int idx, quads; + + idx = quads = 0; + for (p = buffer; length; p++, length--) + { + inbuf[idx++] = *p; + if (idx > 2) + { + outbuf[0] = bintoasc[(*inbuf>>2)&077]; + outbuf[1] = bintoasc[(((*inbuf<<4)&060) + |((inbuf[1] >> 4)&017))&077]; + outbuf[2] = bintoasc[(((inbuf[1]<<2)&074) + |((inbuf[2]>>6)&03))&077]; + outbuf[3] = bintoasc[inbuf[2]&077]; + if (fwrite (outbuf, 4, 1, stdout) != 1) + writerr = 1; + idx = 0; + if (++quads >= (64/4)) + { + if (fwrite ("\n", 1, 1, stdout) != 1) + writerr = 1; + quads = 0; + } + } + } + if (idx) + { + outbuf[0] = bintoasc[(*inbuf>>2)&077]; + if (idx == 1) + { + outbuf[1] = bintoasc[((*inbuf<<4)&060)&077]; + outbuf[2] = outbuf[3] = '='; + } + else + { + outbuf[1] = bintoasc[(((*inbuf<<4)&060) + |((inbuf[1]>>4)&017))&077]; + outbuf[2] = bintoasc[((inbuf[1]<<2)&074)&077]; + outbuf[3] = '='; + } + if (fwrite (outbuf, 4, 1, stdout) != 1) + writerr = 1; + quads++; + } + if (quads && fwrite ("\n", 1, 1, stdout) != 1) + writerr = 1; + } + else if (binary_output) + { + if (fwrite (buffer, length, 1, stdout) != 1) + writerr++; + } + else + { + const unsigned char *p = buffer; + + while (length-- && !ferror (stdout) ) + printf ("%02X", *p++); + if (ferror (stdout)) + writerr++; + } + if (!writerr && fflush (stdout) == EOF) + writerr++; + if (writerr) + { +#ifndef HAVE_W32_SYSTEM + if (loop_mode && errno == EPIPE) + loop_mode = 0; + else +#endif + die ("writing output failed: %s\n", strerror (errno)); + } +} + + + +static gcry_error_t +init_external_rng_test (void **r_context, + unsigned int flags, + const void *key, size_t keylen, + const void *seed, size_t seedlen, + const void *dt, size_t dtlen) +{ + return gcry_control (58, + r_context, flags, + key, keylen, + seed, seedlen, + dt, dtlen); +} + +static gcry_error_t +run_external_rng_test (void *context, void *buffer, size_t buflen) +{ + return gcry_control (59, context, buffer, buflen); +} + +static void +deinit_external_rng_test (void *context) +{ + gcry_control (60, context); +} + + +/* Given an OpenSSL cipher name NAME, return the Libgcrypt algirithm + identified and store the libgcrypt mode at R_MODE. Returns 0 on + error. */ +static int +map_openssl_cipher_name (const char *name, int *r_mode) +{ + static struct { + const char *name; + int algo; + int mode; + } table[] = + { + { "bf-cbc", GCRY_CIPHER_BLOWFISH, GCRY_CIPHER_MODE_CBC }, + { "bf", GCRY_CIPHER_BLOWFISH, GCRY_CIPHER_MODE_CBC }, + { "bf-cfb", GCRY_CIPHER_BLOWFISH, GCRY_CIPHER_MODE_CFB }, + { "bf-ecb", GCRY_CIPHER_BLOWFISH, GCRY_CIPHER_MODE_ECB }, + { "bf-ofb", GCRY_CIPHER_BLOWFISH, GCRY_CIPHER_MODE_OFB }, + + { "cast-cbc", GCRY_CIPHER_CAST5, GCRY_CIPHER_MODE_CBC }, + { "cast", GCRY_CIPHER_CAST5, GCRY_CIPHER_MODE_CBC }, + { "cast5-cbc", GCRY_CIPHER_CAST5, GCRY_CIPHER_MODE_CBC }, + { "cast5-cfb", GCRY_CIPHER_CAST5, GCRY_CIPHER_MODE_CFB }, + { "cast5-ecb", GCRY_CIPHER_CAST5, GCRY_CIPHER_MODE_ECB }, + { "cast5-ofb", GCRY_CIPHER_CAST5, GCRY_CIPHER_MODE_OFB }, + + { "des-cbc", GCRY_CIPHER_DES, GCRY_CIPHER_MODE_CBC }, + { "des", GCRY_CIPHER_DES, GCRY_CIPHER_MODE_CBC }, + { "des-cfb", GCRY_CIPHER_DES, GCRY_CIPHER_MODE_CFB }, + { "des-ofb", GCRY_CIPHER_DES, GCRY_CIPHER_MODE_OFB }, + { "des-ecb", GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB }, + + { "des-ede3-cbc", GCRY_CIPHER_3DES, GCRY_CIPHER_MODE_CBC }, + { "des-ede3 ", GCRY_CIPHER_3DES, GCRY_CIPHER_MODE_ECB }, + { "des3 ", GCRY_CIPHER_3DES, GCRY_CIPHER_MODE_CBC }, + { "des-ede3-cfb", GCRY_CIPHER_3DES, GCRY_CIPHER_MODE_CFB }, + { "des-ede3-ofb", GCRY_CIPHER_3DES, GCRY_CIPHER_MODE_OFB }, + + { "rc4", GCRY_CIPHER_ARCFOUR, GCRY_CIPHER_MODE_STREAM }, + + { "aes-128-cbc", GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CBC }, + { "aes-128", GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CBC }, + { "aes-128-cfb", GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CFB }, + { "aes-128-ecb", GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_ECB }, + { "aes-128-ofb", GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_OFB }, + + { "aes-192-cbc", GCRY_CIPHER_AES192, GCRY_CIPHER_MODE_CBC }, + { "aes-192", GCRY_CIPHER_AES192, GCRY_CIPHER_MODE_CBC }, + { "aes-192-cfb", GCRY_CIPHER_AES192, GCRY_CIPHER_MODE_CFB }, + { "aes-192-ecb", GCRY_CIPHER_AES192, GCRY_CIPHER_MODE_ECB }, + { "aes-192-ofb", GCRY_CIPHER_AES192, GCRY_CIPHER_MODE_OFB }, + + { "aes-256-cbc", GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC }, + { "aes-256", GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC }, + { "aes-256-cfb", GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CFB }, + { "aes-256-ecb", GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_ECB }, + { "aes-256-ofb", GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_OFB }, + + { NULL, 0 , 0 } + }; + int idx; + + for (idx=0; table[idx].name; idx++) + if (!strcmp (name, table[idx].name)) + { + *r_mode = table[idx].mode; + return table[idx].algo; + } + *r_mode = 0; + return 0; +} + + + +/* Run an encrypt or decryption operations. If DATA is NULL the + function reads its input in chunks of size DATALEN from fp and + processes it and writes it out until EOF. */ +static void +run_encrypt_decrypt (int encrypt_mode, + int cipher_algo, int cipher_mode, + const void *iv_buffer, size_t iv_buflen, + const void *key_buffer, size_t key_buflen, + const void *data, size_t datalen, FILE *fp) +{ + gpg_error_t err; + gcry_cipher_hd_t hd; + void *outbuf; + size_t outbuflen; + void *inbuf; + size_t inbuflen; + + err = gcry_cipher_open (&hd, cipher_algo, cipher_mode, 0); + if (err) + die ("gcry_cipher_open failed for algo %d, mode %d: %s\n", + cipher_algo, cipher_mode, gpg_strerror (err)); + + err = gcry_cipher_setkey (hd, key_buffer, key_buflen); + if (err) + die ("gcry_cipher_setkey failed with keylen %u: %s\n", + (unsigned int)key_buflen, gpg_strerror (err)); + + err = gcry_cipher_setiv (hd, iv_buffer, iv_buflen); + if (err) + die ("gcry_cipher_setiv failed with ivlen %u: %s\n", + (unsigned int)iv_buflen, gpg_strerror (err)); + + inbuf = data? NULL : gcry_xmalloc (datalen); + outbuflen = datalen; + outbuf = gcry_xmalloc (outbuflen); + + do + { + if (inbuf) + { + int nread = fread (inbuf, 1, datalen, fp); + if (nread < (int)datalen && ferror (fp)) + die ("error reading input\n"); + data = inbuf; + inbuflen = nread; + } + else + inbuflen = datalen; + + if (encrypt_mode) + err = gcry_cipher_encrypt (hd, outbuf, outbuflen, data, inbuflen); + else + err = gcry_cipher_decrypt (hd, outbuf, outbuflen, data, inbuflen); + if (err) + die ("gcry_cipher_%scrypt failed: %s\n", + encrypt_mode? "en":"de", gpg_strerror (err)); + print_buffer (outbuf, outbuflen); + } + while (inbuf); + + gcry_cipher_close (hd); + gcry_free (outbuf); + gcry_free (inbuf); +} + + + +/* Run a digest operation. */ +static void +run_digest (int digest_algo, const void *data, size_t datalen) +{ + gpg_error_t err; + gcry_md_hd_t hd; + const unsigned char *digest; + unsigned int digestlen; + + err = gcry_md_open (&hd, digest_algo, 0); + if (err) + die ("gcry_md_open failed for algo %d: %s\n", + digest_algo, gpg_strerror (err)); + + gcry_md_write (hd, data, datalen); + digest = gcry_md_read (hd, digest_algo); + digestlen = gcry_md_get_algo_dlen (digest_algo); + print_buffer (digest, digestlen); + gcry_md_close (hd); +} + + +/* Run a HMAC operation. */ +static void +run_hmac (int digest_algo, const void *key, size_t keylen, + const void *data, size_t datalen) +{ + gpg_error_t err; + gcry_md_hd_t hd; + const unsigned char *digest; + unsigned int digestlen; + + err = gcry_md_open (&hd, digest_algo, GCRY_MD_FLAG_HMAC); + if (err) + die ("gcry_md_open failed for HMAC algo %d: %s\n", + digest_algo, gpg_strerror (err)); + + gcry_md_setkey (hd, key, keylen); + if (err) + die ("gcry_md_setkey failed for HMAC algo %d: %s\n", + digest_algo, gpg_strerror (err)); + + gcry_md_write (hd, data, datalen); + digest = gcry_md_read (hd, digest_algo); + digestlen = gcry_md_get_algo_dlen (digest_algo); + print_buffer (digest, digestlen); + gcry_md_close (hd); +} + + +static size_t +compute_tag_length (size_t n) +{ + int needed = 0; + + if (n < 128) + needed += 2; /* Tag and one length byte. */ + else if (n < 256) + needed += 3; /* Tag, number of length bytes, 1 length byte. */ + else if (n < 65536) + needed += 4; /* Tag, number of length bytes, 2 length bytes. */ + else + die ("DER object too long to encode\n"); + + return needed; +} + +static unsigned char * +store_tag_length (unsigned char *p, int tag, size_t n) +{ + if (tag == TAG_SEQUENCE) + tag |= 0x20; /* constructed */ + + *p++ = tag; + if (n < 128) + *p++ = n; + else if (n < 256) + { + *p++ = 0x81; + *p++ = n; + } + else if (n < 65536) + { + *p++ = 0x82; + *p++ = n >> 8; + *p++ = n; + } + + return p; +} + + +/* Generate an RSA key of size KEYSIZE using the public exponent + PUBEXP and print it to stdout in the OpenSSL format. The format + is: + + SEQUENCE { + INTEGER (0) -- Unknown constant. + INTEGER -- n + INTEGER -- e + INTEGER -- d + INTEGER -- p + INTEGER -- q (with p < q) + INTEGER -- dmp1 = d mod (p-1) + INTEGER -- dmq1 = d mod (q-1) + INTEGER -- u = p^{-1} mod q + } + +*/ +static void +run_rsa_gen (int keysize, int pubexp) +{ + gpg_error_t err; + gcry_sexp_t keyspec, key, l1; + const char keyelems[] = "nedpq..u"; + gcry_mpi_t keyparms[8]; + size_t keyparmslen[8]; + int idx; + size_t derlen, needed, n; + unsigned char *derbuf, *der; + + err = gcry_sexp_build (&keyspec, NULL, + "(genkey (rsa (nbits %d)(rsa-use-e %d)))", + keysize, pubexp); + if (err) + die ("gcry_sexp_build failed for RSA key generation: %s\n", + gpg_strerror (err)); + + err = gcry_pk_genkey (&key, keyspec); + if (err) + die ("gcry_pk_genkey failed for RSA: %s\n", gpg_strerror (err)); + + gcry_sexp_release (keyspec); + + l1 = gcry_sexp_find_token (key, "private-key", 0); + if (!l1) + die ("private key not found in genkey result\n"); + gcry_sexp_release (key); + key = l1; + + l1 = gcry_sexp_find_token (key, "rsa", 0); + if (!l1) + die ("returned private key not formed as expected\n"); + gcry_sexp_release (key); + key = l1; + + /* Extract the parameters from the S-expression and store them in a + well defined order in KEYPARMS. */ + for (idx=0; idx < DIM(keyparms); idx++) + { + if (keyelems[idx] == '.') + { + keyparms[idx] = gcry_mpi_new (0); + continue; + } + l1 = gcry_sexp_find_token (key, keyelems+idx, 1); + if (!l1) + die ("no %c parameter in returned private key\n", keyelems[idx]); + keyparms[idx] = gcry_sexp_nth_mpi (l1, 1, GCRYMPI_FMT_USG); + if (!keyparms[idx]) + die ("no value for %c parameter in returned private key\n", + keyelems[idx]); + gcry_sexp_release (l1); + } + + gcry_sexp_release (key); + + /* Check that p < q; if not swap p and q and recompute u. */ + if (gcry_mpi_cmp (keyparms[3], keyparms[4]) > 0) + { + gcry_mpi_swap (keyparms[3], keyparms[4]); + gcry_mpi_invm (keyparms[7], keyparms[3], keyparms[4]); + } + + /* Compute the additional parameters. */ + gcry_mpi_sub_ui (keyparms[5], keyparms[3], 1); + gcry_mpi_mod (keyparms[5], keyparms[2], keyparms[5]); + gcry_mpi_sub_ui (keyparms[6], keyparms[4], 1); + gcry_mpi_mod (keyparms[6], keyparms[2], keyparms[6]); + + /* Compute the length of the DER encoding. */ + needed = compute_tag_length (1) + 1; + for (idx=0; idx < DIM(keyparms); idx++) + { + err = gcry_mpi_print (GCRYMPI_FMT_STD, NULL, 0, &n, keyparms[idx]); + if (err) + die ("error formatting parameter: %s\n", gpg_strerror (err)); + keyparmslen[idx] = n; + needed += compute_tag_length (n) + n; + } + + /* Store the key parameters. */ + derlen = compute_tag_length (needed) + needed; + der = derbuf = gcry_xmalloc (derlen); + + der = store_tag_length (der, TAG_SEQUENCE, needed); + der = store_tag_length (der, TAG_INTEGER, 1); + *der++ = 0; + for (idx=0; idx < DIM(keyparms); idx++) + { + der = store_tag_length (der, TAG_INTEGER, keyparmslen[idx]); + err = gcry_mpi_print (GCRYMPI_FMT_STD, der, + keyparmslen[idx], NULL, keyparms[idx]); + if (err) + die ("error formatting parameter: %s\n", gpg_strerror (err)); + der += keyparmslen[idx]; + } + + /* Print the stuff. */ + for (idx=0; idx < DIM(keyparms); idx++) + gcry_mpi_release (keyparms[idx]); + + assert (der - derbuf == derlen); + + if (base64_output) + puts ("-----BEGIN RSA PRIVATE KEY-----"); + print_buffer (derbuf, derlen); + if (base64_output) + puts ("-----END RSA PRIVATE KEY-----"); + + gcry_free (derbuf); +} + + + +/* Sign DATA of length DATALEN using the key taken from the PEM + encoded KEYFILE and the hash algorithm HASHALGO. */ +static void +run_rsa_sign (const void *data, size_t datalen, + int hashalgo, int pkcs1, const char *keyfile) + +{ + gpg_error_t err; + gcry_sexp_t s_data, s_key, s_sig, s_tmp; + gcry_mpi_t sig_mpi = NULL; + unsigned char *outbuf; + size_t outlen; + +/* showhex ("D", data, datalen); */ + + if (pkcs1) + err = gcry_sexp_build (&s_data, NULL, + "(data (flags pkcs1)(hash %s %b))", + gcry_md_algo_name (hashalgo), (int)datalen, data); + else + { + gcry_mpi_t tmp; + + err = gcry_mpi_scan (&tmp, GCRYMPI_FMT_USG, data, datalen,NULL); + if (!err) + { + err = gcry_sexp_build (&s_data, NULL, + "(data (flags raw)(value %m))", tmp); + gcry_mpi_release (tmp); + } + } + if (err) + die ("gcry_sexp_build failed for RSA data input: %s\n", + gpg_strerror (err)); + + s_key = read_key_file (keyfile, 0); + + err = gcry_pk_sign (&s_sig, s_data, s_key); + if (err) + { + gcry_sexp_release (read_key_file (keyfile, 1)); + die ("gcry_pk_signed failed (datalen=%d,keyfile=%s): %s\n", + (int)datalen, keyfile, gpg_strerror (err)); + } + gcry_sexp_release (s_key); + gcry_sexp_release (s_data); + + s_tmp = gcry_sexp_find_token (s_sig, "sig-val", 0); + if (s_tmp) + { + gcry_sexp_release (s_sig); + s_sig = s_tmp; + s_tmp = gcry_sexp_find_token (s_sig, "rsa", 0); + if (s_tmp) + { + gcry_sexp_release (s_sig); + s_sig = s_tmp; + s_tmp = gcry_sexp_find_token (s_sig, "s", 0); + if (s_tmp) + { + gcry_sexp_release (s_sig); + s_sig = s_tmp; + sig_mpi = gcry_sexp_nth_mpi (s_sig, 1, GCRYMPI_FMT_USG); + } + } + } + gcry_sexp_release (s_sig); + + if (!sig_mpi) + die ("no value in returned S-expression\n"); + err = gcry_mpi_aprint (GCRYMPI_FMT_STD, &outbuf, &outlen, sig_mpi); + if (err) + die ("gcry_mpi_aprint failed: %s\n", gpg_strerror (err)); + gcry_mpi_release (sig_mpi); + + print_buffer (outbuf, outlen); + gcry_free (outbuf); +} + + + + +static void +usage (int show_help) +{ + if (!show_help) + { + fputs ("usage: " PGM + " [OPTION] [FILE] (try --help for more information)\n", stderr); + exit (2); + } + fputs + ("Usage: " PGM " [OPTIONS] MODE [FILE]\n" + "Run a crypto operation using hex encoded input and output.\n" + "MODE:\n" + " encrypt, decrypt, digest, random, hmac-sha, rsa-{gen,sign,verify}\n" + "OPTIONS:\n" + " --verbose print additional information\n" + " --binary input and output is in binary form\n" + " --no-fips do not force FIPS mode\n" + " --key KEY use the hex encoded KEY\n" + " --iv IV use the hex encoded IV\n" + " --dt DT use the hex encoded DT for the RNG\n" + " --algo NAME use algorithm NAME\n" + " --keysize N use a keysize of N bits\n" + " --chunk N read in chunks of N bytes (implies --binary)\n" + " --pkcs1 use PKCS#1 encoding\n" + " --loop enable random loop mode\n" + " --progress print pogress indicators\n" + " --help print this text\n" + "With no FILE, or when FILE is -, read standard input.\n" + "Report bugs to " PACKAGE_BUGREPORT ".\n" , stdout); + exit (0); +} + +int +main (int argc, char **argv) +{ + int last_argc = -1; + gpg_error_t err; + int no_fips = 0; + int progress = 0; + int use_pkcs1 = 0; + const char *mode_string; + const char *key_string = NULL; + const char *iv_string = NULL; + const char *dt_string = NULL; + const char *algo_string = NULL; + const char *keysize_string = NULL; + FILE *input; + void *data; + size_t datalen; + size_t chunksize = 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 (1); + } + else if (!strcmp (*argv, "--version")) + { + fputs (PGM " (Libgcrypt) " PACKAGE_VERSION "\n", stdout); + exit (0); + } + else if (!strcmp (*argv, "--verbose")) + { + verbose++; + argc--; argv++; + } + else if (!strcmp (*argv, "--binary")) + { + binary_input = binary_output = 1; + argc--; argv++; + } + else if (!strcmp (*argv, "--no-fips")) + { + no_fips++; + argc--; argv++; + } + else if (!strcmp (*argv, "--loop")) + { + loop_mode = 1; + argc--; argv++; + } + else if (!strcmp (*argv, "--progress")) + { + progress = 1; + argc--; argv++; + } + else if (!strcmp (*argv, "--key")) + { + argc--; argv++; + if (!argc) + usage (0); + key_string = *argv; + argc--; argv++; + } + else if (!strcmp (*argv, "--iv")) + { + argc--; argv++; + if (!argc) + usage (0); + iv_string = *argv; + argc--; argv++; + } + else if (!strcmp (*argv, "--dt")) + { + argc--; argv++; + if (!argc) + usage (0); + dt_string = *argv; + argc--; argv++; + } + else if (!strcmp (*argv, "--algo")) + { + argc--; argv++; + if (!argc) + usage (0); + algo_string = *argv; + argc--; argv++; + } + else if (!strcmp (*argv, "--keysize")) + { + argc--; argv++; + if (!argc) + usage (0); + keysize_string = *argv; + argc--; argv++; + } + else if (!strcmp (*argv, "--chunk")) + { + argc--; argv++; + if (!argc) + usage (0); + chunksize = atoi (*argv); + binary_input = binary_output = 1; + argc--; argv++; + } + else if (!strcmp (*argv, "--pkcs1")) + { + use_pkcs1 = 1; + argc--; argv++; + } + } + + if (!argc || argc > 2) + usage (0); + mode_string = *argv; + if (argc == 2 && strcmp (argv[1], "-")) + { + input = fopen (argv[1], binary_input? "rb":"r"); + if (!input) + die ("can't open `%s': %s\n", argv[1], strerror (errno)); + } + else + input = stdin; + +#ifndef HAVE_W32_SYSTEM + if (loop_mode) + signal (SIGPIPE, SIG_IGN); +#endif + + if (verbose) + fprintf (stderr, PGM ": started (mode=%s)\n", mode_string); + + gcry_control (GCRYCTL_SET_VERBOSITY, (int)verbose); + if (!no_fips) + gcry_control (GCRYCTL_FORCE_FIPS_MODE, 0); + if (!gcry_check_version ("1.4.3")) + die ("Libgcrypt is not sufficient enough\n"); + if (verbose) + fprintf (stderr, PGM ": using Libgcrypt %s\n", gcry_check_version (NULL)); + if (no_fips) + gcry_control (GCRYCTL_DISABLE_SECMEM, 0); + gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0); + + /* Most operations need some input data. */ + if (!chunksize + && strcmp (mode_string, "random") + && strcmp (mode_string, "rsa-gen") ) + { + data = read_file (input, !binary_input, &datalen); + if (!data) + die ("error reading%s input\n", binary_input?"":" and decoding"); + if (verbose) + fprintf (stderr, PGM ": %u bytes of input data\n", + (unsigned int)datalen); + } + else + { + data = NULL; + datalen = 0; + } + + + if (!strcmp (mode_string, "encrypt") || !strcmp (mode_string, "decrypt")) + { + int cipher_algo, cipher_mode; + void *iv_buffer, *key_buffer; + size_t iv_buflen, key_buflen; + + if (!algo_string) + die ("option --algo is required in this mode\n"); + cipher_algo = map_openssl_cipher_name (algo_string, &cipher_mode); + if (!cipher_algo) + die ("cipher algorithm `%s' is not supported\n", algo_string); + if (!iv_string) + die ("option --iv is required in this mode\n"); + iv_buffer = hex2buffer (iv_string, &iv_buflen); + if (!iv_buffer) + die ("invalid value for IV\n"); + if (!key_string) + die ("option --key is required in this mode\n"); + key_buffer = hex2buffer (key_string, &key_buflen); + if (!key_buffer) + die ("invalid value for KEY\n"); + + run_encrypt_decrypt ((*mode_string == 'e'), + cipher_algo, cipher_mode, + iv_buffer, iv_buflen, + key_buffer, key_buflen, + data, data? datalen:chunksize, input); + gcry_free (key_buffer); + gcry_free (iv_buffer); + } + else if (!strcmp (mode_string, "digest")) + { + int algo; + + if (!algo_string) + die ("option --algo is required in this mode\n"); + algo = gcry_md_map_name (algo_string); + if (!algo) + die ("digest algorithm `%s' is not supported\n", algo_string); + + run_digest (algo, data, datalen); + } + else if (!strcmp (mode_string, "random")) + { + void *context; + unsigned char key[16]; + unsigned char seed[16]; + unsigned char dt[16]; + unsigned char buffer[16]; + size_t count = 0; + + if (hex2bin (key_string, key, 16) < 0 ) + die ("value for --key are not 32 hex digits\n"); + if (hex2bin (iv_string, seed, 16) < 0 ) + die ("value for --iv are not 32 hex digits\n"); + if (hex2bin (dt_string, dt, 16) < 0 ) + die ("value for --dt are not 32 hex digits\n"); + + /* The flag value 1 disables the dup check, so that the RNG + returns all generated data. */ + err = init_external_rng_test (&context, 1, key, 16, seed, 16, dt, 16); + if (err) + die ("init external RNG test failed: %s\n", gpg_strerror (err)); + + do + { + err = run_external_rng_test (context, buffer, sizeof buffer); + if (err) + die ("running external RNG test failed: %s\n", gpg_strerror (err)); + print_buffer (buffer, sizeof buffer); + if (progress) + { + if (!(++count % 1000)) + fprintf (stderr, PGM ": %lu random bytes so far\n", + (unsigned long int)count * sizeof buffer); + } + } + while (loop_mode); + + if (progress) + fprintf (stderr, PGM ": %lu random bytes\n", + (unsigned long int)count * sizeof buffer); + + deinit_external_rng_test (context); + } + else if (!strcmp (mode_string, "hmac-sha")) + { + int algo; + void *key_buffer; + size_t key_buflen; + + if (!data) + die ("no data available (do not use --chunk)\n"); + if (!algo_string) + die ("option --algo is required in this mode\n"); + switch (atoi (algo_string)) + { + case 1: algo = GCRY_MD_SHA1; break; + case 224: algo = GCRY_MD_SHA224; break; + case 256: algo = GCRY_MD_SHA256; break; + case 384: algo = GCRY_MD_SHA384; break; + case 512: algo = GCRY_MD_SHA512; break; + default: algo = 0; break; + } + if (!algo) + die ("no digest algorithm found for hmac type `%s'\n", algo_string); + if (!key_string) + die ("option --key is required in this mode\n"); + key_buffer = hex2buffer (key_string, &key_buflen); + if (!key_buffer) + die ("invalid value for KEY\n"); + + run_hmac (algo, key_buffer, key_buflen, data, datalen); + + gcry_free (key_buffer); + } + else if (!strcmp (mode_string, "rsa-gen")) + { + int keysize; + + if (!binary_output) + base64_output = 1; + + keysize = keysize_string? atoi (keysize_string) : 0; + if (keysize < 128 || keysize > 16384) + die ("invalid keysize specified; needs to be 128 .. 16384\n"); + run_rsa_gen (keysize, 65537); + } + else if (!strcmp (mode_string, "rsa-sign")) + { + int algo; + + if (!key_string) + die ("option --key is required in this mode\n"); + if (access (key_string, R_OK)) + die ("option --key needs to specify an existing keyfile\n"); + if (!algo_string) + die ("option --algo is required in this mode\n"); + algo = gcry_md_map_name (algo_string); + if (!algo) + die ("digest algorithm `%s' is not supported\n", algo_string); + if (!data) + die ("no data available (do not use --chunk)\n"); + + run_rsa_sign (data, datalen, algo, use_pkcs1, key_string); + + } + else if (!strcmp (mode_string, "rsa-verify")) + { + } + else + usage (0); + + gcry_free (data); + + /* Because Libgcrypt does not enforce FIPS mode in all cases we let + the process die if Libgcrypt is not anymore in FIPS mode after + the actual operation. */ + if (!no_fips && !gcry_fips_mode_active ()) + die ("FIPS mode is not anymore active\n"); + + if (verbose) + fputs (PGM ": ready\n", stderr); + + return 0; +} + diff --git a/tests/fipsrngdrv.c b/tests/fipsrngdrv.c index d10c9cac..de2ad1ff 100644 --- a/tests/fipsrngdrv.c +++ b/tests/fipsrngdrv.c @@ -131,6 +131,7 @@ main (int argc, char **argv) int binary = 0; int loop = 0; int progress = 0; + int no_fips = 0; unsigned char key[16]; unsigned char seed[16]; unsigned char dt[16]; @@ -161,6 +162,11 @@ main (int argc, char **argv) verbose++; argc--; argv++; } + else if (!strcmp (*argv, "--no-fips")) + { + no_fips++; + argc--; argv++; + } else if (!strcmp (*argv, "--binary")) { binary = 1; @@ -203,7 +209,8 @@ main (int argc, char **argv) fputs (PGM ": started\n", stderr); gcry_control (GCRYCTL_SET_VERBOSITY, (int)verbose); - gcry_control (GCRYCTL_FORCE_FIPS_MODE, 0); + if (!no_fips) + gcry_control (GCRYCTL_FORCE_FIPS_MODE, 0); if (!gcry_check_version ("1.4.3")) die ("version mismatch\n"); gcry_control (GCRYCTL_DISABLE_SECMEM, 0); |