2006-06-09 Marcus Brinkmann <marcus@g10code.de>
[gnupg.git] / kbx / keybox-blob.c
index 2c80a10..eacc001 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.
  *
@@ -35,11 +35,13 @@ The first record of a plain KBX file has a special format:
  byte reserved
  byte reserved
  u32  magic 'KBXf'
- byte pgp_marginals  used for validity calculation of this file
- byte pgp_completes  ditto.
- byte pgp_cert_depth ditto.
+ u32  reserved
+ u32  file_created_at
+ u32  last_maintenance_run
+ u32  reserved
+ u32  reserved
 
-The OpenPGP and X.509 blob are verry similiar, things which are
+The OpenPGP and X.509 blob are very similiar, things which are
 X.509 specific are noted like [X.509: xxx]
 
  u32  length of this blob (including these 4 bytes)
@@ -47,18 +49,19 @@ 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:
    b20 The keys fingerprint
        (fingerprints are always 20 bytes, MD5 left padded with zeroes)
    u32 offset to the n-th key's keyID (a keyID is always 8 byte)
-        or 0 if not known which is the case opnly for X509.
+        or 0 if not known which is the case only for X509.
    u16 special key flags
-        bit 0 =
+        bit 0 = qualified signature (not yet implemented}
    u16 reserved
  u16  size of serialnumber(may be zero) 
    n  u16 (see above) bytes of serial number
@@ -71,7 +74,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)
@@ -81,8 +84,11 @@ X.509 specific are noted like [X.509: xxx]
        0x00000002 = bad signature
        0x10000000 = valid and expires at some date in 1978.
        0xffffffff = valid and does not expire
- u8    assigned ownertrust [X509: no used]
- u8    all_validity        [X509: no used]
+ u8    assigned ownertrust [X509: not used]
+ u8    all_validity 
+           OpenPGP:  see ../g10/trustdb/TRUST_* [not yet used]
+           X509: Bit 4 set := key has been revoked.  Note that this value
+                              matches TRUST_FLAG_REVOKED
  u16   reserved
  u32   recheck_after
  u32   Newest timestamp in the keyblock (useful for KS syncronsiation?)
@@ -109,6 +115,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,7 +127,6 @@ X.509 specific are noted like [X.509: xxx]
 #include <ksba.h>
 #endif
 
-#include "keybox-defs.h"
 
 
 /* special values of the signature status */
@@ -170,6 +178,7 @@ struct fixup_list {
 struct keyboxblob {
   byte *blob;
   size_t bloblen;
+  off_t fileoffset;
   
   /* stuff used only by keybox_create_blob */
   unsigned char *serialbuf;
@@ -191,7 +200,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 +484,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 +496,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 +538,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 +546,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 */
@@ -637,8 +646,8 @@ static int
 create_blob_finish (KEYBOXBLOB blob)
 {
   struct membuf *a = blob->buf;
-  byte *p;
-  char *pp;
+  unsigned char *p;
+  unsigned char *pp;
   int i;
   size_t n;
 
@@ -647,9 +656,10 @@ create_blob_finish (KEYBOXBLOB blob)
     put32 (a, 0);  /* Hmmm: why put32() ?? */
   
   /* get the memory area */
+  n = 0; /* (Just to avoid compiler warning.) */
   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 +667,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 +686,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 +698,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 +706,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 +731,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 +747,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);
@@ -774,7 +784,7 @@ _keybox_create_pgp_blob (KEYBOXBLOB *r_blob, KBNODE keyblock)
 static char *
 x509_email_kludge (const char *name)
 {
-  const unsigned char *p;
+  const char *p;
   unsigned char *buf;
   int n;
 
@@ -796,7 +806,7 @@ x509_email_kludge (const char *name)
     buf[n] = xtoi_2 (p);
   buf[n++] = '>';
   buf[n] = 0;
-  return buf;
+  return (char *)buf;
 }
 
 
@@ -804,42 +814,43 @@ x509_email_kludge (const char *name)
 /* 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;
-  unsigned char *p;
-  unsigned char **names = NULL;
+  unsigned char *sn;
+  char *p;
+  char **names = NULL;
   size_t max_names;
 
   *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)
+  sn = ksba_cert_get_serial (cert);
+  if (sn)
     {
       size_t n, len;
-      n = gcry_sexp_canon_len (p, 0, NULL, NULL);
+      n = gcry_sexp_canon_len (sn, 0, NULL, NULL);
       if (n < 2)
         {
-          xfree (p);
-          return KEYBOX_General_Error;
+          xfree (sn);
+          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 != ':')
+      blob->serialbuf = sn;
+      sn++; n--; /* skip '(' */
+      for (len=0; n && *sn && *sn != ':' && digitp (sn); n--, sn++)
+        len = len*10 + atoi_1 (sn);
+      if (*sn != ':')
         {
           xfree (blob->serialbuf);
           blob->serialbuf = NULL;
-          return KEYBOX_General_Error;
+          return gpg_error (GPG_ERR_GENERAL);
         }
-      p++;
-      blob->serial = p;
+      sn++;
+      blob->serial = sn;
       blob->seriallen = len;
     }
 
@@ -851,28 +862,28 @@ _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;
+          char **tmp;
           
           max_names += 100;
           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;
             }
         }
@@ -889,7 +900,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;
     }
 
@@ -916,7 +927,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);
@@ -955,21 +966,24 @@ _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,
+                  unsigned 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;
 }
 
+
 void
 _keybox_release_blob (KEYBOXBLOB blob)
 {
@@ -989,9 +1003,32 @@ _keybox_release_blob (KEYBOXBLOB blob)
 
 
 
-const char *
+const unsigned 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;
+}
+
+
+
+void
+_keybox_update_header_blob (KEYBOXBLOB blob)
+{
+  if (blob->bloblen >= 32 && blob->blob[4] == BLOBTYPE_HEADER)
+    {
+      u32 val = make_timestamp ();
+
+      /* Update the last maintenance run times tamp. */
+      blob->blob[20]   = (val >> 24);
+      blob->blob[20+1] = (val >> 16);
+      blob->blob[20+2] = (val >>  8);
+      blob->blob[20+3] = (val      );
+    }
 }