diff -up libgcrypt-1.5.3/random/drbg.c.drbg-cavs libgcrypt-1.5.3/random/drbg.c --- libgcrypt-1.5.3/random/drbg.c.drbg-cavs 2017-02-28 14:28:55.695906569 +0100 +++ libgcrypt-1.5.3/random/drbg.c 2017-02-28 14:28:55.700906686 +0100 @@ -2130,6 +2130,16 @@ gcry_drbg_cavs_test (struct gcry_drbg_te if (ret) goto outbuf; + if (test->entropyrsd) + { + gcry_drbg_string_fill (&testentropy, test->entropyrsd, + test->entropyrsdlen); + gcry_drbg_string_fill (&addtl, test->addtlrsd, + test->addtlrsdlen); + if (gcry_drbg_reseed (drbg, &addtl)) + goto outbuf; + } + gcry_drbg_string_fill (&addtl, test->addtla, test->addtllen); if (test->entpra) { diff -up libgcrypt-1.5.3/random/random.h.drbg-cavs libgcrypt-1.5.3/random/random.h --- libgcrypt-1.5.3/random/random.h.drbg-cavs 2017-02-28 14:28:55.686906357 +0100 +++ libgcrypt-1.5.3/random/random.h 2017-02-28 14:28:55.700906686 +0100 @@ -69,6 +69,10 @@ struct gcry_drbg_test_vector size_t perslen; unsigned char *expected; size_t expectedlen; + unsigned char *entropyrsd; + size_t entropyrsdlen; + unsigned char *addtlrsd; + size_t addtlrsdlen; }; gpg_err_code_t gcry_drbg_cavs_test (struct gcry_drbg_test_vector *test, diff -up libgcrypt-1.5.3/tests/cavs_driver.pl.drbg-cavs libgcrypt-1.5.3/tests/cavs_driver.pl --- libgcrypt-1.5.3/tests/cavs_driver.pl.drbg-cavs 2017-02-28 14:28:55.674906074 +0100 +++ libgcrypt-1.5.3/tests/cavs_driver.pl 2017-02-28 14:41:46.086048300 +0100 @@ -192,15 +192,17 @@ my $rsa_derive; # Sign a message with RSA # $1: data to be signed in hex form # $2: Hash algo -# $3: Key file in PEM format with the private key +# $3: PSS flag +# $4: Key file in PEM format with the private key # return: digest in hex format my $rsa_sign; # Verify a message with RSA # $1: data to be verified in hex form # $2: hash algo -# $3: file holding the public RSA key in PEM format -# $4: file holding the signature in binary form +# $3: PSS flag +# $4: file holding the public RSA key in PEM format +# $5: file holding the signature in binary form # return: 1 == verified / 0 == not verified my $rsa_verify; @@ -329,6 +331,8 @@ my $rsa_keygen; my $rsa_keygen_kat; +my $drbg_kat; + ################################################################ ##### OpenSSL interface functions ################################################################ @@ -350,9 +354,10 @@ sub openssl_encdec($$$$$) { return bin2hex($data); } -sub openssl_rsa_sign($$$) { +sub openssl_rsa_sign($$$$) { my $data = shift; my $cipher = shift; + my $pss = shift; # unsupported my $keyfile = shift; $data=hex2bin($data); @@ -365,6 +370,7 @@ sub openssl_rsa_sign($$$) { sub openssl_rsa_verify($$$$) { my $data = shift; my $cipher = shift; + my $pss = shift; # unsupported my $keyfile = shift; my $sigfile = shift; @@ -497,27 +503,38 @@ sub libgcrypt_rsa_keygen_kat($$$$) { } -sub libgcrypt_rsa_sign($$$) { +sub libgcrypt_rsa_sign($$$$) { my $data = shift; my $hashalgo = shift; + my $pss = shift; my $keyfile = shift; die "ARCFOUR not available for RSA" if $opt{'R'}; + if ($pss) { + return pipe_through_program($data, + "fipsdrv --pss --algo $hashalgo --key $keyfile rsa-sign"); + } return pipe_through_program($data, "fipsdrv --pkcs1 --algo $hashalgo --key $keyfile rsa-sign"); } -sub libgcrypt_rsa_verify($$$$) { +sub libgcrypt_rsa_verify($$$$$) { my $data = shift; my $hashalgo = shift; + my $pss = shift; my $keyfile = shift; my $sigfile = shift; die "ARCFOUR not available for RSA" if $opt{'R'}; + + if ($pss) { + $data = pipe_through_program($data, + "fipsdrv --pss --algo $hashalgo --key $keyfile --signature $sigfile rsa-verify"); + } else { $data = pipe_through_program($data, "fipsdrv --pkcs1 --algo $hashalgo --key $keyfile --signature $sigfile rsa-verify"); - + } # Parse through the output information return ($data =~ /GOOD signature/); } @@ -543,6 +560,16 @@ sub libgcrypt_hash($$) { return pipe_through_program($pt, $program); } +sub libgcrypt_hash_mct($$) { + my $pt = shift; + my $hashalgo = shift; + + my $program = "fipsdrv --algo $hashalgo --loop 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"; @@ -693,6 +720,35 @@ sub libgcrypt_dsa_verify($$$$) { return ($ret =~ /GOOD signature/); } +sub libgcrypt_drbg_kat($$$$$$$$$$$$$$$$$) { + my $mode = shift; + my $cipher = shift; + my $pr = shift; + my $ent = shift; + my $entlen = shift; + my $nonce = shift; + my $noncelen = shift; + my $entrs = shift; + my $addtlrs = shift; + my $entpra = shift; + my $entprb = shift; + my $addtla = shift; + my $addtlb = shift; + my $addtllen = shift; + my $pers = shift; + my $perslen = shift; + my $expectedlen = shift; + + my $entprlen = $entlen; + + # concatenate entropy and nonce + $ent .= $nonce; + $entlen = $entlen + $noncelen; + + return lc(pipe_through_program("$mode\n$pr\n$entlen\n$ent\n$perslen\n$pers\n$expectedlen\n$addtllen\n$entrs\n$addtlrs\n$addtla\n$addtlb\n$entprlen\n$entpra\n$entprb\n", "./fipsdrv --algo $cipher drbg")); +} + + ######### End of libgcrypt implementation ################ ################################################################ @@ -1468,13 +1524,17 @@ sub hash_mct($$) { my $md0=$pt; my $md1=$pt; my $md2=$pt; - for (my $i=0; $i<1000; ++$i) { - #print STDERR "outer loop $j; inner loop $i\n"; - my $mi= $md0 . $md1 . $md2; - $md0=$md1; - $md1=$md2; - $md2 = &$hash($mi, $cipher); - $md2 =~ s/\n//; + if ($opt{'I'} && $opt{'I'} eq 'libgcrypt') { + $md2 = &libgcrypt_hash_mct($pt, $cipher); + } else { + for (my $i=0; $i<1000; ++$i) { + #print STDERR "outer loop $j; inner loop $i\n"; + my $mi= $md0 . $md1 . $md2; + $md0=$md1; + $md1=$md2; + $md2 = &$hash($mi, $cipher); + $md2 =~ s/\n//; + } } $out .= "MD = $md2\n\n"; $pt=$md2; @@ -1483,21 +1543,65 @@ sub hash_mct($$) { return $out; } +sub drbg_kat_driver($$$$$$$$$$$$$$$$$) { + my $mode = shift; + my $cipher = shift; + my $pr = shift; + my $ent = shift; + my $entlen = shift; + my $nonce = shift; + my $noncelen = shift; + my $entrs = shift; + my $addtlrs = shift; + my $entpra = shift; + my $entprb = shift; + my $addtla = shift; + my $addtlb = shift; + my $addtllen = shift; + my $pers = shift; + my $perslen = shift; + my $expectedlen = shift; + + my $out = ""; + + $out .= "ReturnedBits = " . &$drbg_kat($mode, + $cipher, + $pr, + $ent, + $entlen, + $nonce, + $noncelen, + $entrs, + $addtlrs, + $entpra, + $entprb, + $addtla, + $addtlb, + $addtllen, + $pers, + $perslen, + $expectedlen) . "\n"; + + return $out; +} + # RSA SigGen test # $1: Message to be signed in hex form # $2: Hash algorithm -# $3: file name with RSA key in PEM form +# $3: Use PSS +# $4: file name with RSA key in PEM form # return: string formatted as expected by CAVS -sub rsa_siggen($$$) { +sub rsa_siggen($$$$) { my $data = shift; my $cipher = shift; + my $pss = shift; my $keyfile = shift; my $out = ""; $out .= "SHAAlg = $cipher\n"; $out .= "Msg = $data\n"; - $out .= "S = " . &$rsa_sign($data, lc($cipher), $keyfile) . "\n"; + $out .= "S = " . &$rsa_sign($data, lc($cipher), $pss, $keyfile) . "\n"; return $out; } @@ -1505,13 +1609,15 @@ sub rsa_siggen($$$) { # RSA SigVer test # $1: Message to be verified in hex form # $2: Hash algoritm -# $3: Signature of message in hex form -# $4: n of the RSA key in hex in hex form -# $5: e of the RSA key in hex in hex form +# $3: Use PSS +# $4: Signature of message in hex form +# $5: n of the RSA key in hex in hex form +# $6: e of the RSA key in hex in hex form # return: string formatted as expected by CAVS -sub rsa_sigver($$$$$) { +sub rsa_sigver($$$$$$) { my $data = shift; my $cipher = shift; + my $pss = shift; my $signature = shift; my $n = shift; my $e = shift; @@ -1534,7 +1640,7 @@ sub rsa_sigver($$$$$) { print FH hex2bin($signature); close FH; - $out .= "Result = " . (&$rsa_verify($data, lc($cipher), $keyfile, $sigfile) ? "P\n" : "F\n"); + $out .= "Result = " . (&$rsa_verify($data, lc($cipher), $pss, $keyfile, $sigfile) ? "P\n" : "F\n"); unlink($keyfile); unlink($sigfile); @@ -1905,13 +2011,14 @@ sub rsa_keygen_driver($$) { # $2 p in hex form # $3 q in hex form # return: string formatted as expected by CAVS -sub rsa_keygen_kat_driver($$$) { +sub rsa_keygen_kat_driver($$$$) { my $mod = shift; + my $e = shift; my $p = shift; my $q = shift; my $out = ""; - my $ret = &$rsa_keygen_kat($mod, $p, $q); + my $ret = &$rsa_keygen_kat($mod, $e, $p, $q); my ($Result) = split(/\n/, $ret); die "Return value does not contain all expected values of Result for rsa_keygen_kat" if (!defined($Result)); @@ -1999,8 +2106,24 @@ sub parse($$) { my $xq1 = ""; my $xq2 = ""; my $Xq = ""; + my $pr = 0; + my $ent = ""; + my $entlen = 0; + my $nonce = ""; + my $noncelen = 0; + my $entrs = ""; + my $addtlrs = ""; + my $entpra = "x"; + my $entprb = "x"; + my $addtla = "x"; + my $addtlb = "x"; + my $addtllen = 0; + my $pers = ""; + my $perslen = 0; + my $expectedlen = 0; my $mode = ""; + my $pss = 0; open(IN, "<$infile"); while() { @@ -2029,7 +2152,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|PQGGen|KeyGen RSA|KeyGen - Random Probably Prime|KeyPair|PQGVer)/) { + if ($tmpline =~ /^#.*(CBC|ECB|OFB|CFB|SHA-|SigGen|SigVer|RC4VS|ANSI X9\.31|Hash sizes tested|PQGGen|KeyGen RSA|KeyGen - Random Probably Prime|KeyPair|PQGVer|DRBG800-90A)/) { if ($tmpline =~ /CBC/) { $mode="cbc"; } elsif ($tmpline =~ /ECB/) { $mode="ecb"; } elsif ($tmpline =~ /OFB/) { $mode="ofb"; } @@ -2078,7 +2201,11 @@ sub parse($$) { if ($tt == 0) { ##### Identify the test type - if ($tmpline =~ /KeyGen - Random Probably Prime Known Answer Test/) { + if ($tmpline =~ /DRBG800-90A/) { + $tt = 20; + die "Interface function drbg_kat for DRBG KAT not defined for tested library" + if (!defined($drbg_kat)); + } elsif ($tmpline =~ /KeyGen - Random Probably Prime Known Answer Test/) { $tt = 19; die "Interface function rsa_keygen_kat for RSA key generation KAT not defined for tested library" if (!defined($rsa_keygen_kat)); @@ -2123,10 +2250,16 @@ sub parse($$) { die "Interface function state_rng for RNG KAT not defined for tested library" if (!defined($state_rng)); } elsif ($tmpline =~ /SigVer/ ) { + if ($tmpline =~ /RSASSA-PSS/) { + $pss = 1; + } $tt = 6; die "Interface function rsa_verify or gen_rsakey for RSA verification not defined for tested library" if (!defined($rsa_verify) || !defined($gen_rsakey)); } elsif ($tmpline =~ /SigGen/ ) { + if ($tmpline =~ /RSASSA-PSS/) { + $pss = 1; + } $tt = 5; die "Interface function rsa_sign or gen_rsakey for RSA sign not defined for tested library" if (!defined($rsa_sign) || !defined($gen_rsakey)); @@ -2252,7 +2385,7 @@ sub parse($$) { $out .= "G = " . $pqg{'G'} . "\n\n"; } } - elsif ($line =~ /^\[mod\s*=\s*(.*)\]$/) { # found in RSA requests + elsif ($line =~ /^\[mod\s*=\s*(.*)\]/) { # found in RSA requests $modulus = $1; $out .= $line . "\n\n"; # print it # generate the private key with given bit length now @@ -2277,10 +2410,21 @@ sub parse($$) { $n=$1; } elsif ($line =~ /^e\s*=\s*(.*)/) { # found in RSA requests - $e=$1; if ($tt == 19) { + if ($modulus ne "" && + $e ne "" && + $prandom ne "") { + $out .= rsa_keygen_kat_driver($modulus, + $e, + $prandom, + "00"); + $prandom = ""; + $qrandom = ""; + $e = ""; + } $out .= $line . "\n"; # print it } + $e=$1; } elsif ($line =~ /^S\s*=\s*(.*)/) { # found in RSA requests die "S seen twice - input file crap" if ($signature ne ""); @@ -2306,6 +2450,89 @@ sub parse($$) { if ($tlen ne ""); $tlen=$1; } + elsif ($tt == 20) { + if ($line =~ /Hash_DRBG/) { # HASH DRBG request + $mode = "hash"; + } + elsif ($line =~ /HMAC_DRBG/) { # HMAC DRBG request + $mode = "hmac"; + } + elsif ($line =~ /CTR_DRBG/) { # CTR DRBG request + $mode = "ctr"; + } + elsif ($line =~ /^\[SHA-1\]/) { + $cipher= "sha-1"; + } + elsif ($line =~ /^\[SHA-256\]/) { + $cipher= "sha-256"; + } + elsif ($line =~ /^\[SHA-384\]/) { + $cipher= "sha-384"; + } + elsif ($line =~ /^\[SHA-512\]/) { + $cipher= "sha-512"; + } + elsif ($line =~ /^\[AES-128 use df\]/) { + $cipher= "aes-128"; + } + elsif ($line =~ /^\[AES-192 use df\]/) { + $cipher= "aes-192"; + } + elsif ($line =~ /^\[AES-256 use df\]/) { + $cipher= "aes-256"; + } + elsif ($line =~ /^\[PredictionResistance\s*=\s*True\]/) { + $pr = 1; + } + elsif ($line =~ /^\[PredictionResistance\s*=\s*False\]/) { + $pr = 0; + } + elsif ($line =~ /^\[EntropyInputLen\s*=\s*(.*)\]/) { + $entlen = $1; + } + elsif ($line =~ /^\[NonceLen\s*=\s*(.*)\]/) { + $noncelen = $1; + } + elsif ($line =~ /^\[PersonalizationStringLen\s*=\s*(.*)\]/) { + $perslen = $1; + } + elsif ($line =~ /^\[AdditionalInputLen\s*=\s*(.*)\]/) { + $addtllen = $1; + } + elsif ($line =~ /^\[ReturnedBitsLen\s*=\s*(.*)\]/) { + $expectedlen = $1; + } + elsif ($line =~ /^EntropyInput\s*=\s*(.*)/) { + $ent = $1; + } + elsif ($line =~ /^EntropyInputReseed\s*=\s*(.*)/) { + $entrs = $1; + } + elsif ($line =~ /^Nonce\s*=\s*(.*)/) { + $nonce = $1; + } + elsif ($line =~ /^PersonalizationString\s*=\s*(.*)/) { + $pers = $1; + } + elsif ($line =~ /^AdditionalInput\s*=\s*(.*)/) { + if ($addtla eq "x") { + $addtla = $1; + } else { + $addtlb = $1; + } + } + elsif ($line =~ /^EntropyInputPR\s*=\s*(.*)/) { + if ($entpra eq "x") { + $entpra = $1; + } else { + $entprb = $1; + } + } + elsif ($line =~ /^AdditionalInputReseed\s*=\s*(.*)/) { + $addtlrs = $1; + } + $out .= $line . "\n"; # print it + } elsif ($line =~ /^N\s*=\s*(.*)/) { #DSA KeyPair die "N seen twice - check input file" if ($capital_n); @@ -2396,10 +2623,6 @@ sub parse($$) { $qrandom = $1; $out .= $line . "\n"; # print it } - elsif ($tt == 19 && $line =~ /^ / && $qrandom eq "") { #RSA key gen KAT - $qrandom = "00"; - $out .= $line . "\n"; # print it - } else { $out .= $line . "\n"; } @@ -2442,13 +2665,13 @@ sub parse($$) { } elsif ($tt == 5) { if ($pt ne "" && $cipher ne "" && $rsa_keyfile ne "") { - $out .= rsa_siggen($pt, $cipher, $rsa_keyfile); + $out .= rsa_siggen($pt, $cipher, $pss, $rsa_keyfile); $pt = ""; } } elsif ($tt == 6) { if ($pt ne "" && $cipher ne "" && $signature ne "" && $n ne "" && $e ne "") { - $out .= rsa_sigver($pt, $cipher, $signature, $n, $e); + $out .= rsa_sigver($pt, $cipher, $pss, $signature, $n, $e); $pt = ""; $signature = ""; } @@ -2635,6 +2858,37 @@ sub parse($$) { $e = ""; } } + elsif ($tt == 20) { + if (($pr == 1 && $entpra ne "x" && $entprb ne "x") || + ($pr == 0 && $addtla ne "x" && $addtlb ne "x")) { + $out .= drbg_kat_driver($mode, + $cipher, + $pr, + $ent, + $entlen, + $nonce, + $noncelen, + $entrs, + $addtlrs, + $entpra, + $entprb, + $addtla, + $addtlb, + $addtllen, + $pers, + $perslen, + $expectedlen); + $entpra = "x"; + $entprb = "x"; + $addtla = "x"; + $addtlb = "x"; + $ent = ""; + $nonce = ""; + $pers = ""; + $entrs = ""; + $addtlrs = ""; + } + } elsif ($tt > 0) { die "Test case $tt not defined"; } @@ -2701,6 +2955,7 @@ sub main() { $dsa_genpubkey = \&libgcrypt_dsa_genpubkey; $rsa_keygen = \&libgcrypt_rsa_keygen; $rsa_keygen_kat = \&libgcrypt_rsa_keygen_kat; + $drbg_kat = \&libgcrypt_drbg_kat; } else { die "Invalid interface option given"; } diff -up libgcrypt-1.5.3/tests/fipsdrv.c.drbg-cavs libgcrypt-1.5.3/tests/fipsdrv.c --- libgcrypt-1.5.3/tests/fipsdrv.c.drbg-cavs 2017-02-28 14:28:55.674906074 +0100 +++ libgcrypt-1.5.3/tests/fipsdrv.c 2017-02-28 14:43:28.320456712 +0100 @@ -22,6 +22,7 @@ #endif #include #include +#include #include #include #include @@ -893,8 +894,10 @@ print_mpi_line (gcry_mpi_t a, int no_lz) die ("gcry_mpi_aprint failed: %s\n", gpg_strerror (err)); p = buf; - while (*p) - *p++ = tolower(*p); + while (*p) { + *p = tolower(*p); + ++p; + } p = buf; if (no_lz && p[0] == '0' && p[1] == '0' && p[2]) p += 2; @@ -1256,6 +1259,46 @@ run_digest (int digest_algo, const void gcry_md_close (hd); } +/* Run inner loop of digest mct operation. */ +static void +run_digest_mct_loop (int digest_algo, const void *data, size_t datalen, int iter) +{ + gpg_error_t err; + gcry_md_hd_t hd; + const unsigned char *digest; + unsigned int digestlen; + int i; + unsigned char *buf; + + 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)); + + digestlen = gcry_md_get_algo_dlen (digest_algo); + if (digestlen != datalen) + die ("Unexpected seed size %u for Hash mct algo %d\n", datalen, digest_algo); + + buf = malloc (3*datalen); + if (!buf) + die ("Buffer allocation failed\n"); + + memcpy (buf, data, datalen); + memcpy (buf + datalen, data, datalen); + memcpy (buf + 2*datalen, data, datalen); + + for (i = 0; i < iter; ++i) + { + gcry_md_reset (hd); + gcry_md_write (hd, buf, 3*datalen); + digest = gcry_md_read (hd, digest_algo); + memmove (buf, buf + datalen, 2*datalen); + memcpy (buf + 2*datalen, digest, datalen); + } + print_buffer (digest, digestlen); + gcry_md_close (hd); +} + /* Run a HMAC operation. */ static void @@ -1403,7 +1446,7 @@ run_rsa_keygen (const void *data, size_t gcry_sexp_release (l1); if (!mpi) die ("parameter %c missing in private-key\n", parmlist[idx]); - print_mpi_line (mpi, 1); + print_mpi_line (mpi, parmlist[idx] != 'd'); gcry_mpi_release (mpi); } @@ -1592,7 +1635,7 @@ run_rsa_gen (int keysize, int pubexp) 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) + int hashalgo, int pkcs1, int pss, const char *keyfile) { gpg_error_t err; @@ -1616,6 +1659,20 @@ run_rsa_sign (const void *data, size_t d gcry_md_algo_name (hashalgo), (int)hashsize, hash); } + else if (pss) + { + unsigned char hash[64]; + unsigned int hashsize; + + hashsize = gcry_md_get_algo_dlen (hashalgo); + if (!hashsize || hashsize > sizeof hash) + die ("digest too long for buffer or unknown hash algorithm\n"); + gcry_md_hash_buffer (hashalgo, hash, data, datalen); + err = gcry_sexp_build (&s_data, NULL, + "(data (flags pss)(hash %s %b))", + gcry_md_algo_name (hashalgo), + (int)hashsize, hash); + } else { gcry_mpi_t tmp; @@ -1683,7 +1740,7 @@ run_rsa_sign (const void *data, size_t d binary signature in SIGFILE. */ static void run_rsa_verify (const void *data, size_t datalen, int hashalgo, int pkcs1, - const char *keyfile, const char *sigfile) + int pss, const char *keyfile, const char *sigfile) { gpg_error_t err; @@ -1703,6 +1760,20 @@ run_rsa_verify (const void *data, size_t gcry_md_algo_name (hashalgo), (int)hashsize, hash); } + else if (pss) + { + unsigned char hash[64]; + unsigned int hashsize; + + hashsize = gcry_md_get_algo_dlen (hashalgo); + if (!hashsize || hashsize > sizeof hash) + die ("digest too long for buffer or unknown hash algorithm\n"); + gcry_md_hash_buffer (hashalgo, hash, data, datalen); + err = gcry_sexp_build (&s_data, NULL, + "(data (flags pss)(hash %s %b))", + gcry_md_algo_name (hashalgo), + (int)hashsize, hash); + } else { gcry_mpi_t tmp; @@ -2220,7 +2291,150 @@ run_dsa_verify (const void *data, size_t gcry_sexp_release (s_data); } +struct gcry_drbg_test_vector +{ + uint32_t flags; + unsigned char *entropy; + size_t entropylen; + unsigned char *entpra; + unsigned char *entprb; + size_t entprlen; + unsigned char *addtla; + unsigned char *addtlb; + size_t addtllen; + unsigned char *pers; + size_t perslen; + unsigned char *expected; + size_t expectedlen; + unsigned char *entropyrsd; + size_t entropyrsdlen; + unsigned char *addtlrsd; + size_t addtlrsdlen; + }; + +static uint32_t +decode_drbg_flags(const char *algo, const char *mode, const char *pr) +{ + uint32_t flags = 0; + + if (*pr == '1') + flags = GCRY_DRBG_PREDICTION_RESIST; + + if (!strcmp(algo, "sha-1")) + flags |= GCRY_DRBG_HASHSHA1; + else if (!strcmp(algo, "sha-256")) + flags |= GCRY_DRBG_HASHSHA256; + else if (!strcmp(algo, "sha-384")) + flags |= GCRY_DRBG_HASHSHA384; + else if (!strcmp(algo, "sha-512")) + flags |= GCRY_DRBG_HASHSHA512; + else if (!strcmp(algo, "aes-128")) + flags |= GCRY_DRBG_SYM128; + else if (!strcmp(algo, "aes-192")) + flags |= GCRY_DRBG_SYM192; + else if (!strcmp(algo, "aes-256")) + flags |= GCRY_DRBG_SYM256; + + if (!strcmp(mode, "hmac")) + flags |= GCRY_DRBG_HMAC; + else if (!strcmp(mode, "ctr")) + flags |= GCRY_DRBG_CTRAES; + + return flags; +} + +static void +run_drbg_test (const char *algo, void *data, size_t datalen) +{ + char *ptr = data; + char *mode; + char *pr; + char *entlen; + char *ent; + char *perslen; + char *pers; + char *expectedlen; + char *addtllen; + char *entrsd; + char *addtlrsd; + char *addtla; + char *addtlb; + char *entprlen; + char *entpra; + char *entprb; + unsigned char *buf; + size_t len; + struct gcry_drbg_test_vector vect; + + mode = strsep(&ptr, "\n"); + pr = strsep(&ptr, "\n"); + entlen = strsep(&ptr, "\n"); + ent = strsep(&ptr, "\n"); + perslen = strsep(&ptr, "\n"); + pers = strsep(&ptr, "\n"); + expectedlen = strsep(&ptr, "\n"); + addtllen = strsep(&ptr, "\n"); + entrsd = strsep(&ptr, "\n"); + addtlrsd = strsep(&ptr, "\n"); + addtla = strsep(&ptr, "\n"); + addtlb = strsep(&ptr, "\n"); + entprlen = strsep(&ptr, "\n"); + entpra = strsep(&ptr, "\n"); + entprb = strsep(&ptr, "\n"); + + if (entprb == NULL) { + fprintf(stderr, "ERROR - Missing input data\n"); + return; + } + + vect.flags = decode_drbg_flags(algo, mode, pr); + + vect.entropy = hex2buffer(ent, &len); + vect.entropylen = atoi(entlen) / 8; + if (len != vect.entropylen) { + fprintf(stderr, "ERROR - inconsistent input data\n"); + return; + } + vect.pers = hex2buffer(pers, &len); + vect.perslen = atoi(perslen) / 8; + if (len != vect.perslen) { + fprintf(stderr, "ERROR - inconsistent input data\n"); + return; + } + vect.expectedlen = atoi(expectedlen) / 8; + vect.expected = NULL; + vect.addtlrsdlen = vect.addtllen = atoi(addtllen) / 8; + vect.addtla = hex2buffer(addtla, &len); + vect.addtlb = hex2buffer(addtlb, &len); + vect.entropyrsdlen = vect.entprlen = atoi(entprlen) / 8; + vect.entpra = hex2buffer(entpra, &len); + vect.entprb = hex2buffer(entprb, &len); + if (*entrsd != '\0') { + vect.entropyrsd = hex2buffer(entrsd, &len); + if (len != vect.entropyrsdlen) { + fprintf(stderr, "ERROR - inconsistent input data\n"); + return; + } + if (*addtlrsd != '\0') { + vect.addtlrsd = hex2buffer(addtlrsd, &len); + if (len != vect.addtlrsdlen) { + fprintf(stderr, "ERROR - inconsistent input data\n"); + return; + } + } else { + vect.addtlrsd = NULL; + } + } else { + vect.entropyrsd = NULL; + vect.addtlrsd = NULL; + } + + buf = gcry_xmalloc(vect.expectedlen); + gcry_control(75, &vect, buf); + + print_data_line(buf, vect.expectedlen); +} static void @@ -2251,6 +2465,7 @@ usage (int show_help) " --signature NAME Take signature from file NAME\n" " --chunk N Read in chunks of N bytes (implies --binary)\n" " --pkcs1 Use PKCS#1 encoding\n" + " --pss Use PKCS#1 PSS encoding\n" " --mct-server Run a monte carlo test server\n" " --loop Enable random loop mode\n" " --progress Print pogress indicators\n" @@ -2268,6 +2483,7 @@ main (int argc, char **argv) int no_fips = 0; int progress = 0; int use_pkcs1 = 0; + int use_pss = 0; const char *mode_string; const char *key_string = NULL; const char *iv_string = NULL; @@ -2398,6 +2614,11 @@ main (int argc, char **argv) use_pkcs1 = 1; argc--; argv++; } + else if (!strcmp (*argv, "--pss")) + { + use_pss = 1; + argc--; argv++; + } else if (!strcmp (*argv, "--mct-server")) { mct_server = 1; @@ -2414,7 +2635,10 @@ main (int argc, char **argv) usage (0); mode_string = *argv; - if (!strcmp (mode_string, "rsa-derive")) + if (!strcmp (mode_string, "rsa-derive") || + !strcmp (mode_string, "rsa-keygen") || + !strcmp (mode_string, "rsa-keygen-kat") || + !strcmp(mode_string, "drbg")) binary_input = 1; if (argc == 2 && strcmp (argv[1], "-")) @@ -2557,7 +2781,14 @@ main (int argc, char **argv) if (!data) die ("no data available (do not use --chunk)\n"); - run_digest (algo, data, datalen); + if (loop_mode) + { + run_digest_mct_loop (algo, data, datalen, 1000); + } + else + { + run_digest (algo, data, datalen); + } } else if (!strcmp (mode_string, "random")) { @@ -2602,6 +2833,12 @@ main (int argc, char **argv) deinit_external_rng_test (context); } + else if (!strcmp (mode_string, "drbg")) + { + if (!algo_string) + die ("--algo required in this mode\n"); + run_drbg_test (algo_string, data, datalen); + } else if (!strcmp (mode_string, "hmac-sha")) { int algo; @@ -2679,7 +2916,7 @@ main (int argc, char **argv) if (!data) die ("no data available (do not use --chunk)\n"); - run_rsa_sign (data, datalen, algo, use_pkcs1, key_string); + run_rsa_sign (data, datalen, algo, use_pkcs1, use_pss, key_string); } else if (!strcmp (mode_string, "rsa-verify")) @@ -2702,7 +2939,7 @@ main (int argc, char **argv) if (access (signature_string, R_OK)) die ("option --signature needs to specify an existing file\n"); - run_rsa_verify (data, datalen, algo, use_pkcs1, key_string, + run_rsa_verify (data, datalen, algo, use_pkcs1, use_pss, key_string, signature_string); } @@ -2783,12 +3020,6 @@ main (int argc, char **argv) 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);