sexp: Allow long names and white space in gcry_sexp_extract_param.
authorWerner Koch <wk@gnupg.org>
Tue, 22 Oct 2013 12:26:53 +0000 (14:26 +0200)
committerWerner Koch <wk@gnupg.org>
Sat, 7 Dec 2013 14:37:40 +0000 (15:37 +0100)
* src/sexp.c (_gcry_sexp_vextract_param): Skip white space.  Support
long parameter names.
* tests/tsexp.c (check_extract_param): Add test cases for long parameter
names and white space.

Signed-off-by: Werner Koch <wk@gnupg.org>
doc/gcrypt.texi
src/sexp.c
tests/tsexp.c

index 91168a8..927634f 100644 (file)
@@ -4145,10 +4145,10 @@ likely want to use @code{GCRYMPI_FMT_USG}.
   @w{const char *@var{path}}, @
   @w{const char *@var{list}}, ...)
 
-Extract parameters from an S-expression using a list of single letter
-parameter names.  The names of these parameters are specified in
-LIST.  Some special characters may be given to control the
-conversion:
+Extract parameters from an S-expression using a list of parameter
+names.  The names of these parameters are specified in LIST.  White
+space between the parameter names are ignored. Some special characters
+may be given to control the conversion:
 
 @table @samp
 @item +
@@ -4162,21 +4162,25 @@ computations; see @code{gcry_mpi_get_opaque} for details.
 @item &
 Switch to buffer descriptor mode.  See below for details.
 @item ?
-If immediately following a parameter letter, that parameter is
-considered optional.
+If immediately following a parameter letter (no white space allowed),
+that parameter is considered optional.
 @end table
 
+In general parameter names are single letters.  To use a string for a
+parameter name, enclose the name in single quotes.
+
 Unless in buffer descriptor mode for each parameter name a pointer to
 an @code{gcry_mpi_t} variable is expected finally followed by a @code{NULL}.
 For example
 @example
-  _gcry_sexp_extract_param (key, NULL, "n/x+ed",
-                            &mpi_n, &mpi_x, &mpi_e, NULL)
+  _gcry_sexp_extract_param (key, NULL, "n/x+e d-'foo'",
+                            &mpi_n, &mpi_x, &mpi_e, &mpi_foo, NULL)
 @end example
 
 stores the parameter 'n' from @var{key} as an unsigned MPI into
-@var{mpi_n}, the parameter 'x' as an opaque MPI into @var{mpi_x}, and
-the parameter 'e' again as an unsigned MPI into @var{mpi_e}.
+@var{mpi_n}, the parameter 'x' as an opaque MPI into @var{mpi_x}, the
+parameter 'e' again as an unsigned MPI into @var{mpi_e}, and the
+parameter 'foo' as a signed MPI.
 
 @var{path} is an optional string used to locate a token.  The
 exclamation mark separated tokens are used via
index 16def5b..7ff4c0a 100644 (file)
@@ -2113,10 +2113,9 @@ _gcry_sexp_canon_len (const unsigned char *buffer, size_t length,
 }
 
 
-/* Extract MPIs from an s-expression using a list of one letter
- * parameters.  The names of these parameters are given by the string
- * LIST.  Some special characters may be given to control the
- * conversion:
+/* Extract MPIs from an s-expression using a list of parameters.  The
+ * names of these parameters are given by the string LIST.  Some
+ * special characters may be given to control the conversion:
  *
  *    + :: Switch to unsigned integer format (default).
  *    - :: Switch to standard signed format.
@@ -2124,6 +2123,9 @@ _gcry_sexp_canon_len (const unsigned char *buffer, size_t length,
  *    & :: Switch to buffer descriptor mode - see below.
  *    ? :: The previous parameter is optional.
  *
+ * In general parameter names are single letters.  To use a string for
+ * a parameter name, enclose the name in single quotes.
+ *
  * Unless in gcry_buffer_t mode for each parameter name a pointer to
  * an MPI variable is expected and finally a NULL is expected.
  * Example:
@@ -2158,7 +2160,7 @@ _gcry_sexp_vextract_param (gcry_sexp_t sexp, const char *path,
                            const char *list, va_list arg_ptr)
 {
   gpg_err_code_t rc;
-  const char *s;
+  const char *s, *s2;
   gcry_mpi_t *array[20];
   char arrayisdesc[20];
   int idx;
@@ -2173,10 +2175,23 @@ _gcry_sexp_vextract_param (gcry_sexp_t sexp, const char *path,
      was found.  */
   for (s=list, idx=0; *s && idx < DIM (array); s++)
     {
-      if (*s == '&' || *s == '+' || *s == '-' || *s == '/' || *s == '?' )
+      if (*s == '&' || *s == '+' || *s == '-' || *s == '/' || *s == '?')
+        ;
+      else if (whitespacep (s))
         ;
       else
         {
+          if (*s == '\'')
+            {
+              s++;
+              s2 = strchr (s, '\'');
+              if (!s2 || s2 == s)
+                {
+                  /* Closing quote not found or empty string.  */
+                  return GPG_ERR_SYNTAX;
+                }
+              s = s2;
+            }
           array[idx] = va_arg (arg_ptr, gcry_mpi_t *);
           if (!array[idx])
             return GPG_ERR_MISSING_VALUE; /* NULL pointer given.  */
@@ -2221,11 +2236,29 @@ _gcry_sexp_vextract_param (gcry_sexp_t sexp, const char *path,
     {
       if (*s == '&' || *s == '+' || *s == '-' || *s == '/')
         mode = *s;
+      else if (whitespacep (s))
+        ;
       else if (*s == '?')
         ; /* Only used via lookahead.  */
       else
         {
-          l1 = _gcry_sexp_find_token (sexp, s, 1);
+          if (*s == '\'')
+            {
+              /* Find closing quote, find token, set S to closing quote.  */
+              s++;
+              s2 = strchr (s, '\'');
+              if (!s2 || s2 == s)
+                {
+                  /* Closing quote not found or empty string.  */
+                  rc = GPG_ERR_SYNTAX;
+                  goto cleanup;
+                }
+              l1 = _gcry_sexp_find_token (sexp, s, s2 - s);
+              s = s2;
+            }
+          else
+            l1 = _gcry_sexp_find_token (sexp, s, 1);
+
           if (!l1 && s[1] == '?')
             {
               /* Optional element not found.  */
index afa79ff..2f6ad8f 100644 (file)
@@ -684,6 +684,18 @@ check_extract_param (void)
     {
       sample1,
       NULL,
+      "pab'gnq", 7,
+      GPG_ERR_SYNTAX
+    },
+    {
+      sample1,
+      NULL,
+      "pab''gnq", 7,
+      GPG_ERR_SYNTAX
+    },
+    {
+      sample1,
+      NULL,
       "pabgnqd", 7,
       0,
       sample1_px, sample1_ax, sample1_bx, sample1_gx, sample1_nx,
@@ -692,6 +704,14 @@ check_extract_param (void)
     {
       sample1,
       NULL,
+      "  pab\tg nq\nd  ", 7,
+      0,
+      sample1_px, sample1_ax, sample1_bx, sample1_gx, sample1_nx,
+      sample1_qx, sample1_d
+    },
+    {
+      sample1,
+      NULL,
       "abg", 3,
       0,
       sample1_ax, sample1_bx, sample1_gx
@@ -699,6 +719,13 @@ check_extract_param (void)
     {
       sample1,
       NULL,
+      "ab'g'", 3,
+      0,
+      sample1_ax, sample1_bx, sample1_gx
+    },
+    {
+      sample1,
+      NULL,
       "x?abg", 4,
       0,
       NULL, sample1_ax, sample1_bx, sample1_gx
@@ -967,6 +994,50 @@ check_extract_param (void)
     }
 
   gcry_sexp_release (sxp);
+
+  info ("checking gcry_sexp_extract_param long name\n");
+
+  memset (ioarray, 0, sizeof ioarray);
+  memset (mpis, 0, sizeof mpis);
+
+  err = gcry_sexp_new (&sxp, sample1, 0, 1);
+  if (err)
+    die ("converting string to sexp failed: %s", gpg_strerror (err));
+
+  err = gcry_sexp_extract_param (sxp, "key-data!private-key",
+                                 "&'curve'+p",
+                                 ioarray+0, mpis+0, NULL);
+  if (err)
+    fail ("gcry_sexp_extract_param long name failed: %s", gpg_strerror (err));
+
+  if (!ioarray[0].data)
+    fail ("gcry_sexp_extract_param long name failed: no curve");
+  else if (ioarray[0].size != 7)
+    fail ("gcry_sexp_extract_param long name failed: curve has wrong size");
+  else if (ioarray[0].len != 7)
+    fail ("gcry_sexp_extract_param long name failed: curve has wrong length");
+  else if (ioarray[0].off)
+    fail ("gcry_sexp_extract_param long name failed: curve has OFF set");
+  else if (strncmp (ioarray[0].data, "Ed25519", 7))
+    {
+      fail ("gcry_sexp_extract_param long name failed: curve mismatch");
+      gcry_log_debug ("expected: %s\n", "Ed25519");
+      gcry_log_debug ("     got: %.*s\n", (int)ioarray[0].len, ioarray[0].data);
+    }
+
+  if (!mpis[0])
+    fail ("gcry_sexp_extract_param long name failed: p not returned");
+  else if (cmp_mpihex (mpis[0], sample1_p))
+    {
+      fail ("gcry_sexp_extract_param long name failed: p mismatch");
+      gcry_log_debug    ("expected: %s\n", sample1_p);
+      gcry_log_debugmpi ("     got", mpis[0]);
+    }
+
+  gcry_mpi_release (mpis[0]);
+
+  gcry_sexp_release (sxp);
+
 }