summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWerner Koch <wk@gnupg.org>2008-10-02 18:53:31 +0000
committerWerner Koch <wk@gnupg.org>2008-10-02 18:53:31 +0000
commite9c29dc331090fe9b92cca05b88a6aae6af478ea (patch)
treed590623c26ff69157ee1aecc5686017682956e98
parent7d31a0c3fd7613f86929ce0f0b2cda052080eb1a (diff)
downloadlibgcrypt-e9c29dc331090fe9b92cca05b88a6aae6af478ea.tar.gz
Add CAVS test.
Various minor fixes. Sigbus fixes for AES.
-rw-r--r--AUTHORS5
-rw-r--r--NEWS7
-rw-r--r--cipher/rsa.c3
-rw-r--r--configure.ac4
-rw-r--r--doc/ChangeLog5
-rw-r--r--doc/announce.txt10
-rw-r--r--doc/fips-fsm.fig16
-rw-r--r--doc/gcrypt.texi35
-rw-r--r--src/ChangeLog17
-rw-r--r--src/cipher-proto.h3
-rw-r--r--src/cipher.h5
-rw-r--r--src/dumpsexp.c2
-rw-r--r--src/fips.c1
-rw-r--r--src/gcrypt-module.h7
-rw-r--r--src/gcrypt.h.in4
-rw-r--r--src/module.c4
-rw-r--r--tests/ChangeLog24
-rw-r--r--tests/Makefile.am8
-rw-r--r--tests/benchmark.c4
-rwxr-xr-x[-rw-r--r--]tests/cavs_driver.pl131
-rwxr-xr-xtests/cavs_tests.sh125
-rw-r--r--tests/fipsdrv.c1458
-rw-r--r--tests/fipsrngdrv.c9
23 files changed, 1832 insertions, 55 deletions
diff --git a/AUTHORS b/AUTHORS
index 718a914f..699e7a82 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -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.
diff --git a/NEWS b/NEWS
index 362e81cf..0678dd28 100644
--- a/NEWS
+++ b/NEWS
@@ -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;
}
diff --git a/src/fips.c b/src/fips.c
index 90fb3e22..0a8a15e9 100644
--- a/src/fips.c
+++ b/src/fips.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);