LCOV - code coverage report
Current view: top level - common - t-name-value.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 167 250 66.8 %
Date: 2016-11-29 15:00:56 Functions: 10 14 71.4 %

          Line data    Source code
       1             : /* t-name-value.c - Module test for name-value.c
       2             :  *      Copyright (C) 2016 g10 Code GmbH
       3             :  *
       4             :  * This file is part of GnuPG.
       5             :  *
       6             :  * GnuPG is free software; you can redistribute it and/or modify
       7             :  * it under the terms of the GNU General Public License as published by
       8             :  * the Free Software Foundation; either version 3 of the License, or
       9             :  * (at your option) any later version.
      10             :  *
      11             :  * GnuPG 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 General Public License for more details.
      15             :  *
      16             :  * You should have received a copy of the GNU General Public License
      17             :  * along with this program; if not, see <https://www.gnu.org/licenses/>.
      18             :  */
      19             : 
      20             : #include <config.h>
      21             : #include <stdio.h>
      22             : #include <stdlib.h>
      23             : #include <errno.h>
      24             : #include <assert.h>
      25             : #include <unistd.h>
      26             : #include <sys/stat.h>
      27             : 
      28             : #include "util.h"
      29             : #include "name-value.h"
      30             : 
      31             : static int verbose;
      32             : static int private_key_mode;
      33             : 
      34             : 
      35             : static nvc_t
      36           4 : my_nvc_new (void)
      37             : {
      38           4 :   if (private_key_mode)
      39           2 :     return nvc_new_private_key ();
      40             :   else
      41           2 :     return nvc_new ();
      42             : }
      43             : 
      44             : 
      45             : void
      46           6 : test_getting_values (nvc_t pk)
      47             : {
      48             :   nve_t e;
      49             : 
      50           6 :   e = nvc_lookup (pk, "Comment:");
      51           6 :   assert (e);
      52             : 
      53             :   /* Names are case-insensitive.  */
      54           6 :   e = nvc_lookup (pk, "comment:");
      55           6 :   assert (e);
      56           6 :   e = nvc_lookup (pk, "COMMENT:");
      57           6 :   assert (e);
      58             : 
      59           6 :   e = nvc_lookup (pk, "SomeOtherName:");
      60           6 :   assert (e);
      61           6 : }
      62             : 
      63             : 
      64             : void
      65           2 : test_key_extraction (nvc_t pk)
      66             : {
      67             :   gpg_error_t err;
      68             :   gcry_sexp_t key;
      69             : 
      70           2 :   if (private_key_mode)
      71             :     {
      72           1 :       err = nvc_get_private_key (pk, &key);
      73           1 :       assert (err == 0);
      74           1 :       assert (key);
      75             : 
      76           1 :       if (verbose)
      77           0 :         gcry_sexp_dump (key);
      78             : 
      79           1 :       gcry_sexp_release (key);
      80             :     }
      81             :   else
      82             :     {
      83           1 :       err = nvc_get_private_key (pk, &key);
      84           1 :       assert (gpg_err_code (err) == GPG_ERR_MISSING_KEY);
      85             :     }
      86           2 : }
      87             : 
      88             : 
      89             : void
      90           2 : test_iteration (nvc_t pk)
      91             : {
      92             :   int i;
      93             :   nve_t e;
      94             : 
      95           2 :   i = 0;
      96          10 :   for (e = nvc_first (pk); e; e = nve_next (e))
      97           8 :     i++;
      98           2 :   assert (i == 4);
      99             : 
     100           2 :   i = 0;
     101          10 :   for (e = nvc_lookup (pk, "Comment:");
     102             :        e;
     103           6 :        e = nve_next_value (e, "Comment:"))
     104           6 :     i++;
     105           2 :   assert (i == 3);
     106           2 : }
     107             : 
     108             : 
     109             : void
     110           2 : test_whitespace (nvc_t pk)
     111             : {
     112             :   nve_t e;
     113             : 
     114           2 :   e = nvc_lookup (pk, "One:");
     115           2 :   assert (e);
     116           2 :   assert (strcmp (nve_value (e), "WithoutWhitespace") == 0);
     117             : 
     118           2 :   e = nvc_lookup (pk, "Two:");
     119           2 :   assert (e);
     120           2 :   assert (strcmp (nve_value (e), "With Whitespace") == 0);
     121             : 
     122           2 :   e = nvc_lookup (pk, "Three:");
     123           2 :   assert (e);
     124           2 :   assert (strcmp (nve_value (e),
     125             :                   "Blank lines in continuations encode newlines.\n"
     126             :                   "Next paragraph.") == 0);
     127           2 : }
     128             : 
     129             : 
     130             : struct
     131             : {
     132             :   char *value;
     133             :   void (*test_func) (nvc_t);
     134             : } tests[] =
     135             :   {
     136             :     {
     137             :       "# This is a comment followed by an empty line\n"
     138             :       "\n",
     139             :       NULL,
     140             :     },
     141             :     {
     142             :       "# This is a comment followed by two empty lines, Windows style\r\n"
     143             :       "\r\n"
     144             :       "\r\n",
     145             :       NULL,
     146             :     },
     147             :     {
     148             :       "# Some name,value pairs\n"
     149             :       "Comment: Some comment.\n"
     150             :       "SomeOtherName: Some value.\n",
     151             :       test_getting_values,
     152             :     },
     153             :     {
     154             :       "  # Whitespace is preserved as much as possible\r\n"
     155             :       "Comment:Some comment.\n"
     156             :       "SomeOtherName: Some value.   \n",
     157             :       test_getting_values,
     158             :     },
     159             :     {
     160             :       "# Values may be continued in the next line as indicated by leading\n"
     161             :       "# space\n"
     162             :       "Comment: Some rather long\n"
     163             :       "  comment that is continued in the next line.\n"
     164             :       "\n"
     165             :       "  Blank lines with or without whitespace are allowed within\n"
     166             :       "  continuations to allow paragraphs.\n"
     167             :       "SomeOtherName: Some value.\n",
     168             :       test_getting_values,
     169             :     },
     170             :     {
     171             :       "# Names may be given multiple times forming an array of values\n"
     172             :       "Comment: Some comment, element 0.\n"
     173             :       "Comment: Some comment, element 1.\n"
     174             :       "Comment: Some comment, element 2.\n"
     175             :       "SomeOtherName: Some value.\n",
     176             :       test_iteration,
     177             :     },
     178             :     {
     179             :       "# One whitespace at the beginning of a continuation is swallowed.\n"
     180             :       "One: Without\n"
     181             :       " Whitespace\n"
     182             :       "Two: With\n"
     183             :       "  Whitespace\n"
     184             :       "Three: Blank lines in continuations encode newlines.\n"
     185             :       "\n"
     186             :       "  Next paragraph.\n",
     187             :       test_whitespace,
     188             :     },
     189             :     {
     190             :       "Description: Key to sign all GnuPG released tarballs.\n"
     191             :       "  The key is actually stored on a smart card.\n"
     192             :       "Use-for-ssh: yes\n"
     193             :       "OpenSSH-cert: long base64 encoded string wrapped so that this\n"
     194             :       "  key file can be easily edited with a standard editor.\n"
     195             :       "Key: (shadowed-private-key\n"
     196             :       "  (rsa\n"
     197             :       "  (n #00AA1AD2A55FD8C8FDE9E1941772D9CC903FA43B268CB1B5A1BAFDC900\n"
     198             :       "  2961D8AEA153424DC851EF13B83AC64FBE365C59DC1BD3E83017C90D4365B4\n"
     199             :       "  83E02859FC13DB5842A00E969480DB96CE6F7D1C03600392B8E08EF0C01FC7\n"
     200             :       "  19F9F9086B25AD39B4F1C2A2DF3E2BE317110CFFF21D4A11455508FE407997\n"
     201             :       "  601260816C8422297C0637BB291C3A079B9CB38A92CE9E551F80AA0EBF4F0E\n"
     202             :       "  72C3F250461E4D31F23A7087857FC8438324A013634563D34EFDDCBF2EA80D\n"
     203             :       "  F9662C9CCD4BEF2522D8BDFED24CEF78DC6B309317407EAC576D889F88ADA0\n"
     204             :       "  8C4FFB480981FB68C5C6CA27503381D41018E6CDC52AAAE46B166BDC10637A\n"
     205             :       "  E186A02BA2497FDC5D1221#)\n"
     206             :       "  (e #00010001#)\n"
     207             :       "  (shadowed t1-v1\n"
     208             :       "   (#D2760001240102000005000011730000# OPENPGP.1)\n"
     209             :       "    )))\n",
     210             :       test_key_extraction,
     211             :     },
     212             :   };
     213             : 
     214             : 
     215             : static char *
     216          43 : nvc_to_string (nvc_t pk)
     217             : {
     218             :   gpg_error_t err;
     219             :   char *buf;
     220             :   size_t len;
     221             :   estream_t sink;
     222             : 
     223          43 :   sink = es_fopenmem (0, "rw");
     224          43 :   assert (sink);
     225             : 
     226          43 :   err = nvc_write (pk, sink);
     227          43 :   assert (err == 0);
     228             : 
     229          43 :   len = es_ftell (sink);
     230          43 :   buf = xmalloc (len+1);
     231          43 :   assert (buf);
     232             : 
     233          43 :   es_fseek (sink, 0, SEEK_SET);
     234          43 :   es_read (sink, buf, len, NULL);
     235          43 :   buf[len] = 0;
     236             : 
     237          43 :   es_fclose (sink);
     238          43 :   return buf;
     239             : }
     240             : 
     241             : 
     242          16 : void dummy_free (void *p) { (void) p; }
     243           0 : void *dummy_realloc (void *p, size_t s) { (void) s; return p; }
     244             : 
     245             : void
     246           2 : run_tests (void)
     247             : {
     248             :   gpg_error_t err;
     249             :   nvc_t pk;
     250             : 
     251             :   int i;
     252          18 :   for (i = 0; i < DIM (tests); i++)
     253             :     {
     254             :       estream_t source;
     255             :       char *buf;
     256             :       size_t len;
     257             : 
     258          16 :       len = strlen (tests[i].value);
     259          16 :       source = es_mopen (tests[i].value, len, len,
     260             :                          0, dummy_realloc, dummy_free, "r");
     261          16 :       assert (source);
     262             : 
     263          16 :       if (private_key_mode)
     264           8 :         err = nvc_parse_private_key (&pk, NULL, source);
     265             :       else
     266           8 :         err = nvc_parse (&pk, NULL, source);
     267          16 :       assert (err == 0);
     268          16 :       assert (pk);
     269             : 
     270          16 :       if (verbose)
     271             :         {
     272           0 :           err = nvc_write (pk, es_stderr);
     273           0 :           assert (err == 0);
     274             :         }
     275             : 
     276          16 :       buf = nvc_to_string (pk);
     277          16 :       assert (memcmp (tests[i].value, buf, len) == 0);
     278             : 
     279          16 :       es_fclose (source);
     280          16 :       xfree (buf);
     281             : 
     282          16 :       if (tests[i].test_func)
     283          12 :         tests[i].test_func (pk);
     284             : 
     285          16 :       nvc_release (pk);
     286             :     }
     287           2 : }
     288             : 
     289             : 
     290             : void
     291           2 : run_modification_tests (void)
     292             : {
     293             :   gpg_error_t err;
     294             :   nvc_t pk;
     295             :   gcry_sexp_t key;
     296             :   char *buf;
     297             : 
     298           2 :   pk = my_nvc_new ();
     299           2 :   assert (pk);
     300             : 
     301           2 :   nvc_set (pk, "Foo:", "Bar");
     302           2 :   buf = nvc_to_string (pk);
     303           2 :   assert (strcmp (buf, "Foo: Bar\n") == 0);
     304           2 :   xfree (buf);
     305             : 
     306           2 :   nvc_set (pk, "Foo:", "Baz");
     307           2 :   buf = nvc_to_string (pk);
     308           2 :   assert (strcmp (buf, "Foo: Baz\n") == 0);
     309           2 :   xfree (buf);
     310             : 
     311           2 :   nvc_set (pk, "Bar:", "Bazzel");
     312           2 :   buf = nvc_to_string (pk);
     313           2 :   assert (strcmp (buf, "Foo: Baz\nBar: Bazzel\n") == 0);
     314           2 :   xfree (buf);
     315             : 
     316           2 :   nvc_add (pk, "Foo:", "Bar");
     317           2 :   buf = nvc_to_string (pk);
     318           2 :   assert (strcmp (buf, "Foo: Baz\nFoo: Bar\nBar: Bazzel\n") == 0);
     319           2 :   xfree (buf);
     320             : 
     321           2 :   nvc_add (pk, "DontExistYet:", "Bar");
     322           2 :   buf = nvc_to_string (pk);
     323           2 :   assert (strcmp (buf, "Foo: Baz\nFoo: Bar\nBar: Bazzel\nDontExistYet: Bar\n")
     324             :           == 0);
     325           2 :   xfree (buf);
     326             : 
     327           2 :   nvc_delete (pk, nvc_lookup (pk, "DontExistYet:"));
     328           2 :   buf = nvc_to_string (pk);
     329           2 :   assert (strcmp (buf, "Foo: Baz\nFoo: Bar\nBar: Bazzel\n") == 0);
     330           2 :   xfree (buf);
     331             : 
     332           2 :   nvc_delete (pk, nve_next_value (nvc_lookup (pk, "Foo:"), "Foo:"));
     333           2 :   buf = nvc_to_string (pk);
     334           2 :   assert (strcmp (buf, "Foo: Baz\nBar: Bazzel\n") == 0);
     335           2 :   xfree (buf);
     336             : 
     337           2 :   nvc_delete (pk, nvc_lookup (pk, "Foo:"));
     338           2 :   buf = nvc_to_string (pk);
     339           2 :   assert (strcmp (buf, "Bar: Bazzel\n") == 0);
     340           2 :   xfree (buf);
     341             : 
     342           2 :   nvc_delete (pk, nvc_first (pk));
     343           2 :   buf = nvc_to_string (pk);
     344           2 :   assert (strcmp (buf, "") == 0);
     345           2 :   xfree (buf);
     346             : 
     347           2 :   nvc_set (pk, "Foo:", "A really long value spanning across multiple lines"
     348             :            " that has to be wrapped at a convenient space.");
     349           2 :   buf = nvc_to_string (pk);
     350           2 :   assert (strcmp (buf, "Foo: A really long value spanning across multiple"
     351             :                   " lines that has to be\n  wrapped at a convenient space.\n")
     352             :           == 0);
     353           2 :   xfree (buf);
     354             : 
     355           2 :   nvc_set (pk, "Foo:", "XA really long value spanning across multiple lines"
     356             :            " that has to be wrapped at a convenient space.");
     357           2 :   buf = nvc_to_string (pk);
     358           2 :   assert (strcmp (buf, "Foo: XA really long value spanning across multiple"
     359             :                   " lines that has to\n  be wrapped at a convenient space.\n")
     360             :           == 0);
     361           2 :   xfree (buf);
     362             : 
     363           2 :   nvc_set (pk, "Foo:", "XXXXA really long value spanning across multiple lines"
     364             :            " that has to be wrapped at a convenient space.");
     365           2 :   buf = nvc_to_string (pk);
     366           2 :   assert (strcmp (buf, "Foo: XXXXA really long value spanning across multiple"
     367             :                   " lines that has\n  to be wrapped at a convenient space.\n")
     368             :           == 0);
     369           2 :   xfree (buf);
     370             : 
     371           2 :   nvc_set (pk, "Foo:", "Areallylongvaluespanningacrossmultiplelines"
     372             :            "thathastobewrappedataconvenientspacethatisnotthere.");
     373           2 :   buf = nvc_to_string (pk);
     374           2 :   assert (strcmp (buf, "Foo: Areallylongvaluespanningacrossmultiplelinesthat"
     375             :                   "hastobewrappedataco\n nvenientspacethatisnotthere.\n")
     376             :           == 0);
     377           2 :   xfree (buf);
     378           2 :   nvc_release (pk);
     379             : 
     380           2 :   pk = my_nvc_new ();
     381           2 :   assert (pk);
     382             : 
     383           2 :   err = gcry_sexp_build (&key, NULL, "(hello world)");
     384           2 :   assert (err == 0);
     385           2 :   assert (key);
     386             : 
     387           2 :   if (private_key_mode)
     388             :     {
     389           1 :       err = nvc_set_private_key (pk, key);
     390           1 :       assert (err == 0);
     391             : 
     392           1 :       buf = nvc_to_string (pk);
     393           1 :       assert (strcmp (buf, "Key: (hello world)\n") == 0);
     394           1 :       xfree (buf);
     395             :     }
     396             :   else
     397             :     {
     398           1 :       err = nvc_set_private_key (pk, key);
     399           1 :       assert (gpg_err_code (err) == GPG_ERR_MISSING_KEY);
     400             :     }
     401           2 :   gcry_sexp_release (key);
     402           2 :   nvc_release (pk);
     403           2 : }
     404             : 
     405             : 
     406             : void
     407           0 : convert (const char *fname)
     408             : {
     409             :   gpg_error_t err;
     410             :   estream_t source;
     411             :   gcry_sexp_t key;
     412             :   char *buf;
     413             :   size_t buflen;
     414             :   struct stat st;
     415             :   nvc_t pk;
     416             : 
     417           0 :   source = es_fopen (fname, "rb");
     418           0 :   if (source == NULL)
     419           0 :     goto leave;
     420             : 
     421           0 :   if (fstat (es_fileno (source), &st))
     422           0 :     goto leave;
     423             : 
     424           0 :   buflen = st.st_size;
     425           0 :   buf = xtrymalloc (buflen+1);
     426           0 :   assert (buf);
     427             : 
     428           0 :   if (es_fread (buf, buflen, 1, source) != 1)
     429           0 :     goto leave;
     430             : 
     431           0 :   err = gcry_sexp_sscan (&key, NULL, buf, buflen);
     432           0 :   if (err)
     433             :     {
     434           0 :       fprintf (stderr, "malformed s-expression in %s\n", fname);
     435           0 :       exit (1);
     436             :     }
     437             : 
     438           0 :   pk = my_nvc_new ();
     439           0 :   assert (pk);
     440             : 
     441           0 :   err = nvc_set_private_key (pk, key);
     442           0 :   assert (err == 0);
     443             : 
     444           0 :   err = nvc_write (pk, es_stdout);
     445           0 :   assert (err == 0);
     446             : 
     447           0 :   return;
     448             : 
     449             :  leave:
     450           0 :   perror (fname);
     451           0 :   exit (1);
     452             : }
     453             : 
     454             : 
     455             : void
     456           0 : parse (const char *fname)
     457             : {
     458             :   gpg_error_t err;
     459             :   estream_t source;
     460             :   char *buf;
     461             :   nvc_t pk_a, pk_b;
     462             :   nve_t e;
     463             :   int line;
     464             : 
     465           0 :   source = es_fopen (fname, "rb");
     466           0 :   if (source == NULL)
     467             :     {
     468           0 :       perror (fname);
     469           0 :       exit (1);
     470             :     }
     471             : 
     472           0 :   if (private_key_mode)
     473           0 :     err = nvc_parse_private_key (&pk_a, &line, source);
     474             :   else
     475           0 :     err = nvc_parse (&pk_a, &line, source);
     476           0 :   if (err)
     477             :     {
     478           0 :       fprintf (stderr, "failed to parse %s line %d: %s\n",
     479             :                fname, line, gpg_strerror (err));
     480           0 :       exit (1);
     481             :     }
     482             : 
     483           0 :   buf = nvc_to_string (pk_a);
     484           0 :   xfree (buf);
     485             : 
     486           0 :   pk_b = my_nvc_new ();
     487           0 :   assert (pk_b);
     488             : 
     489           0 :   for (e = nvc_first (pk_a); e; e = nve_next (e))
     490             :     {
     491           0 :       gcry_sexp_t key = NULL;
     492             : 
     493           0 :       if (private_key_mode && !strcasecmp (nve_name (e), "Key:"))
     494             :         {
     495           0 :           err = nvc_get_private_key (pk_a, &key);
     496           0 :           if (err)
     497           0 :             key = NULL;
     498             :         }
     499             : 
     500           0 :       if (key)
     501             :         {
     502           0 :           err = nvc_set_private_key (pk_b, key);
     503           0 :           assert (err == 0);
     504             :         }
     505             :       else
     506             :         {
     507           0 :           err = nvc_add (pk_b, nve_name (e), nve_value (e));
     508           0 :           assert (err == 0);
     509             :         }
     510             :     }
     511             : 
     512           0 :     buf = nvc_to_string (pk_b);
     513           0 :     if (verbose)
     514           0 :       fprintf (stdout, "%s", buf);
     515           0 :     xfree (buf);
     516           0 : }
     517             : 
     518             : 
     519             : void
     520           0 : print_usage (void)
     521             : {
     522           0 :   fprintf (stderr,
     523             :            "usage: t-private-keys [--verbose]"
     524             :            " [--convert <private-key-file>"
     525             :            " || --parse-key <extended-private-key-file>"
     526             :            " || --parse <file> ]\n");
     527           0 :   exit (2);
     528             : }
     529             : 
     530             : 
     531             : int
     532           1 : main (int argc, char **argv)
     533             : {
     534           1 :   enum { TEST, CONVERT, PARSE, PARSEKEY } command = TEST;
     535             : 
     536           1 :   if (argc)
     537           1 :     { argc--; argv++; }
     538           1 :   if (argc && !strcmp (argv[0], "--verbose"))
     539             :     {
     540           0 :       verbose = 1;
     541           0 :       argc--; argv++;
     542             :     }
     543             : 
     544           1 :   if (argc && !strcmp (argv[0], "--convert"))
     545             :     {
     546           0 :       command = CONVERT;
     547           0 :       argc--; argv++;
     548           0 :       if (argc != 1)
     549           0 :         print_usage ();
     550             :     }
     551             : 
     552           1 :   if (argc && !strcmp (argv[0], "--parse-key"))
     553             :     {
     554           0 :       command = PARSEKEY;
     555           0 :       argc--; argv++;
     556           0 :       if (argc != 1)
     557           0 :         print_usage ();
     558             :     }
     559             : 
     560           1 :   if (argc && !strcmp (argv[0], "--parse"))
     561             :     {
     562           0 :       command = PARSE;
     563           0 :       argc--; argv++;
     564           0 :       if (argc != 1)
     565           0 :         print_usage ();
     566             :     }
     567             : 
     568           1 :   switch (command)
     569             :     {
     570             :     case TEST:
     571           1 :       run_tests ();
     572           1 :       run_modification_tests ();
     573           1 :       private_key_mode = 1;
     574           1 :       run_tests ();
     575           1 :       run_modification_tests ();
     576           1 :       break;
     577             : 
     578             :     case CONVERT:
     579           0 :       convert (*argv);
     580           0 :       break;
     581             : 
     582             :     case PARSEKEY:
     583           0 :       private_key_mode = 1;
     584           0 :       parse (*argv);
     585           0 :       break;
     586             : 
     587             :     case PARSE:
     588           0 :       parse (*argv);
     589           0 :       break;
     590             :     }
     591             : 
     592           1 :   return 0;
     593             : }

Generated by: LCOV version 1.11