libgcrypt/libgcrypt-1.6.1-fips-cavs.patch

1127 lines
34 KiB
Diff
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

Index: libgcrypt-1.7.2/tests/cavs_driver.pl
===================================================================
--- libgcrypt-1.7.2.orig/tests/cavs_driver.pl
+++ libgcrypt-1.7.2/tests/cavs_driver.pl
@@ -1,9 +1,11 @@
#!/usr/bin/env perl
#
-# $Id: cavs_driver.pl 1497 2009-01-22 14:01:29Z smueller $
+# $Id: cavs_driver.pl 2124 2010-12-20 07:56:30Z smueller $
#
# CAVS test driver (based on the OpenSSL driver)
# Written by: Stephan Müller <sm@atsec.com>
+# Werner Koch <wk@g10code.com> (libgcrypt interface)
+# Tomas Mraz <tmraz@redhat.com> (addition of DSA2)
# Copyright (c) atsec information security corporation
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -85,13 +87,16 @@
# T[CBC|CFB??|ECB|OFB]varkey
# T[CBC|CFB??|ECB|OFB]invperm
# T[CBC|CFB??|ECB|OFB]vartext
+# WARNING: TDES in CFB and OFB mode problems see below
#
# ANSI X9.31 RNG
# ANSI931_AES128MCT
# ANSI931_AES128VST
#
-# DSA
+# DSA2
# PQGGen
+# PQGVer
+# KeyPair
# SigGen
# SigVer
#
@@ -101,6 +106,36 @@
# RC4PltBD
# RC4REGT
#
+#
+# TDES MCT for CFB and OFB:
+# -------------------------
+# The inner loop cannot be handled by this script. If you want to have tests
+# for these cipher types, implement your own inner loop and add it to
+# crypto_mct.
+#
+# the value $next_source in crypto_mct is NOT set by the standard implementation
+# of this script. It would need to be set as follows for these two (code take
+# from fipsdrv.c from libgcrypt - the value input at the end will contain the
+# the value for $next_source:
+#
+# ... inner loop ...
+# ...
+# get_current_iv (hd, last_iv, blocklen);
+# ... encrypt / decrypt (input is the data to be en/decrypted and output is the
+# result of operation) ...
+# if (encrypt_mode && (cipher_mode == GCRY_CIPHER_MODE_CFB))
+# memcpy (input, last_iv, blocklen);
+# else if (cipher_mode == GCRY_CIPHER_MODE_OFB)
+# memcpy (input, last_iv, blocklen);
+# else if (!encrypt_mode && cipher_mode == GCRY_CIPHER_MODE_CFB)
+# {
+# /* Reconstruct the output vector. */
+# int i;
+# for (i=0; i < blocklen; i++)
+# input[i] ^= output[i];
+# }
+# ... inner loop ends ...
+# ==> now, the value of input is to be put into $next_source
use strict;
use warnings;
@@ -226,6 +261,8 @@ my $hmac;
# Generate the P, Q, G, Seed, counter, h (value used to generate g) values
# for DSA
# $1: modulus size
+# $2: q size
+# $3: seed (might be empty string)
# 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
@@ -236,6 +273,19 @@ my $hmac;
# h
my $dsa_pqggen;
+# Generate the G value from P and Q
+# for DSA
+# $1: modulus size
+# $2: q size
+# $3: P in hex form
+# $4: Q in hex form
+# 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
+my $dsa_ggen;
+
#
# Generate an DSA public key from the provided parameters:
# $1: Name of file to create
@@ -255,10 +305,20 @@ 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
+# $1: modulus size
+# $2: q size
+# $3 keyfile name
+# return: file created with key, string with values of P, Q, G in hex format
my $gen_dsakey;
+# generate a new DSA private key XY parameters in domain:
+# PEM format
+# $1: P in hex form
+# $2: Q in hex form
+# $3: G in hex form
+# return: string with values of X, Y in hex format
+my $gen_dsakey_domain;
+
# Sign a message with DSA
# $1: data to be signed in hex form
# $2: Key file in PEM format with the private key
@@ -500,17 +560,32 @@ sub libgcrypt_hmac($$$$) {
return pipe_through_program($msg, $program);
}
-sub libgcrypt_dsa_pqggen($) {
+sub libgcrypt_dsa_pqggen($$$) {
+ my $mod = shift;
+ my $qsize = shift;
+ my $seed = shift;
+
+ my $program = "fipsdrv --keysize $mod --qsize $qsize dsa-pqg-gen";
+ return pipe_through_program($seed, $program);
+}
+
+sub libgcrypt_dsa_ggen($$$$) {
my $mod = shift;
+ my $qsize = shift;
+ my $p = shift;
+ my $q = shift;
+ my $domain = "(domain (p #$p#)(q #$q#))";
- my $program = "fipsdrv --keysize $mod dsa-pqg-gen";
+ my $program = "fipsdrv --keysize $mod --qsize $qsize --key \'$domain\' dsa-g-gen";
return pipe_through_program("", $program);
}
-sub libgcrypt_gen_dsakey($) {
+sub libgcrypt_gen_dsakey($$$) {
+ my $mod = shift;
+ my $qsize = shift;
my $file = shift;
- my $program = "fipsdrv --keysize 1024 --key $file dsa-gen";
+ my $program = "fipsdrv --keysize $mod --qsize $qsize --key $file dsa-gen";
my $tmp;
my %ret;
@@ -519,10 +594,21 @@ sub libgcrypt_gen_dsakey($) {
$tmp = pipe_through_program("", $program);
die "dsa key gen failed: file $file not created" if (! -f $file);
- @ret{'P', 'Q', 'G', 'Seed', 'c', 'H'} = split(/\n/, $tmp);
+ @ret{'P', 'Q', 'G'} = split(/\n/, $tmp);
return %ret;
}
+sub libgcrypt_gen_dsakey_domain($$$) {
+ my $p = shift;
+ my $q = shift;
+ my $g = shift;
+ my $domain = "(domain (p #$p#)(q #$q#)(g #$g#))";
+
+ my $program = "fipsdrv --key '$domain' dsa-gen-key";
+
+ return pipe_through_program("", $program);
+}
+
sub libgcrypt_dsa_genpubkey($$$$$) {
my $filename = shift;
my $p = shift;
@@ -1139,7 +1225,7 @@ sub hmac_kat($$$$) {
$out .= "Tlen = $tlen\n";
$out .= "Key = $key\n";
$out .= "Msg = $msg\n";
- $out .= "Mac = " . &$hmac($key, $tlen, $msg, $hashtype{$tlen}) . "\n";
+ $out .= "Mac = " . lc(&$hmac($key, $tlen, $msg, $hashtype{$tlen})) . "\n";
return $out;
}
@@ -1205,7 +1291,7 @@ sub crypto_mct($$$$$$$$) {
}
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/);
+ $cipher_imp = &$state_cipher_des($cipher, $enc, $bufsize, $key1, $iv) if($cipher =~ /des/ && defined($state_cipher_des));
my $pid = open2($CO, $CI, $cipher_imp);
my $calc_data = $iv; # CT[j]
@@ -1213,8 +1299,8 @@ sub crypto_mct($$$$$$$$) {
my $old_old_calc_data; # CT[j-2]
my $next_source;
- # TDES inner loop implements logic within driver
- if ($cipher =~ /des/) {
+ # TDES inner loop implements logic within driver of libgcrypt
+ if ($cipher =~ /des/ && $opt{'I'} && $opt{'I'} eq 'libgcrypt' ) {
# Need to provide a dummy IV in case of ECB mode.
my $iv_arg = (defined($iv) && $iv ne "")
? bin2hex($iv)
@@ -1238,6 +1324,10 @@ sub crypto_mct($$$$$$$$) {
$line = <$CO>;
} else {
for (my $j = 0; $j < $iloop; ++$j) {
+ if ($cipher =~ /des-ede3-ofb/ ||
+ (!$enc && $cipher =~ /des-ede3-cfb/)) {
+ die "Implementation lacks support for TDES OFB and TDES CFB in encryption mode - the problem is that we would need to extract the IV of the last round of encryption which would be the input for the next round - see comments in this script for implementation requirements";
+ }
$old_old_calc_data = $old_calc_data;
$old_calc_data = $calc_data;
@@ -1503,21 +1593,23 @@ sub rngx931($$$$) {
return $out;
}
-# DSA PQGGen test
+# DSA PQGen test
# $1 modulus size
-# $2 number of rounds to perform the test
+# $2 q size
+# $3 number of rounds to perform the test
# return: string formatted as expected by CAVS
-sub dsa_pqggen_driver($$) {
+sub dsa_pqgen_driver($$$) {
my $mod = shift;
+ my $qsize = shift;
my $rounds = shift;
my $out = "";
for(my $i=0; $i<$rounds; $i++) {
- my $ret = &$dsa_pqggen($mod);
+ my $ret = &$dsa_pqggen($mod, $qsize, "");
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));
+ die "Return value does not contain all expected values of P, Q, Seed, c for dsa_pqggen"
+ if (!defined($P) || !defined($Q) ||
+ !defined($Seed) || !defined($c));
# now change the counter to decimal as CAVS wants decimal
# counter value although all other is HEX
@@ -1525,15 +1617,166 @@ sub dsa_pqggen_driver($$) {
$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";
+ $out .= "domain_parameter_seed = $Seed\n";
+ $out .= "counter = $c\n\n";
}
return $out;
}
+# DSA GGen test
+# $1 modulus size
+# $2 q size
+# $3 p in hex form
+# $4 q in hex form
+# return: string formatted as expected by CAVS
+sub dsa_ggen_driver($$$$) {
+ my $mod = shift;
+ my $qsize = shift;
+ my $p = shift;
+ my $q = shift;
+
+ my $out = "";
+ my $ret = &$dsa_ggen($mod, $qsize, $p, $q);
+ my ($P, $Q, $G) = split(/\n/, $ret);
+ die "Return value does not contain all expected values of P, Q, G for dsa_ggen"
+ if (!defined($P) || !defined($Q) || !defined($G));
+
+ $out .= "G = $G\n\n";
+
+ return $out;
+}
+
+sub hexcomp($$) {
+ my $a = lc shift;
+ my $b = lc shift;
+
+ if (length $a < length $b) {
+ my $c = $a;
+ $a = $b;
+ $b = $a;
+ }
+
+ while (length $b < length $a) {
+ $b = "00$b";
+ }
+
+ return $a eq $b;
+}
+
+# DSA PQVer test
+# $1 modulus size
+# $2 q size
+# $3 p in hex form
+# $4 q in hex form
+# $5 seed in hex form
+# $6 c decimal counter
+# return: string formatted as expected by CAVS
+sub dsa_pqver_driver($$$$$$) {
+ my $mod = shift;
+ my $qsize = shift;
+ my $p = shift;
+ my $q = shift;
+ my $seed = shift;
+ my $c = shift;
+
+ my $out = "";
+ my $ret = &$dsa_pqggen($mod, $qsize, $seed);
+ my ($P, $Q, $G, $seed2, $c2, $h2) = split(/\n/, $ret);
+ die "Return value does not contain all expected values of P, Q, G, seed, c for dsa_pqggen"
+ if (!defined($P) || !defined($Q) || !defined($G) ||
+ !defined($seed2) || !defined($c2));
+
+ $c2 = hex($c2);
+
+ $out .= "Seed = $seed\n";
+ $out .= "c = $c\n";
+
+ if (hexcomp($P, $p) && hexcomp($Q, $q) && hexcomp($seed, $seed2) && $c == $c2) {
+ $out .= "Result = P\n\n";
+ }
+ else {
+ $out .= "Result = F\n\n";
+ }
+ return $out;
+}
+
+# DSA PQGVer test
+# $1 modulus size
+# $2 q size
+# $3 p in hex form
+# $4 q in hex form
+# $5 g in hex form
+# $6 seed in hex form
+# $7 c decimal counter
+# $8 h in hex form
+# return: string formatted as expected by CAVS
+sub dsa_pqgver_driver($$$$$$$$) {
+ my $mod = shift;
+ my $qsize = shift;
+ my $p = shift;
+ my $q = shift;
+ my $g = shift;
+ my $seed = shift;
+ my $c = shift;
+ my $h = shift;
+
+ my $out = "";
+ my $ret = &$dsa_pqggen($mod, $qsize, $seed);
+ my ($P, $Q, $G, $seed2, $c2, $h2) = 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($seed2) || !defined($c2) || !defined($h2));
+
+
+
+ $out .= "Seed = $seed\n";
+ $out .= "c = $c\n";
+ $out .= "H = $h\n";
+
+ $c2 = hex($c2);
+
+ if (hexcomp($P, $p) && hexcomp($Q, $q) && hexcomp($G, $g) && hexcomp($seed, $seed2) &&
+ $c == $c2 && hex($h) == hex($h2)) {
+ $out .= "Result = P\n\n";
+ }
+ else {
+ $out .= "Result = F\n\n";
+ }
+
+ return $out;
+}
+
+# DSA Keypair test
+# $1 modulus size
+# $2 q size
+# $3 number of rounds to perform the test
+# return: string formatted as expected by CAVS
+sub dsa_keypair_driver($$$) {
+ my $mod = shift;
+ my $qsize = shift;
+ my $rounds = shift;
+
+ my $out = "";
+ my $tmpkeyfile = "dsa_siggen.tmp.$$";
+ my %pqg = &$gen_dsakey($mod, $qsize, $tmpkeyfile);
+ $out .= "P = " . $pqg{'P'} . "\n";
+ $out .= "Q = " . $pqg{'Q'} . "\n";
+ $out .= "G = " . $pqg{'G'} . "\n\n";
+ unlink($tmpkeyfile);
+
+ for(my $i=0; $i<$rounds; $i++) {
+ my $ret = &$gen_dsakey_domain($pqg{'P'}, $pqg{'Q'}, $pqg{'G'});
+ my ($X, $Y) = split(/\n/, $ret);
+ die "Return value does not contain all expected values of X, Y for gen_dsakey_domain"
+ if (!defined($X) || !defined($Y));
+
+ $out .= "X = $X\n";
+ $out .= "Y = $Y\n\n";
+ }
+
+ return $out;
+}
# DSA SigGen test
# $1: Message to be signed in hex form
@@ -1658,12 +1901,16 @@ sub parse($$) {
my $klen = "";
my $tlen = "";
my $modulus = "";
+ my $qsize = "";
my $capital_n = 0;
+ my $num = 0;
my $capital_p = "";
my $capital_q = "";
my $capital_g = "";
my $capital_y = "";
my $capital_r = "";
+ my $capital_h = "";
+ my $c = "";
my $xp1 = "";
my $xp2 = "";
my $Xp = "";
@@ -1700,7 +1947,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)/) {
+ if ($tmpline =~ /^#.*(CBC|ECB|OFB|CFB|SHA-|SigGen|SigVer|RC4VS|ANSI X9\.31|Hash sizes tested|PQGGen|KeyGen RSA|KeyPair|PQGVer)/) {
if ($tmpline =~ /CBC/) { $mode="cbc"; }
elsif ($tmpline =~ /ECB/) { $mode="ecb"; }
elsif ($tmpline =~ /OFB/) { $mode="ofb"; }
@@ -1749,7 +1996,15 @@ sub parse($$) {
if ($tt == 0) {
##### Identify the test type
- if ($tmpline =~ /KeyGen RSA \(X9\.31\)/) {
+ if ($tmpline =~ /PQGVer/) {
+ $tt = 16;
+ die "Interface function for DSA PQGVer testing not defined for tested library"
+ if (!defined($dsa_pqggen));
+ } elsif ($tmpline =~ /KeyPair/) {
+ $tt = 14;
+ die "Interface function dsa_keygen for DSA key generation not defined for tested library"
+ if (!defined($gen_dsakey_domain));
+ } elsif ($tmpline =~ /KeyGen RSA \(X9\.31\)/) {
$tt = 13;
die "Interface function rsa_derive for RSA key generation not defined for tested library"
if (!defined($rsa_derive));
@@ -1760,11 +2015,11 @@ sub parse($$) {
} 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));
+ if (!defined($dsa_sign) || !defined($gen_dsakey));
} elsif ($tmpline =~ /PQGGen/) {
$tt = 10;
die "Interface function for DSA PQGGen testing not defined for tested library"
- if (!defined($dsa_pqggen));
+ if (!defined($dsa_pqggen) || !defined($dsa_ggen));
} elsif ($tmpline =~ /Hash sizes tested/) {
$tt = 9;
die "Interface function hmac for HMAC testing not defined for tested library"
@@ -1792,7 +2047,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) || !defined($state_cipher_des));
+ if (!defined($state_cipher) && !defined($state_cipher_des));
} elsif ($cipher =~ /^sha/) {
$tt = 3;
die "Interface function hash for Hashing not defined for tested library"
@@ -1875,18 +2130,44 @@ sub parse($$) {
die "Msg/Seed seen twice - input file crap" if ($pt ne "");
$pt=$2;
}
- elsif ($line =~ /^\[mod\s*=\s*(.*)\]$/) { # found in RSA requests
+ elsif ($line =~ /^\[A.2.1\s.*\]$/) { # found in DSA2 PQGGen request
+ $out .= $line . "\n"; # print it
+ if ($tt == 10) {
+ # now generate G from PQ
+ $tt = 15;
+ }
+ }
+ elsif ($line =~ /^\[A.2.2\s.*\]$/) { # found in DSA2 PQGVer request
+ $out .= $line . "\n"; # print it
+ if ($tt == 16) {
+ # now verify PQG
+ $tt = 17;
+ }
+ }
+ elsif ($line =~ /^\[mod\s*=\s*L=([0-9]*),\s*N=([0-9]*).*\]$/) { # found in DSA2 requests
$modulus = $1;
+ $qsize = $2;
$out .= $line . "\n\n"; # print it
+ # clear eventual PQG
+ $capital_p = "";
+ $capital_q = "";
+ $capital_g = "";
# generate the private key with given bit length now
# as we have the required key length in bit
if ($tt == 11) {
$dsa_keyfile = "dsa_siggen.tmp.$$";
- my %pqg = &$gen_dsakey($dsa_keyfile);
+ my %pqg = &$gen_dsakey($modulus, $qsize, $dsa_keyfile);
$out .= "P = " . $pqg{'P'} . "\n";
$out .= "Q = " . $pqg{'Q'} . "\n";
- $out .= "G = " . $pqg{'G'} . "\n";
- } elsif ( $tt == 5 ) {
+ $out .= "G = " . $pqg{'G'} . "\n\n";
+ }
+ }
+ 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
+ # as we have the required key length in bit
+ if ( $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
@@ -1932,11 +2213,16 @@ sub parse($$) {
if ($tlen ne "");
$tlen=$1;
}
- elsif ($line =~ /^N\s*=\s*(.*)/) { #DSA PQGGen
+ elsif ($line =~ /^N\s*=\s*(.*)/) { #DSA KeyPair
die "N seen twice - check input file"
if ($capital_n);
$capital_n = $1;
}
+ elsif ($line =~ /^Num\s*=\s*(.*)/) { #DSA PQGGen
+ die "Num seen twice - check input file"
+ if ($num);
+ $num = $1;
+ }
elsif ($line =~ /^P\s*=\s*(.*)/) { #DSA SigVer
die "P seen twice - check input file"
if ($capital_p);
@@ -1965,6 +2251,16 @@ sub parse($$) {
if ($capital_r);
$capital_r = $1;
}
+ elsif ($line =~ /^H\s*=\s*(.*)/) { #DSA PQGVer
+ die "H seen twice - check input file"
+ if ($capital_h);
+ $capital_h = $1;
+ }
+ elsif ($line =~ /^c\s*=\s*(.*)/) { #DSA PQGVer
+ die "c seen twice - check input file"
+ if ($c);
+ $c = $1;
+ }
elsif ($line =~ /^xp1\s*=\s*(.*)/) { #RSA key gen
die "xp1 seen twice - check input file"
if ($xp1);
@@ -2074,11 +2370,10 @@ sub parse($$) {
}
}
elsif ($tt == 10) {
- if ($modulus ne "" && $capital_n > 0) {
- $out .= dsa_pqggen_driver($modulus, $capital_n);
- #$mod is not resetted
- $capital_n = 0;
- }
+ if ($modulus ne "" && $qsize ne "" && $num > 0) {
+ $out .= dsa_pqgen_driver($modulus, $qsize, $num);
+ $num = 0;
+ }
}
elsif ($tt == 11) {
if ($pt ne "" && $dsa_keyfile ne "") {
@@ -2141,6 +2436,74 @@ sub parse($$) {
$Xq = "";
}
}
+ elsif ($tt == 14) {
+ if ($modulus ne "" &&
+ $qsize ne "" &&
+ $capital_n > 0) {
+ $out .= dsa_keypair_driver($modulus,
+ $qsize,
+ $capital_n);
+ $capital_n = 0;
+ }
+ }
+ elsif ($tt == 15) {
+ if ($modulus ne "" &&
+ $qsize ne "" &&
+ $capital_p ne "" &&
+ $capital_q ne "") {
+ $out .= dsa_ggen_driver($modulus,
+ $qsize,
+ $capital_p,
+ $capital_q);
+ $capital_p = "";
+ $capital_q = "";
+ $num--;
+ }
+ }
+ elsif ($tt == 16) {
+ if ($modulus ne "" &&
+ $qsize ne "" &&
+ $capital_p ne "" &&
+ $capital_q ne "" &&
+ $pt ne "" &&
+ $c ne "") {
+ $out .= dsa_pqver_driver($modulus,
+ $qsize,
+ $capital_p,
+ $capital_q,
+ $pt,
+ $c);
+ $capital_p = "";
+ $capital_q = "";
+ $pt = "";
+ $c = "";
+ }
+ }
+ elsif ($tt == 17) {
+ if ($modulus ne "" &&
+ $qsize ne "" &&
+ $capital_p ne "" &&
+ $capital_q ne "" &&
+ $capital_g ne "" &&
+ $pt ne "" &&
+ $c ne "" &&
+ $capital_h ne "") {
+ $out .= dsa_pqgver_driver($modulus,
+ $qsize,
+ $capital_p,
+ $capital_q,
+ $capital_g,
+ $pt,
+ $c,
+ $capital_h);
+ $capital_p = "";
+ $capital_q = "";
+ $capital_g = "";
+ $pt = "";
+ $c = "";
+ $capital_h = "";
+ }
+ }
elsif ($tt > 0) {
die "Test case $tt not defined";
}
@@ -2199,7 +2562,9 @@ sub main() {
$state_rng = \&libgcrypt_state_rng;
$hmac = \&libgcrypt_hmac;
$dsa_pqggen = \&libgcrypt_dsa_pqggen;
+ $dsa_ggen = \&libgcrypt_dsa_ggen;
$gen_dsakey = \&libgcrypt_gen_dsakey;
+ $gen_dsakey_domain = \&libgcrypt_gen_dsakey_domain;
$dsa_sign = \&libgcrypt_dsa_sign;
$dsa_verify = \&libgcrypt_dsa_verify;
$dsa_genpubkey = \&libgcrypt_dsa_genpubkey;
Index: libgcrypt-1.7.2/tests/cavs_tests.sh
===================================================================
--- libgcrypt-1.7.2.orig/tests/cavs_tests.sh
+++ libgcrypt-1.7.2/tests/cavs_tests.sh
@@ -55,7 +55,7 @@ function run_one_test () {
[ -d "$respdir" ] || mkdir "$respdir"
[ -f "$rspfile" ] && rm "$rspfile"
- if echo "$reqfile" | grep '/DSA/req/' >/dev/null 2>/dev/null; then
+ if echo "$reqfile" | grep '/DSA.\?/req/' >/dev/null 2>/dev/null; then
dflag="-D"
fi
Index: libgcrypt-1.7.2/tests/fipsdrv.c
===================================================================
--- libgcrypt-1.7.2.orig/tests/fipsdrv.c
+++ libgcrypt-1.7.2/tests/fipsdrv.c
@@ -892,6 +892,9 @@ 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);
+ p = buf;
if (no_lz && p[0] == '0' && p[1] == '0' && p[2])
p += 2;
@@ -1765,14 +1768,14 @@ run_rsa_verify (const void *data, size_t
/* Generate a DSA key of size KEYSIZE and return the complete
S-expression. */
static gcry_sexp_t
-dsa_gen (int keysize)
+dsa_gen (int keysize, int qsize)
{
gpg_error_t err;
gcry_sexp_t keyspec, key;
err = gcry_sexp_build (&keyspec, NULL,
- "(genkey (dsa (nbits %d)(use-fips186-2)))",
- keysize);
+ "(genkey (dsa (nbits %d)(qbits %d)(use-fips186)))",
+ keysize, qsize);
if (err)
die ("gcry_sexp_build failed for DSA key generation: %s\n",
gpg_strerror (err));
@@ -1790,7 +1793,7 @@ dsa_gen (int keysize)
/* Generate a DSA key of size KEYSIZE and return the complete
S-expression. */
static gcry_sexp_t
-dsa_gen_with_seed (int keysize, const void *seed, size_t seedlen)
+dsa_gen_with_seed (int keysize, int qsize, const void *seed, size_t seedlen)
{
gpg_error_t err;
gcry_sexp_t keyspec, key;
@@ -1799,10 +1802,11 @@ dsa_gen_with_seed (int keysize, const vo
"(genkey"
" (dsa"
" (nbits %d)"
- " (use-fips186-2)"
+ " (qbits %d)"
+ " (use-fips186)"
" (derive-parms"
" (seed %b))))",
- keysize, (int)seedlen, seed);
+ keysize, qsize, (int)seedlen, seed);
if (err)
die ("gcry_sexp_build failed for DSA key generation: %s\n",
gpg_strerror (err));
@@ -1810,6 +1814,37 @@ dsa_gen_with_seed (int keysize, const vo
err = gcry_pk_genkey (&key, keyspec);
if (err)
die ("gcry_pk_genkey failed for DSA: %s\n", gpg_strerror (err));
+
+ gcry_sexp_release (keyspec);
+
+ return key;
+}
+
+/* Generate a DSA key with specified domain parameters and return the complete
+ S-expression. */
+static gcry_sexp_t
+dsa_gen_key (const char *domain)
+{
+ gpg_error_t err;
+ gcry_sexp_t keyspec, key, domspec;
+
+ err = gcry_sexp_new (&domspec, domain, strlen(domain), 0);
+ if (err)
+ die ("gcry_sexp_build failed for domain spec: %s\n",
+ gpg_strerror (err));
+
+ err = gcry_sexp_build (&keyspec, NULL,
+ "(genkey"
+ " (dsa"
+ " (use-fips186)"
+ " %S))",
+ domspec);
+ if (err)
+ die ("gcry_sexp_build failed for DSA key generation: %s\n",
+ gpg_strerror (err));
+ err = gcry_pk_genkey (&key, keyspec);
+ if (err)
+ die ("gcry_pk_genkey failed for DSA: %s\n", gpg_strerror (err));
gcry_sexp_release (keyspec);
@@ -1849,7 +1884,7 @@ ecdsa_gen_key (const char *curve)
with one parameter per line in hex format using this order: p, q,
g, seed, counter, h. */
static void
-print_dsa_domain_parameters (gcry_sexp_t key)
+print_dsa_domain_parameters (gcry_sexp_t key, int print_misc)
{
gcry_sexp_t l1, l2;
gcry_mpi_t mpi;
@@ -1885,6 +1920,9 @@ print_dsa_domain_parameters (gcry_sexp_t
}
gcry_sexp_release (l1);
+ if (!print_misc)
+ return;
+
/* Extract the seed values. */
l1 = gcry_sexp_find_token (key, "misc-key-info", 0);
if (!l1)
@@ -1976,38 +2014,106 @@ print_ecdsa_dq (gcry_sexp_t key)
}
-/* Generate DSA domain parameters for a modulus size of KEYSIZE. The
+/* Print just the XY private key parameters. KEY
+ is the complete key as returned by dsa_gen. We print to stdout
+ with one parameter per line in hex format using this order: x, y. */
+static void
+print_dsa_xy (gcry_sexp_t key)
+{
+ gcry_sexp_t l1, l2;
+ gcry_mpi_t mpi;
+ int idx;
+
+ 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; "xy"[idx]; idx++)
+ {
+ l2 = gcry_sexp_find_token (l1, "xy"+idx, 1);
+ if (!l2)
+ die ("no %c parameter in returned public key\n", "xy"[idx]);
+ mpi = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG);
+ if (!mpi)
+ die ("no value for %c parameter in returned private key\n","xy"[idx]);
+ gcry_sexp_release (l2);
+ if (standalone_mode)
+ printf ("%c = ", "XY"[idx]);
+ print_mpi_line (mpi, 1);
+ gcry_mpi_release (mpi);
+ }
+
+ gcry_sexp_release (l1);
+}
+
+
+/* Generate DSA pq domain 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. If SEED is
+ format and in this order: p, q, seed, counter. If SEED is
not NULL this seed value will be used for the generation. */
static void
-run_dsa_pqg_gen (int keysize, const void *seed, size_t seedlen)
+run_dsa_pqg_gen (int keysize, int qsize, const void *seed, size_t seedlen)
{
gcry_sexp_t key;
if (seed)
- key = dsa_gen_with_seed (keysize, seed, seedlen);
+ key = dsa_gen_with_seed (keysize, qsize, seed, seedlen);
else
- key = dsa_gen (keysize);
- print_dsa_domain_parameters (key);
+ key = dsa_gen (keysize, qsize);
+ print_dsa_domain_parameters (key, 1);
+ gcry_sexp_release (key);
+}
+
+
+/* Generate DSA domain 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. If SEED is
+ not NULL this seed value will be used for the generation. */
+static void
+run_dsa_g_gen (int keysize, int qsize, const char *domain)
+{
+ gcry_sexp_t key;
+
+ key = dsa_gen_key (domain);
+ print_dsa_domain_parameters (key, 0);
+ gcry_sexp_release (key);
+}
+
+/* Generate a DSA key with specified domain parameters
+ and print the XY values. */
+static void
+run_dsa_gen_key (const char *domain)
+{
+ gcry_sexp_t key;
+
+ key = dsa_gen_key (domain);
+ print_dsa_xy (key);
+
gcry_sexp_release (key);
}
/* Generate a DSA key of size of KEYSIZE and write the private key to
FILENAME. Also write the parameters to stdout in the same way as
- run_dsa_pqg_gen. */
+ run_dsa_g_gen. */
static void
-run_dsa_gen (int keysize, const char *filename)
+run_dsa_gen (int keysize, int qsize, const char *filename)
{
gcry_sexp_t key, private_key;
FILE *fp;
- key = dsa_gen (keysize);
+ key = dsa_gen (keysize, qsize);
private_key = gcry_sexp_find_token (key, "private-key", 0);
if (!private_key)
die ("private key not found in genkey result\n");
- print_dsa_domain_parameters (key);
+ print_dsa_domain_parameters (key, 1);
fp = fopen (filename, "wb");
if (!fp)
@@ -2020,6 +2126,53 @@ run_dsa_gen (int keysize, const char *fi
}
+static int
+dsa_hash_from_key(gcry_sexp_t s_key)
+{
+ gcry_sexp_t l1, l2;
+ gcry_mpi_t q;
+ unsigned int qbits;
+
+ l1 = gcry_sexp_find_token (s_key, "public-key", 0);
+ if (!l1)
+ {
+ l1 = gcry_sexp_find_token (s_key, "private-key", 0);
+ if (!l1)
+ die ("neither private nor public key found in the loaded key\n");
+ }
+
+ l2 = gcry_sexp_find_token (l1, "dsa", 0);
+ if (!l2)
+ die ("public key not formed as expected - no dsa\n");
+ gcry_sexp_release (l1);
+ l1 = l2;
+
+ l2 = gcry_sexp_find_token (l1, "q", 0);
+ if (!l2)
+ die ("public key not formed as expected - no q\n");
+ gcry_sexp_release (l1);
+ l1 = l2;
+
+ q = gcry_sexp_nth_mpi (l1, 1, GCRYMPI_FMT_USG);
+ if (!q)
+ die ("public key not formed as expected - no mpi in q\n");
+ qbits = gcry_mpi_get_nbits(q);
+ gcry_sexp_release(l1);
+ gcry_mpi_release(q);
+ switch(qbits)
+ {
+ case 160:
+ return GCRY_MD_SHA1;
+ case 224:
+ return GCRY_MD_SHA224;
+ case 256:
+ return GCRY_MD_SHA256;
+ default:
+ die("bad number bits (%d) of q in key\n", qbits);
+ }
+ return GCRY_MD_NONE;
+}
+
/* Sign DATA of length DATALEN using the key taken from the S-expression
encoded KEYFILE. */
@@ -2029,11 +2182,16 @@ run_dsa_sign (const void *data, size_t d
{
gpg_error_t err;
gcry_sexp_t s_data, s_key, s_sig, s_tmp, s_tmp2;
- char hash[20];
+ char hash[128];
gcry_mpi_t tmpmpi;
+ int algo;
+
+ s_key = read_sexp_from_file (keyfile);
+ algo = dsa_hash_from_key(s_key);
- gcry_md_hash_buffer (GCRY_MD_SHA1, hash, data, datalen);
- err = gcry_mpi_scan (&tmpmpi, GCRYMPI_FMT_USG, hash, 20, NULL);
+ gcry_md_hash_buffer (algo, hash, data, datalen);
+ err = gcry_mpi_scan (&tmpmpi, GCRYMPI_FMT_USG, hash,
+ gcry_md_get_algo_dlen(algo), NULL);
if (!err)
{
err = gcry_sexp_build (&s_data, NULL,
@@ -2044,8 +2202,6 @@ run_dsa_sign (const void *data, size_t d
die ("gcry_sexp_build failed for DSA data input: %s\n",
gpg_strerror (err));
- s_key = read_sexp_from_file (keyfile);
-
err = gcry_pk_sign (&s_sig, s_data, s_key);
if (err)
{
@@ -2121,13 +2277,18 @@ run_dsa_verify (const void *data, size_t
{
gpg_error_t err;
gcry_sexp_t s_data, s_key, s_sig;
- char hash[20];
+ char hash[128];
gcry_mpi_t tmpmpi;
+ int algo;
- gcry_md_hash_buffer (GCRY_MD_SHA1, hash, data, datalen);
+ s_key = read_sexp_from_file (keyfile);
+ algo = dsa_hash_from_key(s_key);
+
+ gcry_md_hash_buffer (algo, hash, data, datalen);
/* Note that we can't simply use %b with HASH to build the
S-expression, because that might yield a negative value. */
- err = gcry_mpi_scan (&tmpmpi, GCRYMPI_FMT_USG, hash, 20, NULL);
+ err = gcry_mpi_scan (&tmpmpi, GCRYMPI_FMT_USG, hash,
+ gcry_md_get_algo_dlen(algo), NULL);
if (!err)
{
err = gcry_sexp_build (&s_data, NULL,
@@ -2138,7 +2299,6 @@ run_dsa_verify (const void *data, size_t
die ("gcry_sexp_build failed for DSA data input: %s\n",
gpg_strerror (err));
- s_key = read_sexp_from_file (keyfile);
s_sig = read_sexp_from_file (sigfile);
err = gcry_pk_verify (s_sig, s_data, s_key);
@@ -2304,7 +2464,7 @@ usage (int show_help)
"MODE:\n"
" encrypt, decrypt, digest, random, hmac-sha,\n"
" rsa-{derive,gen,sign,verify},\n"
- " dsa-{pqg-gen,gen,sign,verify}, ecdsa-{gen-key,sign,verify}\n"
+ " dsa-{pq-gen,g-gen,gen,sign,verify}, ecdsa-{gen-key,sign,verify}\n"
"OPTIONS:\n"
" --verbose Print additional information\n"
" --binary Input and output is in binary form\n"
@@ -2315,6 +2475,7 @@ usage (int show_help)
" --algo NAME Use algorithm NAME\n"
" --curve NAME Select ECC curve spec NAME\n"
" --keysize N Use a keysize of N bits\n"
+ " --qize N Use a DSA q parameter size of N bits\n"
" --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"
@@ -2344,6 +2505,7 @@ main (int argc, char **argv)
const char *dt_string = NULL;
const char *algo_string = NULL;
const char *keysize_string = NULL;
+ const char *qsize_string = NULL;
const char *signature_string = NULL;
FILE *input;
void *data;
@@ -2437,6 +2599,14 @@ main (int argc, char **argv)
keysize_string = *argv;
argc--; argv++;
}
+ else if (!strcmp (*argv, "--qsize"))
+ {
+ argc--; argv++;
+ if (!argc)
+ usage (0);
+ qsize_string = *argv;
+ argc--; argv++;
+ }
else if (!strcmp (*argv, "--signature"))
{
argc--; argv++;
@@ -2792,23 +2962,49 @@ main (int argc, char **argv)
}
else if (!strcmp (mode_string, "dsa-pqg-gen"))
{
- int keysize;
+ int keysize, qsize;
+
+ keysize = keysize_string? atoi (keysize_string) : 0;
+ if (keysize < 1024 || keysize > 3072)
+ die ("invalid keysize specified; needs to be 1024 .. 3072\n");
+ qsize = qsize_string? atoi (qsize_string) : 0;
+ if (qsize < 160 || qsize > 256)
+ die ("invalid qsize specified; needs to be 160 .. 256\n");
+ run_dsa_pqg_gen (keysize, qsize, datalen? data:NULL, datalen);
+ }
+ else if (!strcmp (mode_string, "dsa-g-gen"))
+ {
+ int keysize, qsize;
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, datalen? data:NULL, datalen);
+ qsize = qsize_string? atoi (qsize_string) : 0;
+ if (qsize < 160 || qsize > 256)
+ die ("invalid qsize specified; needs to be 160 .. 256\n");
+ if (!key_string)
+ die ("option --key containing pq domain parameters is required in this mode\n");
+ run_dsa_g_gen (keysize, qsize, key_string);
+ }
+ else if (!strcmp (mode_string, "dsa-gen-key"))
+ {
+ if (!key_string)
+ die ("option --key containing pqg domain parameters is required in this mode\n");
+ run_dsa_gen_key (key_string);
}
else if (!strcmp (mode_string, "dsa-gen"))
{
- int keysize;
+ int keysize, qsize;
keysize = keysize_string? atoi (keysize_string) : 0;
if (keysize < 1024 || keysize > 3072)
die ("invalid keysize specified; needs to be 1024 .. 3072\n");
+ qsize = qsize_string? atoi (qsize_string) : 0;
+ if (qsize < 160 || qsize > 256)
+ die ("invalid qsize specified; needs to be 160 .. 256\n");
if (!key_string)
die ("option --key is required in this mode\n");
- run_dsa_gen (keysize, key_string);
+ run_dsa_gen (keysize, qsize, key_string);
}
else if (!strcmp (mode_string, "dsa-sign"))
{