* libksba.vers: Add new functions.
authorWerner Koch <wk@gnupg.org>
Wed, 28 Apr 2004 16:40:16 +0000 (16:40 +0000)
committerWerner Koch <wk@gnupg.org>
Wed, 28 Apr 2004 16:40:16 +0000 (16:40 +0000)
* crl.h (crl_extn_s, crl_extn_t): New.
(ksba_crl_s): Add member EXTENSION_LIST;
* crl.c (ksba_crl_release): Free an extension list.
(parse_one_extension, store_one_extension): New.
(parse_crl_extensions): Store extensions.
(ksba_crl_get_extension, ksba_crl_get_auth_key_id)
(ksba_crl_get_crl_number): New.

* t-crl-parser.c (print_names): New.
(one_file): Print extensions info.

NEWS
src/ChangeLog
src/certreq.c
src/crl.c
src/crl.h
src/ksba.h
src/libksba.vers
tests/ChangeLog
tests/t-crl-parser.c

diff --git a/NEWS b/NEWS
index 17829c9..0ee2732 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,13 @@ Noteworthy changes in version 0.9.6
 ------------------------------------------------
 
 
+
+ * Interface changes relative to the 0.9.5 release:
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ksba_crl_get_extension               NEW.
+ksba_crl_get_auth_key_id             NEW.
+ksba_crl_get_crl_number              NEW.
+
 Noteworthy changes in version 0.9.5 (2004-04-06)
 ------------------------------------------------
 
index 10842dc..8af5d6d 100644 (file)
@@ -1,3 +1,15 @@
+2004-04-28  Werner Koch  <wk@gnupg.org>
+
+       * libksba.vers: Add new functions.
+
+       * crl.h (crl_extn_s, crl_extn_t): New.
+       (ksba_crl_s): Add member EXTENSION_LIST;
+       * crl.c (ksba_crl_release): Free an extension list.
+       (parse_one_extension, store_one_extension): New.
+       (parse_crl_extensions): Store extensions.
+       (ksba_crl_get_extension, ksba_crl_get_auth_key_id)
+       (ksba_crl_get_crl_number): New.
+
 2004-04-06  Werner Koch  <wk@gnupg.org>
 
        * cms.c (ksba_cms_add_smime_capability): Oops, we forgot to store
index 4f520d4..45ba9ad 100644 (file)
@@ -129,7 +129,7 @@ ksba_certreq_add_subject (ksba_certreq_t cr, const char *name)
   /* this is assumed to be an subjectAltName */
 
   /* We only support email addresses for now, do some very basic
-     checks.  Note that the way we pass the name should match waht
+     checks.  Note that the way we pass the name should match what
      ksba_cert_get_subject() returns */
   namelen = strlen (name);
   if (*name != '<' || name[namelen-1] != '>'
index 9390af2..67b449e 100644 (file)
--- a/src/crl.c
+++ b/src/crl.c
@@ -1,5 +1,5 @@
 /* crl.c - CRL parser
- *      Copyright (C) 2002 g10 Code GmbH
+ *      Copyright (C) 2002, 2004 g10 Code GmbH
  *
  * This file is part of KSBA.
  *
 #include "ber-decoder.h"
 #include "crl.h"
 
-/* we better buffer the hashing */
+static const char oidstr_crlNumber[] = "2.5.29.20";
+static const char oidstr_authorityKeyIdentifier[] = "2.5.29.35";
+
+/* We better buffer the hashing. */
 static inline void
 do_hash (ksba_crl_t crl, const void *buffer, size_t length)
 {
@@ -61,6 +64,101 @@ do_hash (ksba_crl_t crl, const void *buffer, size_t length)
 #define HASH(a,b) do_hash (crl, (a), (b))
 
 
+
+static  void
+parse_skip (unsigned char const **buf, size_t *len, struct tag_info *ti)
+{
+  if (ti->length)
+    {
+      assert (ti->length <= *len);
+      *len -= ti->length;
+      *buf += ti->length;
+    }
+}
+
+static gpg_error_t
+parse_sequence (unsigned char const **buf, size_t *len, struct tag_info *ti)
+{
+  gpg_error_t err;
+
+  err = _ksba_ber_parse_tl (buf, len, ti);
+  if (err)
+    ;
+  else if (!(ti->class == CLASS_UNIVERSAL && ti->tag == TYPE_SEQUENCE
+             && ti->is_constructed) )
+    err = gpg_error (GPG_ERR_INV_OBJ);
+  else if (ti->length > *len)
+    err = gpg_error (GPG_ERR_BAD_BER);
+  return err;
+}
+
+static gpg_error_t
+parse_integer (unsigned char const **buf, size_t *len, struct tag_info *ti)
+{
+  gpg_error_t err;
+
+  err = _ksba_ber_parse_tl (buf, len, ti);
+  if (err)
+     ;
+  else if (!(ti->class == CLASS_UNIVERSAL && ti->tag == TYPE_INTEGER
+             && !ti->is_constructed) )
+    err = gpg_error (GPG_ERR_INV_OBJ);
+  else if (!ti->length)
+    err = gpg_error (GPG_ERR_TOO_SHORT);
+  else if (ti->length > *len)
+    err = gpg_error (GPG_ERR_BAD_BER);
+
+  return err;
+}
+
+static gpg_error_t
+parse_octet_string (unsigned char const **buf, size_t *len, struct tag_info *ti)
+{
+  gpg_error_t err;
+
+  err= _ksba_ber_parse_tl (buf, len, ti);
+  if (err)
+    ;
+  else if (!(ti->class == CLASS_UNIVERSAL && ti->tag == TYPE_OCTET_STRING
+             && !ti->is_constructed) )
+    err = gpg_error (GPG_ERR_INV_OBJ);
+  else if (!ti->length)
+    err = gpg_error (GPG_ERR_TOO_SHORT);
+  else if (ti->length > *len)
+    err = gpg_error (GPG_ERR_BAD_BER);
+
+  return err;
+}
+
+static gpg_error_t
+parse_object_id_into_str (unsigned char const **buf, size_t *len, char **oid)
+{
+  struct tag_info ti;
+  gpg_error_t err;
+
+  *oid = NULL;
+  err = _ksba_ber_parse_tl (buf, len, &ti);
+  if (err)
+    ;
+  else if (!(ti.class == CLASS_UNIVERSAL && ti.tag == TYPE_OBJECT_ID
+                && !ti.is_constructed) )
+    err = gpg_error (GPG_ERR_INV_OBJ);
+  else if (!ti.length)
+    err = gpg_error (GPG_ERR_TOO_SHORT);
+  else if (ti.length > *len)
+    err = gpg_error (GPG_ERR_BAD_BER);
+  else if (!(*oid = ksba_oid_to_str (*buf, ti.length)))
+    err = gpg_error_from_errno (errno);
+  else
+    {
+      *buf += ti.length;
+      *len -= ti.length;
+    }
+  return err;
+}
+
+
+
 \f
 /**
  * ksba_crl_new:
@@ -99,6 +197,14 @@ ksba_crl_release (ksba_crl_t crl)
   xfree (crl->item.serial);
 
   xfree (crl->sigval);
+  while (crl->extension_list)
+    {
+      crl_extn_t tmp = crl->extension_list->next;
+      xfree (crl->extension_list->oid);
+      xfree (crl->extension_list);
+      crl->extension_list = tmp;
+    }
+
   xfree (crl);
 }
 
@@ -197,6 +303,221 @@ ksba_crl_get_issuer (ksba_crl_t crl, char **r_issuer)
   return err;
 }
 
+
+/* Return the CRL extension in OID, CRITICAL, DER and DERLEN.  The
+   caller should iterate IDX from 0 upwards until GPG_ERR_EOF is
+   returned. Note, that the returned values are valid as long as the
+   context is valid and no new parsing has been started. */
+gpg_error_t
+ksba_crl_get_extension (ksba_crl_t crl, int idx, 
+                        char const **oid, int *critical,
+                        unsigned char const **der, size_t *derlen)
+{
+  crl_extn_t e;
+
+  if (!crl)
+    return gpg_error (GPG_ERR_INV_VALUE);
+  if (idx < 0)
+    return gpg_error (GPG_ERR_INV_INDEX);
+
+  for (e=crl->extension_list; e && idx; e = e->next, idx-- )
+    ;
+  if (!e)
+    return gpg_error (GPG_ERR_EOF);
+
+  if (oid)
+    *oid = e->oid;
+  if (critical)
+    *critical = e->critical;
+  if (der)
+    *der = e->der;
+  if (derlen)
+    *derlen = e->derlen;
+
+  return 0;
+}
+
+
+/* Return the authorityKeyIdentifier in r_name and r_serial or in
+   r_keyID.  Note that r_keyID is not yet supported and must be passed
+   as NULL.  GPG_ERR_NO_DATA is returned if no authorityKeyIdentifier
+   or only one using the keyIdentifier method is available. 
+
+   FIXME: This function shares a lot of code with the one in cert.c 
+*/
+gpg_error_t 
+ksba_crl_get_auth_key_id (ksba_crl_t crl,
+                          ksba_sexp_t *r_keyid,
+                          ksba_name_t *r_name,
+                          ksba_sexp_t *r_serial)
+{
+  gpg_error_t err;
+  size_t derlen;
+  const unsigned char *der;
+  struct tag_info ti;
+  char numbuf[30];
+  size_t numbuflen;
+  crl_extn_t e;
+
+  if (r_keyid)
+    return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+  if (!crl || !r_name || !r_serial)
+    return gpg_error (GPG_ERR_INV_VALUE);
+  *r_name = NULL;
+  *r_serial = NULL;
+
+  for (e=crl->extension_list; e; e = e->next)
+    if (!strcmp (e->oid, oidstr_authorityKeyIdentifier))
+      break;
+  if (!e)
+    return gpg_error (GPG_ERR_NO_DATA); /* not available */
+    
+  /* Check that there is only one */
+  {
+    crl_extn_t e2;
+
+    for (e2 = e->next; e2; e2 = e2->next)
+      if (!strcmp (e2->oid, oidstr_authorityKeyIdentifier))
+        return gpg_error (GPG_ERR_DUP_VALUE); 
+  }
+  
+  der = e->der;
+  derlen = e->derlen;
+
+  err = _ksba_ber_parse_tl (&der, &derlen, &ti);
+  if (err)
+    return err;
+  if ( !(ti.class == CLASS_UNIVERSAL && ti.tag == TYPE_SEQUENCE
+         && ti.is_constructed) )
+    return gpg_error (GPG_ERR_INV_CRL_OBJ);
+  if (ti.ndef)
+    return gpg_error (GPG_ERR_NOT_DER_ENCODED);
+  if (ti.length > derlen)
+    return gpg_error (GPG_ERR_BAD_BER);
+
+  err = _ksba_ber_parse_tl (&der, &derlen, &ti);
+  if (err)
+    return err;
+  if (ti.class != CLASS_CONTEXT) 
+    return gpg_error (GPG_ERR_INV_CRL_OBJ); /* we expected a tag */
+  if (ti.ndef)
+    return gpg_error (GPG_ERR_NOT_DER_ENCODED);
+  if (derlen < ti.length)
+    return gpg_error (GPG_ERR_BAD_BER);
+
+  if (ti.tag == 0)
+    { /* We do not support the keyIdentifier method yet, but we need
+         to skip it. */
+      der += ti.length;
+      derlen -= ti.length;
+      if (!derlen)
+        return gpg_error (GPG_ERR_NO_DATA); /* not available */
+        
+      err = _ksba_ber_parse_tl (&der, &derlen, &ti);
+      if (err)
+        return err;
+      if (ti.class != CLASS_CONTEXT) 
+        return gpg_error (GPG_ERR_INV_CRL_OBJ); /* we expected a tag */
+      if (ti.ndef)
+        return gpg_error (GPG_ERR_NOT_DER_ENCODED);
+      if (derlen < ti.length)
+        return gpg_error (GPG_ERR_BAD_BER);
+    }
+
+  if (ti.tag != 1 || !derlen)
+    return gpg_error (GPG_ERR_INV_CRL_OBJ);
+
+  err = _ksba_name_new_from_der (r_name, der, ti.length);
+  if (err)
+    return err;
+
+  der += ti.length;
+  derlen -= ti.length;
+
+  /* Fixme: we should release r_name before returning on error */
+  err = _ksba_ber_parse_tl (&der, &derlen, &ti);
+  if (err)
+    return err;
+  if (ti.class != CLASS_CONTEXT) 
+    return gpg_error (GPG_ERR_INV_CRL_OBJ); /* we expected a tag */
+  if (ti.ndef)
+    return gpg_error (GPG_ERR_NOT_DER_ENCODED);
+  if (derlen < ti.length)
+    return gpg_error (GPG_ERR_BAD_BER);
+
+  if (ti.tag != 2 || !derlen)
+    return gpg_error (GPG_ERR_INV_CRL_OBJ);
+  sprintf (numbuf,"(%u:", (unsigned int)ti.length);
+  numbuflen = strlen (numbuf);
+  *r_serial = xtrymalloc (numbuflen + ti.length + 2);
+  if (!*r_serial)
+    return gpg_error_from_errno (errno);
+  strcpy (*r_serial, numbuf);
+  memcpy (*r_serial+numbuflen, der, ti.length);
+  (*r_serial)[numbuflen + ti.length] = ')';
+  (*r_serial)[numbuflen + ti.length + 1] = 0;
+
+  return 0;
+}
+
+
+/* Return the optional crlNumber in NUMBER or GPG_ERR_NO_DATA if it is
+   not available.  Caller must release NUMBER if the fuction retruned
+   with success. */
+gpg_error_t 
+ksba_crl_get_crl_number (ksba_crl_t crl, ksba_sexp_t *number)
+{
+  gpg_error_t err;
+  size_t derlen;
+  const unsigned char *der;
+  struct tag_info ti;
+  char numbuf[30];
+  size_t numbuflen;
+  crl_extn_t e;
+
+  if (!crl || !number)
+    return gpg_error (GPG_ERR_INV_VALUE);
+  *number = NULL;
+
+  for (e=crl->extension_list; e; e = e->next)
+    if (!strcmp (e->oid, oidstr_crlNumber))
+      break;
+  if (!e)
+    return gpg_error (GPG_ERR_NO_DATA); /* not available */
+    
+  /* Check that there is only one. */
+  {
+    crl_extn_t e2;
+
+    for (e2 = e->next; e2; e2 = e2->next)
+      if (!strcmp (e2->oid, oidstr_crlNumber))
+        return gpg_error (GPG_ERR_DUP_VALUE); 
+  }
+  
+  der = e->der;
+  derlen = e->derlen;
+
+  err = parse_integer (&der, &derlen, &ti);
+  if (err)
+    return err;
+  sprintf (numbuf,"(%u:", (unsigned int)ti.length);
+  numbuflen = strlen (numbuf);
+  *number = xtrymalloc (numbuflen + ti.length + 2);
+  if (!*number)
+    return gpg_error_from_errno (errno);
+  strcpy (*number, numbuf);
+  memcpy (*number+numbuflen, der, ti.length);
+  (*number)[numbuflen + ti.length] = ')';
+  (*number)[numbuflen + ti.length + 1] = 0;
+
+  return 0;
+}
+
+
+
+
 /**
  * ksba_crl_get_update_times:
  * @crl: CRL object
@@ -378,6 +699,101 @@ create_and_run_decoder (ksba_reader_t reader, const char *elem_name,
 }
 
 
+/* Parse the extension in the buffer DER or length DERLEN and return
+   the result in OID, CRITICAL, OFF and LEN. */
+static gpg_error_t
+parse_one_extension (const unsigned char *der, size_t derlen,
+                     char **oid, int *critical, size_t *off, size_t *len)
+{
+  gpg_error_t err;
+  struct tag_info ti;
+  const unsigned char *start = der;
+  
+  *oid = NULL;
+  *critical = 0;
+  *off = *len = 0;
+
+  /* 
+     Extension  ::=  SEQUENCE {
+         extnID      OBJECT IDENTIFIER,
+         critical    BOOLEAN DEFAULT FALSE,
+         extnValue   OCTET STRING }
+  */
+  err = parse_sequence (&der, &derlen, &ti);
+  if (err)
+    goto failure;
+
+  err = parse_object_id_into_str (&der, &derlen, oid);
+  if (err)
+    goto failure;
+
+  err = _ksba_ber_parse_tl (&der, &derlen, &ti);
+  if (err)
+    goto failure;
+  if (ti.length > derlen)
+    return gpg_error (GPG_ERR_BAD_BER);
+  if (ti.class == CLASS_UNIVERSAL && ti.tag == TYPE_BOOLEAN
+           && !ti.is_constructed)
+    { 
+      if (ti.length != 1)
+        goto bad_ber;
+      *critical = !!*der;
+      parse_skip (&der, &derlen, &ti);
+    }
+  else
+    { /* Undo that read. */
+      der -= ti.nhdr;
+      derlen += ti.nhdr;
+    }
+
+  err = parse_octet_string (&der, &derlen, &ti);
+  if (err)
+    goto failure;
+  *off = der - start;
+  *len = ti.length;
+
+  return 0;
+
+ bad_ber:
+  err = gpg_error (GPG_ERR_BAD_BER);
+ failure:
+  xfree (*oid);
+  *oid = NULL;
+  return err;
+}
+
+
+/* Store an extension into the context. */
+static gpg_error_t
+store_one_extension (ksba_crl_t crl, const unsigned char *der, size_t derlen)
+{
+  gpg_error_t err;
+  char *oid;
+  int critical;
+  size_t off, len;
+  crl_extn_t e;
+
+  err = parse_one_extension (der, derlen, &oid, &critical, &off, &len);
+  if (err)
+    return err;
+  e = xtrymalloc (sizeof *e + len - 1);
+  if (!e)
+    {
+      err = gpg_error_from_errno (errno);
+      xfree (oid);
+      return err;
+    }
+  e->oid = oid;
+  e->critical = critical;
+  e->derlen = len;
+  memcpy (e->der, der + off, len);
+  e->next = crl->extension_list;
+  crl->extension_list = e;
+
+  return 0;
+}
+
+
 \f
 /* Parse the fixed block at the beginning.  We use a custom parser
    here because our BER decoder is not yet able to stop at certain
@@ -416,10 +832,12 @@ parse_to_next_update (ksba_crl_t crl)
   if (!outer_ndef)
     {
       if (outer_len < ti.nhdr)
-        return gpg_error (GPG_ERR_BAD_BER); /* triplet header larger that outer sequence */
+        return gpg_error (GPG_ERR_BAD_BER); /* Triplet header larger
+                                               than outer sequence */
       outer_len -= ti.nhdr;
       if (!ti.ndef && outer_len < ti.length)
-        return gpg_error (GPG_ERR_BAD_BER); /* triplet larger that outer sequence */
+        return gpg_error (GPG_ERR_BAD_BER); /* Triplet larger than
+                                               outer sequence */
       outer_len -= ti.length;
     }
   tbs_len = ti.length; 
@@ -850,7 +1268,9 @@ parse_crl_extensions (ksba_crl_t crl)
       if (err)
         return err;
       HASH (tmpbuf, ti.nhdr+ti.length);
-      /* fixme: handle extension */
+      err = store_one_extension (crl, tmpbuf, ti.nhdr+ti.length);
+      if (err)
+        return err;
     }
 
   /* read ahead */
index e72d749..ec3fbea 100644 (file)
--- a/src/crl.h
+++ b/src/crl.h
@@ -28,6 +28,16 @@ typedef struct asn_node_struct *AsnNode;  /* FIXME: should not go here */
 #define HAVE_TYPEDEFD_ASNNODE
 #endif
 
+
+struct crl_extn_s {
+  struct crl_extn_s *next;
+  char *oid;
+  int critical;
+  size_t derlen;
+  unsigned char der[1];
+};
+typedef struct crl_extn_s *crl_extn_t;
+
 struct ksba_crl_s {
   gpg_error_t last_error;
 
@@ -64,6 +74,7 @@ struct ksba_crl_s {
     ksba_isotime_t revocation_date;
   } item;
 
+  crl_extn_t extension_list;
   ksba_sexp_t sigval;
 
   struct {
index 31b8c35..35bed8d 100644 (file)
@@ -372,6 +372,14 @@ void        ksba_crl_set_hash_function (ksba_crl_t crl,
                                         void *hash_fnc_arg);
 const char *ksba_crl_get_digest_algo (ksba_crl_t crl);
 gpg_error_t ksba_crl_get_issuer (ksba_crl_t crl, char **r_issuer);
+gpg_error_t ksba_crl_get_extension (ksba_crl_t crl, int idx, 
+                                    char const **oid, int *critical,
+                                    unsigned char const **der, size_t *derlen);
+gpg_error_t ksba_crl_get_auth_key_id (ksba_crl_t crl,
+                                      ksba_sexp_t *r_keyid,
+                                      ksba_name_t *r_name,
+                                      ksba_sexp_t *r_serial);
+gpg_error_t ksba_crl_get_crl_number (ksba_crl_t crl, ksba_sexp_t *number);
 gpg_error_t ksba_crl_get_update_times (ksba_crl_t crl,
                                        ksba_isotime_t this,
                                        ksba_isotime_t next);
index 75fa1b7..b918ec4 100644 (file)
@@ -61,6 +61,8 @@ KSBA_0.9 {
     ksba_crl_get_sig_val; ksba_crl_get_update_times; ksba_crl_new;
     ksba_crl_parse; ksba_crl_release; ksba_crl_set_hash_function;
     ksba_crl_set_reader;
+    ksba_crl_get_extension; ksba_crl_get_auth_key_id;
+    ksba_crl_get_crl_number;      
 
     ksba_name_enum; ksba_name_get_uri; ksba_name_new; ksba_name_ref;
     ksba_name_release;
index 0d2120c..40b56bb 100644 (file)
@@ -1,3 +1,8 @@
+2004-04-28  Werner Koch  <wk@gnupg.org>
+
+       * t-crl-parser.c (print_names): New.
+       (one_file): Print extensions info.
+
 2004-03-23  Werner Koch  <wk@gnupg.org>
 
        * cert-basic.c (print_oid_and_desc): New.
index 1e65b56..2bb1df8 100644 (file)
@@ -1,5 +1,5 @@
 /* t-crl-parser.c - basic test for the CRl parser.
- *      Copyright (C) 2002 g10 Code GmbH
+ *      Copyright (C) 2002, 2004 g10 Code GmbH
  *
  * This file is part of KSBA.
  *
@@ -47,6 +47,30 @@ my_hasher (void *arg, const void *buffer, size_t length)
 }
 
 
+static void
+print_names (int indent, ksba_name_t name)
+{
+  int idx;
+  const char *s;
+  int indent_all;
+
+  if ((indent_all = (indent < 0)))
+    indent = - indent;
+
+  if (!name)
+    {
+      fputs ("none\n", stdout);
+      return;
+    }
+  
+  for (idx=0; (s = ksba_name_enum (name, idx)); idx++)
+    {
+      char *p = ksba_name_get_uri (name, idx);
+      printf ("%*s%s\n", idx||indent_all?indent:0, "", p?p:s);
+      xfree (p);
+    }
+}
+
 
 
 static void
@@ -165,6 +189,69 @@ one_file (const char *fname)
     fail ("digest algorithm mismatch");
 
   {
+    ksba_name_t name1;
+    ksba_sexp_t serial;
+
+    err = ksba_crl_get_auth_key_id (crl, NULL, &name1, &serial);
+    if (!err || gpg_err_code (err) == GPG_ERR_NO_DATA)
+      {
+        fputs ("AuthorityKeyIdentifier: ", stdout);
+        if (gpg_err_code (err) == GPG_ERR_NO_DATA)
+          fputs ("none", stdout);
+        else
+          {
+            print_names (24, name1);
+            ksba_name_release (name1);
+            fputs ("                serial: ", stdout);
+            print_sexp (serial);
+            ksba_free (serial);
+          }
+        putchar ('\n');
+      }
+    else
+      fail_if_err (err);
+  }
+
+  {
+    ksba_sexp_t serial;
+
+    err = ksba_crl_get_crl_number (crl, &serial);
+    if (!err || gpg_err_code (err) == GPG_ERR_NO_DATA)
+      {
+        fputs ("crlNumber: ", stdout);
+        if (gpg_err_code (err) == GPG_ERR_NO_DATA)
+          fputs ("none", stdout);
+        else
+          {
+            print_sexp (serial);
+            ksba_free (serial);
+          }
+        putchar ('\n');
+      }
+    else
+      fail_if_err (err);
+  }
+
+
+  {
+    int idx, crit;
+    const char *oid;
+    size_t derlen;
+
+    for (idx=0; !(err=ksba_crl_get_extension (crl, idx,
+                                              &oid, &crit,
+                                              NULL, &derlen)); idx++)
+      {
+        printf ("%sExtn: %s   (%lu octets)\n",
+                crit? "Crit":"", oid, (unsigned long)derlen);
+      }
+    if (err && gpg_err_code (err) != GPG_ERR_EOF 
+        && gpg_err_code (err) != GPG_ERR_NO_DATA )
+      fail_if_err (err);
+  }      
+  
+
+  {
     ksba_sexp_t sigval;
 
     sigval = ksba_crl_get_sig_val (crl);
@@ -175,6 +262,7 @@ one_file (const char *fname)
     xfree (sigval);
   }
 
+
   ksba_crl_release (crl);
   ksba_reader_release (r);
   fclose (fp);