Some minor bug fixes, new test utilities and started support for other
[gnupg.git] / kbx / keybox-blob.c
index 18503a5..3d81532 100644 (file)
@@ -1,5 +1,5 @@
 /* keybox-blob.c - KBX Blob handling
- *     Copyright (C) 2000, 2001 Free Software Foundation, Inc.
+ *     Copyright (C) 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -47,9 +47,10 @@ X.509 specific are noted like [X.509: xxx]
  byte version number of this blob type (1)
  u16  Blob flags
        bit 0 = contains secret key material
+        bit 1 = ephemeral blob (e.g. used while quering external resources)
 
  u32  offset to the OpenPGP keyblock or X509 DER encoded certificate
- u32  ant its length
+ u32  and its length
  u16  number of keys (at least 1!) [X509: always 1]
  u16  size of additional key information
  n times:
@@ -71,7 +72,7 @@ X.509 specific are noted like [X.509: xxx]
         bit 0 =
    byte validity
    byte reserved
-   [For X509, the first user ID is the ISsuer, the second the subject
+   [For X509, the first user ID is the Issuer, the second the Subject
    and the others are subjectAltNames]
  u16  number of signatures
  u16  size of signature information (4)
@@ -109,6 +110,9 @@ X.509 specific are noted like [X.509: xxx]
 #include <string.h>
 #include <errno.h>
 #include <assert.h>
+#include <time.h>
+
+#include "keybox-defs.h"
 #include <gcrypt.h>
 
 #ifdef KEYBOX_WITH_OPENPGP
@@ -118,8 +122,6 @@ X.509 specific are noted like [X.509: xxx]
 #include <ksba.h>
 #endif
 
-#include "keybox-defs.h"
-
 
 
 /* special values of the signature status */
@@ -171,9 +173,11 @@ struct fixup_list {
 struct keyboxblob {
   byte *blob;
   size_t bloblen;
+  off_t fileoffset;
   
   /* stuff used only by keybox_create_blob */
-  unsigned char *serial;
+  unsigned char *serialbuf;
+  const unsigned char *serial;
   size_t seriallen;
   int nkeys;
   struct keyboxblob_key *keys;
@@ -191,7 +195,7 @@ struct keyboxblob {
 
 
 \f
-/* A simple implemnation of a dynamic buffer.  Use init_membuf() to
+/* A simple implemention of a dynamic buffer.  Use init_membuf() to
    create a buffer, put_membuf to append bytes and get_membuf to
    release and return the buffer.  Allocation errors are detected but
    only returned at the final get_membuf(), this helps not to clutter
@@ -475,7 +479,7 @@ pgp_create_blob_keyblock (KEYBOXBLOB blob, KBNODE keyblock)
 
 /* Write the raw certificate out */
 static int
-x509_create_blob_cert (KEYBOXBLOB blob, KsbaCert cert)
+x509_create_blob_cert (KEYBOXBLOB blob, ksba_cert_t cert)
 {
   struct membuf *a = blob->buf;
   const unsigned char *image;
@@ -487,7 +491,7 @@ x509_create_blob_cert (KEYBOXBLOB blob, KsbaCert cert)
 
   image = ksba_cert_get_image (cert, &length);
   if (!image)
-    return KEYBOX_General_Error;
+    return gpg_error (GPG_ERR_GENERAL);
   put_membuf (a, image, length);
 
   add_fixup (blob, 12, a->len - kbstart);
@@ -529,7 +533,7 @@ release_kid_list (struct keyid_list *kl)
 
 
 static int
-create_blob_header (KEYBOXBLOB blob, int blobtype)
+create_blob_header (KEYBOXBLOB blob, int blobtype, int as_ephemeral)
 {
   struct membuf *a = blob->buf;
   int i;
@@ -537,7 +541,7 @@ create_blob_header (KEYBOXBLOB blob, int blobtype)
   put32 ( a, 0 ); /* blob length, needs fixup */
   put8 ( a, blobtype);  
   put8 ( a, 1 );  /* blob type version */
-  put16 ( a, 0 ); /* blob flags */
+  put16 ( a, as_ephemeral? 2:0 ); /* blob flags */
 
   put32 ( a, 0 ); /* offset to the raw data, needs fixup */
   put32 ( a, 0 ); /* length of the raw data, needs fixup */
@@ -555,7 +559,7 @@ create_blob_header (KEYBOXBLOB blob, int blobtype)
 
   put16 (a, blob->seriallen); /*fixme: check that it fits into 16 bits*/
   if (blob->serial)
-    put_membuf (a, blob->serial+4, blob->seriallen);
+    put_membuf (a, blob->serial, blob->seriallen);
 
   put16 ( a, blob->nuids );
   put16 ( a, 4 + 4 + 2 + 1 + 1 );  /* size of uid info */
@@ -649,7 +653,7 @@ create_blob_finish (KEYBOXBLOB blob)
   /* get the memory area */
   p = get_membuf (a, &n);
   if (!p)
-    return KEYBOX_Out_Of_Core;
+    return gpg_error (GPG_ERR_ENOMEM);
   assert (n >= 20);
 
   /* fixup the length */
@@ -657,7 +661,7 @@ create_blob_finish (KEYBOXBLOB blob)
 
   /* do the fixups */
   if (blob->fixup_out_of_core)
-    return KEYBOX_Out_Of_Core;
+    return gpg_error (GPG_ERR_ENOMEM);
 
   {
     struct fixup_list *fl;
@@ -676,7 +680,7 @@ create_blob_finish (KEYBOXBLOB blob)
 
   pp = xtrymalloc (n);
   if ( !pp )
-    return KEYBOX_Out_Of_Core;
+    return gpg_error (gpg_err_code_from_errno (errno));
   memcpy (pp , p, n);
   blob->blob = pp;
   blob->bloblen = n;
@@ -688,7 +692,7 @@ create_blob_finish (KEYBOXBLOB blob)
 #ifdef KEYBOX_WITH_OPENPGP
 
 int
-_keybox_create_pgp_blob (KEYBOXBLOB *r_blob, KBNODE keyblock)
+_keybox_create_pgp_blob (KEYBOXBLOB *r_blob, KBNODE keyblock, int as_ephemeral)
 {
   int rc = 0;
   KBNODE node;
@@ -696,8 +700,8 @@ _keybox_create_pgp_blob (KEYBOXBLOB *r_blob, KBNODE keyblock)
 
   *r_blob = NULL;
   blob = xtrycalloc (1, sizeof *blob);
-  if( !blob )
-    return KEYBOX_Out_Of_Core;
+  if (!blob)
+    return gpg_error (gpg_err_code_from_errno (errno));
 
   /* fixme: Do some sanity checks on the keyblock */
 
@@ -721,7 +725,7 @@ _keybox_create_pgp_blob (KEYBOXBLOB *r_blob, KBNODE keyblock)
   blob->sigs = xtrycalloc (blob->nsigs, sizeof *blob->sigs );
   if (!blob->keys || !blob->uids || !blob->sigs)
     {
-      rc = KEYBOX_Out_Of_Core;
+      rc = gpg_error (GPG_ERR_ENOMEM);
       goto leave;
     }
 
@@ -737,7 +741,7 @@ _keybox_create_pgp_blob (KEYBOXBLOB *r_blob, KBNODE keyblock)
   
   init_membuf (&blob->bufbuf, 1024);
   blob->buf = &blob->bufbuf;
-  rc = create_blob_header (blob, BLOBTYPE_OPENPGP);
+  rc = create_blob_header (blob, BLOBTYPE_OPENPGP, as_ephemeral);
   if (rc)
     goto leave;
   rc = pgp_create_blob_keyblock (blob, keyblock);
@@ -768,11 +772,44 @@ _keybox_create_pgp_blob (KEYBOXBLOB *r_blob, KBNODE keyblock)
 #endif /*KEYBOX_WITH_OPENPGP*/
 
 #ifdef KEYBOX_WITH_X509
+
+/* return an allocated string with the email address extracted from a
+   DN */
+static char *
+x509_email_kludge (const char *name)
+{
+  const unsigned char *p;
+  unsigned char *buf;
+  int n;
+
+  if (strncmp (name, "1.2.840.113549.1.9.1=#", 22))
+    return NULL;
+  /* This looks pretty much like an email address in the subject's DN
+     we use this to add an additional user ID entry.  This way,
+     openSSL generated keys get a nicer and usable listing */
+  name += 22;    
+  for (n=0, p=name; hexdigitp (p) && hexdigitp (p+1); p +=2, n++)
+    ;
+  if (*p != '#' || !n)
+    return NULL;
+  buf = xtrymalloc (n+3);
+  if (!buf)
+    return NULL; /* oops, out of core */
+  *buf = '<';
+  for (n=1, p=name; *p != '#'; p +=2, n++)
+    buf[n] = xtoi_2 (p);
+  buf[n++] = '>';
+  buf[n] = 0;
+  return buf;
+}
+
+
+
 /* Note: We should move calculation of the digest into libksba and
    remove that parameter */
 int
-_keybox_create_x509_blob (KEYBOXBLOB *r_blob, KsbaCert cert,
-                          unsigned char *sha1_digest)
+_keybox_create_x509_blob (KEYBOXBLOB *r_blob, ksba_cert_t cert,
+                          unsigned char *sha1_digest, int as_ephemeral)
 {
   int i, rc = 0;
   KEYBOXBLOB blob;
@@ -783,14 +820,31 @@ _keybox_create_x509_blob (KEYBOXBLOB *r_blob, KsbaCert cert,
   *r_blob = NULL;
   blob = xtrycalloc (1, sizeof *blob);
   if( !blob )
-    return KEYBOX_Out_Of_Core;
+    return gpg_error (gpg_err_code_from_errno (errno));
 
   p = ksba_cert_get_serial (cert);
   if (p)
     {
-      size_t n = (p[0] << 24) | (p[1] << 16) | (p[2] <<8) | p[3];
-      blob->seriallen = n;
+      size_t n, len;
+      n = gcry_sexp_canon_len (p, 0, NULL, NULL);
+      if (n < 2)
+        {
+          xfree (p);
+          return gpg_error (GPG_ERR_GENERAL);
+        }
+      blob->serialbuf = p;
+      p++; n--; /* skip '(' */
+      for (len=0; n && *p && *p != ':' && digitp (p); n--, p++)
+        len = len*10 + atoi_1 (p);
+      if (*p != ':')
+        {
+          xfree (blob->serialbuf);
+          blob->serialbuf = NULL;
+          return gpg_error (GPG_ERR_GENERAL);
+        }
+      p++;
       blob->serial = p;
+      blob->seriallen = len;
     }
 
   blob->nkeys = 1;
@@ -801,18 +855,19 @@ _keybox_create_x509_blob (KEYBOXBLOB *r_blob, KsbaCert cert,
   names = xtrymalloc (max_names * sizeof *names);
   if (!names)
     {
-      rc = KEYBOX_Out_Of_Core;
+      rc = gpg_error (gpg_err_code_from_errno (errno));
       goto leave;
     }
   p = ksba_cert_get_issuer (cert, 0);
   if (!p)
     {
-      rc =  KEYBOX_Missing_Value;
+      rc =  gpg_error (GPG_ERR_MISSING_VALUE);
       goto leave;
     }
   names[blob->nuids++] = p;
   for (i=0; (p = ksba_cert_get_subject (cert, i)); i++)
     {
+
       if (blob->nuids >= max_names)
         {
           unsigned char **tmp;
@@ -821,11 +876,13 @@ _keybox_create_x509_blob (KEYBOXBLOB *r_blob, KsbaCert cert,
           tmp = xtryrealloc (names, max_names * sizeof *names);
           if (!tmp)
             {
-              rc = KEYBOX_Out_Of_Core;
+              rc = gpg_error (gpg_err_code_from_errno (errno));
               goto leave;
             }
         }
       names[blob->nuids++] = p;
+      if (!i && (p=x509_email_kludge (p)))
+        names[blob->nuids++] = p; /* due to !i we don't need to check bounds*/
     }
   
   /* space for signature information */
@@ -836,7 +893,7 @@ _keybox_create_x509_blob (KEYBOXBLOB *r_blob, KsbaCert cert,
   blob->sigs = xtrycalloc (blob->nsigs, sizeof *blob->sigs );
   if (!blob->keys || !blob->uids || !blob->sigs)
     {
-      rc = KEYBOX_Out_Of_Core;
+      rc = gpg_error (GPG_ERR_ENOMEM);
       goto leave;
     }
 
@@ -863,7 +920,7 @@ _keybox_create_x509_blob (KEYBOXBLOB *r_blob, KsbaCert cert,
   init_membuf (&blob->bufbuf, 1024);
   blob->buf = &blob->bufbuf;
   /* write out what we already have */
-  rc = create_blob_header (blob, BLOBTYPE_X509);
+  rc = create_blob_header (blob, BLOBTYPE_X509, as_ephemeral);
   if (rc)
     goto leave;
   rc = x509_create_blob_cert (blob, cert);
@@ -902,17 +959,18 @@ _keybox_create_x509_blob (KEYBOXBLOB *r_blob, KsbaCert cert,
 
 \f
 int
-_keybox_new_blob (KEYBOXBLOB *r_blob, char *image, size_t imagelen)
+_keybox_new_blob (KEYBOXBLOB *r_blob, char *image, size_t imagelen, off_t off)
 {
   KEYBOXBLOB blob;
   
   *r_blob = NULL;
   blob = xtrycalloc (1, sizeof *blob);
   if (!blob)
-    return KEYBOX_Out_Of_Core;
+    return gpg_error (gpg_err_code_from_errno (errno));
 
   blob->blob = image;
   blob->bloblen = imagelen;
+  blob->fileoffset = off;
   *r_blob = blob;
   return 0;
 }
@@ -925,7 +983,7 @@ _keybox_release_blob (KEYBOXBLOB blob)
     return;
   /* hmmm: release membuf here?*/
   xfree (blob->keys );
-  xfree (blob->serial);
+  xfree (blob->serialbuf);
   for (i=0; i < blob->nuids; i++)
     xfree (blob->uids[i].name);
   xfree (blob->uids );
@@ -939,6 +997,13 @@ _keybox_release_blob (KEYBOXBLOB blob)
 const char *
 _keybox_get_blob_image ( KEYBOXBLOB blob, size_t *n )
 {
-    *n = blob->bloblen;
-    return blob->blob;
+  *n = blob->bloblen;
+  return blob->blob;
 }
+
+off_t
+_keybox_get_blob_fileoffset (KEYBOXBLOB blob)
+{
+  return blob->fileoffset;
+}
+