Added more functionality, basic certificate stuff can now be handled.
authorWerner Koch <wk@gnupg.org>
Tue, 6 Nov 2001 10:35:59 +0000 (10:35 +0000)
committerWerner Koch <wk@gnupg.org>
Tue, 6 Nov 2001 10:35:59 +0000 (10:35 +0000)
14 files changed:
TODO
src/Makefile.am
src/asn1-func.c
src/asn1-func.h
src/ber-decoder.c
src/cert.c
src/cert.h
src/convert.h
src/dn.c
src/keyinfo.c
src/keyinfo.h
src/ksba.h
src/shared.h [new file with mode: 0644]
tests/cert-basic.c

diff --git a/TODO b/TODO
index e6639a5..6a64eb9 100644 (file)
--- a/TODO
+++ b/TODO
@@ -1,2 +1,21 @@
+                                                              -*- outline -*-
+
+* src/dn.c:
+
+  * Implement utf8 conversion. 
+
+* src/der-decoder.c:  
+
+  * should work on a stripped down parse tree
+
+  * Allow to specify the desired top element.  Or a list so that it
+    can detect the needed tree itself
+
+* src/asn1-*
+  
+  * Cleanup the used data structures and remove unneeded functions.
+
+  * Make use of pre-generated tables and remove hardwired filenames.
+
+
 
-* 
\ No newline at end of file
index d04472d..8e3afa8 100644 (file)
@@ -39,7 +39,7 @@ libksba_la_SOURCES = \
        cert.c cert.h \
        keyinfo.c keyinfo.h \
        oid.c dn.c time.c convert.h \
-       util.c util.h errors.c  
+       util.c util.h shared.h errors.c 
 
 asn1_gentables_SOURCES = \
        asn1-gentables.c \
index 6370845..edbcf41 100755 (executable)
@@ -185,6 +185,9 @@ copy_value (AsnNode d, const AsnNode s)
       return_if_fail (0);
     }
   _ksba_asn_set_value (d, s->valuetype, buf, len);
+  d->off = s->off;
+  d->nhdr = s->nhdr;
+  d->len = s->len;
 }
 
 static AsnNode 
@@ -1743,6 +1746,50 @@ _ksba_asn_type_set_config (AsnNode node)
     }
 }
 
+/* Create a copy the tree at SRC_ROOT. s is a helper which should be
+   set to SRC_ROOT by the caller */
+static AsnNode
+copy_tree (AsnNode src_root, AsnNode s)
+{
+  AsnNode first=NULL, dprev=NULL, d, down, tmp;
+
+  for (; s; s=s->right )
+    {
+      down = s->down;
+      d = copy_node (s);
+
+      if (!first)
+        first = d;
+      else
+        {
+          dprev->right = d;
+          d->left = dprev;
+        }
+      dprev = d;
+      if (down)
+        {
+          tmp = copy_tree (src_root, down);
+          if (d->down && tmp)
+            { /* Need to merge it with the existing down */
+              AsnNode x;
+
+              for (x=d->down; x->right; x = x->right)
+                ;
+              x->right = tmp;
+              tmp->left = x;
+            }
+          else 
+            {
+              d->down = tmp;
+              if (d->down)
+                d->down->left = d;
+            }
+        }
+    }
+  return first;
+}
+
+
 
 static AsnNode
 resolve_identifier (AsnNode root, AsnNode node)
@@ -1853,3 +1900,25 @@ _ksba_asn_expand_tree (AsnNode src_root)
   /* FIXME: add a too deep recursion check */
   return do_expand_tree (src_root, src_root);
 }
+
+
+/* Insert a copy of the entire tree at NODE as the sibling of itself
+   and return the copy */
+AsnNode
+_ksba_asn_insert_copy (AsnNode node)
+{
+  AsnNode n;
+
+  n = copy_tree (node, node);
+  if (!n)
+    return NULL; /* out of core */
+  return_null_if_fail (n->right == node->right);
+  node->right = n;
+  n->left = node;
+  
+  return n;
+}
+
+
+
+
index 58484b5..eea9d5c 100755 (executable)
@@ -153,6 +153,7 @@ struct asn_node_struct {
   int off;                       /* offset of this TLV */
   int nhdr;                      /* length of the header */
   int len;                       /* length part of the TLV */
+  node_type_t actual_type;       /* ugly helper to overcome TYPE_ANY probs*/
 
   AsnNode down;                  /* Pointer to the son node */
   AsnNode right;                 /* Pointer to the brother node */
@@ -194,6 +195,7 @@ int _ksba_asn_expand_object_id(AsnNode node);
 void _ksba_asn_set_default_tag (AsnNode node);
 void _ksba_asn_type_set_config (AsnNode node);
 AsnNode _ksba_asn_expand_tree (AsnNode src_root);
+AsnNode _ksba_asn_insert_copy (AsnNode node);
 
 
 /*-- asn1-func.c --*/
index f112928..1c80a79 100644 (file)
@@ -82,6 +82,7 @@ struct ber_decoder_s {
     int primitive;  /* current value is a primitive one */
     int length;     /* length of the primitive one */
     int nhdr;       /* length of the header */
+    int tag; 
     AsnNode node;   /* NULL or matching node */
   } val; 
 };
@@ -298,6 +299,29 @@ clear_help_flags (AsnNode node)
   
 }
 
+static void
+prepare_copied_tree (AsnNode node)
+{
+  AsnNode p;
+
+  clear_help_flags (node);
+  for (p=node; p; p = _ksba_asn_walk_tree (node, p))
+    p->off = -1;
+  
+}
+
+static void
+fixup_type_any (AsnNode node)
+{
+  AsnNode p;
+
+  for (p=node; p; p = _ksba_asn_walk_tree (node, p))
+    {
+      if (p->type == TYPE_ANY && p->off != -1)
+        p->type = p->actual_type;
+    }
+}
+
 
 \f
 BerDecoder
@@ -603,6 +627,9 @@ match_der (AsnNode root, const struct tag_info *ti,
         {
           if (debug)
             puts ("  Reiterating");
+          node = _ksba_asn_insert_copy (node);
+          if (node)
+            prepare_copied_tree (node);
         }
       else
         node = node->down;
@@ -627,6 +654,9 @@ match_der (AsnNode root, const struct tag_info *ti,
         {
           if (debug)
             puts ("  Reiterating this");
+          node = _ksba_asn_insert_copy (node);
+          if (node)
+            prepare_copied_tree (node);
         }
       else if (ds->cur.went_up || ds->cur.next_tag)
         {
@@ -913,6 +943,7 @@ decoder_next (BerDecoder d)
   d->val.primitive = !ti.is_constructed;
   d->val.length = ti.length;
   d->val.nhdr = ti.nhdr;
+  d->val.tag  = ti.tag; /* kludge to fix TYPE_ANY probs */
   d->val.node = d->bypass? NULL : node;
   if (debug)
     dump_decoder_state (ds);
@@ -1091,6 +1122,8 @@ _ksba_ber_decoder_decode (BerDecoder d, AsnNode *r_root,
           node->off = ksba_reader_tell (d->reader) - d->val.nhdr;
           node->nhdr = d->val.nhdr;
           node->len = d->val.length;
+          if (node->type == TYPE_ANY)
+            node->actual_type = d->val.tag;
           if (d->image.used + d->val.length > d->image.length)
             err = set_error(d, NULL, "TLV length too large");
           else if (d->val.primitive)
@@ -1145,11 +1178,15 @@ _ksba_ber_decoder_decode (BerDecoder d, AsnNode *r_root,
 
   if (r_root && !err)
     {
+      fixup_type_any (d->root);
       *r_root = d->root;
       d->root = NULL;
       *r_image = d->image.buf;
       d->image.buf = NULL;
       *r_imagelen = d->image.used;
+/*        fputs ("Value Tree:\n", stdout); */
+/*        _ksba_asn_node_dump_all (*r_root, stdout); */
+
     }
 
   decoder_deinit (d);
index 0d5136f..7a159dc 100644 (file)
@@ -27,6 +27,7 @@
 #include "util.h"
 #include "ber-decoder.h"
 #include "convert.h"
+#include "keyinfo.h"
 #include "cert.h"
 
 
@@ -135,7 +136,7 @@ ksba_cert_hash (KsbaCert cert,
     return KSBA_No_Data;
 
   n = _ksba_asn_find_node (cert->root,
-                           "TMTTv2.Certificate.tbsCertificate.subjectPublicKeyInfo");
+                           "TMTTv2.Certificate.signatureAlgorithm");
   if (!n)
     return KSBA_No_Value; /* oops - should be there */
   if (n->off == -1)
@@ -145,12 +146,72 @@ ksba_cert_hash (KsbaCert cert,
       return KSBA_No_Value;
     }
 
-  _ksba_keyinfo_to_sexp (cert->image + n->off, n->nhdr + n->len);
+  {  
+    KsbaError err;
+    char *string;
+    AsnNode n2;
+#if 0
+    err = _ksba_keyinfo_to_sexp (cert->image + n->off, n->nhdr + n->len,
+                                 &string);
+    if (err)
+      return err;
+    printf ("KEY = `%s'\n", string);
+#endif
+    n2 = n->right;
+    
+    err = _ksba_sigval_to_sexp (cert->image + n->off,
+                                n->nhdr + n->len
+                                + ((!n2||n2->off == -1)? 0:(n2->nhdr+n2->len)),
+                                &string);
+    if (err)
+      return err;
+    printf ("SIG = `%s'\n", string);
+  }
 
   return 0;
 }
 
 
+/**
+ * ksba_cert_get_digest_algo:
+ * @cert: Initialized certificate object
+ * 
+ * Figure out the the digest algorithm used for the signature and
+ * return it as a number suitable to be used to identify a digest
+ * algorithm in Libgcrypt.
+ *
+ * This function is intended as a helper for the ksba_cert_hash().
+ * 
+ * Return value: 0 for error or unknown algoritm, otherwise a
+ * GCRY_MD_xxx constant.
+ **/
+int
+ksba_cert_get_digest_algo (KsbaCert cert)
+{
+  AsnNode n;
+  int algo;
+
+  if (!cert)
+    return KSBA_Invalid_Value;
+  if (!cert->initialized)
+    return KSBA_No_Data;
+
+  n = _ksba_asn_find_node (cert->root,
+                           "TMTTv2.Certificate.signatureAlgorithm.algorithm");
+  algo = _ksba_map_oid_to_digest_algo (cert->image, n);
+  if (!algo)
+    cert->last_error = KSBA_Unknown_Algorithm;
+  else if (algo == -1)
+    {
+      cert->last_error = KSBA_No_Value;
+      algo = 0;
+    }
+
+  return algo;
+}
+
+
+
 
 /**
  * ksba_cert_get_serial:
@@ -216,7 +277,32 @@ ksba_cert_get_serial (KsbaCert cert)
 char *
 ksba_cert_get_issuer (KsbaCert cert)
 {
-  return NULL;
+  KsbaError err;
+  AsnNode n;
+  char *p;
+
+  if (!cert || !cert->initialized)
+    return NULL;
+  
+  n = _ksba_asn_find_node (cert->root,
+                           "TMTTv2.Certificate.tbsCertificate.issuer");
+  if (!n || !n->down)
+    return NULL; /* oops - should be there */
+  n = n->down; /* dereference the choice node */
+
+  if (n->off == -1)
+    {
+      fputs ("get_issuer problem at node:\n", stderr);
+      _ksba_asn_node_dump_all (n, stderr);
+      return NULL;
+    }
+  err = _ksba_dn_to_str (cert->image, n, &p);
+  if (err)
+    {
+      cert->last_error = err;
+      return NULL;
+    }
+  return p;
 }
 
 
@@ -273,7 +359,99 @@ ksba_cert_get_validity (KsbaCert cert, int what)
 char *
 ksba_cert_get_subject (KsbaCert cert)
 {
-  return NULL;
+  KsbaError err;
+  AsnNode n;
+  char *p;
+
+  if (!cert || !cert->initialized)
+    return NULL;
+  
+  n = _ksba_asn_find_node (cert->root,
+                           "TMTTv2.Certificate.tbsCertificate.subject");
+  if (!n || !n->down)
+    return NULL; /* oops - should be there */
+  n = n->down; /* dereference the choice node */
+
+  if (n->off == -1)
+    {
+      fputs ("get_issuer problem at node:\n", stderr);
+      _ksba_asn_node_dump_all (n, stderr);
+      return NULL;
+    }
+  err = _ksba_dn_to_str (cert->image, n, &p);
+  if (err)
+    {
+      cert->last_error = err;
+      return NULL;
+    }
+  return p;
+}
+
+
+char *
+ksba_cert_get_public_key (KsbaCert cert)
+{
+  AsnNode n;
+  KsbaError err;
+  char *string;
+
+  if (!cert)
+    return NULL;
+  if (!cert->initialized)
+    return NULL;
+
+  n = _ksba_asn_find_node (cert->root,
+                           "TMTTv2.Certificate"
+                           ".tbsCertificate.subjectPublicKeyInfo");
+  if (!n)
+    {
+      cert->last_error = KSBA_No_Value;
+      return NULL;
+    }
+
+  err = _ksba_keyinfo_to_sexp (cert->image + n->off, n->nhdr + n->len,
+                               &string);
+  if (err)
+    {
+      cert->last_error = err;
+      return NULL;
+    }
+
+  return string;
+}
+
+char *
+ksba_cert_get_sig_val (KsbaCert cert)
+{
+  AsnNode n, n2;
+  KsbaError err;
+  char *string;
+
+  if (!cert)
+    return NULL;
+  if (!cert->initialized)
+    return NULL;
+
+  n = _ksba_asn_find_node (cert->root,
+                           "TMTTv2.Certificate.algorithmIdentifier");
+  if (!n)
+    {
+      cert->last_error = KSBA_No_Value;
+      return NULL;
+    }
+
+  n2 = n->right;
+  err = _ksba_sigval_to_sexp (cert->image + n->off,
+                              n->nhdr + n->len
+                              + ((!n2||n2->off == -1)? 0:(n2->nhdr+n2->len)),
+                              &string);
+  if (err)
+    {
+      cert->last_error = err;
+      return NULL;
+    }
+
+  return string;
 }
 
 
index bb387fe..640c221 100644 (file)
@@ -29,6 +29,7 @@ struct ksba_cert_s {
   AsnNode root;  /* root of the tree with the values */
   unsigned char *image;
   size_t imagelen;
+  KsbaError last_error;
 };
 
 
index 6855c47..67aedfa 100644 (file)
 #ifndef CONVERT_H
 #define CONVERT_H
 
+#include "asn1-func.h"
+
 /*-- time.c --*/
 time_t _ksba_asntime_to_epoch (const char *buffer, size_t length);
 
+/*-- dn.c --*/
+KsbaError _ksba_dn_to_str (const unsigned char *image, AsnNode node,
+                           char **r_string);
 
 
 #endif /*CONVERT_H*/
index 27fd7d7..5016438 100644 (file)
--- a/src/dn.c
+++ b/src/dn.c
@@ -27,7 +27,7 @@
 #include <assert.h>
 
 #include "util.h"
-#include "asn1-func.c"
+#include "asn1-func.h"
 
 struct {
   const char *name;
@@ -35,32 +35,283 @@ struct {
   int                  oidlen;
   const unsigned char *oid;
 } oid_name_tbl[] = {
-{"CN", "commonName",            5, "\x06\x03\x55\x04\x03"}, /* 2.5.4.3 */
-{"C",  "countryName",           5, "\x06\x03\x55\x04\x06"}, /* 2.5.4.6 */
-{"L" , "localityName",          5, "\x06\x03\x55\x04\x07"}, /* 2.5.4.7 */
-{"ST", "stateOrProvinceName",   5, "\x06\x03\x55\x04\x08"}, /* 2.5.4.8 */
-{"STREET", "streetAddress",     5, "\x06\x03\x55\x04\x09"}, /* 2.5.4.9 */
-{"O",  "organizationName",      5, "\x06\x03\x55\x04\x0a"}, /* 2.5.4.10 */
-{"OU", "organizationalUnitName",5, "\x06\x03\x55\x04\x0b"}, /* 2.5.4.11 */
-{"DC", "domainComponent",      12
-       "\x06\x0a\x09\x92\x26\x89\x93\xF2\x2C\x64\x01\x01"},
+{"CN", "commonName",            3, "\x55\x04\x03"}, /* 2.5.4.3 */
+{"C",  "countryName",           3, "\x55\x04\x06"}, /* 2.5.4.6 */
+{"L" , "localityName",          3, "\x55\x04\x07"}, /* 2.5.4.7 */
+{"ST", "stateOrProvinceName",   3, "\x55\x04\x08"}, /* 2.5.4.8 */
+{"STREET", "streetAddress",     3, "\x55\x04\x09"}, /* 2.5.4.9 */
+{"O",  "organizationName",      3, "\x55\x04\x0a"}, /* 2.5.4.10 */
+{"OU", "organizationalUnitName",3, "\x55\x04\x0b"}, /* 2.5.4.11 */
+{"DC", "domainComponent",      10
+       "\x09\x92\x26\x89\x93\xF2\x2C\x64\x01\x01"},
                             /* 0.9.2342.19200300.100.1.25 */
+
 /* {"UID","userid",}  FIXME: I don't have the OID  it might be ...100.1.1 */
 { NULL }
 };
 
 
+struct stringbuf {
+  size_t len;
+  size_t size;
+  char *buf;
+  int out_of_core;
+};
+
+
+
+static void
+init_stringbuf (struct stringbuf *sb, int initiallen)
+{
+  sb->len = 0;
+  sb->size = initiallen;
+  sb->out_of_core = 0;
+  /* allocate one more, so that get_stringbuf can append a nul */
+  sb->buf = xtrymalloc (initiallen+1);
+  if (!sb->buf)
+      sb->out_of_core = 1;
+}
+
+static void
+deinit_stringbuf (struct stringbuf *sb)
+{
+  xfree (sb->buf); 
+  sb->buf = NULL;
+  sb->out_of_core = 1; /* make sure the caller does an init before reuse */
+}
+
+
+static void
+put_stringbuf (struct stringbuf *sb, const char *text)
+{
+  size_t n = strlen (text);
+
+  if (sb->out_of_core)
+    return;
+
+  if (sb->len + n >= sb->size)
+    {
+      char *p;
+      
+      sb->size += n + 100;
+      p = xtryrealloc (sb->buf, sb->size);
+      if ( !p)
+        {
+          sb->out_of_core = 1;
+          return;
+        }
+      sb->buf = p;
+    }
+  memcpy (sb->buf+sb->len, text, n);
+  sb->len += n;
+}
+
+/* FIXME: This function is a temporary kludge */
+static void
+put_stringbuf_mem (struct stringbuf *sb, const char *text, size_t n)
+{
+  if (sb->out_of_core)
+    return;
+
+  if (sb->len + n >= sb->size)
+    {
+      char *p;
+      
+      sb->size += n + 100;
+      p = xtryrealloc (sb->buf, sb->size);
+      if ( !p)
+        {
+          sb->out_of_core = 1;
+          return;
+        }
+      sb->buf = p;
+    }
+  memcpy (sb->buf+sb->len, text, n);
+  sb->len += n;
+}
 
-char *
-_ksba_dn_to_str (AsnNode node)
+static char *
+get_stringbuf (struct stringbuf *sb)
 {
+  char *p;
+
+  if (sb->out_of_core)
+    {
+      xfree (sb->buf); sb->buf = NULL;
+      return NULL;
+    }
+
+  sb->buf[sb->len] = 0;
+  p = sb->buf;
+  sb->buf = NULL;
+  sb->out_of_core = 1; /* make sure the caller does an init before reuse */
+  return p;
+}
+
+
+
+\f
+/* Append VALUE of LENGTH and TYPE to SB.  Perform quoting and
+   character set conversion when needed */
+static void
+append_value (node_type_t type, const unsigned char *value, size_t length,
+              struct stringbuf *sb)
+{
+  /* FIXME:  Most stuff is missing */
+
+  
+  put_stringbuf_mem (sb, value, length);
+}
+
+/* Append attribute and value.  ROOT is the sequence */
+static KsbaError
+append_atv (const unsigned char *image, AsnNode root, struct stringbuf *sb)
+{
+  AsnNode node = root->down;
+  const char *name;
+  int use_hex = 0;
+  int i;
   
+  if (!node || node->type != TYPE_OBJECT_ID)
+    return KSBA_Unexpected_Tag;
+  if (node->off == -1)
+    return KSBA_No_Value; /* Hmmm, this might lead to misunderstandings */
+
+  name = NULL;
+  for (i=0; oid_name_tbl[i].name; i++)
+    {
+      if (node->len == oid_name_tbl[i].oidlen
+          && !memcmp (image+node->off+node->nhdr,
+                      oid_name_tbl[i].oid, node->len))
+        {
+          name = oid_name_tbl[i].name;
+          break;
+        }
+    }
+  if (name)
+    put_stringbuf (sb, name);
+  else
+    { /* No name in table: use the oid */
+      
+      char *p = ksba_oid_to_str (image+node->off+node->nhdr, node->len);
+      if (!p)
+        return KSBA_Out_Of_Core;
+      put_stringbuf (sb, p);
+      xfree (p);
+      use_hex = 1;
+    }
+  put_stringbuf (sb, "=");
+  node = node->right;
+  if (!node || node->off == -1)
+    return KSBA_No_Value;
+
+  switch (node->type)
+    {
+    case TYPE_UTF8_STRING:
+    case TYPE_PRINTABLE_STRING:
+/*      case TYPE_TELETEX_STRING: */
+    case TYPE_IA5_STRING:
+/*      case TYPE_GRAPHIC_STRING: */
+/*      case TYPE_VISIBLE_STRING: */
+/*      case TYPE_GENERAL_STRING: */
+/*      case TYPE_UNIVERSAL_STRING: */
+/*      case TYPE_CHARACTER_STRING: */
+/*      case TYPE_BMP_STRING: */
+      break;
+    default:
+      use_hex = 1;
+      break;
+    }
+
+  if (use_hex)
+    {
+      put_stringbuf (sb, "#");
+      for (i=0; i < node->len; i++)
+        { 
+          char tmp[3];
+          sprintf (tmp, "%02X", image[node->off+node->nhdr+i]);
+          put_stringbuf (sb, tmp);
+        }
+      put_stringbuf (sb, "#");
+    }
+  else
+    append_value (node->type, image+node->off+node->nhdr, node->len, sb);
+
+  return 0;
+}
+
+static KsbaError
+dn_to_str (const unsigned char *image, AsnNode root, struct stringbuf *sb)
+{
+  KsbaError err;
+  AsnNode nset;
+
+  if (!root )
+    return 0; /* empty DN */
+  nset = root->down;
+  if (!nset)
+    return 0; /* consider this as empty */
+  if (nset->type != TYPE_SET_OF)
+    return KSBA_Unexpected_Tag;
+
+  /* output in reverse order */
+  while (nset->right)
+    nset = nset->right;
+
+  for (;;)
+    {
+      AsnNode nseq;
+
+      if (nset->type != TYPE_SET_OF)
+        return KSBA_Unexpected_Tag;
+      for (nseq = nset->down; nseq; nseq = nseq->right)
+        {
+          if (nseq->type != TYPE_SEQUENCE)
+            return KSBA_Unexpected_Tag;
+          if (nseq != nset->down)
+            put_stringbuf (sb, "+");
+          err = append_atv (image, nseq, sb);
+          if (err)
+            return err;
+        }
+      if (nset == root->down)
+        break;
+      put_stringbuf (sb, ",");
+      nset = nset->left;
+    }
+      
+  return 0;
+}
+
+
+KsbaError
+_ksba_dn_to_str (const unsigned char *image, AsnNode node, char **r_string)
+{
+  KsbaError err;
+  struct stringbuf sb;
+
+  *r_string = NULL;
+  if (!node || node->type != TYPE_SEQUENCE_OF)
+    return KSBA_Invalid_Value;
+
+  init_stringbuf (&sb, 100);
+  err = dn_to_str (image, node, &sb);
+  if (!err)
+    {
+      *r_string = get_stringbuf (&sb);
+      if (!*r_string)
+        err = KSBA_Out_Of_Core;
+    }
+  deinit_stringbuf (&sb);
+
+  return err;
 }
 
 
-int
-ksba_dn_from_str (const char *string, char **rbuf, size_t *rlength)
+KsbaError
+_ksba_dn_from_str (const char *string, char **rbuf, size_t *rlength)
 {
+  return KSBA_Not_Implemented;  /* FIXME*/
 }
 
 
index 14710a4..322ca8e 100644 (file)
 #include "util.h"
 #include "asn1-func.h"
 
+#include "shared.h"
 
-struct {
+struct algo_table_s {
   const unsigned char *oid;  /* NULL indicattes end of table */
   int                  oidlen;
+  int supported;
+  const char *algo_string;
+  const char *elem_string; /* parameter name or '-' */
+  const char *ctrl_string; /* expected tag values (value > 127 are raw data)*/
+  int digest_algo;
+};
+
+static struct algo_table_s pk_algo_table[] = {
+  { /* iso.member-body.us.rsadsi.pkcs.pkcs-1.1 */
+    /* 1.2.840.113549.1.1.1  rsaEncryption (RSAES-PKCA1-v1.5) */ 
+    "\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01", 9, 
+    1, "rsa", "-ne", "\x30\x02\x02" },
+  { /* iso.member-body.us.rsadsi.pkcs.pkcs-1.7 */
+    /* 1.2.840.113549.1.1.7  RSAES-OAEP */ 
+    "\x2a\x86\x48\x86\xf7\x0d\x01\x01\x07", 9, 
+    0, "rsa", "-ne", "\x30\x02\x02"}, /* (patent problems) */
+  { /* */
+    /* 2.5.8.1.1 rsa (ambiguous due to missing padding rules)*/
+    "\x55\x08\x01\x01", 4, 
+    1, "ambiguous-rsa", "-ne", "\x30\x02\x02" },
+  { /* iso.member-body.us.x9-57.x9cm.1 */
+    /* 1.2.840.10040.4.1  dsa */
+    "\x2a\x86\x48\xce\x38\x04\x01", 7, 
+    1, "dsa"  "y", "\x02" }, 
+  /* FIXME: Need code to extract p,q,g from the parameters */
 
+  {NULL}
+};
 
-} algo_table[] = {
-  {"\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01", 11, 
-   /* 1.2.840.113549.1.1.1  rsaEncryption (pkcs#1) */ }
 
+static struct algo_table_s sig_algo_table[] = {
+  {  /* iso.member-body.us.rsadsi.pkcs.pkcs-1.5 */
+    /* 1.2.840.113549.1.1.5  sha1WithRSAEncryption */ 
+    "\x2A\x86\x48\x86\xF7\x0D\x01\x01\x05", 9, 
+    1, "rsa", "s", "\x82", GCRY_MD_SHA1 },
+  { /* iso.member-body.us.rsadsi.pkcs.pkcs-1.4 */
+    /* 1.2.840.113549.1.1.4  md5WithRSAEncryption */ 
+    "\x2A\x86\x48\x86\xF7\x0D\x01\x01\x04", 9, 
+    1, "rsa", "s", "\x82", GCRY_MD_MD5 },
+  { /* iso.member-body.us.rsadsi.pkcs.pkcs-1.2 */
+    /* 1.2.840.113549.1.1.2  md2WithRSAEncryption */ 
+    "\x2A\x86\x48\x86\xF7\x0D\x01\x01\x02", 9, 
+    0, "rsa", "s", "\x82", 0 },
+  { /* iso.member-body.us.x9-57.x9cm.3 */
+    /* 1.2.840.10040.4.3  dsaWithSha1 */
+    "\x2a\x86\x48\xce\x38\x04\x03", 7, 
+    1, "dsa", "-rs", "\x30\x02\x02", GCRY_MD_SHA1 }, 
 
   {NULL}
 };
 
 
-
+struct stringbuf {
+  size_t len;
+  size_t size;
+  char *buf;
+  int out_of_core;
+};
 
 
 #define TLV_LENGTH() do {         \
@@ -80,22 +127,16 @@ struct {
 
 /* Return the OFF and the LEN of algorithm within DER.  Do some checks
    and return the number of bytes read in r_nread, adding this to der
-   does point into the BIT STRING */
+   does point into the BIT STRING
+ */
 static KsbaError
 get_algorithm (const unsigned char *der, size_t derlen,
                size_t *r_nread, size_t *r_pos, size_t *r_len)
 {
   int c;
-  const char *start;
-  unsigned long len;
-
-  /* check the outer sequence */
-  if (!derlen)
-    return KSBA_Invalid_Keyinfo;
-  c = *der++; derlen--;
-  if ( c != 0x30 )
-    return KSBA_Unexpected_Tag; /* not a SEQUENCE */
-  TLV_LENGTH();
+  const unsigned char *start = der;
+  const unsigned char *startseq;
+  unsigned long seqlen, len;
 
   /* get the inner sequence */
   if (!derlen)
@@ -104,17 +145,19 @@ get_algorithm (const unsigned char *der, size_t derlen,
   if ( c != 0x30 )
     return KSBA_Unexpected_Tag; /* not a SEQUENCE */
   TLV_LENGTH(); 
+  seqlen = len;
+  startseq = der;
 
   /* get the object identifier */
   if (!derlen)
     return KSBA_Invalid_Keyinfo;
-  c = *der++; derlen--;
+  c = *der++; derlen--; 
   if ( c != 0x06 )
     return KSBA_Unexpected_Tag; /* not an OBJECT IDENTIFIER */
   TLV_LENGTH();
 
   /* der does now point to an oid of length LEN */
-  *r_off = der - start;
+  *r_pos = der - start;
   *r_len = len;
   {
     char *p = ksba_oid_to_str (der, len);
@@ -123,25 +166,49 @@ get_algorithm (const unsigned char *der, size_t derlen,
   }
   der += len;
   derlen -= len;
+  seqlen -= der - startseq;;
 
   /* check that the parameter is NULL or not there */
-  if (!derlen)
-    return KSBA_Invalid_Keyinfo;
-  c = *der++; derlen--;
-  if ( c == 0x05 ) 
+  if (!seqlen)
     {
-      printf ("parameter: NULL\n");
-      if (!derlen)
-        return KSBA_Invalid_Keyinfo;
-      c = *der++; derlen--;
-      if (c) 
-        return KSBA_BER_Error;  /* NULL must have a length of 0 */
-      
-      /* move forward to the BIT_STR */
+      printf ("parameter: none\n");
+    }
+  else
+    {
+      const unsigned char *startparm = der;
+
       if (!derlen)
         return KSBA_Invalid_Keyinfo;
       c = *der++; derlen--;
+      if ( c == 0x05 ) 
+        {
+          printf ("parameter: NULL \n"); /* the only correct thing */
+          if (!derlen)
+            return KSBA_Invalid_Keyinfo;
+          c = *der++; derlen--;
+          if (c) 
+            return KSBA_BER_Error;  /* NULL must have a length of 0 */
+          seqlen -= 2;
+        }
+      else
+        {
+          printf ("parameter: with tag %02x - ignored\n", c);
+          TLV_LENGTH();
+          seqlen -= der - startparm;
+          /* skip the value */
+          der += len;
+          derlen -= len;
+          seqlen -= len;
+        }
     }
+
+  if (seqlen)
+    return KSBA_Invalid_Keyinfo;
+
+  /* move forward to the BIT_STR */
+  if (!derlen)
+    return KSBA_Invalid_Keyinfo;
+  c = *der++; derlen--;
     
   if (c != 0x03)
     return KSBA_Unexpected_Tag; /* not a BIT STRING */
@@ -155,6 +222,63 @@ get_algorithm (const unsigned char *der, size_t derlen,
   return 0;
 }
 
+
+static void
+init_stringbuf (struct stringbuf *sb, int initiallen)
+{
+  sb->len = 0;
+  sb->size = initiallen;
+  sb->out_of_core = 0;
+  /* allocate one more, so that get_stringbuf can append a nul */
+  sb->buf = xtrymalloc (initiallen+1);
+  if (!sb->buf)
+      sb->out_of_core = 1;
+}
+
+static void
+put_stringbuf (struct stringbuf *sb, const char *text)
+{
+  size_t n = strlen (text);
+
+  if (sb->out_of_core)
+    return;
+
+  if (sb->len + n >= sb->size)
+    {
+      char *p;
+      
+      sb->size += n + 100;
+      p = xtryrealloc (sb->buf, sb->size);
+      if ( !p)
+        {
+          sb->out_of_core = 1;
+          return;
+        }
+      sb->buf = p;
+    }
+  memcpy (sb->buf+sb->len, text, n);
+  sb->len += n;
+}
+
+static char *
+get_stringbuf (struct stringbuf *sb)
+{
+  char *p;
+
+  if (sb->out_of_core)
+    {
+      xfree (sb->buf); sb->buf = NULL;
+      return NULL;
+    }
+
+  sb->buf[sb->len] = 0;
+  p = sb->buf;
+  sb->buf = NULL;
+  sb->out_of_core = 1; /* make sure the caller does an init before reuse */
+  return p;
+}
+
+
 /* Assume that der is a buffer of length DERLEN with a DER encoded
  Asn.1 structure like this:
  
@@ -177,35 +301,256 @@ _ksba_keyinfo_to_sexp (const unsigned char *der, size_t derlen,
                        char **r_string)
 {
   KsbaError err;
+  int c;
   size_t nread, off, len;
   int algoidx;
+  const unsigned char *ctrl;
+  const char *elem;
+  struct stringbuf sb;
 
   *r_string = NULL;
 
-  printf ("parsing keyinfo ...\n");
-
+  /* check the outer sequence */
+  if (!derlen)
+    return KSBA_Invalid_Keyinfo;
+  c = *der++; derlen--;
+  if ( c != 0x30 )
+    return KSBA_Unexpected_Tag; /* not a SEQUENCE */
+  TLV_LENGTH();
+  /* and now the inner part */
   err = get_algorithm (der, derlen, &nread, &off, &len);
   if (err)
     return err;
   
   /* look into our table of supported algorithms */
-  for (algoidx=0; algo_table[algoidx].oid; algoidx++)
+  for (algoidx=0; pk_algo_table[algoidx].oid; algoidx++)
     {
-      if ( len == algo_table[algoidx].oidlen
-           && !memcmp (der+off, algo_table[algoidx].oid, len))
+      if ( len == pk_algo_table[algoidx].oidlen
+           && !memcmp (der+off, pk_algo_table[algoidx].oid, len))
         break;
     }
-  if (!algo_table[algoidx].oid)
-    return KSAB_Unknown_Algorithm;
+  if (!pk_algo_table[algoidx].oid)
+    return KSBA_Unknown_Algorithm;
+  if (!pk_algo_table[algoidx].supported)
+    return KSBA_Unsupported_Algorithm;
+
+  der += nread;
+  derlen -= nread;
+
+  if (!derlen)
+    return KSBA_Invalid_Keyinfo;
+  c = *der++; derlen--;
+  if (c) 
+    fprintf (stderr, "warning: number of unused bits is not zero\n");
+
+  /* fixme: we should calculate the initial length form the size of the
+     sequence, so that we don't neen a realloc later */
+  init_stringbuf (&sb, 100);
+  put_stringbuf (&sb, "(public-key(");
+  put_stringbuf (&sb, pk_algo_table[algoidx].algo_string);
+
+  /* FIXME: We don't release the stringbuf in case of error
+     better let the macro jump to a label */
+  elem = pk_algo_table[algoidx].elem_string; 
+  ctrl = pk_algo_table[algoidx].ctrl_string; 
+  for (; *elem; ctrl++, elem++)
+    {
+      int is_int;
+
+      if (!derlen)
+        return KSBA_Invalid_Keyinfo;
+      c = *der++; derlen--;
+      if ( c != *ctrl )
+        return KSBA_Unexpected_Tag; /* not the required tag */
+      is_int = c == 0x02;
+      TLV_LENGTH ();
+      if (is_int && *elem != '-')
+        { /* take this integer */
+          char tmp[100];
+          int i, n;
+          
+          strcpy (tmp, "(. #"); 
+          tmp[1] = *elem;
+          put_stringbuf (&sb, tmp);
+          for (i=n=0; n < len; n++)
+            {
+              if (!derlen)
+                return KSBA_Invalid_Keyinfo;
+              c = *der++; derlen--;
+              sprintf (tmp+2*i, "%02X", c);
+              if ( !(++i%10) )
+                {
+                  put_stringbuf (&sb, tmp);
+                  i=0;
+                }
+            }
+          if (i)
+            put_stringbuf (&sb, tmp);
+          put_stringbuf (&sb, "#)");
+        }
+    }
+  put_stringbuf (&sb, "))");
+  
+  *r_string = get_stringbuf (&sb);
+  if (!*r_string)
+    return KSBA_Out_Of_Core;
+
+  return 0;
+}
+
+
+/* Assume that der is a buffer of length DERLEN with a DER encoded
+ Asn.1 structure like this:
+     SEQUENCE { 
+        algorithm    OBJECT IDENTIFIER,
+        parameters   ANY DEFINED BY algorithm OPTIONAL }
+     signature  BIT STRING 
+  
+  We only allow parameters == NULL.
+
+  The function parses this structure and creates a S-Exp suitable to be
+  used as signature value in Libgcrypt:
+  
+  (sig-val
+    (<algo>
+      (<param_name1> <mpi>)
+      ...
+      (<param_namen> <mpi>)
+    ))
+
+ The S-Exp will be returned in a string which the caller must free.
+ We don't pass an ASN.1 node here but a plain memory block.  */
+KsbaError
+_ksba_sigval_to_sexp (const unsigned char *der, size_t derlen,
+                       char **r_string)
+{
+  KsbaError err;
+  int c;
+  size_t nread, off, len;
+  int algoidx;
+  const unsigned char *ctrl;
+  const char *elem;
+  struct stringbuf sb;
+
+  /* FIXME: The entire function is very similar to keyinfo_to_sexp */
 
-  WORK
+  *r_string = NULL;
 
+  err = get_algorithm (der, derlen, &nread, &off, &len);
+  if (err)
+    return err;
+  
+  /* look into our table of supported algorithms */
+  for (algoidx=0; sig_algo_table[algoidx].oid; algoidx++)
+    {
+      if ( len == sig_algo_table[algoidx].oidlen
+           && !memcmp (der+off, sig_algo_table[algoidx].oid, len))
+        break;
+    }
+  if (!sig_algo_table[algoidx].oid)
+    return KSBA_Unknown_Algorithm;
+  if (!sig_algo_table[algoidx].supported)
+    return KSBA_Unsupported_Algorithm;
 
+  der += nread;
+  derlen -= nread;
+
+  if (!derlen)
+    return KSBA_Invalid_Keyinfo;
+  c = *der++; derlen--;
+  if (c) 
+    fprintf (stderr, "warning: number of unused bits is not zero\n");
+
+  /* fixme: we should calculate the initial length form the size of the
+     sequence, so that we don't neen a realloc later */
+  init_stringbuf (&sb, 100);
+  put_stringbuf (&sb, "(sig-val(");
+  put_stringbuf (&sb, sig_algo_table[algoidx].algo_string);
+
+  /* FIXME: We don't release the stringbuf in case of error
+     better let the macro jump to a label */
+  elem = sig_algo_table[algoidx].elem_string; 
+  ctrl = sig_algo_table[algoidx].ctrl_string; 
+  for (; *elem; ctrl++, elem++)
+    {
+      int is_int;
+
+      if ( (*ctrl & 0x80) && !elem[1] )
+        {  /* Hack to allow a raw value */
+          is_int = 1;
+          len = derlen;
+        }
+      else
+        {
+          if (!derlen)
+            return KSBA_Invalid_Keyinfo;
+          c = *der++; derlen--;
+          if ( c != *ctrl )
+            return KSBA_Unexpected_Tag; /* not the required tag */
+          is_int = c == 0x02;
+          TLV_LENGTH ();
+        }
+      if (is_int && *elem != '-')
+        { /* take this integer */
+          char tmp[100];
+          int i, n;
+          
+          strcpy (tmp, "(. #"); 
+          tmp[1] = *elem;
+          put_stringbuf (&sb, tmp);
+          for (i=n=0; n < len; n++)
+            {
+              if (!derlen)
+                return KSBA_Invalid_Keyinfo;
+              c = *der++; derlen--;
+              sprintf (tmp+2*i, "%02X", c);
+              if ( !(++i%10) )
+                {
+                  put_stringbuf (&sb, tmp);
+                  i=0;
+                }
+            }
+          if (i)
+            put_stringbuf (&sb, tmp);
+          put_stringbuf (&sb, "#)");
+        }
+    }
+  put_stringbuf (&sb, "))");
+  
+  *r_string = get_stringbuf (&sb);
+  if (!*r_string)
+    return KSBA_Out_Of_Core;
 
   return 0;
 }
 
 
+/* Take the OID at the given node and map it to a libgcrypt digest algo.
+   Return 0 if the algo is unknown, -1 for an invalid OID 
+   
+   Fixme: This function belongs to another file, but as long as we
+   don't have a generic OID registry we put it here.  */
+int
+_ksba_map_oid_to_digest_algo (const unsigned char *image, AsnNode node) 
+{
+  int algoidx;
+  int off, len;
 
+  if (!node || node->type != TYPE_OBJECT_ID || node->off == -1)
+    return -1;
 
+  off = node->off + node->nhdr;
+  len = node->len;
+  for (algoidx=0; sig_algo_table[algoidx].oid; algoidx++)
+    {
+      if ( len == sig_algo_table[algoidx].oidlen
+           && !memcmp (image + off, sig_algo_table[algoidx].oid, len))
+        break;
+    }
+  if (!sig_algo_table[algoidx].oid)
+    return 0;
+
+  return sig_algo_table[algoidx].digest_algo;
+}
 
index 830273d..1d8cbfb 100644 (file)
 #ifndef KEYINFO_H
 #define KEYINFO_H
 
-KsbaError
-_ksba_keyinfo_to_sexp (const unsigned char *der, size_t derlen,
-                       char **r_string);
+KsbaError _ksba_keyinfo_to_sexp (const unsigned char *der, size_t derlen,
+                                 char **r_string);
+KsbaError _ksba_sigval_to_sexp (const unsigned char *der, size_t derlen,
+                                char **r_string);
+
+int _ksba_map_oid_to_digest_algo (const unsigned char *image, AsnNode node);
+
 
 
 #endif /*KEYINFO_H*/
index 574466b..96a93ff 100644 (file)
@@ -55,6 +55,7 @@ typedef enum {
   KSBA_Unexpected_Tag = 20,
   KSBA_Not_DER_Encoded = 21,
   KSBA_Unknown_Algorithm = 22,
+  KSBA_Unsupported_Algorithm = 23,
 } KsbaError;
 
 typedef enum {
@@ -85,10 +86,19 @@ typedef struct ksba_asn_tree_s *KsbaAsnTree;
 KsbaCert ksba_cert_new (void);
 void     ksba_cert_release (KsbaCert cert);
 KsbaError ksba_cert_read_der (KsbaCert cert, KsbaReader reader);
+KsbaError ksba_cert_hash (KsbaCert cert,
+                          void (*hasher)(void *,
+                                         const unsigned char *,
+                                         size_t length), 
+                          void *hasher_arg);
+int  ksba_cert_get_digest_algo (KsbaCert cert);
 unsigned char *ksba_cert_get_serial (KsbaCert cert);
 char *ksba_cert_get_issuer (KsbaCert cert);
 time_t ksba_cert_get_validity (KsbaCert cert, int what);
 char *ksba_cert_get_subject (KsbaCert cert);
+char *ksba_cert_get_public_key (KsbaCert cert);
+char *ksba_cert_get_sig_val (KsbaCert cert);
+
 
 
 /*-- reader.c --*/
diff --git a/src/shared.h b/src/shared.h
new file mode 100644 (file)
index 0000000..1ef4033
--- /dev/null
@@ -0,0 +1,44 @@
+/* shared.h - values shared with other software 
+ *      Copyright (C) 2001 g10 Code GmbH
+ *
+ * This file is part of KSBA.
+ *
+ * KSBA 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * KSBA 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifndef SHARED_H
+#define SHARED_H
+
+#ifdef GCRYPT_VERSION 
+/* It is pretty useless to use this file if we would link this library
+   to Libgcrypt anyway */
+#error please make shure that gcrypt.h is not included
+#endif
+
+enum gcry_md_algos {
+    GCRY_MD_NONE    = 0,
+    GCRY_MD_MD5     = 1,
+    GCRY_MD_SHA1    = 2,
+    GCRY_MD_RMD160  = 3,
+    GCRY_MD_TIGER   = 6
+};
+
+
+
+#endif /*SHARED_H*/
+
+
+
+
index 4d2fac0..d6052c9 100644 (file)
@@ -76,6 +76,16 @@ print_time (time_t t)
 }
 
 static void
+print_dn (char *p)
+{
+
+  if (!p)
+    fputs ("error", stdout);
+  else
+    printf ("`%s'", p);
+}
+
+static void
 one_file (const char *fname)
 {
   KsbaError err;
@@ -83,6 +93,7 @@ one_file (const char *fname)
   KsbaReader r;
   KsbaCert cert;
   unsigned char *p;
+  char *dn;
   time_t t;
 
   fp = fopen (fname, "r");
@@ -123,6 +134,20 @@ one_file (const char *fname)
   print_time (t);
   putchar ('\n');
 
+  dn = ksba_cert_get_issuer (cert);
+  fputs ("issuer: ", stdout);
+  print_dn (dn);
+  ksba_free (dn);
+  putchar ('\n');
+
+  dn = ksba_cert_get_subject (cert);
+  fputs ("subject: ", stdout);
+  print_dn (dn);
+  ksba_free (dn);
+  putchar ('\n');
+
+  printf ("hash algo: %d\n", ksba_cert_get_digest_algo (cert));
+
   ksba_cert_hash (cert, NULL, NULL);