Move OpenPGP OID helpers to common/.
authorWerner Koch <wk@gnupg.org>
Mon, 31 Jan 2011 17:19:14 +0000 (18:19 +0100)
committerWerner Koch <wk@gnupg.org>
Mon, 31 Jan 2011 17:19:14 +0000 (18:19 +0100)
This is needed so that the agent will be able to export and import
OpenPGP secret keys.  Add test case.

Removed unused function.

common/ChangeLog
common/Makefile.am
common/convert.c
common/openpgp-oid.c [new file with mode: 0644]
common/t-openpgp-oid.c [new file with mode: 0644]
common/util.h
g10/ChangeLog
g10/main.h
g10/misc.c
g13/utils.h

index 0150658..0214583 100644 (file)
@@ -1,3 +1,10 @@
+2011-01-31  Werner Koch  <wk@g10code.com>
+
+       * openpgp-oid.c: New.
+       * t-openpgp-oid.c: New.
+
+       * convert.c (mpi2hex): Remove.
+
 2011-01-20  Werner Koch  <wk@g10code.com>
 
        Fix bug#1313.
index 110fc5f..2539859 100644 (file)
@@ -90,6 +90,7 @@ common_sources = \
        localename.c \
        session-env.c session-env.h \
        userids.c userids.h \
+       openpgp-oid.c \
        helpfile.c
 
 # To make the code easier to read we have split home some code into
@@ -160,7 +161,7 @@ if HAVE_W32_SYSTEM
 jnlib_tests += t-w32-reg
 endif
 module_tests = t-convert t-percent t-gettime t-sysutils t-sexputil \
-              t-session-env
+              t-session-env t-openpgp-oid
 if !HAVE_W32CE_SYSTEM
 module_tests += t-exechelp
 endif
@@ -192,6 +193,7 @@ t_sexputil_LDADD = $(t_common_ldadd)
 t_b64_LDADD = $(t_common_ldadd)
 t_exechelp_LDADD = $(t_common_ldadd)
 t_session_env_LDADD = $(t_common_ldadd)
+t_openpgp_oid_LDADD = $(t_common_ldadd)
 
 
 
index 5df6b33..c314ec9 100644 (file)
@@ -245,37 +245,3 @@ hex2str_alloc (const char *hexstring, size_t *r_count)
     BUG ();
   return result;
 }
-
-/* returns hex representation of the MPI; 
- * caller must free with xfree 
- * Returns NULL on error, never throws
- */
-char *
-mpi2hex( gcry_mpi_t m )
-{
-#warning we have code for this in libcrypt
-  size_t nbytes;
-  size_t nbytes2;
-  int rc;
-  byte *p;
-
-  nbytes = (mpi_get_nbits ( m )+7)/8;
-  if( nbytes == 0 )
-    return NULL;
-  p = xtrymalloc( nbytes*3+1 );
-  if( p==NULL )
-    return NULL;
-  rc = gcry_mpi_print (GCRYMPI_FMT_USG, p+2*nbytes+1, nbytes, &nbytes2, m);
-  if( rc )  {
-      xfree( p );
-      return NULL;
-  }
-
-  bin2hex( p+2*nbytes+1, nbytes2, p );
-  p[nbytes2*2] = '\0';
-  /*printf("%s:%d>>>> Created the string %s from %d bytes %02x %02x
-    ..., MPI was %d bytes\n", __FILE__, __LINE__, p, nbytes2,
-    p[2*nbytes+1], p[2*nbytes+2], nbytes); */
-  return p;
-}    
-
diff --git a/common/openpgp-oid.c b/common/openpgp-oid.c
new file mode 100644 (file)
index 0000000..222c5a0
--- /dev/null
@@ -0,0 +1,227 @@
+/* openpgp-oids.c - OID helper for OpenPGP
+ * Copyright (C) 2011 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <ctype.h>
+#include <assert.h>
+
+#include "util.h"
+
+
+/* Helper for openpgp_oid_from_str.  */
+static size_t
+make_flagged_int (unsigned long value, char *buf, size_t buflen)
+{
+  int more = 0;
+  int shift;
+
+  /* fixme: figure out the number of bits in an ulong and start with
+     that value as shift (after making it a multiple of 7) a more
+     straigtforward implementation is to do it in reverse order using
+     a temporary buffer - saves a lot of compares */
+  for (more=0, shift=28; shift > 0; shift -= 7)
+    {
+      if (more || value >= (1<<shift))
+        {
+          buf[buflen++] = 0x80 | (value >> shift);
+          value -= (value >> shift) << shift;
+          more = 1;
+        }
+    }
+  buf[buflen++] = value;
+  return buflen;
+}
+
+
+/* Convert the OID given in dotted decimal form in STRING to an DER
+ * encoding and store it as an opaque value at R_MPI.  The format of
+ * the DER encoded is not a regular ASN.1 object but the modified
+ * format as used by OpenPGP for the ECC curve description.  On error
+ * the function returns and error code an NULL is stored at R_BUG.
+ * Note that scanning STRING stops at the first white space
+ * character.  */
+gpg_error_t
+openpgp_oid_from_str (const char *string, gcry_mpi_t *r_mpi)
+{
+  unsigned char *buf;
+  size_t buflen;
+  unsigned long val1, val;
+  const char *endp;
+  int arcno;
+
+  *r_mpi = NULL;
+
+  if (!string || !*string)
+    return gpg_error (GPG_ERR_INV_VALUE);
+
+  /* We can safely assume that the encoded OID is shorter than the string. */
+  buf = xtrymalloc (1 + strlen (string) + 2);
+  if (!buf)
+    return gpg_error_from_syserror ();
+  /* Save the first byte for the length.  */
+  buflen = 1;
+
+  val1 = 0; /* Avoid compiler warning.  */
+  arcno = 0;
+  do {
+    arcno++;
+    val = strtoul (string, (char**)&endp, 10);
+    if (!digitp (string) || !(*endp == '.' || !*endp))
+      {
+        xfree (buf);
+        return gpg_error (GPG_ERR_INV_OID_STRING);
+      }
+    if (*endp == '.')
+      string = endp+1;
+
+    if (arcno == 1)
+      {
+        if (val > 2)
+          break; /* Not allowed, error catched below.  */
+        val1 = val;
+      }
+    else if (arcno == 2)
+      { /* Need to combine the first two arcs in one octet.  */
+        if (val1 < 2)
+          {
+            if (val > 39)
+              {
+                xfree (buf);
+                return gpg_error (GPG_ERR_INV_OID_STRING);
+              }
+            buf[buflen++] = val1*40 + val;
+          }
+        else
+          {
+            val += 80;
+            buflen = make_flagged_int (val, buf, buflen);
+          }
+      }
+    else
+      {
+        buflen = make_flagged_int (val, buf, buflen);
+      }
+  } while (*endp == '.');
+
+  if (arcno == 1 || buflen < 2 || buflen > 254 )
+    { /* It is not possible to encode only the first arc.  */
+      xfree (buf);
+      return gpg_error (GPG_ERR_INV_OID_STRING);
+    }
+
+  *buf = buflen - 1;
+  *r_mpi = gcry_mpi_set_opaque (NULL, buf, buflen * 8);
+  if (!*r_mpi)
+    {
+      xfree (buf);
+      return gpg_error_from_syserror ();
+    }
+  return 0;
+}
+
+
+/* Return a malloced string represenation of the OID in the opaque MPI
+   A.  In case of an error NULL is returned and ERRNO is set.  */
+char *
+openpgp_oid_to_str (gcry_mpi_t a)
+{
+  const unsigned char *buf;
+  size_t length;
+  char *string, *p;
+  int n = 0;
+  unsigned long val, valmask;
+
+  valmask = (unsigned long)0xfe << (8 * (sizeof (valmask) - 1));
+
+  if (!a || !gcry_mpi_get_flag (a, GCRYMPI_FLAG_OPAQUE))
+    {
+      gpg_err_set_errno (EINVAL);
+      return NULL;
+    }
+
+  buf = gcry_mpi_get_opaque (a, &length);
+  length = (length+7)/8;
+
+  /* The first bytes gives the length; check consistency.  */
+  if (!length || buf[0] != length -1)
+    {
+      gpg_err_set_errno (EINVAL);
+      return NULL;
+    }
+  /* Skip length byte.  */
+  length--;
+  buf++;
+
+  /* To calculate the length of the string we can safely assume an
+     upper limit of 3 decimal characters per byte.  Two extra bytes
+     account for the special first octect */
+  string = p = xtrymalloc (length*(1+3)+2+1);
+  if (!string)
+    return NULL;
+  if (!buf || !length)
+    {
+      *p = 0;
+      return string;
+    }
+
+  if (buf[0] < 40)
+    p += sprintf (p, "0.%d", buf[n]);
+  else if (buf[0] < 80)
+    p += sprintf (p, "1.%d", buf[n]-40);
+  else {
+    val = buf[n] & 0x7f;
+    while ( (buf[n]&0x80) && ++n < length )
+      {
+        if ( (val & valmask) )
+          goto badoid;  /* Overflow.  */
+        val <<= 7;
+        val |= buf[n] & 0x7f;
+      }
+    val -= 80;
+    sprintf (p, "2.%lu", val);
+    p += strlen (p);
+  }
+  for (n++; n < length; n++)
+    {
+      val = buf[n] & 0x7f;
+      while ( (buf[n]&0x80) && ++n < length )
+        {
+          if ( (val & valmask) )
+            goto badoid;  /* Overflow.  */
+          val <<= 7;
+          val |= buf[n] & 0x7f;
+        }
+      sprintf (p, ".%lu", val);
+      p += strlen (p);
+    }
+
+  *p = 0;
+  return string;
+
+ badoid:
+  /* Return a special OID (gnu.gnupg.badoid) to indicate the error
+     case.  The OID is broken and thus we return one which can't do
+     any harm.  Formally this does not need to be a bad OID but an OID
+     with an arc that can't be represented in a 32 bit word is more
+     than likely corrupt.  */
+  xfree (string);
+  return xtrystrdup ("1.3.6.1.4.1.11591.2.12242973");
+}
diff --git a/common/t-openpgp-oid.c b/common/t-openpgp-oid.c
new file mode 100644 (file)
index 0000000..80e5763
--- /dev/null
@@ -0,0 +1,148 @@
+/* t-openpgp-oid.c - Module test for openpgp-oid.c
+ *     Copyright (C) 2011 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "util.h"
+
+#define pass()  do { ; } while(0)
+#define fail(a,e)                                                       \
+  do { fprintf (stderr, "%s:%d: test %d failed (%s)\n",                 \
+                __FILE__,__LINE__, (a), gpg_strerror (e));              \
+    exit (1);                                                           \
+  } while(0)
+
+
+static void
+test_openpgp_oid_from_str (void)
+{
+  static char *sample_oids[] =
+    {
+      "0.0",
+      "1.0",
+      "1.2.3",
+      "1.2.840.10045.3.1.7",
+      "1.3.132.0.34",
+      "1.3.132.0.35",
+      NULL
+    };
+  gpg_error_t err;
+  gcry_mpi_t a;
+  int idx;
+  char *string;
+  unsigned char *p;
+  unsigned int nbits;
+  size_t length;
+
+  err = openpgp_oid_from_str ("", &a);
+  if (gpg_err_code (err) != GPG_ERR_INV_VALUE)
+    fail (0, err);
+  gcry_mpi_release (a);
+
+  err = openpgp_oid_from_str (".", &a);
+  if (gpg_err_code (err) != GPG_ERR_INV_OID_STRING)
+    fail (0, err);
+  gcry_mpi_release (a);
+
+  err = openpgp_oid_from_str ("0", &a);
+  if (gpg_err_code (err) != GPG_ERR_INV_OID_STRING)
+    fail (0, err);
+  gcry_mpi_release (a);
+
+  for (idx=0; sample_oids[idx]; idx++)
+    {
+      err = openpgp_oid_from_str (sample_oids[idx], &a);
+      if (err)
+        fail (idx, err);
+
+      string = openpgp_oid_to_str (a);
+      if (!string)
+        fail (idx, gpg_error_from_syserror ());
+      if (strcmp (string, sample_oids[idx]))
+        fail (idx, 0);
+      xfree (string);
+
+      p = gcry_mpi_get_opaque (a, &nbits);
+      length = (nbits+7)/8;
+      if (!p || !length || p[0] != length - 1)
+        fail (idx, 0);
+
+      gcry_mpi_release (a);
+    }
+
+}
+
+
+static void
+test_openpgp_oid_to_str (void)
+{
+  static struct {
+    const char *string;
+    unsigned char der[10];
+  } samples[] = {
+    { "1.2.840.10045.3.1.7",
+      {8, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07 }},
+
+    { "1.3.132.0.34",
+      {5, 0x2B, 0x81, 0x04, 0x00, 0x22 }},
+
+    { "1.3.132.0.35",
+      { 5, 0x2B, 0x81, 0x04, 0x00, 0x23 }},
+
+    { NULL }};
+  gcry_mpi_t a;
+  int idx;
+  char *string;
+  unsigned char *p;
+
+  for (idx=0; samples[idx].string; idx++)
+    {
+      p = xmalloc (samples[idx].der[0]+1);
+      memcpy (p, samples[idx].der, samples[idx].der[0]+1);
+      a = gcry_mpi_set_opaque (NULL, p, (samples[idx].der[0]+1)*8);
+      if (!a)
+        fail (idx, gpg_error_from_syserror ());
+
+      string = openpgp_oid_to_str (a);
+      if (!string)
+        fail (idx, gpg_error_from_syserror ());
+      if (strcmp (string, samples[idx].string))
+        fail (idx, 0);
+      xfree (string);
+      gcry_mpi_release (a);
+    }
+
+}
+
+
+
+int
+main (int argc, char **argv)
+{
+  (void)argc;
+  (void)argv;
+
+  test_openpgp_oid_from_str ();
+  test_openpgp_oid_to_str ();
+
+  return 0;
+}
index 99d58e1..cf38ad4 100644 (file)
@@ -196,7 +196,6 @@ gpg_error_t get_pk_algo_from_canon_sexp (const unsigned char *keydata,
 int hex2bin (const char *string, void *buffer, size_t length);
 int hexcolon2bin (const char *string, void *buffer, size_t length);
 char *bin2hex (const void *buffer, size_t length, char *stringbuf);
-char *mpi2hex (gcry_mpi_t m);
 char *bin2hexcolon (const void *buffer, size_t length, char *stringbuf);
 const char *hex2str (const char *hexstring,
                      char *buffer, size_t bufsize, size_t *buflen);
@@ -210,6 +209,11 @@ char *percent_unescape (const char *string, int nulrepl);
 size_t percent_plus_unescape_inplace (char *string, int nulrepl);
 size_t percent_unescape_inplace (char *string, int nulrepl);
 
+/*-- openpgp-oid.c --*/
+gpg_error_t openpgp_oid_from_str (const char *string, gcry_mpi_t *r_mpi);
+char *openpgp_oid_to_str (gcry_mpi_t a);
+
+
 
 /*-- homedir.c --*/
 const char *standard_homedir (void);
index 587c9f1..2a284e7 100644 (file)
@@ -1,5 +1,8 @@
 2011-01-31  Werner Koch  <wk@g10code.com>
 
+       * misc.c (make_flagged_int, openpgp_oid_from_str)
+       (openpgp_oid_to_str): Move to ../common/openpgp-oids.c.
+
        * ecdh.c (pk_ecdh_encrypt_with_shared_point): Return an opaque MPI.
 
        * build-packet.c (mpi_write): Rename to gpg_mpi_write and make global.
index d76d96b..d70c169 100644 (file)
@@ -165,10 +165,6 @@ unsigned int pubkey_nbits( int algo, gcry_mpi_t *pkey );
 int mpi_print (estream_t stream, gcry_mpi_t a, int mode);
 unsigned int ecdsa_qbits_from_Q (unsigned int qbits);
 
-/* Other stuff */
-gpg_error_t openpgp_oid_from_str (const char *string, gcry_mpi_t *r_mpi);
-char *openpgp_oid_to_str (gcry_mpi_t a);
-
 
 /*-- status.c --*/
 void set_status_fd ( int fd );
index 2052e96..dcd2bd1 100644 (file)
@@ -1552,204 +1552,3 @@ ecdsa_qbits_from_Q (unsigned int qbits)
 }
 
 
-
-/* Helper for openpgp_oid_from_str.  */
-static size_t
-make_flagged_int (unsigned long value, char *buf, size_t buflen)
-{
-  int more = 0;
-  int shift;
-
-  /* fixme: figure out the number of bits in an ulong and start with
-     that value as shift (after making it a multiple of 7) a more
-     straigtforward implementation is to do it in reverse order using
-     a temporary buffer - saves a lot of compares */
-  for (more=0, shift=28; shift > 0; shift -= 7)
-    {
-      if (more || value >= (1<<shift))
-        {
-          buf[buflen++] = 0x80 | (value >> shift);
-          value -= (value >> shift) << shift;
-          more = 1;
-        }
-    }
-  buf[buflen++] = value;
-  return buflen;
-}
-
-
-/* Convert the OID given in dotted decimal form in STRING to an DER
- * encoding and store it as an opaque value at R_MPI.  The format of
- * the DER encoded is not a regular ASN.1 object but the modified
- * format as used by OpenPGP for the ECC curve description.  On error
- * the function returns and error code an NULL is stored at R_BUG.
- * Note that scanning STRING stops at the first white space
- * character.  */
-gpg_error_t
-openpgp_oid_from_str (const char *string, gcry_mpi_t *r_mpi)
-{
-  unsigned char *buf;
-  size_t buflen;
-  unsigned long val1, val;
-  const char *endp;
-  int arcno;
-
-  *r_mpi = NULL;
-
-  if (!string || !*string)
-    return gpg_error (GPG_ERR_INV_VALUE);
-
-  /* We can safely assume that the encoded OID is shorter than the string. */
-  buf = xtrymalloc (1 + strlen (string) + 2);
-  if (!buf)
-    return gpg_error_from_syserror ();
-  /* Save the first byte for the length.  */
-  buflen = 1;
-
-  val1 = 0; /* Avoid compiler warning.  */
-  arcno = 0;
-  do {
-    arcno++;
-    val = strtoul (string, (char**)&endp, 10);
-    if (!digitp (string) || !(*endp == '.' || !*endp))
-      {
-        xfree (buf);
-        return gpg_error (GPG_ERR_INV_OID_STRING);
-      }
-    if (*endp == '.')
-      string = endp+1;
-
-    if (arcno == 1)
-      {
-        if (val > 2)
-          break; /* Not allowed, error catched below.  */
-        val1 = val;
-      }
-    else if (arcno == 2)
-      { /* Need to combine the first two arcs in one octet.  */
-        if (val1 < 2)
-          {
-            if (val > 39)
-              {
-                xfree (buf);
-                return gpg_error (GPG_ERR_INV_OID_STRING);
-              }
-            buf[buflen++] = val1*40 + val;
-          }
-        else
-          {
-            val += 80;
-            buflen = make_flagged_int (val, buf, buflen);
-          }
-      }
-    else
-      {
-        buflen = make_flagged_int (val, buf, buflen);
-      }
-  } while (*endp == '.');
-
-  if (arcno == 1 || buflen < 2 || buflen > 254 )
-    { /* It is not possible to encode only the first arc.  */
-      xfree (buf);
-      return gpg_error (GPG_ERR_INV_OID_STRING);
-    }
-
-  *buf = buflen - 1;
-  *r_mpi = gcry_mpi_set_opaque (NULL, buf, buflen * 8);
-  if (!*r_mpi)
-    {
-      xfree (buf);
-      return gpg_error_from_syserror ();
-    }
-  return 0; 
-}
-
-
-/* Return a malloced string represenation of the OID in the opaque MPI
-   A.  In case of an error NULL is returned and ERRNO is set.  */
-char *
-openpgp_oid_to_str (gcry_mpi_t a)
-{
-  const unsigned char *buf;
-  size_t length;
-  char *string, *p;
-  int n = 0;
-  unsigned long val, valmask;
-
-  valmask = (unsigned long)0xfe << (8 * (sizeof (valmask) - 1));
-
-  if (!a || !gcry_mpi_get_flag (a, GCRYMPI_FLAG_OPAQUE))
-    {
-      gpg_err_set_errno (EINVAL);
-      return NULL;
-    }
-
-  buf = gcry_mpi_get_opaque (a, &length);
-  length = (length+7)/8;
-
-  /* The first bytes gives the length; check consistency.  */
-  if (!length || buf[0] != length -1)
-    {
-      gpg_err_set_errno (EINVAL);
-      return NULL;
-    }
-  /* Skip length byte.  */
-  length--;
-  buf++;
-
-  /* To calculate the length of the string we can safely assume an
-     upper limit of 3 decimal characters per byte.  Two extra bytes
-     account for the special first octect */
-  string = p = xtrymalloc (length*(1+3)+2+1);
-  if (!string)
-    return NULL;
-  if (!buf || !length)
-    {
-      *p = 0;
-      return string;
-    }
-
-  if (buf[0] < 40)
-    p += sprintf (p, "0.%d", buf[n]);
-  else if (buf[0] < 80)
-    p += sprintf (p, "1.%d", buf[n]-40);
-  else {
-    val = buf[n] & 0x7f;
-    while ( (buf[n]&0x80) && ++n < length )
-      {
-        if ( (val & valmask) )
-          goto badoid;  /* Overflow.  */
-        val <<= 7;
-        val |= buf[n] & 0x7f;
-      }
-    val -= 80;
-    sprintf (p, "2.%lu", val);
-    p += strlen (p);
-  }
-  for (n++; n < length; n++)
-    {
-      val = buf[n] & 0x7f;
-      while ( (buf[n]&0x80) && ++n < length )
-        {
-          if ( (val & valmask) )
-            goto badoid;  /* Overflow.  */
-          val <<= 7;
-          val |= buf[n] & 0x7f;
-        }
-      sprintf (p, ".%lu", val);
-      p += strlen (p);
-    }
-    
-  *p = 0;
-  return string;
-
- badoid:
-  /* Return a special OID (gnu.gnupg.badoid) to indicate the error
-     case.  The OID is broken and thus we return one which can't do
-     any harm.  Formally this does not need to be a bad OID but an OID
-     with an arc that can't be represented in a 32 bit word is more
-     than likely corrupt.  */
-  xfree (string);
-  return xtrystrdup ("1.3.6.1.4.1.11591.2.12242973"); 
-}
-
index 528ce16..cebd043 100644 (file)
@@ -38,7 +38,6 @@ const void *find_tuple (tupledesc_t tupledesc,
                         unsigned int tag, size_t *r_length);
 const void *next_tuple (tupledesc_t tupledesc, 
                         unsigned int *r_tag, size_t *r_length);
-char *mpi2hex( gcry_mpi_t m );
 
 
 #endif /*G13_UTILS_H*/