summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWerner Koch <wk@gnupg.org>2008-11-28 19:10:15 +0000
committerWerner Koch <wk@gnupg.org>2008-11-28 19:10:15 +0000
commitee188790d59e674b31b964709971d0c94508c152 (patch)
tree2f6a9066e3a81ed825c17f22e1fab1a5f90e9f1b
parentd665b72c1f810b88849bf839d382264fe52f38bc (diff)
downloadlibgcrypt-ee188790d59e674b31b964709971d0c94508c152.tar.gz
Fixed the fips 186 dsa key generation.
Allow apssing of a seed value. Add a new regression test. Updated the cavs driver.
-rw-r--r--cipher/ChangeLog7
-rw-r--r--cipher/dsa.c30
-rw-r--r--cipher/primegen.c8
-rw-r--r--tests/ChangeLog8
-rw-r--r--tests/Makefile.am2
-rwxr-xr-xtests/cavs_driver.pl473
-rw-r--r--tests/fips186-dsa.c460
-rw-r--r--tests/fipsdrv.c161
8 files changed, 1017 insertions, 132 deletions
diff --git a/cipher/ChangeLog b/cipher/ChangeLog
index 86a2d523..84b9d4f4 100644
--- a/cipher/ChangeLog
+++ b/cipher/ChangeLog
@@ -1,3 +1,10 @@
+2008-11-28 Werner Koch <wk@g10code.com>
+
+ * dsa.c (generate_fips186): Add arg DERIVEPARMS and use the seed
+ value if available.
+
+ * primegen.c (_gcry_generate_fips186_2_prime): Fix inner p loop.
+
2008-11-26 Werner Koch <wk@g10code.com>
* primegen.c (_gcry_generate_fips186_3_prime): New.
diff --git a/cipher/dsa.c b/cipher/dsa.c
index 8e687936..40930897 100644
--- a/cipher/dsa.c
+++ b/cipher/dsa.c
@@ -356,15 +356,20 @@ generate (DSA_secret_key *sk, unsigned int nbits, unsigned int qbits,
/* Generate a DSA key pair with a key of size NBITS using the
algorithm given in FIPS-186-3. If USE_FIPS186_2 is true,
- FIPS-186-2 is used and thus the length is restricted to
- 1024/160. */
+ FIPS-186-2 is used and thus the length is restricted to 1024/160.
+ If DERIVEPARMS are not NULL the may contain a seed value. */
static gpg_err_code_t
generate_fips186 (DSA_secret_key *sk, unsigned int nbits, unsigned int qbits,
- int use_fips186_2,
+ gcry_sexp_t deriveparms, int use_fips186_2,
int *r_counter, void **r_seed, size_t *r_seedlen,
gcry_mpi_t *r_h)
{
gpg_err_code_t ec;
+ struct {
+ gcry_sexp_t sexp;
+ const void *seed;
+ size_t seedlen;
+ } initial_seed = { NULL, NULL, 0 };
gcry_mpi_t prime_q = NULL;
gcry_mpi_t prime_p = NULL;
gcry_mpi_t value_g = NULL; /* The generator. */
@@ -403,10 +408,22 @@ generate_fips186 (DSA_secret_key *sk, unsigned int nbits, unsigned int qbits,
else
return GPG_ERR_INV_VALUE;
+ /* Get an initial seed value. */
+ if (deriveparms)
+ {
+ initial_seed.sexp = gcry_sexp_find_token (deriveparms, "seed", 0);
+ if (initial_seed.sexp)
+ initial_seed.seed = gcry_sexp_nth_data (initial_seed.sexp, 1,
+ &initial_seed.seedlen);
+ }
+
/* Fixme: Enable 186-3 after it has been approved and after fixing
- the generation fucntion. */
+ the generation function. */
/* if (use_fips186_2) */
- ec = _gcry_generate_fips186_2_prime (nbits, qbits, NULL, 0,
+ (void)use_fips186_2;
+ ec = _gcry_generate_fips186_2_prime (nbits, qbits,
+ initial_seed.seed,
+ initial_seed.seedlen,
&prime_q, &prime_p,
r_counter,
r_seed, r_seedlen);
@@ -415,6 +432,7 @@ generate_fips186 (DSA_secret_key *sk, unsigned int nbits, unsigned int qbits,
/* &prime_q, &prime_p, */
/* r_counter, */
/* r_seed, r_seedlen, NULL); */
+ gcry_sexp_release (initial_seed.sexp);
if (ec)
goto leave;
@@ -669,7 +687,7 @@ dsa_generate_ext (int algo, unsigned int nbits, unsigned long evalue,
size_t seedlen;
gcry_mpi_t h_value;
- ec = generate_fips186 (&sk, nbits, qbits, use_fips186_2,
+ ec = generate_fips186 (&sk, nbits, qbits, deriveparms, use_fips186_2,
&counter, &seed, &seedlen, &h_value);
gcry_sexp_release (deriveparms);
if (!ec)
diff --git a/cipher/primegen.c b/cipher/primegen.c
index 1d8aba86..b869bee8 100644
--- a/cipher/primegen.c
+++ b/cipher/primegen.c
@@ -1549,7 +1549,7 @@ _gcry_generate_fips186_2_prime (unsigned int pbits, unsigned int qbits,
if (ec)
goto leave;
if (value_k == value_n)
- mpi_clear_highbit (tmpval, value_b+1); /* (V_n mod 2^b) */
+ mpi_clear_highbit (tmpval, value_b); /* (V_n mod 2^b) */
mpi_lshift (tmpval, tmpval, value_k*qbits);
mpi_add (value_w, value_w, tmpval);
}
@@ -1570,7 +1570,7 @@ _gcry_generate_fips186_2_prime (unsigned int pbits, unsigned int qbits,
if (mpi_get_nbits (prime_p) >= pbits-1
&& check_prime (prime_p, val_2, 64, NULL, NULL) )
break; /* Yes, P is prime, continue with Step 15. */
-
+
/* Step 13: counter = counter + 1, offset = offset + n + 1. */
counter++;
@@ -1582,7 +1582,7 @@ _gcry_generate_fips186_2_prime (unsigned int pbits, unsigned int qbits,
/* Step 15: Save p, q, counter and seed. */
/* log_debug ("fips186-2 pbits p=%u q=%u counter=%d\n", */
/* mpi_get_nbits (prime_p), mpi_get_nbits (prime_q), counter); */
-/* log_printhex("fips186-2 seed:", seed, seedlen); */
+/* log_printhex("fips186-2 seed:", seed, seedlen); */
/* log_mpidump ("fips186-2 prime p", prime_p); */
/* log_mpidump ("fips186-2 prime q", prime_q); */
if (r_q)
@@ -1790,7 +1790,7 @@ _gcry_generate_fips186_3_prime (unsigned int pbits, unsigned int qbits,
if (ec)
goto leave;
if (value_j == value_n)
- mpi_clear_highbit (tmpval, value_b+1); /* (V_n mod 2^b) */
+ mpi_clear_highbit (tmpval, value_b); /* (V_n mod 2^b) */
mpi_lshift (tmpval, tmpval, value_j*qbits);
mpi_add (value_w, value_w, tmpval);
}
diff --git a/tests/ChangeLog b/tests/ChangeLog
index 229fd1c3..703a816a 100644
--- a/tests/ChangeLog
+++ b/tests/ChangeLog
@@ -1,3 +1,11 @@
+2008-11-28 Werner Koch <wk@g10code.com>
+
+ * fips186-dsa.c: New.
+
+ * fipsdrv.c (print_mpi_line, print_data_line): New.
+ (run_dsa_pqg_gen): New.
+ (usage): Add mode dsa-pqg-gen.
+
2008-11-25 Werner Koch <wk@g10code.com>
* pubkey.c (get_dsa_key_new): New.
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 38901f66..f9f39258 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -19,7 +19,7 @@
## Process this file with automake to produce Makefile.in
TESTS = version t-mpi-bit prime register ac ac-schemes ac-data basic \
- mpitests tsexp keygen pubkey hmac keygrip
+ mpitests tsexp keygen pubkey hmac keygrip fips186-dsa
# random.c uses fork() thus a test for W32 does not make any sense.
diff --git a/tests/cavs_driver.pl b/tests/cavs_driver.pl
index 8b4079ce..c1edb57c 100755
--- a/tests/cavs_driver.pl
+++ b/tests/cavs_driver.pl
@@ -1,6 +1,6 @@
#!/usr/bin/env perl
#
-# $Id: cavs_driver.pl 1383 2008-10-30 11:45:31Z smueller $
+# $Id: cavs_driver.pl 1395 2008-11-10 15:18:03Z smueller $
#
# CAVS test driver (based on the OpenSSL driver)
# Written by: Stephan Müller <sm@atsec.com>
@@ -89,6 +89,11 @@
# ANSI931_AES128MCT
# ANSI931_AES128VST
#
+# DSA
+# PQGGen
+# SigGen
+# SigVer
+#
# RC4 (atsec developed tests)
# RC4KeyBD
# RC4MCT
@@ -105,7 +110,6 @@ use MIME::Base64;
# Contains the command line options
my %opt;
-
#################################################################
##### Central interface functions to the external ciphers #######
#################################################################
@@ -143,7 +147,7 @@ my $rsa_sign;
# $2: hash algo
# $3: file holding the public RSA key in PEM format
# $4: file holding the signature in binary form
-# return: 1 == verfied / 0 == not verified
+# return: 1 == verified / 0 == not verified
my $rsa_verify;
# generate a new private RSA key with the following properties:
@@ -171,6 +175,9 @@ my $hash;
# $5: IV in binary form
# return: command line to execute the application
my $state_cipher;
+# the only difference of the DES version is that it implements the inner loop
+# of the TDES tests
+my $state_cipher_des;
# supplying the call to the external cipher implementation
# that is being used to keep STDIN and STDOUT open
@@ -196,6 +203,40 @@ my $state_rng;
# return: calculated HMAC in hex format
my $hmac;
+#
+# Generate the P, Q, G, Seed, counter, h (value used to generate g) values
+# for DSA
+# $1: modulus size
+# return: string with the calculated values in hex format, where each value
+# is separated from the previous with a \n in the following order:
+# P\n
+# Q\n
+# G\n
+# Seed\n
+# counter\n
+# h
+my $dsa_pqggen;
+
+# Verify a message with DSA
+# $1: data to be verified in hex form
+# $2: file holding the public DSA key in PEM format
+# $3: R value of the signature
+# $4: S value of the signature
+# return: 1 == verified / 0 == not verified
+my $dsa_verify;
+
+# generate a new DSA key with the following properties:
+# PEM format
+# $1 keyfile name
+# return: file created, hash with keys of P, Q, G in hex format
+my $gen_dsakey;
+
+# Sign a message with DSA
+# $1: data to be signed in hex form
+# $2: Key file in PEM format with the private key
+# return: hash of digest information in hex format with Y, R, S as keys
+my $dsa_sign;
+
################################################################
##### OpenSSL interface functions
################################################################
@@ -273,8 +314,6 @@ sub openssl_state_cipher($$$$$) {
my $key = shift;
my $iv = shift;
- #FIXME: Implement the inner loop right here.
-
my $enc = $encdec ? "-e": "-d";
# We only invoke the driver with the IV parameter, if we have
@@ -362,7 +401,28 @@ sub libgcrypt_state_cipher($$$$$) {
my $key = shift;
my $iv = shift;
+ # We only invoke the driver with the IV parameter, if we have
+ # an IV, otherwise, we skip it
+ $iv = "--iv ".bin2hex($iv) if ($iv);
+
+ my $program="fipsdrv --binary --key ".bin2hex($key)." $iv --algo '$cipher' --chunk '$bufsize' $enc";
+
+ return $program;
+}
+
+sub libgcrypt_state_cipher_des($$$$$) {
+ my $cipher = shift;
+ my $enc = (shift) ? "encrypt": "decrypt";
+ my $bufsize = shift;
+ my $key = shift;
+ my $iv = shift;
+
+ # We only invoke the driver with the IV parameter, if we have
+ # an IV, otherwise, we skip it
+ $iv = "--iv ".bin2hex($iv) if ($iv);
+
my $program="fipsdrv --algo '$cipher' --mct-server $enc";
+
return $program;
}
@@ -384,6 +444,13 @@ sub libgcrypt_hmac($$$$) {
return pipe_through_program($msg, $program);
}
+sub libgcrypt_dsa_pqggen($) {
+ my $mod = shift;
+
+ my $program = "fipsdrv --keysize $mod dsa-pqg-gen";
+ return pipe_through_program("", $program);
+}
+
######### End of libgcrypt implementation ################
################################################################
@@ -532,39 +599,6 @@ sub fix_key_parity($) {
}
####################################################
-# Encrypt/Decrypt routines
-
-# encryption
-# $1 key in hex form
-# $2 iv in hex form
-# $3 cipher
-# $4 data in hex form
-# return encrypted data
-sub encrypt($$$$) {
- my $key=shift;
- my $iv=shift;
- my $cipher=shift;
- my $data=shift;
-
- return &$encdec($key, $iv, $cipher, 1, $data);
-}
-
-# decryption
-# $1 key in hex form
-# $2 iv in hex form
-# $3 cipher
-# $4 data in hex form
-# return encrypted data
-sub decrypt($$$$) {
- my $key=shift;
- my $iv=shift;
- my $cipher=shift;
- my $data=shift;
-
- return &$encdec($key, $iv, $cipher, 0, $data);
-}
-
-####################################################
# DER/PEM utility functions
# Cf. http://www.columbia.edu/~ariel/ssleay/layman.html
@@ -920,10 +954,10 @@ sub kat($$$$$$$$) {
$out .= "IV = $iv\n" if (defined($iv) && $iv ne "");
if ($enc) {
$out .= "PLAINTEXT = $pt\n";
- $out .= "CIPHERTEXT = " . encrypt($key1, $iv, $cipher, $pt) . "\n";
+ $out .= "CIPHERTEXT = " . &$encdec($key1, $iv, $cipher, 1, $pt) . "\n";
} else {
$out .= "CIPHERTEXT = $pt\n";
- $out .= "PLAINTEXT = " . decrypt($key1, $iv, $cipher, $pt) . "\n";
+ $out .= "PLAINTEXT = " . &$encdec($key1, $iv, $cipher, 0, $pt) . "\n";
}
return $out;
@@ -1008,8 +1042,6 @@ sub crypto_mct($$$$$$$$) {
my $source_data = hex2bin(shift);
my $cipher = shift;
my $enc = shift;
- my $line;
- my $next_source;
my $out = "";
@@ -1025,18 +1057,7 @@ sub crypto_mct($$$$$$$$) {
my $iloop=1000;
if ($ciph =~ /des/) {$oloop=400;$iloop=10000;}
- my ($CO, $CI);
- my $cipher_imp = &$state_cipher($cipher, $enc, $bufsize, $key1, $iv);
- my $pid = open2($CO, $CI, $cipher_imp);
- my $len;
-
for (my $i=0; $i<$oloop; ++$i) {
- my $calc_data;
- my $old_calc_data;
- my $old_old_calc_data;
- my $ov;
- my $iv_arg;
-
$out .= "COUNT = $i\n";
if (defined($key2)) {
$out .= "$keytype = ". bin2hex($key1). "\n";
@@ -1059,45 +1080,69 @@ sub crypto_mct($$$$$$$$) {
} else {
$out .= "CIPHERTEXT = ". bin2hex($source_data). "\n";
}
-
- # Need to provide a dummy IV in case of ECB mode.
- $iv_arg = (defined($iv) && $iv ne "")
- ? bin2hex($iv)
- : "00"x(length($source_data));
-
- print $CI "1\n"
- .$iloop."\n"
- .bin2hex($key1)."\n"
- .$iv_arg."\n"
- .bin2hex($source_data)."\n\n" or die;
-
- # fixme: We should skip over empty lines here.
-
- chomp($line = <$CO>); #print STDERR " calc=$line\n";
- $calc_data = hex2bin($line);
-
- chomp($line = <$CO>); #print STDERR " old_calc=$line\n";
- $old_calc_data = hex2bin($line);
-
- chomp($line = <$CO>); #print STDERR "old_old_calc=$line\n";
- $old_old_calc_data = hex2bin($line);
-
- chomp($line = <$CO>); #print STDERR " ov=$line\n";
- $ov = hex2bin($line);
-
- chomp($line = <$CO>); #print STDERR " next source=$line\n";
- $next_source = hex2bin($line);
-
- # Skip over empty line.
- $line = <$CO>;
-
+ my ($CO, $CI);
+ my $cipher_imp = &$state_cipher($cipher, $enc, $bufsize, $key1, $iv);
+ $cipher_imp = &$state_cipher_des($cipher, $enc, $bufsize, $key1, $iv) if($cipher =~ /des/);
+ my $pid = open2($CO, $CI, $cipher_imp);
+
+ my $calc_data = $iv; # CT[j]
+ my $old_calc_data; # CT[j-1]
+ my $old_old_calc_data; # CT[j-2]
+ my $next_source;
+
+ # TDES inner loop implements logic within driver
+ if ($cipher =~ /des/) {
+ print $CI "1\n"
+ .$iloop."\n"
+ .bin2hex($key1)."\n"
+ .bin2hex($iv)."\n"
+ .bin2hex($source_data)."\n\n" or die;
+ chomp(my $line = <$CO>);
+ $calc_data = hex2bin($line);
+ chomp($line = <$CO>);
+ $old_calc_data = hex2bin($line);
+ chomp($line = <$CO>);
+ $old_old_calc_data = hex2bin($line);
+ chomp($line = <$CO>);
+ $iv = hex2bin($line);
+ chomp($line = <$CO>);
+ $next_source = hex2bin($line);
+ # Skip over empty line.
+ $line = <$CO>;
+ } else {
+ for (my $j = 0; $j < $iloop; ++$j) {
+ $old_old_calc_data = $old_calc_data;
+ $old_calc_data = $calc_data;
+
+ #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";
+ die if $len ne $bufsize;
+ #print STDERR "calc_data=", bin2hex($calc_data), "\n";
+
+ if ( (!$enc && $ciph =~ /des/) ||
+ $ciph =~ /rc4/ ||
+ $cipher =~ /ecb/ ) {
+ #TDES in decryption mode, RC4 and ECB mode
+ #have a special rule
+ $source_data = $calc_data;
+ } else {
+ $source_data = $old_calc_data;
+ }
+ }
+ }
+ close $CO;
+ close $CI;
+ waitpid $pid, 0;
if ($enc) {
$out .= "CIPHERTEXT = ". bin2hex($calc_data). "\n\n";
} else {
$out .= "PLAINTEXT = ". bin2hex($calc_data). "\n\n";
}
-
+
if ( $ciph =~ /aes/ ) {
$key1 ^= substr($old_calc_data . $calc_data, -$keylen);
#print STDERR bin2hex($key1)."\n";
@@ -1135,13 +1180,15 @@ sub crypto_mct($$$$$$$$) {
die "Test limitation: cipher '$cipher' not supported in Monte Carlo testing";
}
- if ($ciph =~ /des/) {
- $iv = $ov if (defined($iv) && $iv ne "");
- if ($cipher =~ /des-ede3-ofb/) {
+ if ($cipher =~ /des-ede3-ofb/) {
$source_data = $source_data ^ $next_source;
- } else {
- $source_data = $next_source;
- }
+ } elsif (!$enc && $cipher =~ /des-ede3-cfb/) {
+ #TDES decryption CFB has a special rule
+ $source_data = $next_source;
+ } elsif (! $enc && $ciph =~ /des/ ) {
+ #TDES in decryption mode has a special rule
+ $iv = $old_calc_data;
+ $source_data = $calc_data;
} elsif ( $ciph =~ /rc4/ || $cipher =~ /ecb/ ) {
#No resetting of IV as the IV is all zero set initially (i.e. no IV)
$source_data = $calc_data;
@@ -1149,11 +1196,7 @@ sub crypto_mct($$$$$$$$) {
$iv = $calc_data;
$source_data = $old_calc_data;
}
-
}
- close $CO;
- close $CI;
- waitpid $pid, 0;
return $out;
}
@@ -1291,6 +1334,96 @@ sub rngx931($$$$) {
return $out;
}
+# DSA PQGGen test
+# $1 modulus size
+# $2 number of rounds to perform the test
+# return: string formatted as expected by CAVS
+sub dsa_pqggen_driver($$) {
+ my $mod = shift;
+ my $rounds = shift;
+
+ my $out = "";
+ for(my $i=0; $i<$rounds; $i++) {
+ my $ret = &$dsa_pqggen($mod);
+ my ($P, $Q, $G, $Seed, $c, $H) = split(/\n/, $ret);
+ die "Return value does not contain all expected values of P, Q, G, Seed, c, H for dsa_pqggen"
+ if (!defined($P) || !defined($Q) || !defined($G) ||
+ !defined($Seed) || !defined($c) || !defined($H));
+ $out .= "P = $P\n";
+ $out .= "Q = $Q\n";
+ $out .= "G = $G\n";
+ $out .= "Seed = $Seed\n";
+ $out .= "c = $c\n";
+ $out .= "H = $H\n\n";
+ }
+
+ return $out;
+}
+
+
+# DSA SigGen test
+# $1: Message to be signed in hex form
+# $2: file name with DSA key in PEM form
+# return: string formatted as expected by CAVS
+sub dsa_siggen($$) {
+ my $data = shift;
+ my $keyfile = shift;
+
+ my $out = "";
+
+ my %ret = &$dsa_sign($data, $keyfile);
+
+ $out .= "Msg = $data\n";
+ $out .= "Y = " . $ret{'Y'} . "\n";
+ $out .= "R = " . $ret{'R'} . "\n";
+ $out .= "S = " . $ret{'S'} . "\n";
+
+ return $out;
+}
+
+
+# DSA signature verification
+# $1 modulus
+# $2 P
+# $3 Q
+# $4 G
+# $5 Y - public key
+# $6 r
+# $7 s
+# $8 message to be verified
+# return: string formatted as expected by CAVS
+sub dsa_sigver($$$$$$$$) {
+ my $modulus = shift;
+ my $p = shift;
+ my $q = shift;
+ my $g = shift;
+ my $y = shift;
+ my $r = shift;
+ my $s = shift;
+ my $msg = shift;
+
+ my $out = "";
+
+ #PQG are already printed - do not print them here
+
+ $out .= "Msg = $msg\n";
+ $out .= "Y = $y\n";
+ $out .= "R = $r\n";
+ $out .= "S = $s\n";
+
+ # XXX maybe a secure temp file name is better here
+ # but since it is not run on a security sensitive
+ # system, I hope that this is fine
+ my $keyfile = "dsa_sigver.tmp.$$";
+ gen_pubdsakey($keyfile, $p, $q, $g, $y);
+
+ $out .= "Result = " . (&$dsa_verify($msg, $keyfile, $r, $s) ? "P\n" : "F\n");
+
+ unlink($keyfile);
+
+ return $out;
+}
+
##############################################################
# Parser of input file and generator of result file
#
@@ -1298,12 +1431,16 @@ sub rngx931($$$$) {
sub usage() {
print STDERR "Usage:
-$0 [-R] [-I name] <CAVS-test vector file>
+$0 [-R] [-D] [-I name] <CAVS-test vector file>
-R execution of ARCFOUR instead of OpenSSL
-I NAME Use interface style NAME:
openssl OpenSSL (default)
- libgcrypt Libgcrypt";
+ libgcrypt Libgcrypt
+-D SigGen and SigVer are executed with DSA
+ Please note that the DSA CAVS vectors do not allow distinguishing
+ them from the RSA vectors. As the RSA test is the default, you have
+ to supply this option to apply the DSA logic";
}
# Parser of CAVS test vector file
@@ -1316,9 +1453,6 @@ sub parse($$) {
my $out = "";
- # Do I need to generate the key?
- my $rsa_keygen = 0;
-
# this is my cipher/hash type
my $cipher = "";
@@ -1344,10 +1478,19 @@ sub parse($$) {
my $e = "";
my $signature = "";
my $rsa_keyfile = "";
+ my $dsa_keyfile = "";
my $dt = "";
my $v = "";
my $klen = "";
my $tlen = "";
+ my $modulus = "";
+ my $capital_n = 0;
+ my $capital_p = "";
+ my $capital_q = "";
+ my $capital_g = "";
+ my $capital_y = "";
+ my $capital_r = "";
+ my $capital_s = "";
my $mode = "";
@@ -1378,7 +1521,7 @@ sub parse($$) {
##### Extract cipher
# XXX there may be more - to be added
- if ($tmpline =~ /^#.*(CBC|ECB|OFB|CFB|SHA-|SigGen|SigVer|RC4VS|ANSI X9\.31|Hash sizes tested)/) {
+ if ($tmpline =~ /^#.*(CBC|ECB|OFB|CFB|SHA-|SigGen|SigVer|RC4VS|ANSI X9\.31|Hash sizes tested|PQGGen)/) {
if ($tmpline =~ /CBC/) { $mode="cbc"; }
elsif ($tmpline =~ /ECB/) { $mode="ecb"; }
elsif ($tmpline =~ /OFB/) { $mode="ofb"; }
@@ -1397,10 +1540,6 @@ sub parse($$) {
$cipher="sha1"; #place holder - might be overwritten later
}
- # RSA Key Generation test
- if ($tmpline =~ /SigGen/) {
- $rsa_keygen = 1;
- }
if ($tmpline =~ /^#.*AESVS/) {
# AES cipher (part of it)
$cipher="aes";
@@ -1431,12 +1570,19 @@ sub parse($$) {
if ($tt == 0) {
##### Identify the test type
- if ($tmpline =~ /KeyGen RSA \(X9.31\)/) {
- $tt =~ 10;
- die "Interface function for RSA KeyGen testing not defined for tested library"
- if (!defined($gen_rsakey));
- }
- if ($tmpline =~ /Hash sizes tested/) {
+ if ($tmpline =~ /SigVer/ && $opt{'D'} ) {
+ $tt = 12;
+ die "Interface function dsa_verify for dSA verification not defined for tested library"
+ if (!defined($dsa_verify));
+ } elsif ($tmpline =~ /SigGen/ && $opt{'D'}) {
+ $tt = 11;
+ die "Interface function dsa_sign or gen_dsakey for DSA sign not defined for tested library"
+ if (!defined($dsa_sign) || !defined($gen_rsakey));
+ } elsif ($tmpline =~ /PQGGen/) {
+ $tt = 10;
+ die "Interface function for DSA PQGGen testing not defined for tested library"
+ if (!defined($dsa_pqggen));
+ } elsif ($tmpline =~ /Hash sizes tested/) {
$tt = 9;
die "Interface function hmac for HMAC testing not defined for tested library"
if (!defined($hmac));
@@ -1463,7 +1609,7 @@ sub parse($$) {
} elsif ($tmpline =~ /Monte|MCT|Carlo/) {
$tt = 2;
die "Interface function state_cipher for Stateful Cipher operation defined for tested library"
- if (!defined($state_cipher));
+ if (!defined($state_cipher) || !defined($state_cipher_des));
} elsif ($cipher =~ /^sha/) {
$tt = 3;
die "Interface function hash for Hashing not defined for tested library"
@@ -1547,19 +1693,26 @@ sub parse($$) {
$pt=$2;
}
elsif ($line =~ /^\[mod\s*=\s*(.*)\]$/) { # found in RSA requests
- $out .= $line . "\n"; # print it
+ $modulus = $1;
+ $out .= $line . "\n\n"; # print it
# generate the private key with given bit length now
# as we have the required key length in bit
- if ($tt == 5) {
+ if ($tt == 11) {
+ $dsa_keyfile = "dsa_siggen.tmp.$$";
+ my %pqg = &$gen_dsakey($dsa_keyfile);
+ $out .= "P = " . $pqg{'P'} . "\n";
+ $out .= "Q = " . $pqg{'Q'} . "\n";
+ $out .= "G = " . $pqg{'G'} . "\n";
+ } elsif ( $tt == 5 ) {
# XXX maybe a secure temp file name is better here
# but since it is not run on a security sensitive
# system, I hope that this is fine
$rsa_keyfile = "rsa_siggen.tmp.$$";
- &$gen_rsakey($1, $rsa_keyfile);
+ &$gen_rsakey($modulus, $rsa_keyfile);
my $modulus = pipe_through_program("", "openssl rsa -pubout -modulus -in $rsa_keyfile");
$modulus =~ s/Modulus=(.*?)\s(.|\s)*/$1/;
- $out .= "\nn = $modulus\n";
- $out .= "\ne = 10001\n"
+ $out .= "n = $modulus\n";
+ $out .= "\ne = 10001\n"
}
}
elsif ($line =~ /^SHAAlg\s*=\s*(.*)/) { #found in RSA requests
@@ -1596,6 +1749,44 @@ sub parse($$) {
if ($tlen ne "");
$tlen=$1;
}
+ elsif ($line =~ /^N\s*=\s*(.)/) { #DSA PQGGen
+ die "N seen twice - check input file"
+ if ($capital_n);
+ $capital_n = $1;
+ }
+ elsif ($line =~ /^P\s*=\s*(.)/) { #DSA SigVer
+ die "P seen twice - check input file"
+ if ($capital_p);
+ $capital_p = $1;
+ $out .= $line . "\n"; # print it
+ }
+ elsif ($line =~ /^Q\s*=\s*(.)/) { #DSA SigVer
+ die "Q seen twice - check input file"
+ if ($capital_q);
+ $capital_q = $1;
+ $out .= $line . "\n"; # print it
+ }
+ elsif ($line =~ /^G\s*=\s*(.)/) { #DSA SigVer
+ die "G seen twice - check input file"
+ if ($capital_g);
+ $capital_g = $1;
+ $out .= $line . "\n"; # print it
+ }
+ elsif ($line =~ /^Y\s*=\s*(.)/) { #DSA SigVer
+ die "Y seen twice - check input file"
+ if ($capital_y);
+ $capital_y = $1;
+ }
+ elsif ($line =~ /^R\s*=\s*(.)/) { #DSA SigVer
+ die "R seen twice - check input file"
+ if ($capital_r);
+ $capital_r = $1;
+ }
+ elsif ($line =~ /^S\s*=\s*(.)/) { #DSA SigVer
+ die "S seen twice - check input file"
+ if ($capital_s);
+ $capital_s = $1;
+ }
else {
$out .= $line . "\n";
}
@@ -1674,6 +1865,48 @@ sub parse($$) {
$pt = "";
}
}
+ elsif ($tt == 10) {
+ if ($modulus ne "" && $capital_n > 0) {
+ $out .= dsa_pqggen_driver($modulus, $capital_n);
+ #$mod is not resetted
+ $capital_n = 0;
+ }
+ }
+ elsif ($tt == 11) {
+ if ($pt ne "" && $dsa_keyfile ne "") {
+ $out .= dsa_siggen($pt, $dsa_keyfile);
+ $pt = "";
+ }
+ }
+ elsif ($tt == 12) {
+ if ($modulus ne "" &&
+ $capital_p ne "" &&
+ $capital_q ne "" &&
+ $capital_g ne "" &&
+ $capital_y ne "" &&
+ $capital_r ne "" &&
+ $capital_s ne "" &&
+ $pt ne "") {
+ $out .= dsa_sigver($modulus,
+ $capital_p,
+ $capital_q,
+ $capital_g,
+ $capital_y,
+ $capital_r,
+ $capital_s,
+ $pt);
+
+ # We do not clear the domain values PQG and
+ # the modulus value as they
+ # are specified only once in a file
+ # and we do not need to print them as they
+ # are already printed above
+ $capital_y = "";
+ $capital_r = "";
+ $capital_s = "";
+ $pt = "";
+ }
+ }
elsif ($tt > 0) {
die "Test case $tt not defined";
}
@@ -1704,7 +1937,7 @@ sub main() {
usage() unless @ARGV;
- getopts("RI:", \%opt) or die "bad option";
+ getopts("DRI:", \%opt) or die "bad option";
##### Set library
@@ -1724,8 +1957,10 @@ sub main() {
$gen_rsakey = \&libgcrypt_gen_rsakey;
$hash = \&libgcrypt_hash;
$state_cipher = \&libgcrypt_state_cipher;
+ $state_cipher_des = \&libgcrypt_state_cipher_des;
$state_rng = \&libgcrypt_state_rng;
$hmac = \&libgcrypt_hmac;
+ $dsa_pqggen = \&libgcrypt_dsa_pqggen;
} else {
die "Invalid interface option given";
}
diff --git a/tests/fips186-dsa.c b/tests/fips186-dsa.c
new file mode 100644
index 00000000..c676c5d5
--- /dev/null
+++ b/tests/fips186-dsa.c
@@ -0,0 +1,460 @@
+/* fips186-dsa.c - FIPS 186 DSA 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 "../src/gcrypt.h"
+
+#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)
+
+static int verbose;
+static int error_count;
+
+static void
+info (const char *format, ...)
+{
+ va_list arg_ptr;
+
+ va_start (arg_ptr, format);
+ vfprintf (stderr, format, arg_ptr);
+ va_end (arg_ptr);
+}
+
+static void
+fail (const char *format, ...)
+{
+ va_list arg_ptr;
+
+ va_start (arg_ptr, format);
+ vfprintf (stderr, format, arg_ptr);
+ va_end (arg_ptr);
+ error_count++;
+}
+
+static void
+die (const char *format, ...)
+{
+ va_list arg_ptr;
+
+ va_start (arg_ptr, format);
+ vfprintf (stderr, format, arg_ptr);
+ va_end (arg_ptr);
+ exit (1);
+}
+
+static void
+show_sexp (const char *prefix, gcry_sexp_t a)
+{
+ char *buf;
+ size_t size;
+
+ if (prefix)
+ fputs (prefix, stderr);
+ size = gcry_sexp_sprint (a, GCRYSEXP_FMT_ADVANCED, NULL, 0);
+ buf = gcry_xmalloc (size);
+
+ gcry_sexp_sprint (a, GCRYSEXP_FMT_ADVANCED, buf, size);
+ fprintf (stderr, "%.*s", (int)size, buf);
+ gcry_free (buf);
+}
+
+static gcry_mpi_t
+mpi_from_string (const char *string)
+{
+ gpg_error_t err;
+ gcry_mpi_t a;
+
+ err = gcry_mpi_scan (&a, GCRYMPI_FMT_HEX, string, 0, NULL);
+ if (err)
+ die ("error converting string to mpi: %s\n", gpg_strerror (err));
+ return a;
+}
+
+/* Convert STRING consisting of hex characters into its binary
+ representation and return it as an allocated buffer. The valid
+ length of the buffer is returned at R_LENGTH. The string is
+ delimited by end of string. The function returns NULL on
+ error. */
+static void *
+data_from_hex (const char *string, size_t *r_length)
+{
+ const char *s;
+ unsigned char *buffer;
+ size_t length;
+
+ buffer = gcry_xmalloc (strlen(string)/2+1);
+ length = 0;
+ for (s=string; *s; s +=2 )
+ {
+ if (!hexdigitp (s) || !hexdigitp (s+1))
+ die ("error parsing hex string `%s'\n", string);
+ ((unsigned char*)buffer)[length++] = xtoi_2 (s);
+ }
+ *r_length = length;
+ return buffer;
+}
+
+
+static void
+extract_cmp_mpi (gcry_sexp_t sexp, const char *name, const char *expected)
+{
+ gcry_sexp_t l1;
+ gcry_mpi_t a, b;
+
+ l1 = gcry_sexp_find_token (sexp, name, 0);
+ a = gcry_sexp_nth_mpi (l1, 1, GCRYMPI_FMT_USG);
+ b = mpi_from_string (expected);
+ if (!a)
+ fail ("parameter \"%s\" missing in key\n", name);
+ else if ( gcry_mpi_cmp (a, b) )
+ fail ("parameter \"%s\" does not match expected value\n", name);
+ gcry_mpi_release (b);
+ gcry_mpi_release (a);
+ gcry_sexp_release (l1);
+}
+
+
+static void
+extract_cmp_data (gcry_sexp_t sexp, const char *name, const char *expected)
+{
+ gcry_sexp_t l1;
+ const void *a;
+ size_t alen;
+ void *b;
+ size_t blen;
+
+ l1 = gcry_sexp_find_token (sexp, name, 0);
+ a = gcry_sexp_nth_data (l1, 1, &alen);
+ b = data_from_hex (expected, &blen);
+ if (!a)
+ fail ("parameter \"%s\" missing in key\n", name);
+ else if ( alen != blen || memcmp (a, b, alen) )
+ fail ("parameter \"%s\" does not match expected value\n", name);
+ gcry_free (b);
+ gcry_sexp_release (l1);
+}
+
+static void
+extract_cmp_int (gcry_sexp_t sexp, const char *name, int expected)
+{
+ gcry_sexp_t l1;
+ char *a;
+
+ l1 = gcry_sexp_find_token (sexp, name, 0);
+ a = gcry_sexp_nth_string (l1, 1);
+ if (!a)
+ fail ("parameter \"%s\" missing in key\n", name);
+ else if ( strtoul (a, NULL, 10) != expected )
+ fail ("parameter \"%s\" does not match expected value\n", name);
+ gcry_free (a);
+ gcry_sexp_release (l1);
+}
+
+
+static void
+check_dsa_gen_186_2 (void)
+{
+ static struct {
+ int nbits;
+ const char *p, *q, *g;
+ const char *seed;
+ int counter;
+ const char *h;
+ } tbl[] = {
+ /* These tests are from FIPS 186-2, B.3.1. */
+ {
+ 1024,
+ "d3aed1876054db831d0c1348fbb1ada72507e5fbf9a62cbd47a63aeb7859d6921"
+ "4adeb9146a6ec3f43520f0fd8e3125dd8bbc5d87405d1ac5f82073cd762a3f8d7"
+ "74322657c9da88a7d2f0e1a9ceb84a39cb40876179e6a76e400498de4bb9379b0"
+ "5f5feb7b91eb8fea97ee17a955a0a8a37587a272c4719d6feb6b54ba4ab69",
+ "9c916d121de9a03f71fb21bc2e1c0d116f065a4f",
+ "8157c5f68ca40b3ded11c353327ab9b8af3e186dd2e8dade98761a0996dda99ab"
+ "0250d3409063ad99efae48b10c6ab2bba3ea9a67b12b911a372a2bba260176fad"
+ "b4b93247d9712aad13aa70216c55da9858f7a298deb670a403eb1e7c91b847f1e"
+ "ccfbd14bd806fd42cf45dbb69cd6d6b43add2a78f7d16928eaa04458dea44",
+ "0cb1990c1fd3626055d7a0096f8fa99807399871",
+ 98,
+ "00000000000000000000000000000000000000000000000000000000000000000"
+ "00000000000000000000000000000000000000000000000000000000000000000"
+ "00000000000000000000000000000000000000000000000000000000000000000"
+ "0000000000000000000000000000000000000000000000000000000000002"
+ },
+ {
+ 1024,
+ "f5c73304080353357de1b5967597c27d65f70aa2fe9b6aed1d0afc2b499adf22f"
+ "8e37937096d88548ac36c4a067f8353c7fed73f96f0d688b19b0624aedbae5dbb"
+ "0ee8835a4c269288c0e1d69479e701ee266bb767af39d748fe7d6afc73fdf44be"
+ "3eb6e661e599670061203e75fc8b3dbd59e40b54f358d0097013a0f3867f9",
+ "f8751166cf4f6f3b07c081fd2a9071f23ca1988d",
+ "1e288a442e02461c418ed67a66d24cacbeb8936fbde62ff995f5fd569dee6be62"
+ "4e4f0f9f8c8093f5d192ab3b3f9ae3f2665d95d27fb10e382f45cd356e7f4eb7a"
+ "665db432113ed06478f93b7cf188ec7a1ee97aec8f91ea7bfceaf8b6e7e5a349c"
+ "4ad3225362ef440c57cbc6e69df15b6699caac85f733555075f04781b2b33",
+ "34b3520d45d240a8861b82c8b61ffa16e67b5cce",
+ 622,
+ "00000000000000000000000000000000000000000000000000000000000000000"
+ "00000000000000000000000000000000000000000000000000000000000000000"
+ "00000000000000000000000000000000000000000000000000000000000000000"
+ "0000000000000000000000000000000000000000000000000000000000002",
+ },
+ {
+ 1024,
+ "c6c6f4f4eed927fb1c3b0c81010967e530658e6f9698ebe058b4f47b2dc8fcbc7"
+ "b69296b9e8b6cf55681181fe72492668061b262b0046a0d409902e269b0cb69a4"
+ "55ed1a086caf41927f5912bf0e0cbc45ee81a4f98bf6146f6168a228aec80e9cc"
+ "1162d6f6aa412efe82d4f18b95e34ab790daac5bd7aef0b22fa08ba5dbaad",
+ "d32b29f065c1394a30490b6fcbf812a32a8634ab",
+ "06f973c879e2e89345d0ac04f9c34ad69b9eff1680f18d1c8f3e1596c2e8fa8e1"
+ "ecef6830409e9012d4788bef6ec7414d09c981b47c941b77f39dfc49caff5e714"
+ "c97abe25a7a8b5d1fe88700bb96eff91cca64d53700a28b1146d81bad1212d231"
+ "80154c95a01f5aeebb553a8365c38a5ebe05539b51734233776ce9aff98b2",
+ "b6ec750da2f824cb42c5f7e28c81350d97f75125",
+ 185,
+ "00000000000000000000000000000000000000000000000000000000000000000"
+ "00000000000000000000000000000000000000000000000000000000000000000"
+ "00000000000000000000000000000000000000000000000000000000000000000"
+ "0000000000000000000000000000000000000000000000000000000000002",
+ },
+ {
+ 1024,
+ "b827a9dc9221a6ed1bec7b64d61232aacb2812f888b0a0b3a95033d7a22e77d0b"
+ "ff23bfeed0fb1281b21b8ff7421f0c727d1fb8aa2b843d6885f067e763f83d41f"
+ "d800ab15a7e2b12f71ec2058ee7bd62cd72c26989b272e519785da57bfa1f974b"
+ "c652e1a2d6cfb68477de5635fd019b37add656cff0b802558b31b6d2851e5",
+ "de822c03445b77cec4ad3a6fb0ca39ff97059ddf",
+ "65a9e2d43a378d7063813104586868cacf2fccd51aec1e0b6af8ba3e66dee6371"
+ "681254c3fb5e3929d65e3c4bcd20abd4ddc7cf815623e17b9fc92f02b8d44278b"
+ "848480ffd193104cf5612639511e45bd247708ff6028bd3824f8844c263b46c69"
+ "1f2076f8cd13c5d0be95f1f2a1a17ab1f7e5bc73500bac27d57b473ba9748",
+ "cd2221dd73815a75224e9fde7faf52829b81ac7a",
+ 62,
+ "00000000000000000000000000000000000000000000000000000000000000000"
+ "00000000000000000000000000000000000000000000000000000000000000000"
+ "00000000000000000000000000000000000000000000000000000000000000000"
+ "0000000000000000000000000000000000000000000000000000000000002",
+ },
+ {
+ 1024,
+ "898a8d93e295c8ef2ffd46976225a1543640640d155a576fafa0be32136165803"
+ "ba2eff2782a2be75cc9ec65db6bd3238cca695b3a5a14726a2a314775c377d891"
+ "354b3de6c89e714a05599ca04132c987f889f72c4fe298ccb31f711c03b07e1d9"
+ "8d72af590754cf3847398b60cecd55a4611692b308809560a83880404c227",
+ "c6d786643d2acfc6b8d576863fda8cfbfbd5e03f",
+ "2fd38b8d21c58e8fb5315a177b8d5dc4c450d574e69348b7b9da367c26e72438d"
+ "af8372e7f0bee84ef5dcbbc3727194a2228431192f1779be24837f22a0e14d10d"
+ "5344da1b8b403df9f9b2655095b3d0f67418ed6cd989f35aa4232e4b7001764fb"
+ "e85d6b2c716980f13272fc4271ac1e234f7e24c023cfc2d2dc0aa1e9af2fb",
+ "73483e697599871af983a281e3afa22e0ed86b68",
+ 272,
+ "00000000000000000000000000000000000000000000000000000000000000000"
+ "00000000000000000000000000000000000000000000000000000000000000000"
+ "00000000000000000000000000000000000000000000000000000000000000000"
+ "0000000000000000000000000000000000000000000000000000000000002",
+ },
+
+ /* These tests are generated by the OpenSSL FIPS version. */
+ {
+ 1024,
+ "A404363903FDCE86839BCFD953AAD2DA2B0E70CAED3B5FF5D68F15A1C4BB0A793C"
+ "A9D58FC956804C5901DE0AF99F345ED1A8617C687864BAC044B7C3C3E732A2B255"
+ "EC986AA76EA8CB0E0815B3E0E605650AF7D8058EE7E8EBCDEFFDAB8100D3FC1033"
+ "11BA3AB232EF06BB74BA9A949EC0C7ED324C19B202F4AB725BBB4080C9",
+ "C643946CEA8748E12D430C48DB038F9165814389",
+ "59B7E7BA0033CCE8E6837173420FBB382A784D4154A3C166043F5A68CB92945D16"
+ "892D4CC5585F2D28C780E75A6C20A379E2B58304C1E5FC0D8C15E4E89C4498C8BC"
+ "B90FB36ED8DC0489B9D0BC09EC4411FB0BFADF25485EEAB6700BE0ACF5C44A6ED7"
+ "44A015382FF9B8DA7EAA00DEA135FADC59212DBBFFC1537336FA4B7225",
+ "02708ab36e3f0bfd67ec3b8bd8829d03b84f56bd",
+ 50,
+ "02"
+ },
+ {
+ 1024,
+ "9C664033DB8B203D826F896D2293C62EF9351D5CFD0F4C0AD7EFDA4DDC7F15987"
+ "6A3C68CAB2586B44FD1BD4DEF7A17905D88D321DD77C4E1720D848CA21D79F9B3"
+ "D8F537338E09B44E9F481E8DA3C56569F63146596A050EF8FAEE8ACA32C666450"
+ "04F675C8806EB4025B0A5ECC39CE89983EA40A183A7CF5208BA958045ABD5",
+ "AD0D8CBA369AF6CD0D2BAC0B4CFCAF0A1F9BCDF7",
+ "74D717F7092A2AF725FDD6C2561D1DBE5AEE40203C638BA8B9F49003857873701"
+ "95A44E515C4E8B344F5CDC7F4A6D38097CD57675E7643AB9700692C69F0A99B0E"
+ "039FDDDFCA8CEB607BDB4ADF2834DE1690F5823FC8199FB8F6F29E5A583B6786A"
+ "C14C7E67106C3B30568CBB9383F89287D578159778EB18216799D16D46498",
+ "6481a12a50384888ee84b61024f7c9c685d6ac96",
+ 289,
+ "02"
+ },
+ {
+ 1024,
+
+ "B0DFB602EB8462B1DC8C2214A52B587D3E6842CCF1C38D0F7C7F967ED30CF6828"
+ "1E2675B3BAB594755FB1634E66B4C23936F0725A358F8DFF3C307E2601FD66D63"
+ "5B17270450C50BD2BEC29E0E9A471DF1C15B0191517952268A2763D4BD28B8503"
+ "B3399686272B76B11227F693D7833105EF70C2289C3194CF4527024B272DF",
+ "EA649C04911FAB5A41440287A517EF752A40354B",
+ "88C5A4563ECB949763E0B696CD04B21321360F54C0EE7B23E2CEDC30E9E486162"
+ "01BFB1619E7C54B653D1F890C50E04B29205F5E3E2F93A13B0751AF25491C5194"
+ "93C09DDF6B9C173B3846DFB0E7A5C870BBFC78419260C90E20315410691C8326C"
+ "858D7063E7921F3F601158E912C7EE487FF259202BEEB10F6D9E99190F696",
+ "5bf9d17bc62fbbf3d569c92bd4505586b2e5ef1a",
+ 626,
+ "02"
+ },
+ {
+ 1024,
+ "F783C08D7F9463E48BA87893805C4B34B63C85DF7EBDD9EBEE94DB4AF4E4A415C"
+ "F0F3793AE55096BA1199598798FA8403B28DED7F7C7AFD54FD535861A0150EF4D"
+ "5871465B13837CCF46BEB0A22F8D38DC7D6AE0E14A3845FD0C027CFA97791B977"
+ "CE2808BAD9B43CE69390C0F40016056722D82C0D7B1B27413D026A39D7DAD",
+ "A40D9EE456AED4C8A653FDB47B6629C0B843FE8F",
+ "DF876263E21F263AE6DA57409BD517DCEADB9216048F066D6B58867F8E59A5EEE"
+ "700283A946C1455534618979BE6C227673C1B803910262BD93BC94D5089850614"
+ "F3E29AB64E8C989A7E3E28FE670FFA3EE21DEEEC1AB0B60E1D8E2AA39663BADD7"
+ "2C9F957D7F3D4F17D9FDAD050EB373A6DEFD09F5DA752EAFE046836E14B67",
+ "8a9a57706f69f4f566252cdf6d5cbfdf2020150b",
+ 397,
+ "02"
+ },
+ {
+ 1024,
+ "D40E4F6461E145859CCF60FD57962840BD75FFF12C22F76626F566842252AD068"
+ "29745F0147056354F6C016CF12762B0E331787925B8128CF5AF81F9B176A51934"
+ "96D792430FF83C7B79BD595BDA10787B34600787FA552EFE3662F37B99AAD3F3A"
+ "093732680A01345192A19BECCE6BF5D498E44ED6BED5B0BA72AAD49E8276B",
+ "D12F1BD0AA78B99247FD9F18EAFEE5C136686EA5",
+ "468EBD20C99449C1E440E6F8E452C6A6BC7551C555FE5E94996E20CFD4DA3B9CC"
+ "58499D6CC2374CCF9C392715A537DE10CFCA8A6A37AFBD187CF6B88D26881E5F5"
+ "7521D9D2C9BBA51E7B87B070BBE73F5C5FE31E752CAF88183516D8503BAAC1159"
+ "928EF50DEE52D96F396B93FB4138D786464C315401A853E57C9A0F9D25839",
+ "30b3599944a914a330a3f49d11ec88f555422aef",
+ 678,
+ "02"
+ }
+ };
+ gpg_error_t err;
+ int tno;
+ gcry_sexp_t key_spec, key, pub_key, sec_key, seed_values;
+ gcry_sexp_t l1;
+
+ for (tno = 0; tno < DIM (tbl); tno++)
+ {
+ if (verbose)
+ info ("generating FIPS 186-2 test key %d\n", tno);
+
+ {
+ void *data;
+ size_t datalen;
+
+ data = data_from_hex (tbl[tno].seed, &datalen);
+ err = gcry_sexp_build (&key_spec, NULL,
+ "(genkey (dsa (nbits %d)(use-fips186-2)"
+ "(derive-parms(seed %b))))",
+ tbl[tno].nbits, (int)datalen, data);
+ gcry_free (data);
+ }
+ if (err)
+ die ("error creating S-expression %d: %s\n", tno, gpg_strerror (err));
+
+ err = gcry_pk_genkey (&key, key_spec);
+ gcry_sexp_release (key_spec);
+ if (err)
+ {
+ fail ("error generating key %d: %s\n", tno, gpg_strerror (err));
+ continue;
+ }
+
+ if (verbose > 1)
+ show_sexp ("generated key:\n", key);
+
+ pub_key = gcry_sexp_find_token (key, "public-key", 0);
+ if (!pub_key)
+ fail ("public part missing in key %d\n", tno);
+
+ sec_key = gcry_sexp_find_token (key, "private-key", 0);
+ if (!sec_key)
+ fail ("private part missing in key %d\n", tno);
+
+ l1 = gcry_sexp_find_token (key, "misc-key-info", 0);
+ if (!l1)
+ fail ("misc_key_info part missing in key %d\n", tno);
+ seed_values = gcry_sexp_find_token (l1, "seed-values", 0);
+ if (!seed_values)
+ fail ("seed-values part missing in key %d\n", tno);
+ gcry_sexp_release (l1);
+
+ extract_cmp_mpi (sec_key, "p", tbl[tno].p);
+ extract_cmp_mpi (sec_key, "q", tbl[tno].q);
+ extract_cmp_mpi (sec_key, "g", tbl[tno].g);
+
+ extract_cmp_data (seed_values, "seed", tbl[tno].seed);
+ extract_cmp_int (seed_values, "counter", tbl[tno].counter);
+ extract_cmp_mpi (seed_values, "h", tbl[tno].h);
+
+ gcry_sexp_release (seed_values);
+ gcry_sexp_release (sec_key);
+ gcry_sexp_release (pub_key);
+ gcry_sexp_release (key);
+ }
+}
+
+
+
+int
+main (int argc, char **argv)
+{
+ int debug = 0;
+
+ if (argc > 1 && !strcmp (argv[1], "--verbose"))
+ verbose = 1;
+ else if (argc > 1 && !strcmp (argv[1], "--debug"))
+ {
+ verbose = 2;
+ debug = 1;
+ }
+
+ gcry_control (GCRYCTL_DISABLE_SECMEM, 0);
+ if (!gcry_check_version (GCRYPT_VERSION))
+ die ("version mismatch\n");
+ gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
+ if (debug)
+ gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1u, 0);
+ /* No valuable keys are create, so we can speed up our RNG. */
+ gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
+
+
+ check_dsa_gen_186_2 ();
+
+
+ return error_count ? 1 : 0;
+}
diff --git a/tests/fipsdrv.c b/tests/fipsdrv.c
index e27b84c1..d20b2bbd 100644
--- a/tests/fipsdrv.c
+++ b/tests/fipsdrv.c
@@ -823,6 +823,53 @@ print_buffer (const void *buffer, size_t length)
}
+/* Print an MPI on a line. */
+static void
+print_mpi_line (gcry_mpi_t a, int no_lz)
+{
+ unsigned char *buf, *p;
+ gcry_error_t err;
+ int writerr = 0;
+
+ err = gcry_mpi_aprint (GCRYMPI_FMT_HEX, &buf, NULL, a);
+ if (err)
+ die ("gcry_mpi_aprint failed: %s\n", gpg_strerror (err));
+
+ p = buf;
+ if (no_lz && p[0] == '0' && p[1] == '0' && p[2])
+ p +=2;
+
+ printf ("%s\n", p);
+ if (ferror (stdout))
+ writerr++;
+ if (!writerr && fflush (stdout) == EOF)
+ writerr++;
+ if (writerr)
+ die ("writing output failed: %s\n", strerror (errno));
+ gcry_free (buf);
+}
+
+
+/* Print some data on hex format on a line. */
+static void
+print_data_line (const void *data, size_t datalen)
+{
+ const unsigned char *p = data;
+ int writerr = 0;
+
+ while (data && datalen-- && !ferror (stdout) )
+ printf ("%02X", *p++);
+ putchar ('\n');
+ if (ferror (stdout))
+ writerr++;
+ if (!writerr && fflush (stdout) == EOF)
+ writerr++;
+ if (writerr)
+ die ("writing output failed: %s\n", strerror (errno));
+}
+
+
+
static gcry_error_t
init_external_rng_test (void **r_context,
@@ -1487,6 +1534,105 @@ run_rsa_verify (const void *data, size_t datalen, int hashalgo, int pkcs1,
}
+
+/* Generate DSA donmain parameters for a modulus size of KEYSIZE. The
+ result is printed to stdout with one parameter per line in hex
+ format and in this order: p, q, g, seed, counter, h. */
+static void
+run_dsa_pqg_gen (int keysize)
+{
+ gpg_error_t err;
+ gcry_sexp_t keyspec, key, l1, l2;
+ gcry_mpi_t mpi;
+ int idx;
+ const void *data;
+ size_t datalen;
+ char *string;
+
+ /* Note that we create a complete key but don't return the x and y
+ values. */
+ err = gcry_sexp_build (&keyspec, NULL,
+ "(genkey (dsa (nbits %d)(use-fips186-2)))",
+ keysize);
+ if (err)
+ die ("gcry_sexp_build failed for DSA domain parameter 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");
+
+ l2 = gcry_sexp_find_token (l1, "dsa", 0);
+ if (!l2)
+ die ("returned private key not formed as expected\n");
+ gcry_sexp_release (l1);
+ l1 = l2;
+
+ /* Extract the parameters from the S-expression and print them to stdout. */
+ for (idx=0; "pqg"[idx]; idx++)
+ {
+ l2 = gcry_sexp_find_token (l1, "pqg"+idx, 1);
+ if (!l2)
+ die ("no %c parameter in returned private key\n", "pqg"[idx]);
+ mpi = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG);
+ if (!mpi)
+ die ("no value for %c parameter in returned private key\n","pqg"[idx]);
+ gcry_sexp_release (l2);
+ print_mpi_line (mpi, 1);
+ gcry_mpi_release (mpi);
+ }
+ gcry_sexp_release (l1);
+
+ /* Extract the seed values. */
+ l1 = gcry_sexp_find_token (key, "misc-key-info", 0);
+ if (!l1)
+ die ("misc-key-info not found in genkey result\n");
+
+ l2 = gcry_sexp_find_token (l1, "seed-values", 0);
+ if (!l2)
+ die ("no seed-values in returned private key\n");
+ gcry_sexp_release (l1);
+ l1 = l2;
+
+ l2 = gcry_sexp_find_token (l1, "seed", 0);
+ if (!l2)
+ die ("no seed value in returned private key\n");
+ data = gcry_sexp_nth_data (l2, 1, &datalen);
+ if (!data)
+ die ("no seed value in returned private key\n");
+ print_data_line (data, datalen);
+ gcry_sexp_release (l2);
+
+ l2 = gcry_sexp_find_token (l1, "counter", 0);
+ if (!l2)
+ die ("no counter value in returned private key\n");
+ string = gcry_sexp_nth_string (l2, 1);
+ if (!string)
+ die ("no counter value in returned private key\n");
+ printf ("%lX\n", strtoul (string, NULL, 10));
+ gcry_free (string);
+ gcry_sexp_release (l2);
+
+ l2 = gcry_sexp_find_token (l1, "h", 0);
+ if (!l2)
+ die ("no n value in returned private key\n");
+ mpi = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG);
+ if (!mpi)
+ die ("no h value in returned private key\n");
+ print_mpi_line (mpi, 1);
+ gcry_mpi_release (mpi);
+ gcry_sexp_release (l2);
+
+ gcry_sexp_release (l1);
+ gcry_sexp_release (key);
+}
+
static void
@@ -1502,7 +1648,8 @@ usage (int show_help)
("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"
+ " encrypt, decrypt, digest, random, hmac-sha, rsa-{gen,sign,verify},\n"
+ " dsa-pqg-gen\n"
"OPTIONS:\n"
" --verbose Print additional information\n"
" --binary Input and output is in binary form\n"
@@ -1695,7 +1842,8 @@ main (int argc, char **argv)
if (!chunksize
&& !mct_server
&& strcmp (mode_string, "random")
- && strcmp (mode_string, "rsa-gen") )
+ && strcmp (mode_string, "rsa-gen")
+ && strcmp (mode_string, "dsa-pqg-gen") )
{
data = read_file (input, !binary_input, &datalen);
if (!data)
@@ -1933,6 +2081,15 @@ main (int argc, char **argv)
signature_string);
}
+ else if (!strcmp (mode_string, "dsa-pqg-gen"))
+ {
+ int keysize;
+
+ keysize = keysize_string? atoi (keysize_string) : 0;
+ if (keysize < 1024 || keysize > 3072)
+ die ("invalid keysize specified; needs to be 1024 .. 3072\n");
+ run_dsa_pqg_gen (keysize);
+ }
else
usage (0);