common: Minor change of hex2str to allow for embedded nul.
authorWerner Koch <wk@gnupg.org>
Thu, 23 Apr 2015 12:31:04 +0000 (14:31 +0200)
committerWerner Koch <wk@gnupg.org>
Thu, 23 Apr 2015 13:51:51 +0000 (15:51 +0200)
* common/convert.c (hex2str): Set ERRNO.  Return adjusted COUNT.
--

hex2str is only used at one place for in-place converting an hex
encoded passphrase.  This change does not affect this use.  The change
is however useful to use the function for in-place conversion of
arbitrary hex encoded strings.

Take care for in-place conversion of a hex string encoding binary data
you need to use it this way:

  if (hex2str (string, string, strlen (string) + 1, &length)
     oops ("probably out of memory but see ERRNO");
  for (i=0; i < length; i++)
     foo (string[i));

Note that strlen() + 1.

Signed-off-by: Werner Koch <wk@gnupg.org>
common/convert.c
common/t-convert.c

index e86ccec..6b0ff35 100644 (file)
@@ -175,21 +175,26 @@ bin2hexcolon (const void *buffer, size_t length, char *stringbuf)
 /* Convert HEXSTRING consisting of hex characters into string and
    store that at BUFFER.  HEXSTRING is either delimited by end of
    string or a white space character.  The function makes sure that
-   the resulting string in BUFFER is terminated by a Nul character.
+   the resulting string in BUFFER is terminated by a Nul byte.  Note
+   that the retruned string may include embedded Nul bytes; the extra
+   Nul byte at the end is used to make sure tha the result can always
+   be used as a C-string.
+
    BUFSIZE is the availabe length of BUFFER; if the converted result
-   plus a possible required Nul character does not fit into this
+   plus a possible required extra Nul character does not fit into this
    buffer, the function returns NULL and won't change the existing
-   conent of buffer.  In-place conversion is possible as long as
+   content of BUFFER.  In-place conversion is possible as long as
    BUFFER points to HEXSTRING.
 
-   If BUFFER is NULL and bufsize is 0 the function scans HEXSTRING but
+   If BUFFER is NULL and BUFSIZE is 0 the function scans HEXSTRING but
    does not store anything.  This may be used to find the end of
-   hexstring.
+   HEXSTRING.
 
    On sucess the function returns a pointer to the next character
    after HEXSTRING (which is either end-of-string or a the next white
-   space).  If BUFLEN is not NULL the strlen of buffer is stored
-   there; this will even be done if BUFFER has been passed as NULL. */
+   space).  If BUFLEN is not NULL the number of valid vytes in BUFFER
+   is stored there (an extra Nul byte is not counted); this will even
+   be done if BUFFER has been passed as NULL. */
 const char *
 hex2str (const char *hexstring, char *buffer, size_t bufsize, size_t *buflen)
 {
@@ -203,7 +208,10 @@ hex2str (const char *hexstring, char *buffer, size_t bufsize, size_t *buflen)
   for (s=hexstring, count=0; hexdigitp (s) && hexdigitp (s+1); s += 2, count++)
     ;
   if (*s && (!isascii (*s) || !isspace (*s)) )
-    return NULL;   /* Not followed by Nul or white space.  */
+    {
+      gpg_err_set_errno (EINVAL);
+      return NULL;   /* Not followed by Nul or white space.  */
+    }
   /* We need to append a nul character.  However we don't want that if
      the hexstring already ends with "00".  */
   need_nul = ((s == hexstring) || !(s[-2] == '0' && s[-1] == '0'));
@@ -213,7 +221,10 @@ hex2str (const char *hexstring, char *buffer, size_t bufsize, size_t *buflen)
   if (buffer)
     {
       if (count > bufsize)
-        return NULL; /* Too long.  */
+        {
+          gpg_err_set_errno (EINVAL);
+          return NULL; /* Too long.  */
+        }
 
       for (s=hexstring, idx=0; hexdigitp (s) && hexdigitp (s+1); s += 2)
         ((unsigned char*)buffer)[idx++] = xtoi_2 (s);
@@ -222,7 +233,7 @@ hex2str (const char *hexstring, char *buffer, size_t bufsize, size_t *buflen)
     }
 
   if (buflen)
-    *buflen = count - 1;
+    *buflen = count - need_nul;
   return s;
 }
 
@@ -242,7 +253,6 @@ hex2str_alloc (const char *hexstring, size_t *r_count)
     {
       if (r_count)
         *r_count = 0;
-      gpg_err_set_errno (EINVAL);
       return NULL;
     }
   if (r_count)
index d6056b9..a03c680 100644 (file)
@@ -27,7 +27,7 @@
 #define pass()  do { ; } while(0)
 #define fail(a)  do { fprintf (stderr, "%s:%d: test %d failed\n",\
                                __FILE__,__LINE__, (a));          \
-                     exit (1);                                   \
+    /*exit (1)*/;                                                \
                    } while(0)
 
 
@@ -282,73 +282,74 @@ test_hex2str (void)
   static struct {
     const char *hex;
     const char *str;
+    int len; /* Length of STR.  This may included embedded nuls.  */
     int off;
     int no_alloc_test;
   } tests[] = {
     /* Simple tests.  */
     { "112233445566778899aabbccddeeff1122",
       "\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee\xff\x11\x22",
-      34 },
+      17, 34 },
     { "112233445566778899aabbccddeeff1122 blah",
       "\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee\xff\x11\x22",
-      34 },
+      17, 34 },
     { "112233445566778899aabbccddeeff1122\tblah",
       "\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee\xff\x11\x22",
-      34 },
+      17, 34 },
     { "112233445566778899aabbccddeeff1122\nblah",
       "\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee\xff\x11\x22",
-      34 },
+      17, 34 },
     /* Valid tests yielding an empty string.  */
     { "00",
       "",
-      2 },
+      1, 2 },
     { "00 x",
       "",
-      2 },
+      1, 2 },
     { "",
       "",
-      0 },
+      0, 0 },
     { " ",
       "",
-      0 },
+      0, 0 },
     /* Test trailing Nul feature.  */
-    { "112233445566778899aabbccddeeff112200",
-      "\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee\xff\x11\x22",
-      36 },
-    { "112233445566778899aabbccddeeff112200 ",
-      "\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee\xff\x11\x22",
-      36 },
+    { "112233445566778899aabbccddeeff1100",
+      "\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee\xff\x11\x00",
+      17, 34 },
+    { "112233445566778899aabbccddeeff1100 ",
+      "\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee\xff\x11\x00",
+      17, 34 },
     /* Test buffer size. (buffer is of length 20)  */
     { "6162636465666768696A6b6c6D6e6f70717273",
       "abcdefghijklmnopqrs",
-      38 },
+      19, 38 },
     { "6162636465666768696A6b6c6D6e6f7071727300",
       "abcdefghijklmnopqrs",
-      40 },
+      20, 40 },
     { "6162636465666768696A6b6c6D6e6f7071727374",
       NULL,
-      0, 1 },
+      0, 0, 1 },
     { "6162636465666768696A6b6c6D6e6f707172737400",
       NULL,
-      0, 1 },
+      0, 0, 1 },
     { "6162636465666768696A6b6c6D6e6f707172737475",
       NULL,
-      0, 1 },
+      0, 0, 1 },
 
     /* Invalid tests. */
-    { "112233445566778899aabbccddeeff1122334",      NULL, 0 },
-    { "112233445566778899AABBCCDDEEFF1122334",      NULL, 0 },
-    { "112233445566778899AABBCCDDEEFG11223344",     NULL, 0 },
-    { "0:0112233445566778899aabbccddeeff11223344",  NULL, 0 },
-    { "112233445566778899aabbccddeeff11223344:",    NULL, 0 },
-    { "112233445566778899aabbccddeeff112233445",    NULL, 0 },
-    { "112233445566778899aabbccddeeff1122334455",   NULL, 0, 1 },
-    { "112233445566778899aabbccddeeff11223344blah", NULL, 0 },
-    { "0",    NULL, 0 },
-    { "00:",  NULL, 0 },
-    { "00x",  NULL, 0 },
-
-    { NULL, NULL, 0 }
+    { "112233445566778899aabbccddeeff1122334",      NULL, 0, 0 },
+    { "112233445566778899AABBCCDDEEFF1122334",      NULL, 0, 0 },
+    { "112233445566778899AABBCCDDEEFG11223344",     NULL, 0, 0 },
+    { "0:0112233445566778899aabbccddeeff11223344",  NULL, 0, 0 },
+    { "112233445566778899aabbccddeeff11223344:",    NULL, 0, 0 },
+    { "112233445566778899aabbccddeeff112233445",    NULL, 0, 0 },
+    { "112233445566778899aabbccddeeff1122334455",   NULL, 0, 0, 1 },
+    { "112233445566778899aabbccddeeff11223344blah", NULL, 0, 0 },
+    { "0",    NULL, 0, 0 },
+    { "00:",  NULL, 0, 0 },
+    { "00x",  NULL, 0, 0 },
+
+    { NULL, NULL, 0, 0 }
   };
 
   int idx;
@@ -369,7 +370,7 @@ test_hex2str (void)
             fail (idx);
           else if (tail - tests[idx].hex != tests[idx].off)
             fail (idx);
-          else if (strlen (buffer) != count)
+          else if (tests[idx].len != count)
             fail (idx);
         }
       else
@@ -400,7 +401,7 @@ test_hex2str (void)
             fail (idx);
           else if (tail - tmpbuf != tests[idx].off)
             fail (idx);
-          else if (strlen (tmpbuf) != count)
+          else if (tests[idx].len != count)
             fail (idx);
         }
       else