New CAVS driver from upstream.
authorWerner Koch <wk@gnupg.org>
Mon, 6 Oct 2008 16:31:37 +0000 (16:31 +0000)
committerWerner Koch <wk@gnupg.org>
Mon, 6 Oct 2008 16:31:37 +0000 (16:31 +0000)
Fixed RSA FIPS tests.

tests/ChangeLog
tests/cavs_driver.pl
tests/fipsdrv.c

index 4633115..ff5d0b4 100644 (file)
@@ -1,3 +1,15 @@
+2008-10-06  Werner Koch  <wk@g10code.com>
+
+       * cavs_driver.pl: New version from upstream.
+       (libgcrypt_rsa_verify($$$$)): Pass pkcs1.
+       (libgcrypt_rsa_sign($$$)): Pass pkcs1 and hash algo.
+
+       * fipsdrv.c (run_rsa_sign): Hash data in pkcs1 mode.
+       (run_rsa_verify): Ditto.
+       (read_key_file): Rename to read_private_key_file.  Factor public
+       key code out to..
+       (read_public_key_file): .. new.
+
 2008-10-02  Werner Koch  <wk@g10code.com>
 
        * fipsdrv.c (print_buffer): Add base64 printing code.
@@ -5,6 +17,7 @@
        (run_rsa_gen, run_rsa_sign): New.
        (main): Add modes rsa-gen, rsa-sign and rsa-verify.
 
+       
 2008-09-29  Werner Koch  <wk@g10code.com>
 
        * fipsdrv.c: Merge code from fipsrngdrv.c
index 2929410..8556a81 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/env perl
 #
-# Id: cavs_driver.pl 1236 2008-09-17 13:00:06Z smueller
+# $Id: cavs_driver.pl 1243 2008-09-18 18:42:57Z smueller $
 #
 # CAVS test driver (based on the OpenSSL driver)
 # Written by: Stephan Müller <sm@atsec.com>
@@ -294,7 +294,6 @@ sub libgcrypt_encdec($$$$$) {
        return pipe_through_program($data,$program);
 }
 
-
 sub libgcrypt_rsa_sign($$$) {
        my $data = shift;
        my $hashalgo = shift;
@@ -302,49 +301,44 @@ sub libgcrypt_rsa_sign($$$) {
 
        die "ARCFOUR not available for RSA" if $opt{'R'};
        return pipe_through_program($data,
-                  "fipsdrv --verbose --algo $hashalgo --key $keyfile rsa-sign");
+               "fipsdrv --verbose --pkcs1 --algo $hashalgo --key $keyfile rsa-sign");
 }
 
-
 sub libgcrypt_rsa_verify($$$$) {
        my $data = shift;
-       my $cipher = shift;
+       my $hashalgo = shift;
        my $keyfile = shift;
        my $sigfile = shift;
 
-       $data = hex2bin($data);
        die "ARCFOUR not available for RSA" if $opt{'R'};
        $data = pipe_through_program($data,
-                   "fipsdrv --verbose --algo $hashalgo --key $keyfile --signature $sigfile rsa-verify");
+               "fipsdrv --verbose --pkcs1 --algo $hashalgo --key $keyfile --signature $sigfile rsa-verify");
 
        # Parse through the output information
        return ($data =~ /GOOD signature/);
 }
 
-
 sub libgcrypt_gen_rsakey($$) {
        my $keylen = shift;
        my $file = shift;
 
        die "ARCFOUR not available for RSA" if $opt{'R'};
        my @args = ("fipsdrv --keysize $keylen rsa-gen > $file");
-        system(@args) == 0
+       system(@args) == 0
                or die "system @args failed: $?";
        die "system @args failed: file $file not created" if (! -f $file);
 }
 
-
 sub libgcrypt_hash($$) {
        my $pt = shift;
        my $hashalgo = shift;
 
-        my $program = "fipsdrv --no-fips --algo $hashalgo digest";
+       my $program = "fipsdrv --no-fips --algo $hashalgo digest";
        die "ARCFOUR not available for hashes" if $opt{'R'};
-        
+
        return pipe_through_program($pt, $program);
 }
 
-
 sub libgcrypt_state_cipher($$$$$) {
        my $cipher = shift;
        my $enc = (shift) ? "encrypt": "decrypt";
@@ -356,7 +350,6 @@ sub libgcrypt_state_cipher($$$$$) {
        return $program;
 }
 
-
 sub libgcrypt_state_rng($$$) {
        my $key = shift;
        my $dt = shift;
@@ -372,11 +365,41 @@ sub libgcrypt_hmac($$$$) {
        my $hashtype = shift;
 
        my $program = "fipsdrv --no-fips --key $key --algo $hashtype hmac-sha";
-       return pipe_through_program($msg, $program);
+       return pipe_through_program($msg, $program);    
 }
 
 ######### End of libgcrypt implementation ################
 
+################################################################
+###### Vendor1 interface functions
+################################################################
+
+sub vendor1_encdec($$$$$) {
+       my $key=shift;
+       my $iv=shift;
+       my $cipher=shift;
+       my $enc = (shift) ? "encrypt" : "decrypt";
+       my $data=shift;
+
+       $data=hex2bin($data);
+       my $program = "./aes $enc $key";
+       $data=pipe_through_program($data,$program);
+       return bin2hex($data);
+}
+
+sub vendor1_state_cipher($$$$$) {
+       my $cipher = shift;
+       my $encdec = shift;
+       my $bufsize = shift;
+       my $key = shift;
+       my $iv = shift;
+
+       $key = bin2hex($key);
+       my $enc = $encdec ? "encrypt": "decrypt";
+       my $out = "./aes $enc $key $bufsize";
+       return $out;
+}
+
 ##### No other interface functions below this point ######
 ##########################################################
 
@@ -878,7 +901,7 @@ sub kat($$$$$$$$) {
                $key1= $key1 . $key3;
        }
        
-       $out .= "IV = $iv\n";
+       $out .= "IV = $iv\n" if (defined($iv) && $iv ne "");
        if ($enc) {
                $out .= "PLAINTEXT = $pt\n";
                $out .= "CIPHERTEXT = " . encrypt($key1, $iv, $cipher, $pt) . "\n";
@@ -997,7 +1020,8 @@ sub crypto_mct($$$$$$$$) {
                }
                my $keylen = length($key1);
 
-                $out .= "IV = ". bin2hex($iv). "\n";
+                $out .= "IV = ". bin2hex($iv) . "\n"
+                       if (defined($iv) && $iv ne "");
 
                 if ($enc) {
                         $out .= "PLAINTEXT = ". bin2hex($source_data). "\n";
@@ -1016,12 +1040,12 @@ sub crypto_mct($$$$$$$$) {
                         $old_calc_data = $calc_data;
 
                        # $calc_data = AES($key, $calc_data);
-                       #print STDERR "source_data=", bin2hex($source_data), "\n";
+                       #print STDERR "source_data=", bin2hex($source_data), "\n";
                        syswrite $CI, $source_data or die;
                        my $len = sysread $CO, $calc_data, $bufsize;
-                       #print STDERR "len=$len, bufsize=$bufsize\n";
+                       #print STDERR "len=$len, bufsize=$bufsize\n";
                        die if $len ne $bufsize;
-                       #print STDERR "calc_data=", bin2hex($calc_data), "\n";
+                       #print STDERR "calc_data=", bin2hex($calc_data), "\n";
 
                        if ( (!$enc && $ciph =~ /des/) ||
                             $ciph =~ /rc4/ ) {
@@ -1235,10 +1259,10 @@ sub usage() {
        print STDERR "Usage:
 $0 [-R] [-I name] <CAVS-test vector file>
 
--R       execution of ARCFOUR instead of OpenSSL
--I NAME  Use interface style NAME:
-            openssl     OpenSSL (default)
-            libgcrypt   Libgcrypt";
+-R     execution of ARCFOUR instead of OpenSSL
+-I NAME        Use interface style NAME:
+               openssl     OpenSSL (default)
+               libgcrypt   Libgcrypt";
 }
 
 # Parser of CAVS test vector file
@@ -1394,7 +1418,7 @@ sub parse($$) {
                                $tt = 2;
                                die "Interface function state_cipher for Stateful Cipher operation defined for tested library"
                                        if (!defined($state_cipher));
-                       } elsif ($cipher eq "sha" && $tt!=5 && $tt!=6) {
+                       } elsif ($cipher =~ /^sha\d+/ && $tt!=5 && $tt!=6) {
                                $tt = 3;
                                die "Interface function hash for Hashing not defined for tested library"
                                        if (!defined($hash));
@@ -1523,7 +1547,7 @@ sub parse($$) {
 
                # call tests if all input data is there
                if ($tt == 1) {
-                       if ($key1 ne "" && $iv ne "" && $pt ne "" && $cipher ne "") {
+                       if ($key1 ne "" && $pt ne "" && $cipher ne "") {
                                $out .= kat($keytype, $key1, $key2, $key3, $iv, $pt, $cipher, $enc);
                                $keytype = "";
                                $key1 = "";
@@ -1534,7 +1558,7 @@ sub parse($$) {
                        }
                }
                elsif ($tt == 2) {
-                       if ($key1 ne "" && $iv ne "" && $pt ne "" && $cipher ne "") {
+                       if ($key1 ne "" && $pt ne "" && $cipher ne "") {
                                $out .= crypto_mct($keytype, $key1, $key2, $key3, $iv, $pt, $cipher, $enc);
                                $keytype = "";
                                $key1 = "";
@@ -1629,26 +1653,26 @@ sub main() {
 
        ##### Set library
 
-        if ( ! defined $opt{'I'} || $opt{'I'} eq 'openssl' ) {
-               print STDERR "Using OpenSSL interface functions\n";
-                $encdec =      \&openssl_encdec;
-                $rsa_sign =    \&openssl_rsa_sign;
-                $rsa_verify =  \&openssl_rsa_verify;
-                $gen_rsakey =  \&openssl_gen_rsakey;
-                $hash =                \&openssl_hash;
-                $state_cipher =        \&openssl_state_cipher;
-        } elsif ( $opt{'I'} eq 'libgcrypt' ) {
-                print STDERR "Using libgcrypt interface functions\n";
-                $encdec =      \&libgcrypt_encdec;
-                $rsa_sign =    \&libgcrypt_rsa_sign;
-                $rsa_verify =  \&libgcrypt_rsa_verify;
-                $gen_rsakey =  \&libgcrypt_gen_rsakey;
-                $hash =                \&libgcrypt_hash;
-                $state_cipher =        \&libgcrypt_state_cipher;
-                $state_rng =   \&libgcrypt_state_rng;
-                $hmac =                \&libgcrypt_hmac;
+       if ( ! defined $opt{'I'} || $opt{'I'} eq 'openssl' ) {
+               print STDERR "Using OpenSSL interface functions\n";
+               $encdec =       \&openssl_encdec;
+               $rsa_sign =     \&openssl_rsa_sign;
+               $rsa_verify =   \&openssl_rsa_verify;
+               $gen_rsakey =   \&openssl_gen_rsakey;
+               $hash =         \&openssl_hash;
+               $state_cipher = \&openssl_state_cipher;
+       } elsif ( $opt{'I'} eq 'libgcrypt' ) {
+               print STDERR "Using libgcrypt interface functions\n";
+               $encdec =       \&libgcrypt_encdec;
+               $rsa_sign =     \&libgcrypt_rsa_sign;
+               $rsa_verify =   \&libgcrypt_rsa_verify;
+               $gen_rsakey =   \&libgcrypt_gen_rsakey;
+               $hash =         \&libgcrypt_hash;
+               $state_cipher = \&libgcrypt_state_cipher;
+               $state_rng =    \&libgcrypt_state_rng;
+               $hmac =         \&libgcrypt_hmac;
         } else {
-                die "Invalid interface option given"; 
+                die "Invalid interface option given";
         }
 
        my $infile=$ARGV[0];
index 68b48e9..1d5efbf 100644 (file)
@@ -431,11 +431,11 @@ parse_tag (unsigned char const **buffer, size_t *buflen, struct tag_info *ti)
 }
 
 
-/* Read the file FNAME assuming it is a PEM encoded private or public
-   key file and return an S-expression.  With SHOW set, the key
-   parameters are printed.  */
+/* Read the file FNAME assuming it is a PEM encoded private key file
+   and return an S-expression.  With SHOW set, the key parameters are
+   printed.  */
 static gcry_sexp_t
-read_key_file (const char *fname, int private, int show)
+read_private_key_file (const char *fname, int show)
 {
   gcry_error_t err;
   FILE *fp;
@@ -445,7 +445,7 @@ read_key_file (const char *fname, int private, int show)
   size_t derlen;
   struct tag_info ti;
   gcry_mpi_t keyparms[8];
-  int n_keyparms = private? 8 : 2;
+  int n_keyparms = 8;
   int idx;
   gcry_sexp_t s_key;
 
@@ -470,7 +470,7 @@ read_key_file (const char *fname, int private, int show)
     goto bad_asn1;
   if (ti.length != 1 || *der)
     goto bad_asn1;  /* The value of the first integer is no 0. */
-  der += ti.length; derlen += ti.length;
+  der += ti.length; derlen -= ti.length;
 
   for (idx=0; idx < n_keyparms; idx++)
     {
@@ -488,51 +488,135 @@ read_key_file (const char *fname, int private, int show)
       err = gcry_mpi_scan (keyparms+idx, GCRYMPI_FMT_USG, der, ti.length,NULL);
       if (err)
         die ("error scanning RSA parameter %d: %s\n", idx, gpg_strerror (err));
-      der += ti.length; derlen += ti.length;
+      der += ti.length; derlen -= ti.length;
     }
   if (idx != n_keyparms)
     die ("not enough RSA key parameters\n");
 
   gcry_free (buffer);
 
-  if (private)
+  /* Convert from OpenSSL parameter ordering to the OpenPGP order. */
+  /* First check that p < q; if not swap p and q and recompute u.  */ 
+  if (gcry_mpi_cmp (keyparms[3], keyparms[4]) > 0)
     {
-      /* Convert from OpenSSL parameter ordering to the OpenPGP order. */
-      /* First check that p < q; if not swap p and q and recompute u.  */ 
-      if (gcry_mpi_cmp (keyparms[3], keyparms[4]) > 0)
-        {
-          gcry_mpi_swap (keyparms[3], keyparms[4]);
-          gcry_mpi_invm (keyparms[7], keyparms[3], keyparms[4]);
-        }
-      
-      /* Build the S-expression.  */
-      err = gcry_sexp_build (&s_key, NULL,
-                             "(private-key(rsa(n%m)(e%m)"
-                             /**/            "(d%m)(p%m)(q%m)(u%m)))",
-                             keyparms[0], keyparms[1], keyparms[2],
-                             keyparms[3], keyparms[4], keyparms[7] );
+      gcry_mpi_swap (keyparms[3], keyparms[4]);
+      gcry_mpi_invm (keyparms[7], keyparms[3], keyparms[4]);
     }
-  else
+  
+  /* Build the S-expression.  */
+  err = gcry_sexp_build (&s_key, NULL,
+                         "(private-key(rsa(n%m)(e%m)"
+                         /**/            "(d%m)(p%m)(q%m)(u%m)))",
+                         keyparms[0], keyparms[1], keyparms[2],
+                         keyparms[3], keyparms[4], keyparms[7] );
+  if (err)
+    die ("error building S-expression: %s\n", gpg_strerror (err));
+  
+  for (idx=0; idx < n_keyparms; idx++)
+    gcry_mpi_release (keyparms[idx]);
+  
+  return s_key;
+  
+ bad_asn1:
+  die ("invalid ASN.1 structure in `%s'\n", fname);
+  return NULL; /*NOTREACHED*/
+}
+
+
+/* Read the file FNAME assuming it is a PEM encoded public key file
+   and return an S-expression.  With SHOW set, the key parameters are
+   printed.  */
+static gcry_sexp_t
+read_public_key_file (const char *fname, int show)
+{
+  gcry_error_t err;
+  FILE *fp;
+  char *buffer;
+  size_t buflen;
+  const unsigned char *der;
+  size_t derlen;
+  struct tag_info ti;
+  gcry_mpi_t keyparms[2];
+  int n_keyparms = 2;
+  int idx;
+  gcry_sexp_t s_key;
+
+  fp = fopen (fname, binary_input?"rb":"r");
+  if (!fp)
+    die ("can't open `%s': %s\n", fname, strerror (errno));
+  buffer = read_file (fp, 0, &buflen);
+  if (!buffer)
+    die ("error reading `%s'\n", fname);
+  fclose (fp);
+
+  buflen = base64_decode (buffer, buflen);
+  
+  /* Parse the ASN.1 structure.  */
+  der = (const unsigned char*)buffer;
+  derlen = buflen;
+  if ( parse_tag (&der, &derlen, &ti)
+       || ti.tag != TAG_SEQUENCE || ti.class || !ti.cons || ti.ndef)
+    goto bad_asn1;
+  if ( parse_tag (&der, &derlen, &ti)
+       || ti.tag != TAG_SEQUENCE || ti.class || !ti.cons || ti.ndef)
+    goto bad_asn1;
+  /* We skip the description of the key parameters and assume it is RSA.  */
+  der += ti.length; derlen -= ti.length;
+  
+  if ( parse_tag (&der, &derlen, &ti)
+       || ti.tag != TAG_BIT_STRING || ti.class || ti.cons || ti.ndef)
+    goto bad_asn1;
+  if (ti.length < 1 || *der)
+    goto bad_asn1;  /* The number of unused bits needs to be 0. */
+  der += 1; derlen -= 1;
+
+  /* Parse the BIT string.  */
+  if ( parse_tag (&der, &derlen, &ti)
+       || ti.tag != TAG_SEQUENCE || ti.class || !ti.cons || ti.ndef)
+    goto bad_asn1;
+
+  for (idx=0; idx < n_keyparms; idx++)
     {
-      err = gcry_sexp_build (&s_key, NULL,
-                             "(public-key(rsa(n%m)(e%m)))",
-                             keyparms[0], keyparms[1]);
+      if ( parse_tag (&der, &derlen, &ti)
+           || ti.tag != TAG_INTEGER || ti.class || ti.cons || ti.ndef)
+        goto bad_asn1;
+      if (show)
+        {
+          char prefix[2];
 
+          prefix[0] = idx < 2? "ne"[idx] : '?';
+          prefix[1] = 0;
+          showhex (prefix, der, ti.length);
+        }
+      err = gcry_mpi_scan (keyparms+idx, GCRYMPI_FMT_USG, der, ti.length,NULL);
+      if (err)
+        die ("error scanning RSA parameter %d: %s\n", idx, gpg_strerror (err));
+      der += ti.length; derlen -= ti.length;
     }
+  if (idx != n_keyparms)
+    die ("not enough RSA key parameters\n");
+
+  gcry_free (buffer);
+
+  /* Build the S-expression.  */
+  err = gcry_sexp_build (&s_key, NULL,
+                         "(public-key(rsa(n%m)(e%m)))",
+                         keyparms[0], keyparms[1] );
   if (err)
     die ("error building S-expression: %s\n", gpg_strerror (err));
   
   for (idx=0; idx < n_keyparms; idx++)
     gcry_mpi_release (keyparms[idx]);
-
+  
   return s_key;
-
+  
  bad_asn1:
   die ("invalid ASN.1 structure in `%s'\n", fname);
   return NULL; /*NOTREACHED*/
 }
 
 
+
 /* Read the file FNAME assuming it is a binary signature result and
    return an an S-expression suitable for gcry_pk_verify.  */
 static gcry_sexp_t
@@ -1062,11 +1146,20 @@ run_rsa_sign (const void *data, size_t datalen,
   size_t outlen;
   
 /*   showhex ("D", data, datalen); */
-
   if (pkcs1)
-    err = gcry_sexp_build (&s_data, NULL,
-                           "(data (flags pkcs1)(hash %s %b))",
-                           gcry_md_algo_name (hashalgo), (int)datalen, data);
+    {
+      unsigned char hash[50];
+      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 pkcs1)(hash %s %b))",
+                             gcry_md_algo_name (hashalgo),
+                             (int)hashsize, hash);
+    }
   else
     {
       gcry_mpi_t tmp;
@@ -1083,12 +1176,12 @@ run_rsa_sign (const void *data, size_t datalen,
     die ("gcry_sexp_build failed for RSA data input: %s\n",
          gpg_strerror (err));
 
-  s_key = read_key_file (keyfile, 1, 0);
+  s_key = read_private_key_file (keyfile, 0);
 
   err = gcry_pk_sign (&s_sig, s_data, s_key);
   if (err)
     {
-      gcry_sexp_release (read_key_file (keyfile, 1, 1));
+      gcry_sexp_release (read_private_key_file (keyfile, 1));
       die ("gcry_pk_signed failed (datalen=%d,keyfile=%s): %s\n",
            (int)datalen, keyfile, gpg_strerror (err));
     }
@@ -1141,9 +1234,19 @@ run_rsa_verify (const void *data, size_t datalen, int hashalgo, int pkcs1,
   gcry_sexp_t s_data, s_key, s_sig;
   
   if (pkcs1)
-    err = gcry_sexp_build (&s_data, NULL,
-                           "(data (flags pkcs1)(hash %s %b))",
-                           gcry_md_algo_name (hashalgo), (int)datalen, data);
+    {
+      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 pkcs1)(hash %s %b))",
+                             gcry_md_algo_name (hashalgo),
+                             (int)hashsize, hash);
+    }
   else
     {
       gcry_mpi_t tmp;
@@ -1160,15 +1263,15 @@ run_rsa_verify (const void *data, size_t datalen, int hashalgo, int pkcs1,
     die ("gcry_sexp_build failed for RSA data input: %s\n",
          gpg_strerror (err));
 
-  s_key = read_key_file (keyfile, 0, 0);
+  s_key = read_public_key_file (keyfile, 0);
 
   s_sig = read_sig_file (sigfile);
 
   err = gcry_pk_verify (s_sig, s_data, s_key);
   if (!err)
-    puts ("GOOD signature\n");
+    puts ("GOOD signature");
   else if (gpg_err_code (err) == GPG_ERR_BAD_SIGNATURE)
-    puts ("BAD signature\n");
+    puts ("BAD signature");
   else
     printf ("ERROR (%s)\n", gpg_strerror (err));