LCOV - code coverage report
Current view: top level - tests - t-ed25519.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 168 269 62.5 %
Date: 2016-12-01 18:32:04 Functions: 10 13 76.9 %

          Line data    Source code
       1             : /* t-ed25519.c - Check the Ed25519 crypto
       2             :  * Copyright (C) 2013 g10 Code GmbH
       3             :  *
       4             :  * This file is part of Libgcrypt.
       5             :  *
       6             :  * Libgcrypt is free software; you can redistribute it and/or modify
       7             :  * it under the terms of the GNU Lesser General Public License as
       8             :  * published by the Free Software Foundation; either version 2.1 of
       9             :  * the License, or (at your option) any later version.
      10             :  *
      11             :  * Libgcrypt is distributed in the hope that it will be useful,
      12             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14             :  * GNU Lesser General Public License for more details.
      15             :  *
      16             :  * You should have received a copy of the GNU Lesser General Public
      17             :  * License along with this program; if not, see <http://www.gnu.org/licenses/>.
      18             :  */
      19             : 
      20             : #ifdef HAVE_CONFIG_H
      21             : #include <config.h>
      22             : #endif
      23             : #include <stdarg.h>
      24             : #include <stdio.h>
      25             : #include <ctype.h>
      26             : #include <stdlib.h>
      27             : #include <string.h>
      28             : #include <errno.h>
      29             : 
      30             : #include "../src/gcrypt-int.h"
      31             : 
      32             : #include "stopwatch.h"
      33             : 
      34             : #define PGM "t-ed25519"
      35             : #define N_TESTS 1026
      36             : 
      37             : #define my_isascii(c) (!((c) & 0x80))
      38             : #define digitp(p)   (*(p) >= '0' && *(p) <= '9')
      39             : #define hexdigitp(a) (digitp (a)                     \
      40             :                       || (*(a) >= 'A' && *(a) <= 'F')  \
      41             :                       || (*(a) >= 'a' && *(a) <= 'f'))
      42             : #define xtoi_1(p)   (*(p) <= '9'? (*(p)- '0'): \
      43             :                      *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
      44             : #define xtoi_2(p)   ((xtoi_1(p) * 16) + xtoi_1((p)+1))
      45             : #define xmalloc(a)    gcry_xmalloc ((a))
      46             : #define xcalloc(a,b)  gcry_xcalloc ((a),(b))
      47             : #define xstrdup(a)    gcry_xstrdup ((a))
      48             : #define xfree(a)      gcry_free ((a))
      49             : #define pass()        do { ; } while (0)
      50             : 
      51             : static int verbose;
      52             : static int debug;
      53             : static int error_count;
      54             : static int sign_with_pk;
      55             : static int no_verify;
      56             : static int custom_data_file;
      57             : 
      58             : static void
      59           0 : die (const char *format, ...)
      60             : {
      61             :   va_list arg_ptr ;
      62             : 
      63           0 :   fflush (stdout);
      64           0 :   fprintf (stderr, "%s: ", PGM);
      65           0 :   va_start( arg_ptr, format ) ;
      66           0 :   vfprintf (stderr, format, arg_ptr );
      67           0 :   va_end(arg_ptr);
      68           0 :   if (*format && format[strlen(format)-1] != '\n')
      69           0 :     putc ('\n', stderr);
      70           0 :   exit (1);
      71             : }
      72             : 
      73             : static void
      74           0 : fail (const char *format, ...)
      75             : {
      76             :   va_list arg_ptr;
      77             : 
      78           0 :   fflush (stdout);
      79           0 :   fprintf (stderr, "%s: ", PGM);
      80             :   /* if (wherestr) */
      81             :   /*   fprintf (stderr, "%s: ", wherestr); */
      82           0 :   va_start (arg_ptr, format);
      83           0 :   vfprintf (stderr, format, arg_ptr);
      84           0 :   va_end (arg_ptr);
      85           0 :   if (*format && format[strlen(format)-1] != '\n')
      86           0 :     putc ('\n', stderr);
      87           0 :   error_count++;
      88           0 :   if (error_count >= 50)
      89           0 :     die ("stopped after 50 errors.");
      90           0 : }
      91             : 
      92             : static void
      93           2 : show (const char *format, ...)
      94             : {
      95             :   va_list arg_ptr;
      96             : 
      97           2 :   if (!verbose)
      98           4 :     return;
      99           0 :   fprintf (stderr, "%s: ", PGM);
     100           0 :   va_start (arg_ptr, format);
     101           0 :   vfprintf (stderr, format, arg_ptr);
     102           0 :   if (*format && format[strlen(format)-1] != '\n')
     103           0 :     putc ('\n', stderr);
     104           0 :   va_end (arg_ptr);
     105             : }
     106             : 
     107             : 
     108             : static void
     109           5 : show_note (const char *format, ...)
     110             : {
     111             :   va_list arg_ptr;
     112             : 
     113           5 :   if (!verbose && getenv ("srcdir"))
     114           5 :     fputs ("      ", stderr);  /* To align above "PASS: ".  */
     115             :   else
     116           0 :     fprintf (stderr, "%s: ", PGM);
     117           5 :   va_start (arg_ptr, format);
     118           5 :   vfprintf (stderr, format, arg_ptr);
     119           5 :   if (*format && format[strlen(format)-1] != '\n')
     120           0 :     putc ('\n', stderr);
     121           5 :   va_end (arg_ptr);
     122           5 : }
     123             : 
     124             : 
     125             : static void
     126           0 : show_sexp (const char *prefix, gcry_sexp_t a)
     127             : {
     128             :   char *buf;
     129             :   size_t size;
     130             : 
     131           0 :   fprintf (stderr, "%s: ", PGM);
     132           0 :   if (prefix)
     133           0 :     fputs (prefix, stderr);
     134           0 :   size = gcry_sexp_sprint (a, GCRYSEXP_FMT_ADVANCED, NULL, 0);
     135           0 :   buf = xmalloc (size);
     136             : 
     137           0 :   gcry_sexp_sprint (a, GCRYSEXP_FMT_ADVANCED, buf, size);
     138           0 :   fprintf (stderr, "%.*s", (int)size, buf);
     139           0 :   gcry_free (buf);
     140           0 : }
     141             : 
     142             : 
     143             : /* Prepend FNAME with the srcdir environment variable's value and
     144             :    retrun an allocated filename. */
     145             : char *
     146           1 : prepend_srcdir (const char *fname)
     147             : {
     148             :   static const char *srcdir;
     149             :   char *result;
     150             : 
     151           1 :   if (!srcdir && !(srcdir = getenv ("srcdir")))
     152           0 :     srcdir = ".";
     153             : 
     154           1 :   result = xmalloc (strlen (srcdir) + 1 + strlen (fname) + 1);
     155           1 :   strcpy (result, srcdir);
     156           1 :   strcat (result, "/");
     157           1 :   strcat (result, fname);
     158           1 :   return result;
     159             : }
     160             : 
     161             : 
     162             : /* Read next line but skip over empty and comment lines.  Caller must
     163             :    xfree the result.  */
     164             : static char *
     165        6173 : read_textline (FILE *fp, int *lineno)
     166             : {
     167             :   char line[4096];
     168             :   char *p;
     169             : 
     170             :   do
     171             :     {
     172        6173 :       if (!fgets (line, sizeof line, fp))
     173             :         {
     174           1 :           if (feof (fp))
     175           1 :             return NULL;
     176           0 :           die ("error reading input line: %s\n", strerror (errno));
     177             :         }
     178        6172 :       ++*lineno;
     179        6172 :       p = strchr (line, '\n');
     180        6172 :       if (!p)
     181           0 :         die ("input line %d not terminated or too long\n", *lineno);
     182        6172 :       *p = 0;
     183        6172 :       for (p--;p > line && my_isascii (*p) && isspace (*p); p--)
     184           0 :         *p = 0;
     185             :     }
     186        6172 :   while (!*line || *line == '#');
     187             :   /* if (debug) */
     188             :   /*   show ("read line: '%s'\n", line); */
     189        5130 :   return xstrdup (line);
     190             : }
     191             : 
     192             : 
     193             : /* Copy the data after the tag to BUFFER.  BUFFER will be allocated as
     194             :    needed.  */
     195             : static void
     196        4104 : copy_data (char **buffer, const char *line, int lineno)
     197             : {
     198             :   const char *s;
     199             : 
     200        4104 :   xfree (*buffer);
     201        4104 :   *buffer = NULL;
     202             : 
     203        4104 :   s = strchr (line, ':');
     204        4104 :   if (!s)
     205             :     {
     206           0 :       fail ("syntax error at input line %d", lineno);
     207        4104 :       return;
     208             :     }
     209        4104 :   for (s++; my_isascii (*s) && isspace (*s); s++)
     210             :     ;
     211        4104 :   *buffer = xstrdup (s);
     212             : }
     213             : 
     214             : 
     215             : /* Convert STRING consisting of hex characters into its binary
     216             :    representation and return it as an allocated buffer. The valid
     217             :    length of the buffer is returned at R_LENGTH.  The string is
     218             :    delimited by end of string.  The function returns NULL on
     219             :    error.  */
     220             : static void *
     221        3078 : hex2buffer (const char *string, size_t *r_length)
     222             : {
     223             :   const char *s;
     224             :   unsigned char *buffer;
     225             :   size_t length;
     226             : 
     227        3078 :   buffer = xmalloc (strlen(string)/2+1);
     228        3078 :   length = 0;
     229      592552 :   for (s=string; *s; s +=2 )
     230             :     {
     231      589474 :       if (!hexdigitp (s) || !hexdigitp (s+1))
     232           0 :         return NULL;           /* Invalid hex digits. */
     233      589474 :       ((unsigned char*)buffer)[length++] = xtoi_2 (s);
     234             :     }
     235        3078 :   *r_length = length;
     236        3078 :   return buffer;
     237             : }
     238             : 
     239             : 
     240             : static void
     241        1026 : hexdowncase (char *string)
     242             : {
     243             :   char *p;
     244             : 
     245      132354 :   for (p=string; *p; p++)
     246      131328 :     if (my_isascii (*p))
     247      131328 :       *p = tolower (*p);
     248        1026 : }
     249             : 
     250             : 
     251             : static void
     252        1026 : one_test (int testno, const char *sk, const char *pk,
     253             :           const char *msg, const char *sig)
     254             : {
     255             :   gpg_error_t err;
     256             :   int i;
     257             :   char *p;
     258        1026 :   void *buffer = NULL;
     259        1026 :   void *buffer2 = NULL;
     260             :   size_t buflen, buflen2;
     261             :   gcry_sexp_t s_tmp, s_tmp2;
     262        1026 :   gcry_sexp_t s_sk = NULL;
     263        1026 :   gcry_sexp_t s_pk = NULL;
     264        1026 :   gcry_sexp_t s_msg= NULL;
     265        1026 :   gcry_sexp_t s_sig= NULL;
     266        1026 :   unsigned char *sig_r = NULL;
     267        1026 :   unsigned char *sig_s = NULL;
     268        1026 :   char *sig_rs_string = NULL;
     269             :   size_t sig_r_len, sig_s_len;
     270             : 
     271        1026 :   if (verbose > 1)
     272           0 :     show ("Running test %d\n", testno);
     273             : 
     274        1026 :   if (!(buffer = hex2buffer (sk, &buflen)))
     275             :     {
     276           0 :       fail ("error building s-exp for test %d, %s: %s",
     277             :             testno, "sk", "invalid hex string");
     278           0 :       goto leave;
     279             :     }
     280        1026 :   if (!(buffer2 = hex2buffer (pk, &buflen2)))
     281             :     {
     282           0 :       fail ("error building s-exp for test %d, %s: %s",
     283             :             testno, "pk", "invalid hex string");
     284           0 :       goto leave;
     285             :     }
     286        1026 :   if (sign_with_pk)
     287           0 :     err = gcry_sexp_build (&s_sk, NULL,
     288             :                            "(private-key"
     289             :                            " (ecc"
     290             :                            "  (curve \"Ed25519\")"
     291             :                            "  (flags eddsa)"
     292             :                            "  (q %b)"
     293             :                            "  (d %b)))",
     294             :                            (int)buflen2, buffer2,
     295             :                            (int)buflen, buffer);
     296             :   else
     297        1026 :     err = gcry_sexp_build (&s_sk, NULL,
     298             :                            "(private-key"
     299             :                            " (ecc"
     300             :                            "  (curve \"Ed25519\")"
     301             :                            "  (flags eddsa)"
     302             :                            "  (d %b)))",
     303             :                            (int)buflen, buffer);
     304        1026 :   if (err)
     305             :     {
     306           0 :       fail ("error building s-exp for test %d, %s: %s",
     307             :             testno, "sk", gpg_strerror (err));
     308           0 :       goto leave;
     309             :     }
     310             : 
     311        1026 :   if ((err = gcry_sexp_build (&s_pk, NULL,
     312             :                               "(public-key"
     313             :                               " (ecc"
     314             :                               "  (curve \"Ed25519\")"
     315             :                               "  (flags eddsa)"
     316             :                               "  (q %b)))",  (int)buflen2, buffer2)))
     317             :     {
     318           0 :       fail ("error building s-exp for test %d, %s: %s",
     319             :             testno, "pk", gpg_strerror (err));
     320           0 :       goto leave;
     321             :     }
     322             : 
     323        1026 :   xfree (buffer);
     324        1026 :   if (!(buffer = hex2buffer (msg, &buflen)))
     325             :     {
     326           0 :       fail ("error building s-exp for test %d, %s: %s",
     327             :             testno, "msg", "invalid hex string");
     328           0 :       goto leave;
     329             :     }
     330        1026 :   if ((err = gcry_sexp_build (&s_msg, NULL,
     331             :                               "(data"
     332             :                               " (flags eddsa)"
     333             :                               " (hash-algo sha512)"
     334             :                               " (value %b))",  (int)buflen, buffer)))
     335             :     {
     336           0 :       fail ("error building s-exp for test %d, %s: %s",
     337             :             testno, "msg", gpg_strerror (err));
     338           0 :       goto leave;
     339             :     }
     340             : 
     341        1026 :   if ((err = gcry_pk_sign (&s_sig, s_msg, s_sk)))
     342           0 :     fail ("gcry_pk_sign failed for test %d: %s", testno, gpg_strerror (err));
     343        1026 :   if (debug)
     344           0 :     show_sexp ("sig=", s_sig);
     345             : 
     346        1026 :   s_tmp2 = NULL;
     347        1026 :   s_tmp = gcry_sexp_find_token (s_sig, "sig-val", 0);
     348        1026 :   if (s_tmp)
     349             :     {
     350        1026 :       s_tmp2 = s_tmp;
     351        1026 :       s_tmp = gcry_sexp_find_token (s_tmp2, "eddsa", 0);
     352        1026 :       if (s_tmp)
     353             :         {
     354        1026 :           gcry_sexp_release (s_tmp2);
     355        1026 :           s_tmp2 = s_tmp;
     356        1026 :           s_tmp = gcry_sexp_find_token (s_tmp2, "r", 0);
     357        1026 :           if (s_tmp)
     358             :             {
     359        1026 :               sig_r = gcry_sexp_nth_buffer (s_tmp, 1, &sig_r_len);
     360        1026 :               gcry_sexp_release (s_tmp);
     361             :             }
     362        1026 :           s_tmp = gcry_sexp_find_token (s_tmp2, "s", 0);
     363        1026 :           if (s_tmp)
     364             :             {
     365        1026 :               sig_s = gcry_sexp_nth_buffer (s_tmp, 1, &sig_s_len);
     366        1026 :               gcry_sexp_release (s_tmp);
     367             :             }
     368             :         }
     369             :     }
     370        1026 :   gcry_sexp_release (s_tmp2); s_tmp2 = NULL;
     371             : 
     372        1026 :   if (!sig_r || !sig_s)
     373           0 :     fail ("gcry_pk_sign failed for test %d: %s", testno, "r or s missing");
     374             :   else
     375             :     {
     376        1026 :       sig_rs_string = xmalloc (2*(sig_r_len + sig_s_len)+1);
     377        1026 :       p = sig_rs_string;
     378        1026 :       *p = 0;
     379       33858 :       for (i=0; i < sig_r_len; i++, p += 2)
     380       32832 :         snprintf (p, 3, "%02x", sig_r[i]);
     381       33858 :       for (i=0; i < sig_s_len; i++, p += 2)
     382       32832 :         snprintf (p, 3, "%02x", sig_s[i]);
     383        1026 :       if (strcmp (sig_rs_string, sig))
     384             :         {
     385           0 :           fail ("gcry_pk_sign failed for test %d: %s",
     386             :                 testno, "wrong value returned");
     387           0 :           show ("  expected: '%s'", sig);
     388           0 :           show ("       got: '%s'", sig_rs_string);
     389             :         }
     390             :     }
     391             : 
     392        1026 :   if (!no_verify)
     393        1026 :     if ((err = gcry_pk_verify (s_sig, s_msg, s_pk)))
     394           0 :       fail ("gcry_pk_verify failed for test %d: %s",
     395             :             testno, gpg_strerror (err));
     396             : 
     397             : 
     398             :  leave:
     399        1026 :   gcry_sexp_release (s_sig);
     400        1026 :   gcry_sexp_release (s_sk);
     401        1026 :   gcry_sexp_release (s_pk);
     402        1026 :   gcry_sexp_release (s_msg);
     403        1026 :   xfree (buffer);
     404        1026 :   xfree (buffer2);
     405        1026 :   xfree (sig_r);
     406        1026 :   xfree (sig_s);
     407        1026 :   xfree (sig_rs_string);
     408        1026 : }
     409             : 
     410             : 
     411             : static void
     412           1 : check_ed25519 (const char *fname)
     413             : {
     414             :   FILE *fp;
     415             :   int lineno, ntests;
     416             :   char *line;
     417             :   int testno;
     418             :   char *sk, *pk, *msg, *sig;
     419             : 
     420           1 :   show ("Checking Ed25519.\n");
     421             : 
     422           1 :   fp = fopen (fname, "r");
     423           1 :   if (!fp)
     424           0 :     die ("error opening '%s': %s\n", fname, strerror (errno));
     425             : 
     426           1 :   testno = 0;
     427           1 :   sk = pk = msg = sig = NULL;
     428           1 :   lineno = ntests = 0;
     429        5132 :   while ((line = read_textline (fp, &lineno)))
     430             :     {
     431        5130 :       if (!strncmp (line, "TST:", 4))
     432        1026 :         testno = atoi (line+4);
     433        4104 :       else if (!strncmp (line, "SK:", 3))
     434        1026 :         copy_data (&sk, line, lineno);
     435        3078 :       else if (!strncmp (line, "PK:", 3))
     436        1026 :         copy_data (&pk, line, lineno);
     437        2052 :       else if (!strncmp (line, "MSG:", 4))
     438        1026 :         copy_data (&msg, line, lineno);
     439        1026 :       else if (!strncmp (line, "SIG:", 4))
     440        1026 :         copy_data (&sig, line, lineno);
     441             :       else
     442           0 :         fail ("unknown tag at input line %d", lineno);
     443             : 
     444        5130 :       xfree (line);
     445        5130 :       if (testno && sk && pk && msg && sig)
     446             :         {
     447        1026 :           hexdowncase (sig);
     448        1026 :           one_test (testno, sk, pk, msg, sig);
     449        1026 :           ntests++;
     450        1026 :           if (!(ntests % 256))
     451           4 :             show_note ("%d of %d tests done\n", ntests, N_TESTS);
     452        1026 :           xfree (pk);  pk = NULL;
     453        1026 :           xfree (sk);  sk = NULL;
     454        1026 :           xfree (msg); msg = NULL;
     455        1026 :           xfree (sig); sig = NULL;
     456             :         }
     457             : 
     458             :     }
     459           1 :   xfree (pk);
     460           1 :   xfree (sk);
     461           1 :   xfree (msg);
     462           1 :   xfree (sig);
     463             : 
     464           1 :   if (ntests != N_TESTS && !custom_data_file)
     465           0 :     fail ("did %d tests but expected %d", ntests, N_TESTS);
     466           1 :   else if ((ntests % 256))
     467           1 :     show_note ("%d tests done\n", ntests);
     468             : 
     469           1 :   fclose (fp);
     470           1 : }
     471             : 
     472             : 
     473             : int
     474           1 : main (int argc, char **argv)
     475             : {
     476           1 :   int last_argc = -1;
     477           1 :   char *fname = NULL;
     478             : 
     479           1 :   if (argc)
     480           1 :     { argc--; argv++; }
     481             : 
     482           2 :   while (argc && last_argc != argc )
     483             :     {
     484           0 :       last_argc = argc;
     485           0 :       if (!strcmp (*argv, "--"))
     486             :         {
     487           0 :           argc--; argv++;
     488           0 :           break;
     489             :         }
     490           0 :       else if (!strcmp (*argv, "--help"))
     491             :         {
     492           0 :           fputs ("usage: " PGM " [options]\n"
     493             :                  "Options:\n"
     494             :                  "  --verbose       print timings etc.\n"
     495             :                  "  --debug         flyswatter\n"
     496             :                  "  --sign-with-pk  also use the public key for signing\n"
     497             :                  "  --no-verify     skip the verify test\n"
     498             :                  "  --data FNAME    take test data from file FNAME\n",
     499             :                  stdout);
     500           0 :           exit (0);
     501             :         }
     502           0 :       else if (!strcmp (*argv, "--verbose"))
     503             :         {
     504           0 :           verbose++;
     505           0 :           argc--; argv++;
     506             :         }
     507           0 :       else if (!strcmp (*argv, "--debug"))
     508             :         {
     509           0 :           verbose += 2;
     510           0 :           debug++;
     511           0 :           argc--; argv++;
     512             :         }
     513           0 :       else if (!strcmp (*argv, "--sign-with-pk"))
     514             :         {
     515           0 :           sign_with_pk = 1;
     516           0 :           argc--; argv++;
     517             :         }
     518           0 :       else if (!strcmp (*argv, "--no-verify"))
     519             :         {
     520           0 :           no_verify = 1;
     521           0 :           argc--; argv++;
     522             :         }
     523           0 :       else if (!strcmp (*argv, "--data"))
     524             :         {
     525           0 :           argc--; argv++;
     526           0 :           if (argc)
     527             :             {
     528           0 :               xfree (fname);
     529           0 :               fname = xstrdup (*argv);
     530           0 :               argc--; argv++;
     531             :             }
     532             :         }
     533           0 :       else if (!strncmp (*argv, "--", 2))
     534           0 :         die ("unknown option '%s'", *argv);
     535             : 
     536             :     }
     537             : 
     538           1 :   if (!fname)
     539           1 :     fname = prepend_srcdir ("t-ed25519.inp");
     540             :   else
     541           0 :     custom_data_file = 1;
     542             : 
     543           1 :   gcry_control (GCRYCTL_DISABLE_SECMEM, 0);
     544           1 :   if (!gcry_check_version (GCRYPT_VERSION))
     545           0 :     die ("version mismatch\n");
     546           1 :   if (debug)
     547           0 :     gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1u , 0);
     548           1 :   gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
     549           1 :   gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
     550             : 
     551             :   /* Ed25519 isn't supported in fips mode */
     552           1 :   if (gcry_fips_mode_active())
     553           0 :     return 77;
     554             : 
     555           1 :   start_timer ();
     556           1 :   check_ed25519 (fname);
     557           1 :   stop_timer ();
     558             : 
     559           1 :   xfree (fname);
     560             : 
     561           1 :   show ("All tests completed in %s.  Errors: %d\n",
     562             :         elapsed_time (1), error_count);
     563           1 :   return !!error_count;
     564             : }

Generated by: LCOV version 1.11