Reworked the ASN.1 parser a bit, changed a couple of things and made
authorWerner Koch <wk@gnupg.org>
Wed, 31 Oct 2001 17:53:51 +0000 (17:53 +0000)
committerWerner Koch <wk@gnupg.org>
Wed, 31 Oct 2001 17:53:51 +0000 (17:53 +0000)
the ber-dump basically work.  Added library configuration stuff.

16 files changed:
src/Makefile.am
src/asn1-func.c
src/asn1-func.h
src/asn1-gentables.c
src/asn1-parse.y
src/ber-decoder.c
src/cert.c
src/cms.asn
src/ksba-config.in [new file with mode: 0644]
src/ksba.h
src/oid.c [new file with mode: 0644]
src/reader.c
src/reader.h
src/tmttv2.asn
src/util.c
src/util.h

index 0b8f079..89fa716 100644 (file)
 
 ## Process this file with automake to produce Makefile.in
 
-#EXTRA_DIST = 
+EXTRA_DIST = ksba-config.in 
 BUILT_SOURCES = asn1-parse.c
-#bin_SCRIPTS = ksba-config
-#m4datadir = $(datadir)/aclocal
-#m4data_DATA = ksba.m4
-
+bin_SCRIPTS = ksba-config
+include_HEADERS = ksba.h
+lib_LTLIBRARIES = libksba.la
 noinst_PROGRAMS = asn1-gentables ber-dump
 
-#include_HEADERS = ksba.h
-#lib_LTLIBRARIES = libksba.la
-
-#libksba_la_LDFLAGS = -version-info \
-#      @LIBKSBA_LT_CURRENT@:@LIBKSBA_LT_REVISION@:@LIBKSBA_LT_AGE@
-#libksba_la_INCLUDES = -I$(top_srcdir)/foo
+libksba_la_LDFLAGS = -version-info \
+      @LIBKSBA_LT_CURRENT@:@LIBKSBA_LT_REVISION@:@LIBKSBA_LT_AGE@
+libksba_la_INCLUDES = -I$(top_srcdir)/lib 
 
-#libksba_la_SOURCES = \
-#      ksba.h \
-#      asn1-der.c asn1-der.h
+libksba_la_SOURCES = \
+       ksba.h \
+       ber-decoder.c ber-decoder.h \
+       reader.c reader.h \
+       asn1-parse.y asn1-parse.h \
+       asn1-func.c asn1-func.h \
+       oid.c \
+       util.c util.h   
 
 asn1_gentables_SOURCES = \
        asn1-gentables.c \
        asn1-parse.y asn1-parse.h \
        asn1-func.c asn1-func.h \
+       oid.c \
        util.c util.h   
 
 ber_dump_SOURCES = \
@@ -51,6 +53,7 @@ ber_dump_SOURCES = \
        reader.c reader.h \
        asn1-parse.y asn1-parse.h \
        asn1-func.c asn1-func.h \
+       oid.c \
        util.c util.h   
 
 
index 66933af..2c40d43 100755 (executable)
 
 #include "ksba.h"
 #include "asn1-func.h"
-#include "asn1-der.h"
 #include "util.h"
 
 static int expand_identifier (AsnNode * node, AsnNode root);
 static int type_choice_config (AsnNode  node);
 
-
 static char *  /* FIXME: This is error prone */
 _asn1_ltostr (long v, char *str)
 {
@@ -135,6 +133,11 @@ _ksba_asn_set_value (AsnNode node,
       node->value.v_long = *(long *)value;
       break;
 
+    case VALTYPE_ULONG:
+      return_if_fail (sizeof (unsigned long) == len);
+      node->value.v_ulong = *(unsigned long *)value;
+      break;
+
     default:
       return_if_fail (0);
     }
@@ -169,6 +172,10 @@ copy_value (AsnNode d, const AsnNode s)
       len = sizeof (long);
       buf = &s->value.v_long;
       break;
+    case VALTYPE_ULONG:
+      len = sizeof (unsigned long);
+      buf = &s->value.v_ulong;
+      break;
 
     default:
       return_if_fail (0);
@@ -176,6 +183,20 @@ copy_value (AsnNode d, const AsnNode s)
   _ksba_asn_set_value (d, s->valuetype, buf, len);
 }
 
+static AsnNode 
+copy_node (const AsnNode s)
+{
+  AsnNode d = add_node (s->type);
+
+  if (s->name)
+    d->name = xstrdup (s->name);
+  d->flags = s->flags;
+  copy_value (d, s);
+  return d;
+}
+
+
+
 
 /* Change the name field of the node to NAME.  
    NAME may be NULL */
@@ -430,6 +451,9 @@ print_value (AsnNode node, FILE *fp)
     case VALTYPE_LONG:
       fprintf (fp, "%ld", node->value.v_long);
       break;
+    case VALTYPE_ULONG:
+      fprintf (fp, "%lu", node->value.v_ulong);
+      break;
     default:
       return_if_fail (0);
     }
@@ -447,7 +471,8 @@ _ksba_asn_node_dump (AsnNode p, FILE *fp)
     case TYPE_IDENTIFIER:   typestr = "IDENTIFIER"; break;
     case TYPE_INTEGER:     typestr = "INTEGER"; break;
     case TYPE_ENUMERATED:   typestr = "ENUMERATED"; break;
-    case TYPE_TIME:        typestr = "TIME"; break;
+    case TYPE_UTC_TIME:            typestr = "UTCTIME"; break;
+    case TYPE_GENERALIZED_TIME: typestr = "GENERALIZEDTIME"; break;
     case TYPE_BOOLEAN:     typestr = "BOOLEAN"; break;
     case TYPE_SEQUENCE:            typestr = "SEQUENCE"; break;
     case TYPE_BIT_STRING:   typestr = "BIT_STR"; break;
@@ -462,6 +487,11 @@ _ksba_asn_node_dump (AsnNode p, FILE *fp)
     case TYPE_SET_OF:      typestr = "SET_OF"; break;
     case TYPE_CHOICE:      typestr = "CHOICE"; break;
     case TYPE_DEFINITIONS:  typestr = "DEFINITIONS"; break;
+    case TYPE_UTF8_STRING:       typestr = "UTF8_STRING"; break;
+    case TYPE_NUMERIC_STRING:    typestr = "NUMERIC_STRING"; break;
+    case TYPE_PRINTABLE_STRING:  typestr = "PRINTABLE_STRING"; break;
+    case TYPE_TELETEX_STRING:    typestr = "TELETEX_STRING"; break; 
+    case TYPE_IA5_STRING:        typestr = "IA5_STRING"; break;
     default:               typestr = "ERROR\n"; break;
     }
 
@@ -502,14 +532,16 @@ _ksba_asn_node_dump (AsnNode p, FILE *fp)
     fputs (",size", fp);
   if (p->flags.has_defined_by)
     fputs (",def_by", fp);
-  if (p->flags.is_utc_time)
-    fputs (",utc", fp);
   if (p->flags.has_imports)
     fputs (",imports", fp);
   if (p->flags.assignment)
     fputs (",assign",fp);
   if (p->flags.in_set)
     fputs (",in_set",fp);
+  if (p->flags.in_choice)
+    fputs (",in_choice",fp);
+  if (p->flags.in_array)
+    fputs (",in_array",fp);
   if (p->flags.not_used)
     fputs (",not_used",fp);
   
@@ -521,6 +553,9 @@ _ksba_asn_node_dump (AsnNode p, FILE *fp)
  * @tree: A Parse Tree
  * @name: Name of the element or NULL
  * @fp: dump to this stream
+ *
+ * If the first character of the name is a '<' the expanded version of
+ * the tree will be printed.
  * 
  * This function is a debugging aid.
  **/
@@ -528,15 +563,26 @@ void
 ksba_asn_tree_dump (KsbaAsnTree tree, const char *name, FILE *fp)
 {
   AsnNode p, root;
-  int k, indent = 0;
+  int k, expand=0, indent = 0;
 
   if (!tree || !tree->parse_tree)
     return;
 
+  if ( name && *name== '<')
+    {
+      expand = 1;
+      name++;
+      if (!*name)
+        name = NULL;
+    }
+
   root = name? _ksba_asn_find_node (tree->parse_tree, name) : tree->parse_tree;
   if (!root)
     return;
 
+  if (expand)
+    root = _ksba_asn_expand_tree (root);
+
   p = root;
   while (p)
     {
@@ -576,6 +622,8 @@ ksba_asn_tree_dump (KsbaAsnTree tree, const char *name, FILE *fp)
            }
        }
     }
+
+  /* FIXME: release the tree if expanded */
 }
 
 int
@@ -632,7 +680,7 @@ AsnNode
 _asn1_copy_structure3 (AsnNode  source_node)
 {
   AsnNode dest_node, p_s, p_d, p_d_prev;
-  int len, len2;
+  int len;
   enum { DOWN, UP, RIGHT } move;
 
   if (source_node == NULL)
@@ -959,51 +1007,47 @@ ksba_asn1_write_value (AsnNode  node_root, char *name, unsigned char *value,
          return ASN_VALUE_NOT_VALID;
       _ksba_asn_set_value (node, VALTYPE_CSTR, value, 0);
       break;
-    case TYPE_TIME:
-      if (node->flags.is_utc_time)
-       {
-         if (strlen (value) < 11)
-           return ASN_VALUE_NOT_VALID;
-         for (k = 0; k < 10; k++)
-           if (!isdigit (value[k]))
-             return ASN_VALUE_NOT_VALID;
-         switch (strlen (value))
-           {
-           case 11:
-             if (value[10] != 'Z')
-               return ASN_VALUE_NOT_VALID;
-             break;
-           case 13:
-             if ((!isdigit (value[10])) || (!isdigit (value[11])) ||
-                 (value[12] != 'Z'))
-               return ASN_VALUE_NOT_VALID;
-             break;
-           case 15:
-             if ((value[10] != '+') && (value[10] != '-'))
-               return ASN_VALUE_NOT_VALID;
-             for (k = 11; k < 15; k++)
-               if (!isdigit (value[k]))
-                 return ASN_VALUE_NOT_VALID;
-             break;
-           case 17:
-             if ((!isdigit (value[10])) || (!isdigit (value[11])))
-               return ASN_VALUE_NOT_VALID;
-             if ((value[12] != '+') && (value[12] != '-'))
-               return ASN_VALUE_NOT_VALID;
-             for (k = 13; k < 17; k++)
-               if (!isdigit (value[k]))
-                 return ASN_VALUE_NOT_VALID;
-             break;
-           default:
-             return ASN_VALUE_NOT_FOUND;
-           }
-         _ksba_asn_set_value (node, VALTYPE_CSTR, value, 0);
-       }
-      else
-       {                       /* GENERALIZED TIME */
-         if (value)
-           _ksba_asn_set_value (node, VALTYPE_CSTR, value, 0);
-       }
+    case TYPE_UTC_TIME:
+      if (strlen (value) < 11)
+        return ASN_VALUE_NOT_VALID;
+      for (k = 0; k < 10; k++)
+        if (!isdigit (value[k]))
+          return ASN_VALUE_NOT_VALID;
+      switch (strlen (value))
+        {
+        case 11:
+          if (value[10] != 'Z')
+            return ASN_VALUE_NOT_VALID;
+          break;
+        case 13:
+          if ((!isdigit (value[10])) || (!isdigit (value[11])) ||
+              (value[12] != 'Z'))
+            return ASN_VALUE_NOT_VALID;
+          break;
+        case 15:
+          if ((value[10] != '+') && (value[10] != '-'))
+            return ASN_VALUE_NOT_VALID;
+          for (k = 11; k < 15; k++)
+            if (!isdigit (value[k]))
+              return ASN_VALUE_NOT_VALID;
+          break;
+        case 17:
+          if ((!isdigit (value[10])) || (!isdigit (value[11])))
+            return ASN_VALUE_NOT_VALID;
+          if ((value[12] != '+') && (value[12] != '-'))
+            return ASN_VALUE_NOT_VALID;
+          for (k = 13; k < 17; k++)
+            if (!isdigit (value[k]))
+              return ASN_VALUE_NOT_VALID;
+          break;
+        default:
+          return ASN_VALUE_NOT_FOUND;
+        }
+      _ksba_asn_set_value (node, VALTYPE_CSTR, value, 0);
+      break;
+    case TYPE_GENERALIZED_TIME:
+      if (value)
+        _ksba_asn_set_value (node, VALTYPE_CSTR, value, 0);
       break;
     case TYPE_OCTET_STRING:
       _asn1_length_der (len, NULL, &len2);
@@ -1178,7 +1222,8 @@ ksba_asn_read_value (AsnNode root, const char *name,
          PUT_STR_VALUE (value, value_size, node->value);
        }
       break;
-    case TYPE_TIME:
+    case TYPE_UTC_TIME:
+    case TYPE_GENERALIZED_TIME:
       PUT_STR_VALUE (value, value_size, node->value);
       break;
     case TYPE_OCTET_STRING:
@@ -1307,6 +1352,35 @@ _ksba_asn_walk_tree (AsnNode root, AsnNode node)
   return node;
 }
 
+AsnNode
+_ksba_asn_walk_tree_up_right (AsnNode root, AsnNode node)
+{
+  if (node)
+    {
+      if (node == root)
+        node = NULL;
+      else
+        {
+          for (;;)
+            {
+              node = find_up (node);
+              if (node == root)
+                {
+                  node = NULL;
+                  break;
+                }
+              if (node->right)
+                {
+                  node = node->right;
+                  break;
+                }
+            }
+        }
+    }
+
+  return node;
+}
+
 /* walk over the tree and change the value type of all integer types
    from string to long. */
 int
@@ -1421,6 +1495,10 @@ expand_identifier (AsnNode * node, AsnNode root)
             p2->flags.has_default = 1;
           if (p->flags.in_set)
             p2->flags.in_set = 1;;
+          if (p->flags.in_choice)
+            p2->flags.in_choice = 1;;
+          if (p->flags.in_array)
+            p2->flags.in_array = 1;;
           if (p->flags.not_used)
             p2->flags.not_used = 1;
           
@@ -1599,8 +1677,129 @@ _ksba_asn_type_set_config (AsnNode node)
                 }
             }
         }
+      else if (p->type == TYPE_CHOICE)
+        {
+          for (p2 = p->down; p2; p2 = p2->right)
+            {
+              if (p2->type != TYPE_TAG)
+                p2->flags.in_choice = 1;
+            }
+        }
+      else if (p->type == TYPE_SEQUENCE_OF || p->type == TYPE_SET_OF)
+        {
+          for (p2 = p->down; p2; p2 = p2->right)
+            p2->flags.in_array = 1;
+        }
     }
 }
 
+
+static AsnNode
+resolve_identifier (AsnNode root, AsnNode node)
+{
+  char *buf;
+
+  return_null_if_fail (root);
+  return_null_if_fail (node->valuetype == VALTYPE_CSTR);
+
+  buf = alloca (strlen(root->name)+strlen(node->value.v_cstr)+2);
+  return_null_if_fail (buf);
+  strcpy (stpcpy (stpcpy (buf, root->name), "."), node->value.v_cstr);
+  return _ksba_asn_find_node (root, buf);
+}
+
+
+static AsnNode
+do_expand_tree (AsnNode src_root, AsnNode s)
+{
+  AsnNode first=NULL, dprev=NULL, d, down, tmp;
+
+  for (; s; s=s->right )
+    {
+      down = s->down;
+      if (s->type == TYPE_IDENTIFIER)
+        {
+          AsnNode s2, *dp;
+
+          d = resolve_identifier (src_root, s);
+          if (!d)
+            {
+              printf ("RESOLVING IDENTIFIER FAILED\n");
+              continue;
+            }
+          down = d->down;
+          d = copy_node (d);
+          if (s->flags.is_optional)
+            d->flags.is_optional = 1;
+          if (s->flags.in_choice)
+            d->flags.in_choice = 1;
+          if (s->flags.in_array)
+            d->flags.in_array = 1;
+          /* we don't want the resolved name - change it back */
+          _ksba_asn_set_name (d, s->name);
+          /* copy the default and tag attributes */
+          tmp = NULL;
+          dp = &tmp;
+          for (s2=s->down; s2; s2=s2->right)
+            {
+              AsnNode x;
+
+              x = copy_node (s2);
+              x->left = *dp? *dp : d;
+              *dp = x;
+              dp = &(*dp)->right;
+
+              if (x->type == TYPE_TAG)
+                d->flags.has_tag =1;
+              else if (x->type == TYPE_DEFAULT)
+                d->flags.has_default =1;
+            }
+          d->down = tmp;
+        }
+      else
+        d = copy_node (s);
+
+      if (!first)
+        first = d;
+      else
+        {
+          dprev->right = d;
+          d->left = dprev;
+        }
+      dprev = d;
+      if (down)
+        {
+          tmp = do_expand_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;
+}
+
   
-  
+/* Expand the syntax tree so that all references are resolved and we
+   are able to store values right in the tree (except for set/sequence
+   of).  This expanded tree is also an requirement for doing the DER
+   decoding as the resolving of identifiers leads to a lot of
+   problems.  We use more memory of course, but this is negligible
+   because the entire code wioll be simpler and faster */
+AsnNode
+_ksba_asn_expand_tree (AsnNode src_root)
+{
+  /* FIXME: add a too deep recursion check */
+  return do_expand_tree (src_root, src_root);
+}
index a8ee841..023d257 100755 (executable)
@@ -39,17 +39,39 @@ enum {
   ASN_MEM_ERROR           = 12
 };
 
-
+/* The values below 128 correspond to the  Universal tag values */
 typedef enum {
   TYPE_NONE = 0,
   TYPE_BOOLEAN = 1,
   TYPE_INTEGER = 2,
   TYPE_BIT_STRING = 3,
   TYPE_OCTET_STRING = 4,
+  TYPE_NULL = 5,
   TYPE_OBJECT_ID = 6,
+  TYPE_OBJECT_DESCRIPTOR = 7,
+  TYPE_EXTERNAL = 8,
+  TYPE_REAL = 9,
+  TYPE_ENUMERATED = 10,
+  TYPE_EMBEDDED_PDV = 11,
+  TYPE_UTF8_STRING = 12,
+  TYPE_REALTIVE_OID = 13,
   TYPE_SEQUENCE = 16,
   TYPE_SET = 17,
-  TYPE_CONSTANT,
+  TYPE_NUMERIC_STRING = 18,
+  TYPE_PRINTABLE_STRING = 19,
+  TYPE_TELETEX_STRING = 20,
+  TYPE_VIDEOTEX_STRING = 21,
+  TYPE_IA5_STRING = 22,
+  TYPE_UTC_TIME = 23,
+  TYPE_GENERALIZED_TIME = 24,
+  TYPE_GRAPHIC_STRING = 25,
+  TYPE_VISIBLE_STRING = 26,
+  TYPE_GENERAL_STRING = 27,
+  TYPE_UNIVERSAL_STRING = 28,
+  TYPE_CHARACTER_STRING = 29,
+  TYPE_BMP_STRING = 30,
+  /* the following values do not correspond to an Universal tag */
+  TYPE_CONSTANT = 128,
   TYPE_IDENTIFIER,
   TYPE_TAG,
   TYPE_DEFAULT,
@@ -58,11 +80,8 @@ typedef enum {
   TYPE_ANY,
   TYPE_SET_OF,
   TYPE_DEFINITIONS,
-  TYPE_TIME,
   TYPE_CHOICE,
-  TYPE_IMPORTS,
-  TYPE_NULL,
-  TYPE_ENUMERATED
+  TYPE_IMPORTS
 } node_type_t;
 
 
@@ -89,11 +108,14 @@ struct node_flag_s {
   int is_true:1;
   int has_default:1;  /* node has a default value (fixme:needed???)*/
   int is_optional:1;
-  int is_utc_time:1;  /* the time type is acually an UTC time */
   int in_set:1;       
+  int in_choice:1;
+  int in_array:1;
   int not_used:1;     
   int help_down:1;    /* helper for create_tree */
   int help_right:1;   /* helper for create_tree */
+  int tag_seen:1;
+  int skip_this:1;   /* helper */
 };
 
 enum asn_value_type {
@@ -101,7 +123,8 @@ enum asn_value_type {
   VALTYPE_BOOL,
   VALTYPE_CSTR,
   VALTYPE_MEM,
-  VALTYPE_LONG
+  VALTYPE_LONG,
+  VALTYPE_ULONG
 };
 
 union asn_value_u {
@@ -112,6 +135,7 @@ union asn_value_u {
     unsigned char *buf;
   } v_mem;
   long v_long;
+  unsigned long v_ulong;
 };
 
 /******************************************************/
@@ -158,6 +182,7 @@ void _ksba_asn_set_value (AsnNode node, enum asn_value_type vtype,
                           const void *value, size_t len);
 void _ksba_asn_set_name (AsnNode node, const char *name);
 AsnNode _ksba_asn_walk_tree (AsnNode root, AsnNode node);
+AsnNode _ksba_asn_walk_tree_up_right (AsnNode root, AsnNode node);
 AsnNode _ksba_asn_find_node(AsnNode pointer,const char *name);
 int _ksba_asn_check_identifier(AsnNode node);
 int _ksba_asn_change_integer_value(AsnNode node);
@@ -165,6 +190,7 @@ int _ksba_asn_delete_not_used(AsnNode node);
 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);
 
 
 /*-- asn1-func.c --*/
index 96ecbd1..5eb82df 100644 (file)
@@ -138,7 +138,6 @@ create_static_structure (AsnNode pointer, const char *file_name)
       fputs (p->flags.is_true        ? ",1":",0", file);
       fputs (p->flags.has_default     ? ",1":",0", file);
       fputs (p->flags.is_optional    ? ",1":",0", file);
-      fputs (p->flags.is_utc_time    ? ",1":",0", file);
       fputs (p->flags.in_set         ? ",1":",0", file);
       fputs (p->flags.not_used       ? ",1":",0", file);
       fputs (p->flags.help_down      ? ",1":",0", file);
@@ -150,6 +149,8 @@ create_static_structure (AsnNode pointer, const char *file_name)
       else if (p->valuetype == VALTYPE_LONG
                && p->type == TYPE_INTEGER && p->flags.assignment)
         fprintf (file, ",\"%ld\"", p->value.v_long);
+      else if (p->valuetype == VALTYPE_ULONG)
+        fprintf (file, ",\"%lu\"", p->value.v_ulong);
       else
         {
           if (p->valuetype)
@@ -189,7 +190,7 @@ one_file (FILE *fp, const char *fname)
   else 
     {
       if (dump_only)
-        ksba_asn_tree_dump (tree, NULL, stdout);
+        ksba_asn_tree_dump (tree, dump_only==2? "<":NULL, stdout);
       else
         create_static_structure (tree->parse_tree, fname);
     }
@@ -202,7 +203,8 @@ main (int argc, char **argv)
   if (!argc || (argc > 1 &&
                 (!strcmp (argv[1],"--help") || !strcmp (argv[1],"-h"))) )
     {
-      fputs ("usage: asn1-gentables [--dump] [files.asn]\n", stderr);
+      fputs ("usage: asn1-gentables [--dump[-expanded]] [files.asn]\n",
+             stderr);
       return 0;
     }
   
@@ -212,6 +214,12 @@ main (int argc, char **argv)
       argc--; argv++;
       dump_only = 1;
     }
+  else if (argc && !strcmp (*argv,"--dump-expanded"))
+    {
+      argc--; argv++;
+      dump_only = 2;
+    }
+
 
   if (!argc)
     one_file (stdin, "-");
@@ -233,3 +241,4 @@ main (int argc, char **argv)
     }
   return error_counter? 1:0;
 }
+
index bb097c5..a87d37f 100755 (executable)
@@ -41,6 +41,7 @@
 #include "asn1-parse.h"
 #include "asn1-func.h"
 
+/*#define YYDEBUG 1*/
 #define YYERROR_VERBOSE = 1
 #define MAX_STRING_LENGTH 129
 
@@ -53,6 +54,7 @@ enum {
 struct parser_control_s {
   FILE *fp;
   int lineno;
+  int debug;
   int result_parse;
   AsnNode parse_tree;
   AsnNode all_nodes;
@@ -78,6 +80,7 @@ static AsnNode new_node (struct parser_control_s *parsectl, node_type_t type);
 #define NEW_NODE(a)  (new_node (PARSECTL, (a)))
 static void set_name (AsnNode node, const char *name);
 static void set_str_value (AsnNode node, const char *text);
+static void set_ulong_value (AsnNode node, const char *text);
 static void set_right (AsnNode node, AsnNode right);
 static void append_right (AsnNode node, AsnNode right);
 static void set_down (AsnNode node, AsnNode down);
@@ -125,6 +128,15 @@ static void yyerror (const char *s);
 %token FROM
 %token IMPORTS
 %token ENUMERATED
+%token UTF8STRING
+%token NUMERICSTRING
+%token PRINTABLESTRING
+%token TELETEXSTRING  
+%token IA5STRING
+%token UNIVERSALSTRING
+%token BMPSTRING
+
+
 
 %type <node> octet_string_def constant constant_list type_assig_right 
 %type <node> integer_def type_assig type_assig_list sequence_def type_def
@@ -133,7 +145,10 @@ static void yyerror (const char *s);
 %type <node> constant_def type_constant type_constant_list definitions
 %type <node> definitions_id Time bit_element bit_element_list set_def
 %type <node> identifier_list imports_def tag_type tag type_assig_right_tag
-%type <node> type_assig_right_tag_default enumerated_def
+%type <node> type_assig_right_tag_default enumerated_def string_def
+%type <node> utf8_string_def numeric_string_def printable_string_def
+%type <node> teletex_string_def ia5_string_def universal_string_def
+%type <node> bmp_string_def
 %type <str>  pos_num neg_num pos_neg_num pos_neg_identifier num_identifier 
 %type <constant> class explicit_implicit
 
@@ -235,13 +250,13 @@ tag_type :  '[' NUM ']'
                 {
                   $$ = NEW_NODE (TYPE_TAG); 
                   $$->flags.class = CLASS_CONTEXT;
-                  set_str_value ($$, $2);
+                  set_ulong_value ($$, $2);
                 }
           | '[' class NUM ']' 
                 {
                   $$ = NEW_NODE (TYPE_TAG);
                   $$->flags.class = $2;
-                  set_str_value ($$, $3);
+                  set_ulong_value ($$, $3);
                 }
 ;
 
@@ -305,12 +320,11 @@ boolean_def: BOOLEAN
 
 Time:   UTCTime       
           {
-            $$ = NEW_NODE (TYPE_TIME);
-            $$->flags.is_utc_time = 1;
+            $$ = NEW_NODE (TYPE_UTC_TIME);
           } 
       | GeneralizedTime  
           { 
-            $$ = NEW_NODE (TYPE_TIME);
+            $$ = NEW_NODE (TYPE_GENERALIZED_TIME);
           } 
 ;
 
@@ -351,6 +365,79 @@ octet_string_def : OCTET STRING
                      }
 ;
 
+utf8_string_def:   UTF8STRING      { $$ = NEW_NODE (TYPE_UTF8_STRING); }
+                 | UTF8STRING size_def
+                     {
+                       $$ = NEW_NODE (TYPE_UTF8_STRING);
+                       $$->flags.has_size = 1;
+                       set_down ($$,$2);
+                     }
+;
+numeric_string_def:   NUMERICSTRING  { $$ = NEW_NODE (TYPE_NUMERIC_STRING); }
+                    | NUMERICSTRING size_def
+                     {
+                       $$ = NEW_NODE (TYPE_NUMERIC_STRING);
+                       $$->flags.has_size = 1;
+                       set_down ($$,$2);
+                     }
+;
+printable_string_def:  PRINTABLESTRING 
+                        { $$ = NEW_NODE (TYPE_PRINTABLE_STRING); }
+                     | PRINTABLESTRING size_def
+                        { 
+                          $$ = NEW_NODE (TYPE_PRINTABLE_STRING);
+                          $$->flags.has_size = 1;
+                          set_down ($$,$2);
+                        }
+;
+teletex_string_def:   TELETEXSTRING
+                       { $$ = NEW_NODE (TYPE_TELETEX_STRING); }
+                   | TELETEXSTRING size_def
+                     {
+                       $$ = NEW_NODE (TYPE_TELETEX_STRING);
+                       $$->flags.has_size = 1;
+                       set_down ($$,$2);
+                     }
+;
+ia5_string_def:   IA5STRING      { $$ = NEW_NODE (TYPE_IA5_STRING); }
+                | IA5STRING size_def
+                     {
+                       $$ = NEW_NODE (TYPE_IA5_STRING);
+                       $$->flags.has_size = 1;
+                       set_down ($$,$2);
+                     }
+;
+universal_string_def:   UNIVERSALSTRING
+                         { $$ = NEW_NODE (TYPE_UNIVERSAL_STRING); }
+                      | UNIVERSALSTRING size_def
+                         {
+                           $$ = NEW_NODE (TYPE_UNIVERSAL_STRING);
+                           $$->flags.has_size = 1;
+                           set_down ($$,$2);
+                         }
+;
+bmp_string_def:    BMPSTRING      { $$ = NEW_NODE (TYPE_BMP_STRING); }
+                 | BMPSTRING size_def
+                     {
+                       $$ = NEW_NODE (TYPE_BMP_STRING);
+                       $$->flags.has_size = 1;
+                       set_down ($$,$2);
+                     }
+;
+
+
+string_def:  utf8_string_def
+           | numeric_string_def
+           | printable_string_def
+           | teletex_string_def
+           | ia5_string_def
+           | universal_string_def
+           | bmp_string_def
+;
+
+
+
+
 bit_element :  IDENTIFIER'('NUM')'
                  {
                    $$ = NEW_NODE (TYPE_CONSTANT);
@@ -411,6 +498,7 @@ type_assig_right: IDENTIFIER
                 | integer_def        {$$=$1;}
                 | enumerated_def     {$$=$1;}
                 | boolean_def        {$$=$1;}
+                | string_def         {$$=$1;}
                 | Time            
                 | octet_string_def   {$$=$1;}
                 | bit_string_def     {$$=$1;}
@@ -431,10 +519,12 @@ type_assig_right_tag :   type_assig_right
                            }
                        | tag type_assig_right
                            {
-                             $2->flags.has_tag = 1;
-                             $$ = $2;
-                             set_right ($1, $$->down );
-                             set_down ($$, $1);
+/*                               $2->flags.has_tag = 1; */
+/*                               $$ = $2; */
+/*                               set_right ($1, $$->down ); */
+/*                               set_down ($$, $1); */
+                             $$ = $1;
+                             set_down ($$, $2)
                            }
 ;
 
@@ -445,7 +535,8 @@ type_assig_right_tag_default : type_assig_right_tag
                              | type_assig_right_tag default  
                                  {
                                    $1->flags.has_default = 1;
-                                   set_right ($2, $$->down);
+                                   $$ = $1;
+                                   set_right ($2, $$->down); 
                                    set_down ($$, $2);
                                  }
                              | type_assig_right_tag OPTIONAL  
@@ -457,7 +548,7 @@ type_assig_right_tag_default : type_assig_right_tag
  
 type_assig : IDENTIFIER type_assig_right_tag_default
                {
-                 set_name ($2, $1);
+                 set_name ($2, $1); 
                  $$ = $2;
                }
 ;
@@ -642,20 +733,28 @@ definitions: definitions_id
 
 %%
 
-const char *key_word[]={"::=","OPTIONAL","INTEGER","SIZE","OCTET","STRING"
-                       ,"SEQUENCE","BIT","UNIVERSAL","PRIVATE","OPTIONAL"
-                       ,"DEFAULT","CHOICE","OF","OBJECT","IDENTIFIER"
-                       ,"BOOLEAN","TRUE","FALSE","APPLICATION","ANY","DEFINED"
-                       ,"SET","BY","EXPLICIT","IMPLICIT","DEFINITIONS","TAGS"
-                       ,"BEGIN","END","UTCTime","GeneralizedTime","FROM"
-                       ,"IMPORTS","NULL","ENUMERATED"};
-const int key_word_token[]={ASSIG,OPTIONAL,INTEGER,SIZE,OCTET,STRING
-                       ,SEQUENCE,BIT,UNIVERSAL,PRIVATE,OPTIONAL
-                       ,DEFAULT,CHOICE,OF,OBJECT,STR_IDENTIFIER
-                       ,BOOLEAN,TRUE,FALSE,APPLICATION,ANY,DEFINED
-                       ,SET,BY,EXPLICIT,IMPLICIT,DEFINITIONS,TAGS
-                       ,BEGIN,END,UTCTime,GeneralizedTime,FROM
-                       ,IMPORTS,TOKEN_NULL,ENUMERATED};
+const char *key_word[]={
+  "::=","OPTIONAL","INTEGER","SIZE","OCTET","STRING"
+  ,"SEQUENCE","BIT","UNIVERSAL","PRIVATE","OPTIONAL"
+  ,"DEFAULT","CHOICE","OF","OBJECT","IDENTIFIER"
+  ,"BOOLEAN","TRUE","FALSE","APPLICATION","ANY","DEFINED"
+  ,"SET","BY","EXPLICIT","IMPLICIT","DEFINITIONS","TAGS"
+  ,"BEGIN","END","UTCTime","GeneralizedTime","FROM"
+  ,"IMPORTS","NULL","ENUMERATED"
+  ,"UTF8String","NumericString","PrintableString","TeletexString"
+  ,"IA5String","UniversalString","BMPString"
+};
+const int key_word_token[]={
+   ASSIG,OPTIONAL,INTEGER,SIZE,OCTET,STRING
+  ,SEQUENCE,BIT,UNIVERSAL,PRIVATE,OPTIONAL
+  ,DEFAULT,CHOICE,OF,OBJECT,STR_IDENTIFIER
+  ,BOOLEAN,TRUE,FALSE,APPLICATION,ANY,DEFINED
+  ,SET,BY,EXPLICIT,IMPLICIT,DEFINITIONS,TAGS
+  ,BEGIN,END,UTCTime,GeneralizedTime,FROM
+  ,IMPORTS,TOKEN_NULL,ENUMERATED
+  ,UTF8STRING,NUMERICSTRING,PRINTABLESTRING,TELETEXSTRING  
+  ,IA5STRING,UNIVERSALSTRING,BMPSTRING
+};      
 
 \f
 /*************************************************************/
@@ -738,6 +837,9 @@ yylex (YYSTYPE *lvalp, void *parm)
       if (k>=counter)
         {
           strcpy (lvalp->str,string);  
+          if (PARSECTL->debug)
+            fprintf (stderr,"%d: yylex found number `%s'\n",
+                     PARSECTL->lineno, string);
           return NUM;
         }
       
@@ -745,11 +847,19 @@ yylex (YYSTYPE *lvalp, void *parm)
       for (k=0; k<(sizeof(key_word)/sizeof(char*));k++ )
         {
           if (!strcmp(string,key_word[k])) 
-            return key_word_token[k]; 
+            {
+              if (PARSECTL->debug)
+                fprintf (stderr,"%d: yylex found keyword `%s'\n",
+                         PARSECTL->lineno, string);
+              return key_word_token[k]; 
+            }
         }
       
       /* STRING is an IDENTIFIER */
       strcpy(lvalp->str,string);
+      if (PARSECTL->debug)
+        fprintf (stderr,"%d: yylex found identifier `%s'\n",
+                 PARSECTL->lineno, string);
       return IDENTIFIER;
     }
 }
@@ -812,6 +922,18 @@ set_str_value (AsnNode node, const char *text)
 }
 
 static void
+set_ulong_value (AsnNode node, const char *text)
+{
+  unsigned long val;
+
+  if (text && *text)
+    val = strtoul (text, NULL, 10);
+  else
+    val = 0;
+  _ksba_asn_set_value (node, VALTYPE_ULONG, &val, sizeof(val));
+}
+
+static void
 set_right (AsnNode node, AsnNode right)
 {
   return_if_fail (node);
@@ -867,11 +989,15 @@ ksba_asn_parse_file (const char *file_name, KsbaAsnTree *result)
     return ASN_FILE_NOT_FOUND;
 
   parsectl.lineno = 0;
+  parsectl.debug = 0;
   parsectl.result_parse = ASN_SYNTAX_ERROR;
   parsectl.parse_tree = NULL;
   parsectl.all_nodes = NULL;
+  /*yydebug = 1;*/
   if ( yyparse ((void*)&parsectl) || parsectl.result_parse != ASN_OK )
     { /* error */
+      fprintf (stderr, "%s:%d: parse error\n",
+               file_name?file_name:"-", parsectl.lineno ); 
       release_all_nodes (parsectl.all_nodes);
       parsectl.all_nodes = NULL;
     }
@@ -903,3 +1029,4 @@ ksba_asn_tree_release (KsbaAsnTree tree)
   xfree (tree);
 }
 
+
index 4a1448a..c35fc0a 100644 (file)
 #include "asn1-func.h"
 #include "ber-decoder.h"
 
+
+
+struct tag_info {
+  enum tag_class class;
+  int is_constructed;
+  unsigned long tag;
+  unsigned long length; /* length part of the TLV */
+  int ndef;             /* It is an indefinite length */
+  size_t nhdr;          /* number of bytes in the TL */
+};
+
+
+struct decoder_state_item_s {
+  AsnNode node;
+  int went_up;
+  int in_seq_of;
+  int again;
+  int next_tag;
+  int length;  /* length of the value */
+  int ndef_length; /* the length is of indefinite length */
+  int nread;   /* number of value bytes processed */
+};
+typedef struct decoder_state_item_s DECODER_STATE_ITEM;
+
+struct decoder_state_s {
+  DECODER_STATE_ITEM cur;     /* current state */
+  int stacksize;
+  int idx;
+  DECODER_STATE_ITEM stack[1];
+};
+typedef struct decoder_state_s *DECODER_STATE;
+
+
 struct ber_decoder_s {
   AsnNode module;    /* the ASN.1 structure */
   KsbaReader reader;
   const char *last_errdesc; /* string with the error description */
-  int non_der; /* set if the encoding is not DER conform */
+  int non_der;    /* set if the encoding is not DER conform */
+  AsnNode root;   /* of the expanded parse tree */
+  DECODER_STATE ds;
+  int bypass;
+  int debug;
+  struct {
+    int primitive;  /* current value is a primitive one */
+    int length;     /* length of the primitive one */
+    int nhdr;       /* length of the header */
+    AsnNode node;   /* NULL or matching node */
+  } val; 
 };
 
 
+
+\f
+static DECODER_STATE
+new_decoder_state (void)
+{
+  DECODER_STATE ds;
+
+  ds = xmalloc (sizeof (*ds) + 99*sizeof(DECODER_STATE_ITEM));
+  ds->stacksize = 100;
+  ds->idx = 0;
+  ds->cur.node = NULL;
+  ds->cur.in_seq_of = 0;
+  ds->cur.again = 0;
+  ds->cur.next_tag = 0;
+  ds->cur.went_up = 0;
+  ds->cur.length = 0;
+  ds->cur.ndef_length = 1;
+  ds->cur.nread = 0;
+  return ds;
+}
+       
+static void        
+release_decoder_state (DECODER_STATE ds)
+{
+  xfree (ds);
+}
+
+static void
+dump_decoder_state (DECODER_STATE ds)
+{
+  int i;
+
+  for (i=0; i < ds->idx; i++)
+    {
+      fprintf (stdout,"  ds stack[%d] (", i);
+      if (ds->stack[i].node)
+        _ksba_asn_node_dump (ds->stack[i].node, stdout);
+      else
+        printf ("Null");
+      fprintf (stdout,") %s%d (%d)%s\n",
+               ds->stack[i].ndef_length? "ndef ":"",
+               ds->stack[i].length,
+               ds->stack[i].nread,
+               ds->stack[i].in_seq_of? " in_seq_of":"");
+    }
+}
+
+/* Push ITEM onto the stack */
+static void
+push_decoder_state (DECODER_STATE ds)
+{
+  if (ds->idx >= ds->stacksize)
+    {
+      fprintf (stderr, "ERROR: decoder stack overflow!\n");
+      abort ();
+    }
+  ds->stack[ds->idx++] = ds->cur;
+}
+
+static void
+pop_decoder_state (DECODER_STATE ds)
+{
+  if (!ds->idx)
+    {
+      fprintf (stderr, "ERROR: decoder stack underflow!\n");
+      abort ();
+    }
+  ds->cur = ds->stack[--ds->idx];
+}
+
+
+\f
 static int
 set_error (BerDecoder d, AsnNode node, const char *text)
 {
@@ -60,6 +175,41 @@ eof_or_error (BerDecoder d, int premature)
   return -1;
 }
 
+static int
+is_primitive_type (node_type_t type)
+{
+  switch (type)
+    {
+    case TYPE_BOOLEAN:                               
+    case TYPE_INTEGER:                               
+    case TYPE_BIT_STRING:                            
+    case TYPE_OCTET_STRING:                          
+    case TYPE_NULL:                                  
+    case TYPE_OBJECT_ID:                             
+    case TYPE_OBJECT_DESCRIPTOR:                     
+    case TYPE_REAL:                                  
+    case TYPE_ENUMERATED:                            
+    case TYPE_UTF8_STRING:                           
+    case TYPE_REALTIVE_OID:                          
+    case TYPE_NUMERIC_STRING:                        
+    case TYPE_PRINTABLE_STRING:                      
+    case TYPE_TELETEX_STRING:                        
+    case TYPE_VIDEOTEX_STRING:                       
+    case TYPE_IA5_STRING:                            
+    case TYPE_UTC_TIME:                              
+    case TYPE_GENERALIZED_TIME:                      
+    case TYPE_GRAPHIC_STRING:                        
+    case TYPE_VISIBLE_STRING:                        
+    case TYPE_GENERAL_STRING:                        
+    case TYPE_UNIVERSAL_STRING:                      
+    case TYPE_CHARACTER_STRING:                      
+    case TYPE_BMP_STRING:                            
+      return 1;
+    default:
+      return 0;
+    }
+}
+
 static const char *
 universal_tag_name (unsigned long no)
 {
@@ -101,9 +251,45 @@ universal_tag_name (unsigned long no)
 }
 
 
+static void
+dump_tlv (const struct tag_info *ti, FILE *fp)
+{
+  const char *tagname = NULL;
+
+  if (ti->class == CLASS_UNIVERSAL)
+    tagname = universal_tag_name (ti->tag);
+
+  if (tagname)
+    fputs (tagname, fp);
+  else
+    fprintf (fp, "[%s %lu]", 
+             ti->class == CLASS_UNIVERSAL? "UNIVERSAL" :
+             ti->class == CLASS_APPLICATION? "APPLICATION" :
+             ti->class == CLASS_CONTEXT? "CONTEXT-SPECIFIC" : "PRIVATE",
+             ti->tag);
+  fprintf (fp, " %c hdr=%u len=", ti->is_constructed? 'c':'p', ti->nhdr);
+  if (ti->ndef)
+    fputs ("ndef", fp);
+  else
+    fprintf (fp, "%lu", ti->length);
+}
 
 
+static void
+clear_help_flags (AsnNode node)
+{
+  AsnNode p;
 
+  for (p=node; p; p = _ksba_asn_walk_tree (node, p))
+    {
+      if (p->type == TYPE_TAG)
+        {
+          p->flags.tag_seen = 0;
+        }
+      p->flags.skip_this = 0;
+    }
+  
+}
 
 
 \f
@@ -166,13 +352,6 @@ _ksba_ber_decoder_set_reader (BerDecoder d, KsbaReader r)
  ***********  decoding machinery  *************
  **********************************************/
 
-struct tag_info {
-  enum tag_class class;
-  int is_constructed;
-  unsigned long tag;
-};
-
-
 static int
 read_byte (KsbaReader reader)
 {
@@ -190,22 +369,21 @@ read_byte (KsbaReader reader)
  * Read the tag and the length part from the TLV triplet. 
  */
 static KsbaError
-read_tl (BerDecoder d, struct tag_info *r_tag, 
-         unsigned long *r_length, int *r_indefinite, size_t *r_nread)
+read_tl (BerDecoder d, struct tag_info *ti)
 {
   int c;
   unsigned long tag;
 
-  *r_length = 0;
-  *r_indefinite = 0;
-  *r_nread = 0;
+  ti->length = 0;
+  ti->ndef = 0;
+  ti->nhdr = 0;
   /* Get the tag */
   c = read_byte (d->reader);
   if (c==-1)
     return eof_or_error (d, 0);
-  ++*r_nread;
-  r_tag->class = (c & 0xc0) >> 6;
-  r_tag->is_constructed = !!(c & 0x20);
+  ti->nhdr++;
+  ti->class = (c & 0xc0) >> 6;
+  ti->is_constructed = !!(c & 0x20);
   tag = c & 0x1f;
   if (tag == 0x1f)
     {
@@ -217,23 +395,23 @@ read_tl (BerDecoder d, struct tag_info *r_tag,
           c = read_byte (d->reader);
           if (c == -1)
             return eof_or_error (d, 1);
-          ++*r_nread;
+          ti->nhdr++;
           tag |= c & 0x7f;
         }
       while (c & 0x80);
     }
-  r_tag->tag = tag;
+  ti->tag = tag;
 
   /* Get the length */
   c = read_byte (d->reader);
   if (c == -1)
     return eof_or_error (d, 1);
 ++*r_nread;
ti->nhdr++;
   if ( !(c & 0x80) )
-    *r_length = c;
+    ti->length = c;
   else if (c == 0x80)
     {
-      *r_indefinite = 1;
+      ti->ndef = 1;
       d->non_der = 1;
     }
   else if (c == 0xff)
@@ -250,12 +428,16 @@ read_tl (BerDecoder d, struct tag_info *r_tag,
           c = read_byte (d->reader);
           if (c == -1)
             return eof_or_error (d, 1);
-          ++*r_nread;
+          ti->nhdr++;
           len |= c & 0xff;
         }
-      *r_length = len;
+      ti->length = len;
     }
 
+  /* Without this kludge some example certs can't be parsed */
+  if (ti->class == CLASS_UNIVERSAL && !ti->tag)
+    ti->length = 0;
+
   return 0;
 }
 
@@ -263,18 +445,34 @@ read_tl (BerDecoder d, struct tag_info *r_tag,
 static int
 cmp_tag (AsnNode node, const struct tag_info *ti)
 {
-  return ti->tag == node->type && ti->class == node->flags.class;
-}
+  if (node->flags.class != ti->class)
+    return 0;
+  if (node->type == TYPE_TAG)
+    {
+      return_val_if_fail (node->valuetype == VALTYPE_ULONG, 0);
+      return node->value.v_ulong == ti->tag;
+    }
+  if (node->type == ti->tag)
+    return 1;
+  if (ti->class == CLASS_UNIVERSAL)
+    {
+      if (node->type == TYPE_SEQUENCE_OF && ti->tag == TYPE_SEQUENCE)
+        return 1;
+      if (node->type == TYPE_SET_OF && ti->tag == TYPE_SET)
+        return 1;
+      if (node->type == TYPE_ANY && is_primitive_type (ti->tag))
+        return 1; 
+    }
 
+  return 0;
+}
 
-/* Find the matching node for the tag described by ti.  ROOT is the
-   root node of the syntaxtree, node either NULL or the last node
-   matched.  */
+/* Find the node in the tree ROOT corresponding to TI and return that
+   node.  Returns NULL if the node was not found */
 static AsnNode
-find_node (AsnNode root, AsnNode node, const struct tag_info *ti)
+find_anchor_node (AsnNode root, const struct tag_info *ti)
 {
-  if (!node)
-    node = root;
+  AsnNode node = root;
 
   while (node)
     {
@@ -308,15 +506,422 @@ find_node (AsnNode root, AsnNode node, const struct tag_info *ti)
   return NULL;
 }
 
+static int
+match_der (AsnNode root, const struct tag_info *ti,
+           DECODER_STATE ds, AsnNode *retnode, int debug)
+{
+  AsnNode node;
 
-KsbaError
-_ksba_ber_decoder_decode (BerDecoder d)
+  *retnode = NULL;
+  node = ds->cur.node;
+  if (!node)
+    {
+      if (debug)
+        puts ("  looking for anchor");
+      node = find_anchor_node (root,  ti);
+      if (!node)
+        fputs (" anchor node not found\n", stdout);
+    }
+  else if (ds->cur.again)
+    {
+      if (debug)
+        puts ("  doing last again");
+      ds->cur.again = 0;
+    }
+  else if (is_primitive_type (node->type) || node->type == TYPE_ANY
+           || node->type == TYPE_SIZE || node->type == TYPE_DEFAULT )
+    {
+      if (debug)
+        puts ("  primitive type - get next");
+      if (node->right)
+        node = node->right;
+      else if (!node->flags.in_choice)
+        node = NULL;
+      else /* in choice */
+        {
+          if (debug)
+            puts ("  going up after choice - get next");
+          while (node->left && node->left->right == node)
+            node = node->left;
+          node = node->left; /* this is the up pointer */
+          if (node)
+            node = node->right;
+        }
+    }
+  else if (node->type == TYPE_SEQUENCE_OF || node->type == TYPE_SET_OF)
+    {
+      if (debug)
+        {
+          printf ("  prepare for seq/set_of (%d %d)  ",
+                  ds->cur.length, ds->cur.nread);
+          printf ("  cur: ("); _ksba_asn_node_dump (node, stdout);
+          printf (")\n");
+          if (ds->cur.node->flags.in_array)
+            puts ("  This is in an arrat!");
+          if (ds->cur.went_up)
+            puts ("  And we going up!");
+        }
+      if ((ds->cur.went_up && !ds->cur.node->flags.in_array) ||
+          (ds->idx && ds->cur.nread >= ds->stack[ds->idx-1].length))
+        {
+          if (debug)
+            printf ("  advancing\n");
+          if (node->right)
+            node = node->right;
+          else
+            {
+              for (;;)
+                {
+                  while (node->left && node->left->right == node)
+                    node = node->left;
+                  node = node->left; /* this is the up pointer */
+                  if (!node)
+                    break;
+                  if (node->right)
+                    {
+                      node = node->right;
+                      break;
+                    }
+                }
+            }
+        }
+      else if (ds->cur.node->flags.in_array
+               && ds->cur.went_up)
+        {
+          if (debug)
+            puts ("  Reiterating");
+        }
+      else
+        node = node->down;
+    }
+  else /* constructed */
+    {
+      if (debug)
+        {
+          printf ("  prepare for constructed (%d %d) ",
+                  ds->cur.length, ds->cur.nread);
+          printf ("  cur: ("); _ksba_asn_node_dump (node, stdout);
+          printf (")\n");
+          if (ds->cur.node->flags.in_array)
+            puts ("  This is in an arrat!");
+          if (ds->cur.went_up)
+            puts ("  And we going up!");
+        }
+      ds->cur.in_seq_of = 0;
+
+      if (ds->cur.node->flags.in_array
+          && ds->cur.went_up)
+        {
+          if (debug)
+            puts ("  Reiterating this");
+        }
+      else if (ds->cur.went_up || ds->cur.next_tag)
+        {
+          if (node->right)
+            node = node->right;
+          else
+            {
+              for (;;)
+                {
+                  while (node->left && node->left->right == node)
+                    node = node->left;
+                  node = node->left; /* this is the up pointer */
+                  if (!node)
+                    break;
+                  if (node->right)
+                    {
+                      node = node->right;
+                      break;
+                    }
+                }
+            }
+        }
+      else 
+        node = node->down;
+      
+    }
+  if (!node)
+    return -1;
+  ds->cur.node = node;
+  ds->cur.went_up = 0;
+  ds->cur.next_tag = 0;
+
+  if (debug)
+    {
+      printf ("  Expect ("); _ksba_asn_node_dump (node, stdout); printf (")\n");
+    }
+
+  if (node->flags.skip_this)
+    return 1;
+
+  if (node->type == TYPE_SIZE)
+    {
+      if (debug)
+        printf ("   skipping size tag\n");
+      return 1;
+    }
+  if (node->type == TYPE_DEFAULT)
+    {
+      if (debug)
+        printf ("   skipping default tag\n");
+      return 1;
+    }
+
+  if ( cmp_tag (node, ti))
+    {
+      *retnode = node;
+      return 3;
+    }
+    
+  if (node->type == TYPE_CHOICE)
+    {
+      if (debug)
+        printf ("   testing choice...\n");
+      for (node = node->down; node; node = node->right)
+        {
+          if (debug)
+            {
+              printf ("       %s (", node->flags.skip_this? "skip":" cmp");
+              _ksba_asn_node_dump (node, stdout);
+              printf (")\n");
+            }
+
+          if (!node->flags.skip_this && cmp_tag (node, ti))
+            {
+              if (debug)
+                {
+                  printf ("  choice match <"); dump_tlv (ti, stdout);
+                  printf (">\n");
+                }
+              /* mark the remaining as done */
+              for (node=node->right; node; node = node->right)
+                node->flags.skip_this = 1;
+              return 1;
+            }
+          node->flags.skip_this = 1;
+        }
+      node = ds->cur.node; /* reset */
+    }
+
+  if (node->flags.in_choice)
+    {
+      if (debug)
+        printf ("   skipping non matching choice\n");
+      return 1;
+    }
+  
+  if (node->flags.is_optional)
+    {
+      if (debug)
+        printf ("   skipping optional element\n");
+      if (node->type == TYPE_TAG)
+        ds->cur.next_tag = 1;
+      return 1;
+    }
+
+  if (node->flags.has_default)
+    {
+      if (debug)
+        printf ("   use default value\n");
+      *retnode = node;
+      return 2;
+    }
+
+  return -1;
+}
+
+
+static KsbaError 
+decoder_init (BerDecoder d)
+{
+  d->ds = new_decoder_state ();
+
+  d->root = _ksba_asn_expand_tree (d->module);
+  clear_help_flags (d->root);
+  d->bypass = 0;
+
+  return 0;
+}
+
+static void
+decoder_deinit (BerDecoder d)
+{
+  release_decoder_state (d->ds);
+  d->ds = NULL;
+  d->val.node = NULL;
+  /* FIXME: release root */
+}
+
+
+static KsbaError
+decoder_next (BerDecoder d)
 {
+  struct tag_info ti;
+  AsnNode node;
+  KsbaError err;
+  DECODER_STATE ds = d->ds;
+  int debug = d->debug;
+
+  err = read_tl (d, &ti);
+  if (err)
+    {
+      return err;
+    }
   
+  if (debug)
+    {
+      printf ("ReadTLV <"); dump_tlv (&ti, stdout); printf (">\n");
+    }
+
+  if (!d->bypass)
+    {
+      int again;
+
+      do
+        {
+          again = 0;
+          switch ( match_der (d->root, &ti, ds, &node, debug) )
+            { 
+            case -1:
+              if (debug)
+                {
+                  printf ("   FAIL <"); dump_tlv (&ti, stdout); printf (">\n");
+                }
+              d->bypass = 1;
+              break;
+            case 0:
+              if (debug)
+                puts ("  End of description");
+              d->bypass = 1;
+              break;
+            case 1: /* again */
+              if (debug)
+                printf ("  Again\n");
+              again = 1;
+              break;
+            case 2: /* use default value +  again*/
+              if (debug)
+                printf ("  Using default\n");
+              again = 1;
+              break;
+            case 3: /* match */ 
+              if (debug)
+                {
+                  printf ("  Match <"); dump_tlv (&ti, stdout); printf (">\n");
+                }
+              /* increment by the header length */
+              ds->cur.nread += ti.nhdr;
+              /*inc_decoder_state (ds, ti.nhdr);*/
+                  
+              if (!ti.is_constructed)
+                { 
+                  ds->cur.nread += ti.length;
+                  /*inc_decoder_state (ds, ti.length);*/
+                }
+
+              ds->cur.went_up = 0;
+              do
+                {
+                  if (debug)
+                    printf ("  (length %d nread %d) %s\n",
+                            ds->idx? ds->stack[ds->idx-1].length:-1,
+                            ds->cur.nread,
+                            ti.is_constructed? "con":"pri");
+
+                  if ( ds->idx
+                       && !ds->stack[ds->idx-1].ndef_length
+                       && (ds->cur.nread
+                           > ds->stack[ds->idx-1].length)) 
+                    {
+                      fprintf (stderr, "  ERROR: object length field %d octects"
+                               " too large\n",   
+                              ds->cur.nread > ds->cur.length);
+                      ds->cur.nread = ds->cur.length;
+                    }
+                  if ( ds->idx
+                       && !ds->stack[ds->idx-1].ndef_length
+                       && (ds->cur.nread
+                           >= ds->stack[ds->idx-1].length)) 
+                    {
+                      int n = ds->cur.nread;
+                      pop_decoder_state (ds);
+                      ds->cur.nread += n;
+                      ds->cur.went_up++;
+                    }
+                }
+              while ( ds->idx
+                      && !ds->stack[ds->idx-1].ndef_length
+                      && (ds->cur.nread
+                          >= ds->stack[ds->idx-1].length));
+                  
+              if (ti.is_constructed)
+                {
+                  /* prepare for the next level */
+                  ds->cur.length = ti.length;
+                  ds->cur.ndef_length = ti.ndef;
+                  push_decoder_state (ds);
+                  ds->cur.length = 0;
+                  ds->cur.ndef_length = 0;
+                  ds->cur.nread = 0;
+                }
+              if (debug)
+                printf ("  (length %d nread %d) end\n",
+                        ds->idx? ds->stack[ds->idx-1].length:-1,
+                        ds->cur.nread);
+              break;
+            default:
+              never_reached ();
+              abort (); 
+              break;
+            }
+        }
+      while (again);
+    }
+
+  d->val.primitive = !ti.is_constructed;
+  d->val.length = ti.length;
+  d->val.nhdr = ti.nhdr;
+  d->val.node = d->bypass? NULL : node;
+  if (debug)
+    dump_decoder_state (ds);
   
-  return -1;
+  return 0;
+}
+
+static KsbaError
+decoder_skip (BerDecoder d)
+{
+  if (d->val.primitive)
+    { 
+      int n;
+      
+      for (n=0; n < d->val.length; n++)
+        if (read_byte (d->reader) == -1)
+          return eof_or_error (d, 1);
+    }
+  return 0;
+}
+
+
+\f
+/* Calculate the distance between the 2 nodes */
+static int
+distance (AsnNode root, AsnNode node)
+{
+  int n=0;
+
+  while (node && node != root)
+    {
+      while (node->left && node->left->right == node)
+        node = node->left;
+      node = node->left;
+      n++;
+    }
+
+  return n;
 }
 
+
 /**
  * _ksba_ber_decoder_dump:
  * @d: Decoder object
@@ -328,135 +933,102 @@ _ksba_ber_decoder_decode (BerDecoder d)
 KsbaError
 _ksba_ber_decoder_dump (BerDecoder d, FILE *fp)
 {
-  struct tag_info ti;
-  int rc;
-  unsigned long length, tlvlen;
-  int is_indefinite;
+  KsbaError err;
   int depth = 0;
-  size_t nread;
-  struct {
-    unsigned long nleft;
-    unsigned long length;
-    int ndef;
-  } stack[100];
-  AsnNode rootnode, curnode, node;
-  enum {
-    DS_INIT, DS_BYPASS, DS_NEXT
-  } state = DS_INIT;
-    
+  AsnNode node;
+  unsigned char *buf = NULL;
+  size_t buflen = 0;;
 
+  if (!d)
+    return KSBA_Invalid_Value;
 
-  rootnode = d->module;
-  curnode = NULL;
-  while ( !(rc = read_tl (d, &ti, &length, &is_indefinite, &nread)) )
-    {
-      const char *tagname = NULL;
-
-      /* Without this kludge some example certs can't be parsed */
-      if (ti.class == CLASS_UNIVERSAL && !ti.tag)
-        length = 0;
+  err = decoder_init (d);
+  if (err)
+    return err;
 
-      tlvlen = length + nread;
-      if (ti.class == CLASS_UNIVERSAL)
-        tagname = universal_tag_name (ti.tag);
+  while (!(err = decoder_next (d)))
+    {
+      node = d->val.node;
+      if (node)
+        depth = distance (d->root, node);
 
-      fprintf (fp, "%*s", depth*2, "");
-      if (tagname)
-        fputs (tagname, fp);
-      else
-        fprintf (fp, "[%s %lu]", 
-                 ti.class == CLASS_UNIVERSAL? "UNIVERSAL" :
-                 ti.class == CLASS_APPLICATION? "APPLICATION" :
-                 ti.class == CLASS_CONTEXT? "CONTEXT-SPECIFIC" : "PRIVATE",
-                 ti.tag);
-      fprintf (fp, " %c n=%u", ti.is_constructed? 'c':'p', nread);
-      if (is_indefinite)
-        fputs (" indefinite length ", fp);
+      fprintf (fp, "%4lu %4u:%*s",
+               ksba_reader_tell (d->reader) - d->val.nhdr,
+               d->val.length,
+               depth*2, "");
+      if (node)
+        _ksba_asn_node_dump (node, fp);
       else
-        fprintf (fp, " %lu octets ", length);
+        fputs ("[No matching node]", fp);
 
-      if (state != DS_BYPASS)
+      if (node && d->val.primitive)
         {
-          node = find_node (rootnode, curnode, &ti);
-          switch (state)
-            {
-            case DS_INIT:
-              if (!node)
-                {
-                  state = DS_BYPASS;
-                  fputs (" anchor node not found", fp);
-                  break;
-                }
-              /* fall thru */
-            default:
-              if (node)
-                {
-                  putc ('(', fp);
-                  _ksba_asn_node_dump (node, fp);
-                  putc (')', fp);
-                  curnode = node;
-                }
-              state = DS_NEXT;
-              break;
-            } 
-          
-        }
-      putc ('\n', fp);
+          int i, n, c;
+          char *p;
       
-      if (!ti.is_constructed)
-        { /* primitive: skip value */
-          int n;
-
-          for (n=0; n < length; n++)
-            if (read_byte (d->reader) == -1)
-              return eof_or_error (d, 1);
-        }
-
-      if (depth && !ti.is_constructed)
-        {
-          if (stack[depth-1].ndef)
+          if (!buf || buflen < d->val.length)
             {
-              if (ti.class == CLASS_UNIVERSAL && !ti.tag && !length)
-                depth--;
+              xfree (buf);
+              buflen = d->val.length + 100;
+              buf = xtrymalloc (buflen);
+              if (!buf)
+                err = KSBA_Out_Of_Core;
             }
-          else
+
+          for (n=0; !err && n < d->val.length; n++)
             {
-              if (tlvlen > stack[depth-1].nleft)
-                {
-                  fprintf (fp, "error: "
-                           "object length field %lu octects too large\n",
-                           (tlvlen - stack[depth-1].nleft) );
-                  stack[depth-1].nleft = 0;
-                }
-              else
-                stack[depth-1].nleft -= tlvlen;
-/*                fprintf (fp, "depth %d %lu bytes of %lu left\n", */
-/*                         depth, stack[depth-1].nleft, stack[depth-1].length); */
-              if (depth && !stack[depth-1].nleft)
-                  depth--;
+              if ( (c=read_byte (d->reader)) == -1)
+                err =  eof_or_error (d, 1);
+              buf[n] = c;
             }
-        }
-
-      if (ti.is_constructed)
-        {  /* constructed */
-          if (depth == DIM(stack))
+          if (err)
+            break;
+          fputs ("  (", fp);
+          p = NULL;
+          switch (node->type)
             {
-              fprintf (fp, "error: objects nested too deep\n");
-              rc = KSBA_General_Error;
+            case TYPE_OBJECT_ID:
+              p = ksba_oid_to_str (buf, n);
+              break;
+            default:
+              for (i=0; i < n && i < 20; i++)
+                fprintf (fp,"%02x", buf[i]);
+              if (i < n)
+                fputs ("..more..", fp);
               break;
             }
-          stack[depth].nleft  = length; 
-          stack[depth].length = length;
-          stack[depth].ndef = is_indefinite;
-          depth++;
+          if (p)
+            {
+              fputs (p, fp);
+              xfree (p);
+            }
+          fputs (")\n", fp);
         }
-    }
+      else
+        {
+          err = decoder_skip (d);
+          putc ('\n', fp);
+        }
+      if (err)
+        break;
 
-  if (rc==-1 && !d->last_errdesc)
-    rc = 0;
+    }
+  if (err == -1)
+    err = 0;
 
-  return rc;
+  decoder_deinit (d);
+  xfree (buf);
+  return err;
 }
 
 
+\f
+
+KsbaError
+_ksba_ber_decoder_decode (BerDecoder d)
+{
+  
+  return -1;
+}
+
 
index 2ab692f..d839025 100644 (file)
@@ -49,6 +49,12 @@ ksba_cert_new (void)
   return cert;
 }
 
+/**
+ * ksba_cert_release:
+ * @cert: A certificate object
+ * 
+ * Release a certificate object.
+ **/
 void
 ksba_cert_release (KsbaCert cert)
 {
@@ -56,6 +62,18 @@ ksba_cert_release (KsbaCert cert)
 }
 
 
+/**
+ * ksba_cert_read_der:
+ * @cert: An unitialized certificate object
+ * @reader: A KSBA Reader object
+ * 
+ * Read the next certificate from the reader and store it in the
+ * certificate object for future access.  The certificate is parsed
+ * and rejected if it has any syntactical or semantical error
+ * (i.e. does not match the ASN.1 description).
+ * 
+ * Return value: 0 on success or an error value
+ **/
 KsbaError
 ksba_cert_read_der (KsbaCert cert, KsbaReader reader)
 {
@@ -66,9 +84,10 @@ ksba_cert_read_der (KsbaCert cert, KsbaReader reader)
 
   /* FIXME: parse it and store it in our internal format */
 
-
+  return KSBA_Not_Implemented;
 }
 
 
 
 
+
index d0e4fc4..d0edcc9 100644 (file)
@@ -61,18 +61,20 @@ BEGIN
 -- the other ASN.1 modules.  Other applications may use them for their
 -- own purposes.
 
-IMPORTS
+-- Out parser does not support IMPORTS, instead we copy them verbatim
+-- at the end of this file
+--IMPORTS
 
   -- Directory Information Framework (X.501)
-        Name
-           FROM InformationFramework { joint-iso-itu-t ds(5) modules(1)
-                informationFramework(1) 3 }
+--        Name
+--           FROM InformationFramework { joint-iso-itu-t ds(5) modules(1)
+--                informationFramework(1) 3 }
 
   -- Directory Authentication Framework (X.509)
-        AlgorithmIdentifier, AttributeCertificate, Certificate,
-        CertificateList, CertificateSerialNumber
-           FROM AuthenticationFramework { joint-iso-itu-t ds(5)
-                module(1) authenticationFramework(7) 3 } ;
+--        AlgorithmIdentifier, AttributeCertificate, Certificate,
+--        CertificateList, CertificateSerialNumber
+--           FROM AuthenticationFramework { joint-iso-itu-t ds(5)
+--                module(1) authenticationFramework(7) 3 } ;
 
 
 -- Cryptographic Message Syntax
@@ -255,8 +257,9 @@ CertificateRevocationLists ::= SET OF CertificateList
 
 CertificateChoices ::= CHOICE {
   certificate Certificate,  -- See X.509
-  extendedCertificate [0] IMPLICIT ExtendedCertificate,  -- Obsolete
-  attrCert [1] IMPLICIT AttributeCertificate }  -- See X.509 & X9.57
+  extendedCertificate [0] IMPLICIT ExtendedCertificate  -- Obsolete
+-- FIXME  attrCert [1] IMPLICIT AttributeCertificate  -- See X.509 & X9.57
+} 
 
 CertificateSet ::= SET OF CertificateChoices
 
@@ -395,7 +398,444 @@ ExtendedCertificateInfo ::= SEQUENCE {
 
 Signature ::= BIT STRING
 
+--*******************************************
+--***********  Included imports  ************
+--*******************************************
+
+-- Directory Information Framework (X.501)
+--        Name
+--           FROM InformationFramework { joint-iso-itu-t ds(5) modules(1)
+--                informationFramework(1) 3 }
+
+-- Directory Authentication Framework (X.509)
+--        AlgorithmIdentifier, AttributeCertificate, Certificate,
+--        CertificateList, CertificateSerialNumber
+--           FROM AuthenticationFramework { joint-iso-itu-t ds(5)
+--                module(1) authenticationFramework(7) 3 } ;
+
+-- Fixme: For now we just include the tmttv2
+
+-- (TMTTv2 3.1)
+Certificate ::= SEQUENCE {
+  tbsCertificate       TBSCertificate,
+  signatureAlgorithm   AlgorithmIdentifier,
+  signature            BIT STRING 
+}
+
+AlgorithmIdentifier ::= SEQUENCE {
+  algorithm    OBJECT IDENTIFIER,
+  parameters   ANY DEFINED BY algorithm OPTIONAL
+  -- should be used but set to NULL
+}
+
+TBSCertificate ::= SEQUENCE {
+  version         [0] EXPLICIT Version DEFAULT v1,
+  serialNumber                 CertificateSerialNumber,
+  signature                    AlgorithmIdentifier,
+  issuer                       Name,
+  validity                     Validity,
+  subject                      Name,
+  subjectPublicKeyInfo         SubjectPublicKeyInfo,
+  issuerUniqueID  [1] IMPLICIT UniqueIdentifier OPTIONAL,
+  subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL,
+  extensions      [3] EXPLICIT Extensions OPTIONAL
+}
+
+-- (TMTTv2 3.1.1)
+Version ::= INTEGER { v1(0), v2(1), v3(2) } 
+-- Ony v3 is used which is the default anyway
+
+-- (TMTTv2 3.1.2)
+CertificateSerialNumber ::= INTEGER
+-- Must support length of up to 15 byte
+
+-- (TMTTv2 3.1.4)
+Name ::= CHOICE {
+  rdnSequence RDNSequence
+}
+
+RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
+
+RelativeDistinguishedName ::= SET OF AttributeTypeAndValue
+-- pkix defines a SIZE (1 .. MAX), we use a maximum of 1 to avoid
+-- problems with some LDAP implementations.
+
+Attribute ::= SEQUENCE {  -- not specified bt TMTT
+  type    AttributeType,
+  values  SET OF AttributeValue
+}
+
+AttributeTypeAndValue ::= SEQUENCE {
+  type    AttributeType,
+  value   AttributeValue
+}
+
+AttributeType ::= OBJECT IDENTIFIER
+
+AttributeValue ::= ANY
+
+DirectoryString ::= CHOICE {
+  printableString   PrintableString (SIZE (1..maxSize)),
+  teletexString     TeletexString (SIZE (1..maxSize)),
+  utf8String        UTF8String (SIZE (1..maxSize)),
+  bmpString         BMPString (SIZE(1..maxSize)),
+  universalString   UniversalString (SIZE (1..maxSize))
+}
+  -- For Sphinx conformity maxSize must be:
+  -- BusinessCategory  128  LocalityName       128  StateOrProvince  128
+  -- CommonName        128  PostalCode          40  SurName           64
+  -- CountryName         2  OrganizationalUnit  64  Title             64
+  -- GivenName          64  OrganizationalName  64
+
+-- (TMTTv2 3.1.5)
+Validity ::= SEQUENCE {
+  notBefore  Time,
+  notAfter   Time 
+}
+
+Time ::= CHOICE {
+  utcTime      UTCTime,
+  generalTime  GeneralizedTime 
+}
+-- fixme: explain constraints
+
+--(TMTTv2 3.1.7)
+SubjectPublicKeyInfo ::= SEQUENCE {
+  algorithm         AlgorithmIdentifier,
+  subjectPublicKey  BIT STRING 
+}
+
+--(TMTTv2 3.1.9)
+Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension
+
+Extension ::= SEQUENCE {
+  extnID     OBJECT IDENTIFIER,
+  critical   BOOLEAN DEFAULT FALSE,
+  extnValue  OCTET STRING  
+}
+
+
+UniqueIdentifier  ::=  BIT STRING
+
+-- (TMTTv2 3.2.1)
+AuthorityKeyIdentifier ::= SEQUENCE {
+  keyIdentifier              [0] KeyIdentifier OPTIONAL,
+  authorityCertIssuer        [1] GeneralNames OPTIONAL,
+  authorityCertSerialNumber  [2] CertificateSerialNumber OPTIONAL 
+}
+-- Fixme: our parser cant handle this:
+--   ( WITH COMPONENTS   { ..., authorityCertIssuer PRESENT,
+--                         authorityCertSerialNumber PRESENT}
+--     | WITH COMPONENTS { ..., authorityCertIssuer ABSENT,
+--                         authorityCertSerialNumber ABSENT }
+--   )
+
+KeyIdentifier ::= OCTET STRING
+
+-- (TMTTv2 3.2.3)
+KeyUsage ::= BIT STRING {
+  digitalSignature (0),
+  nonRepudiation   (1),
+  keyEncipherment  (2),
+  dataEncipherment (3),
+  keyAgreement     (4),
+  keyCertSign      (5),
+  cRLSign          (6),
+  encipherOnly     (7),
+  decipherOnly     (8)
+}
+
+
+-- (TMTTv2 3.2.5)
+CertificatePolicies ::= SEQUENCE SIZE (1..MAX) OF PolicyInformation
+
+PolicyInformation ::= SEQUENCE {
+  policyIdentifier  CertPolicyId,
+  policyQualifiers  SEQUENCE SIZE (1..MAX) OF PolicyQualifierInfo OPTIONAL 
+}
+
+CertPolicyId ::= OBJECT IDENTIFIER
+
+PolicyQualifierInfo ::= SEQUENCE {
+  policyQualifierId  PolicyQualifierId,
+  qualifier          ANY DEFINED BY policyQualifierId 
+}
+
+PolicyQualifierId ::= OBJECT IDENTIFIER  -- missing in TMTTv2 document
+
+-- (TMTTv2 3.2.6)
+PolicyMappingsSyntax ::= SEQUENCE SIZE (1..MAX) OF SEQUENCE {
+  issuerDomainPolicy      CertPolicyId,
+  subjectDomainPolicy     CertPolicyId
+}
+
+
+-- (TMTTv2 3.2.7)
+SubjectAltName ::= GeneralNames
+
+GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
+
+GeneralName ::= CHOICE {
+  otherName                  [0] OtherName, -- INSTANCE OF OTHER-NAME
+  rfc822Name                 [1] IA5String,
+  dNSName                    [2] IA5String,
+  x400Address                [3] ORAddress,
+  directoryName              [4] Name,
+  ediPartyName               [5] EDIPartyName,
+  uniformResourceIdentifier  [6] IA5String,
+  iPAddress                  [7] OCTET STRING,
+  registeredID               [8] OBJECT IDENTIFIER 
+}
+
+OtherName ::= SEQUENCE {
+  type-id  OBJECT IDENTIFIER,
+  value    [0] EXPLICIT ANY DEFINED BY type-id
+}
+
+EDIPartyName ::= SEQUENCE {
+  nameAssigner  [0] DirectoryString OPTIONAL,
+  partyName     [1] DirectoryString 
+}
+
+-- (TMTTv2 3.2.9)
+SubjectDirectoryAttributes ::= SEQUENCE SIZE (1..MAX) OF Attribute
+
+-- (TMTTv2 3.2.10)
+-- id-biometricData OBJECT IDENTIFIE ::= { fixme 1 }
+
+BiometricData ::= SET OF SEQUENCE {
+  typeId  OBJECT IDENTIFIER,
+  value   ANY DEFINED BY typeId
+}
+
+
+-- (TMTTv2 3.2.11)
+BasicConstraints ::= SEQUENCE {
+  cA                 BOOLEAN DEFAULT FALSE,
+  pathLenConstraint  INTEGER (0..MAX) OPTIONAL 
+}
+
+-- (TMTTv2 3.2.12)
+NameConstraints ::= SEQUENCE {
+  permittedSubtrees  [0] GeneralSubtrees OPTIONAL,
+  excludedSubtrees   [1] GeneralSubtrees OPTIONAL 
+}
+
+GeneralSubtrees ::= SEQUENCE SIZE (1..MAX) OF GeneralSubtree
+
+GeneralSubtree ::= SEQUENCE {
+  base         GeneralName,
+  minimum  [0] BaseDistance DEFAULT 0,
+  maximum  [1] BaseDistance OPTIONAL 
+}
+
+BaseDistance ::= INTEGER (0..MAX)
+
+-- (TMTTv2 3.2.13)
+PolicyConstraintsSyntax ::= SEQUENCE SIZE (1..MAX) OF SEQUENCE {
+  requireExplicitPolicy  [0] SkipCerts OPTIONAL,
+  inhibitPolicyMapping   [1] SkipCerts OPTIONAL
+}
+
+SkipCerts ::= INTEGER (0..MAX)
+
+
+-- (TMTTv2 3.2.14)
+CRLDistPointsSyntax ::= SEQUENCE SIZE (1..MAX) OF DistributionPoint
+
+DistributionPoint ::= SEQUENCE {
+  distributionPoint  [0] DistributionPointName OPTIONAL,
+  reasons            [1] ReasonFlags OPTIONAL,
+  cRLIssuer          [2] GeneralNames OPTIONAL 
+}
+
+DistributionPointName ::= CHOICE {
+  fullName                 [0] GeneralNames,
+  nameRelativeToCRLIssuer  [1] RelativeDistinguishedName 
+}
+
+ReasonFlags ::= BIT STRING {
+  unused                (0),
+  keyCompromise         (1),
+  cACompromise          (2),
+  affiliationChanged    (3),
+  superseded            (4),
+  cessationOfOperation  (5),
+  certificateHold       (6) 
+}
+
+
+-- (TMTTv2 3.2.15)
+-- id-issuerCertDistributionPoint OBJECT IDENTIFIER ::= { fixme 28 }
+
+IssuerCertDistributionPoint ::= IA5String
+
+
+-- (TMTTv2 3.2.16)
+-- id-subjectCertDistributionPoint OBJECT IDENTIFIER ::= { fixme 3 }
+
+SubjectCertDistributionPoint ::= IA5String
+
+
+-- (TMTTv2 3.2.17)
+-- id-policyDistributionPoint OBJECT IDENTIFIER ::= { fixme 4 }
+
+PolicyDistributionPoint ::= IA5String
+
+
+-- (TMTTv2 3.2.18)
+-- id-testIdentifier OBECJT IDENTIFIER ::= { fixme 5 }
+
+TestIdentifier ::= UTF8String
+
+
+--\f
+-- (TMTTv2 4.1)
+CertificateList ::= SEQUENCE {
+  tbsCertList         TBSCertList,
+  signatureAlgorithm  AlgorithmIdentifier,
+  signatureValue      BIT STRING 
+}
+
+TBSCertList ::= SEQUENCE {
+  version              Version OPTIONAL,  -- should be v2 if present
+  signature            AlgorithmIdentifier,
+  issuer               Name,
+  thisUpdate           Time,
+  nextUpdate           Time OPTIONAL,  -- must be used in TMTT
+  revokedCertificates  SEQUENCE OF SEQUENCE {
+    userCertificate      CertificateSerialNumber,
+    revocationDate       Time,
+    crlEntryExtensions   Extensions OPTIONAL  -- should be v2 if present
+  } OPTIONAL,
+  crlExtensions        [0] EXPLICIT Extensions OPTIONAL -- v2 is present
+}
+
+
+-- (TMTTv2 4.2.1)
+CRLReason ::= ENUMERATED {
+  unspecified           (0),  -- not allowed in TMTT
+  keyCompromise         (1),
+  cACompromise          (2),
+  affiliationChanged    (3),
+  superseded            (4),
+  cessationOfOperation  (5),
+  certificateHold       (6),
+  removeFromCRL         (8)  -- should not be used because 
+                             -- Delta-CRLs are not supported
+}
+
+-- (TMTTv2 4.2.3)
+InvalidityDate ::= GeneralizedTime
+
+
+-- (TMTTv2 4.2.4)
+CertificateIssuer ::= GeneralNames
+
+-- (TMTTv2 4.3.3)
+cRLNumber ::= INTEGER (1..MAX)
+
+-- (TMTTv2 4.3.4)
+issuingDistributionPoint ::= SEQUENCE {
+  distributionPoint      [0] DistributionPointName OPTIONAL,
+  onlyContainsUserCerts  [1] BOOLEAN DEFAULT FALSE,
+  onlyContainsCACerts    [2] BOOLEAN DEFAULT FALSE,
+  onlySomeReasons        [3] ReasonFlags OPTIONAL,
+  indirectCRL            [4] BOOLEAN DEFAULT FALSE 
+}
+
+
+
+--\f
+-------------------------
+-- x400 address syntax --
+-------------------------
+ORAddress ::= SEQUENCE {
+  built-in-standard-attributes        BuiltInStandardAttributes,
+  built-in-domain-defined-attributes  BuiltInDomainDefinedAttributes OPTIONAL,
+  extension-attributes                ExtensionAttributes OPTIONAL 
+}
+
+BuiltInStandardAttributes ::= SEQUENCE {
+  country-name               CountryName OPTIONAL,
+  administration-domain-name AdministrationDomainName OPTIONAL,
+  network-address            [0] EXPLICIT NetworkAddress OPTIONAL,
+  terminal-identifier        [1] EXPLICIT TerminalIdentifier OPTIONAL,
+  private-domain-name        [2] EXPLICIT PrivateDomainName OPTIONAL,
+  organization-name          [3] EXPLICIT OrganizationName OPTIONAL,
+  numeric-user-identifier    [4] EXPLICIT NumericUserIdentifier OPTIONAL,
+  personal-name              [5] EXPLICIT PersonalName OPTIONAL,
+  organizational-unit-names  [6] EXPLICIT OrganizationalUnitNames OPTIONAL
+}
+
+CountryName ::= [APPLICATION 1] CHOICE {
+  x121-dcc-code         NumericString (SIZE (ub-country-name-numeric-length)),
+  iso-3166-alpha2-code  PrintableString (SIZE (ub-country-name-alpha-length))
+}
+
+AdministrationDomainName ::= [APPLICATION 2] EXPLICIT CHOICE {
+  numeric    NumericString (SIZE (0..ub-domain-name-length)),
+  printable  PrintableString (SIZE (0..ub-domain-name-length))
+}
+
+NetworkAddress ::= X121Address  -- see also extended-network-address
+
+X121Address ::= NumericString (SIZE (1..ub-x121-address-length))
+
+TerminalIdentifier ::= PrintableString (SIZE (1..ub-terminal-id-length))
+
+PrivateDomainName ::= CHOICE {
+  numeric    NumericString (SIZE (1..ub-domain-name-length)),
+  printable  PrintableString (SIZE (1..ub-domain-name-length))
+}
+
+OrganizationName ::= PrintableString (SIZE (1..ub-organization-name-length))
+                     -- see also teletex-organization-name
+
+NumericUserIdentifier ::= NumericString (SIZE (1..ub-numeric-user-id-length))
+
+PersonalName ::= SET { -- see also teletex-personal-name
+  surname     [0] PrintableString (SIZE (1..ub-surname-length)),
+  given-name  [1] PrintableString (SIZE (1..ub-given-name-length)) OPTIONAL,
+  initials    [2] PrintableString (SIZE (1..ub-initials-length)) OPTIONAL,
+  generation-qualifier [3] PrintableString 
+                           (SIZE (1..ub-generation-qualifier-length)) OPTIONAL 
+}
+                        
+
+OrganizationalUnitNames ::= SEQUENCE SIZE (1..ub-organizational-units)
+                                        OF OrganizationalUnitName
+                            -- see also teletex-organizational-unit-names
+
+OrganizationalUnitName ::= PrintableString 
+                           (SIZE (1..ub-organizational-unit-name-length))
+
+
+BuiltInDomainDefinedAttributes ::= 
+                          SEQUENCE SIZE (1..ub-domain-defined-attributes) 
+                                OF BuiltInDomainDefinedAttribute
+
+BuiltInDomainDefinedAttribute ::= SEQUENCE {
+  type PrintableString (SIZE (1..ub-domain-defined-attribute-type-length)),
+  value PrintableString (SIZE (1..ub-domain-defined-attribute-value-length))
+}
+
+
+ExtensionAttributes ::= SET SIZE (1..ub-extension-attributes) 
+                            OF ExtensionAttribute
+
+ExtensionAttribute ::=  SEQUENCE {
+  extension-attribute-type [0] EXPLICIT INTEGER (0..ub-extension-attributes),
+  extension-attribute-value [1] EXPLICIT ANY DEFINED BY
+                                         extension-attribute-type
+}
+
+
+
+
+
 
 END -- of CryptographicMessageSyntax
 
 
+
diff --git a/src/ksba-config.in b/src/ksba-config.in
new file mode 100644 (file)
index 0000000..a3136b5
--- /dev/null
@@ -0,0 +1,93 @@
+#!/bin/sh
+
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+exec_prefix_set=no
+
+ksba_libs="@KSBA_LIBS@"
+ksba_cflags="@KSBA_CFLAGS@"
+
+
+usage()
+{
+       cat <<EOF
+Usage: ksba-config [OPTIONS]
+Options:
+       [--prefix[=DIR]]
+       [--exec-prefix[=DIR]]
+       [--version]
+       [--libs]
+       [--cflags]
+EOF
+       exit $1
+}
+
+if test $# -eq 0; then
+       usage 1 1>&2
+fi
+
+while test $# -gt 0; do
+  case "$1" in
+  -*=*) optarg=`echo "$1" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
+  *) optarg= ;;
+  esac
+
+  case $1 in
+    --prefix=*)
+      prefix=$optarg
+      if test $exec_prefix_set = no ; then
+       exec_prefix=$optarg
+      fi
+      ;;
+    --prefix)
+      echo_prefix=yes
+      ;;
+    --exec-prefix=*)
+      exec_prefix=$optarg
+      exec_prefix_set=yes
+      ;;
+    --exec-prefix)
+      echo_exec_prefix=yes
+      ;;
+    --version)
+      echo "@VERSION@"
+      exit 0
+      ;;
+    --cflags)
+      echo_cflags=yes
+      ;;
+    --libs)
+      echo_libs=yes
+      ;;
+    *)
+      usage 1 1>&2
+      ;;
+  esac
+  shift
+done
+
+if test "$echo_prefix" = "yes"; then
+    echo $prefix
+fi
+
+if test "$echo_exec_prefix" = "yes"; then
+    echo $exec_prefix
+fi
+
+if test "$echo_cflags" = "yes"; then
+    if test "@includedir@" != "/usr/include" ; then
+      includes="-I@includedir@"
+      for i in $ksba_cflags ; do
+       if test "$i" = "-I@includedir@" ; then
+         includes=""
+       fi
+      done
+    fi
+    echo $includes $ksba_cflags
+fi
+
+if test "$echo_libs" = "yes"; then
+    echo ${ksba_libs}
+fi
+
+
index 2e3e4b8..38a9378 100644 (file)
@@ -28,6 +28,7 @@ extern "C" {
 #endif
 
 typedef enum {
+  KSBA_EOF = -1,
   KSBA_No_Error = 0,
   KSBA_General_Error = 1,
   KSBA_Out_Of_Core = 2,
@@ -93,6 +94,7 @@ KsbaError ksba_reader_set_cb (KsbaReader r,
 
 KsbaError ksba_reader_read (KsbaReader r,
                             char *buffer, size_t length, size_t *nread);
+unsigned long ksba_reader_tell (KsbaReader r);
 
 
 /*-- asn1-parse.y --*/
@@ -102,9 +104,22 @@ void ksba_asn_tree_release (KsbaAsnTree tree);
 /*-- asn1-func.c --*/
 void ksba_asn_tree_dump (KsbaAsnTree tree, const char *name, FILE *fp);
 
+/*-- oid.c --*/
+char *ksba_oid_to_str (const char *buffer, size_t length);
+int ksba_oid_from_str (const char *string, char **rbuf, size_t *rlength);
+
+
+/*-- util.c --*/
+void *ksba_malloc (size_t n );
+void *ksba_calloc (size_t n, size_t m );
+void *ksba_realloc (void *p, size_t n);
+char *ksba_strdup (const char *p);
+void  ksba_free ( void *a );
 
 #ifdef __cplusplus
 }
 #endif
 #endif /*KSBA_H*/
 
+
+
diff --git a/src/oid.c b/src/oid.c
new file mode 100644 (file)
index 0000000..2e13099
--- /dev/null
+++ b/src/oid.c
@@ -0,0 +1,136 @@
+/* oid.c - Object identifier helper functions
+ *      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
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include "util.h"
+#include "ber-decoder.h"
+
+
+/* transform the object id from BER-enocding to IETF format */
+
+
+/**
+ * ksba_oid_to_str:
+ * @buffer: A BER encoded OID
+ * @length: The length of this OID
+ * 
+ * Take a buffer with an object identifier in BER encoding and return
+ * a string representing this OID.  We do not use the ASN.1 syntax
+ * here but delimit the arcs with dots, so it is easier to parse in
+ * most cases.  This dotted-decimal notation is also known as LDAPOID
+ * string and described in RFC-2251.
+ *
+ * The function returns an emtry string for an empty buffer and does
+ * no interpretation of the OID.  The caller must free the returned
+ * string using ksba_free() or the function he has registered as a
+ * replacement.
+ * 
+ *
+ * Return value: A allocated string or NULL in case of memory problem.
+ **/
+char *
+ksba_oid_to_str (const char *buffer, size_t length)
+{
+  const unsigned char *buf = buffer;
+  char *string, *p;
+  int n = 0;
+  unsigned long val;
+
+  /* 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 (!length)
+    {
+      *p = 0;
+      return string;
+    }
+
+  /* fixme: open code the sprintf so that we can open with arbitrary
+     long integers - at least we should check for overflow of ulong */
+
+  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 )
+      {
+        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 )
+        {
+          val <<= 7;
+          val |= buf[n] & 0x7f;
+        }
+      sprintf (p, ".%lu", val);
+      p += strlen (p);
+    }
+    
+  *p = 0;
+  return string;
+}
+
+
+/**
+ * ksba_oid_from_str:
+ * @string: A string with the OID in doitted decimal form
+ * @rbuf:   Returns the DER encoded OID
+ * @rlength: and its length
+ * 
+ * Convertes the OID given in dotted decimal form to an DER encoding
+ * and returns it in allocated buffer rbuf and its length in rlength.
+ * rbuf is set to NULL in case of an error and -1 is returned.
+ * Scanning stops at the first white space.
+
+ * The caller must free the returned buffer using ksba_free() or the
+ * function he has registered as a replacement.
+ * 
+ * Return value: Number of bytes scanned from string, or -1 in case of
+ * an error.
+ **/
+int
+ksba_oid_from_str (const char *string, char **rbuf, size_t *rlength)
+{
+  *rbuf = NULL;
+  *rlength = 0;
+
+  return -1; /* error */
+}
+
+
+
+
index 0808bd8..7f928dc 100644 (file)
@@ -68,6 +68,12 @@ ksba_reader_error (KsbaReader r)
   return r? r->error : -1;
 }
 
+unsigned long
+ksba_reader_tell (KsbaReader r)
+{
+  return r? r->nread : 0;
+}
+
 
 /**
  * ksba_reader_set_mem:
@@ -256,6 +262,7 @@ ksba_reader_read (KsbaReader r, char *buffer, size_t length, size_t *nread)
         nbytes = length;
       memcpy (buffer, r->u.mem.buffer + r->u.mem.readpos, nbytes);
       *nread = nbytes;
+      r->nread += nbytes;
       r->u.mem.readpos += nbytes;
     }
   else if (r->type == READER_TYPE_FILE)
@@ -272,7 +279,13 @@ ksba_reader_read (KsbaReader r, char *buffer, size_t length, size_t *nread)
         }
 
       n = fread (buffer, 1, length, r->u.file);
-      *nread = n > 0? n: 0;
+      if (n > 0)
+        {
+          r->nread += n;
+          *nread = n;
+        }
+      else
+        *nread = 0;
       if (n < length)
         {
           if (ferror(r->u.file))
@@ -293,11 +306,12 @@ ksba_reader_read (KsbaReader r, char *buffer, size_t length, size_t *nread)
           r->eof = 1;
           return -1;
         }
+      r->nread += *nread;
     }
-    else 
-      return KSBA_Bug;
+  else 
+    return KSBA_Bug;
 
-    return 0;
+  return 0;
 } 
 
 
index 114b1df..b710767 100644 (file)
@@ -35,6 +35,7 @@ enum reader_type {
 struct ksba_reader_s {
   int eof;
   int error;
+  unsigned long nread;
   enum reader_type type;
   union {
     struct {
@@ -56,3 +57,10 @@ struct ksba_reader_s {
 
 #endif /*READER_H*/
 
+
+
+
+
+
+
+
index 6f18b05..fa90421 100644 (file)
@@ -365,12 +365,6 @@ issuingDistributionPoint ::= SEQUENCE {
 
 
 
-
-
-
-
-
-
 --\f
 -------------------------
 -- x400 address syntax --
@@ -456,16 +450,5 @@ ExtensionAttribute ::=  SEQUENCE {
 }
 
 
---\f
--- UNIVERSAL Types defined in '93 and '98 ASN.1
-UTF8String ::= [UNIVERSAL 12] IMPLICIT OCTET STRING 
-NumericString ::= [UNIVERSAL 18] IMPLICIT OCTET STRING
-PrintableString ::= [UNIVERSAL 19] IMPLICIT OCTET STRING
-TeletexString ::= [UNIVERSAL 20] IMPLICIT OCTET STRING
-IA5String ::= [UNIVERSAL 22] IMPLICIT OCTET STRING
-UniversalString ::= [UNIVERSAL 28] IMPLICIT OCTET STRING  
-BMPString ::= [UNIVERSAL 30] IMPLICIT OCTET STRING
-
-
 END
 
index ea2768a..292c0f3 100644 (file)
 #include "util.h"
 
 /* Wrapper for the common memory allocation functions.  These are here
-   so that we can add hooks.  The corresponding macros shoudl be used.
+   so that we can add hooks.  The corresponding macros should be used.
    These macros are not named xfoo() because this name is commonly
    used for function which die on errror.  We use macronames like
    xtryfoo() instead. */
 
 void *
-_ksba_malloc (size_t n )
+ksba_malloc (size_t n )
 {
   return malloc (n);
 }
 
 void *
-_ksba_calloc (size_t n, size_t m )
+ksba_calloc (size_t n, size_t m )
 {
   return calloc (n, m);
 }
 
 void *
-_ksba_realloc (void *mem, size_t n)
+ksba_realloc (void *mem, size_t n)
 {
   return realloc (mem, n );
 }
 
 
 char *
-_ksba_strdup (const char *str)
+ksba_strdup (const char *str)
 {
   return strdup (str);
 }
 
 
 void 
-_ksba_free ( void *a )
+ksba_free ( void *a )
 {
   free (a);
 }
@@ -77,7 +77,7 @@ out_of_core(void)
 void *
 _ksba_xmalloc (size_t n )
 {
-  void *p = _ksba_malloc (n);
+  void *p = ksba_malloc (n);
   if (!p)
     out_of_core();
   return p;
@@ -86,7 +86,7 @@ _ksba_xmalloc (size_t n )
 void *
 _ksba_xcalloc (size_t n, size_t m )
 {
-  void *p = _ksba_calloc (n,m);
+  void *p = ksba_calloc (n,m);
   if (!p)
     out_of_core();
   return p;
@@ -95,7 +95,7 @@ _ksba_xcalloc (size_t n, size_t m )
 void *
 _ksba_xrealloc (void *mem, size_t n)
 {
-  void *p = _ksba_realloc (mem,n);
+  void *p = ksba_realloc (mem,n);
   if (!p)
     out_of_core();
   return p;
@@ -105,9 +105,22 @@ _ksba_xrealloc (void *mem, size_t n)
 char *
 _ksba_xstrdup (const char *str)
 {
-  char *p = _ksba_strdup (str);
+  char *p = ksba_strdup (str);
   if (!p)
     out_of_core();
   return p;
 }
 
+\f
+#ifndef HAVE_STPCPY
+char *
+stpcpy (char *a,const char *b)
+{
+  while (*b)
+    *a++ = *b++;
+  *a = 0;
+
+  return a;
+}
+#endif
+
index 700517a..2c292cc 100644 (file)
 #ifndef UTIL_H
 #define UTIL_H
 
-void *_ksba_malloc (size_t n );
-void *_ksba_calloc (size_t n, size_t m );
-void *_ksba_realloc (void *p, size_t n);
-char *_ksba_strdup (const char *p);
-void  _ksba_free ( void *a );
+#include "ksba.h"  /* ksba_malloc() etc. */
+
 void *_ksba_xmalloc (size_t n );
 void *_ksba_xcalloc (size_t n, size_t m );
 void *_ksba_xrealloc (void *p, size_t n);
 char *_ksba_xstrdup (const char *p);
 
-#define xtrymalloc(a)    _ksba_malloc((a))
-#define xtrycalloc(a,b)  _ksba_calloc((a),(b))
-#define xtryrealloc(a,b) _ksba_realloc((a),(b))
-#define xtrystrdup(a)    _ksba_strdup((a))
-#define xfree(a)         _ksba_free((a))
+#define xtrymalloc(a)    ksba_malloc((a))
+#define xtrycalloc(a,b)  ksba_calloc((a),(b))
+#define xtryrealloc(a,b) ksba_realloc((a),(b))
+#define xtrystrdup(a)    ksba_strdup((a))
+#define xfree(a)         ksba_free((a))
+
 #define xmalloc(a)       _ksba_xmalloc((a))
 #define xcalloc(a,b)     _ksba_xcalloc((a),(b))
 #define xrealloc(a,b)    _ksba_xrealloc((a),(b))
@@ -74,6 +72,11 @@ char *_ksba_xstrdup (const char *p);
     } while (0)
 
 
+#ifndef HAVE_STPCPY
+char *stpcpy (char *a, const char *b);
+#endif
+
+
 #endif /* UTIL_H */