]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
allow retrieving extensions in a trust module using GNUTLS_PKCS11_OBJ_FLAG_OVERWRITE_...
authorNikos Mavrogiannopoulos <nmav@redhat.com>
Wed, 10 Sep 2014 14:02:12 +0000 (16:02 +0200)
committerNikos Mavrogiannopoulos <nmav@redhat.com>
Thu, 11 Sep 2014 16:08:21 +0000 (18:08 +0200)
lib/Makefile.am
lib/includes/gnutls/pkcs11.h
lib/includes/gnutls/x509.h
lib/libgnutls.map
lib/pkcs11.c
lib/pkcs11_int.c
lib/pkcs11_int.h
lib/x509/common.h
lib/x509/output.c
lib/x509/x509_ext.c

index bae022a698cb21ecd9d74eda1e6c42fb0d77519c..6acaf8f9b58b266a9b547101799851cef95b043b 100644 (file)
@@ -89,7 +89,7 @@ COBJECTS += crypto-selftests.c crypto-selftests-pk.c
 endif
 
 if ENABLE_PKCS11
-COBJECTS += pkcs11.c pkcs11_privkey.c pkcs11_write.c pkcs11_secret.c \
+COBJECTS += pkcs11.c pkcs11x.c pkcs11_privkey.c pkcs11_write.c pkcs11_secret.c \
        pkcs11_int.c
 endif
 
index 8fd121dab68c3b53647388527fd6d82ab2364b47..93d7ae1f008b3d2366c73f60e4837c2b2386a7db 100644 (file)
@@ -108,6 +108,7 @@ void gnutls_pkcs11_obj_set_pin_function(gnutls_pkcs11_obj_t obj,
  * @GNUTLS_PKCS11_OBJ_FLAG_PRESENT_IN_TRUSTED_MODULE: The object must be present in a marked as trusted module.
  * @GNUTLS_PKCS11_OBJ_FLAG_MARK_CA: Mark the object as a CA.
  * @GNUTLS_PKCS11_OBJ_FLAG_MARK_KEY_WRAP: Mark the generated key pair as wrapping and unwrapping keys.
+ * @GNUTLS_PKCS11_OBJ_FLAG_OVERWRITE_TRUSTMOD_EXT: When an issuer is requested, override its extensions with the ones present in the trust module.
  *
  * Enumeration of different PKCS #11 object flags.
  */
@@ -125,7 +126,8 @@ typedef enum gnutls_pkcs11_obj_flags {
        GNUTLS_PKCS11_OBJ_FLAG_PRESENT_IN_TRUSTED_MODULE = (1<<10),
        GNUTLS_PKCS11_OBJ_FLAG_MARK_CA = (1<<11),
        GNUTLS_PKCS11_OBJ_FLAG_MARK_KEY_WRAP = (1<<12),
-       GNUTLS_PKCS11_OBJ_FLAG_COMPARE_KEY = (1<<13)
+       GNUTLS_PKCS11_OBJ_FLAG_COMPARE_KEY = (1<<13),
+       GNUTLS_PKCS11_OBJ_FLAG_OVERWRITE_TRUSTMOD_EXT = (1<<14)
 } gnutls_pkcs11_obj_flags;
 
 /**
@@ -279,7 +281,8 @@ typedef enum {
        GNUTLS_PKCS11_OBJ_PUBKEY,
        GNUTLS_PKCS11_OBJ_PRIVKEY,
        GNUTLS_PKCS11_OBJ_SECRET_KEY,
-       GNUTLS_PKCS11_OBJ_DATA
+       GNUTLS_PKCS11_OBJ_DATA,
+       GNUTLS_PKCS11_OBJ_X509_CRT_EXTENSION
 } gnutls_pkcs11_obj_type_t;
 
 int
@@ -332,6 +335,11 @@ gnutls_pkcs11_obj_type_t
 gnutls_pkcs11_obj_get_type(gnutls_pkcs11_obj_t obj);
 const char *gnutls_pkcs11_type_get_name(gnutls_pkcs11_obj_type_t type);
 
+int
+gnutls_pkcs11_obj_get_exts(gnutls_pkcs11_obj_t obj,
+                          struct gnutls_x509_ext_st **exts, unsigned int *exts_size,
+                          unsigned int flags);
+
 int
 gnutls_pkcs11_obj_get_flags(gnutls_pkcs11_obj_t obj, unsigned int *oflags);
 char *gnutls_pkcs11_obj_flags_get_str(unsigned int flags);
index 3eeab0eb1dc32d0dd0c5831638ec7d0c4a9b0246..14038b6f2dd748610d00e4f8d2b5d2c78b310f14 100644 (file)
@@ -1354,6 +1354,19 @@ void gnutls_certificate_set_trust_list
     (gnutls_certificate_credentials_t res,
      gnutls_x509_trust_list_t tlist, unsigned flags);
 
+typedef struct gnutls_x509_ext_st {
+       char *oid;
+       unsigned int critical;
+       gnutls_datum_t data;
+} gnutls_x509_ext_st;
+
+void gnutls_x509_ext_deinit(gnutls_x509_ext_st *ext);
+
+int
+gnutls_x509_ext_print(gnutls_x509_ext_st *exts, unsigned int exts_size,
+                     gnutls_certificate_print_formats_t format,
+                     gnutls_datum_t * out);
+
 /* *INDENT-OFF* */
 #ifdef __cplusplus
 }
index 94f99642fc9e547a59d6c8cd947657e4e0166c14..6fc28174845171a63fba45da6d07b1bc5dfd28b6 100644 (file)
@@ -1026,6 +1026,9 @@ GNUTLS_3_1_0 {
        gnutls_x509_trust_list_verify_crt2;
        gnutls_x509_crt_get_extension_by_oid2;
        gnutls_x509_crq_get_extension_by_oid2;
+       gnutls_pkcs11_obj_get_exts;
+       gnutls_x509_ext_deinit;
+       gnutls_x509_ext_print;
 } GNUTLS_3_0_0;
 
 GNUTLS_FIPS140 {
index a7c60296b7761b2126be949f92c542250b072f3c..2e2ea561ad3d641d982bc69fd566c6e94d34cb43 100644 (file)
 #include <pin.h>
 #include <pkcs11_int.h>
 #include <p11-kit/p11-kit.h>
+#include <p11-kit/pkcs11x.h>
 #include <p11-kit/pin.h>
+
 #include <atfork.h>
 
 #define MAX_PROVIDERS 16
 
-/* XXX: try to eliminate this */
-#define MAX_CERT_SIZE 32*1024
 #define MAX_SLOTS 48
 
 extern void *_gnutls_pkcs11_mutex;
@@ -1197,6 +1197,9 @@ pkcs11_obj_import(ck_object_class_t class, gnutls_pkcs11_obj_t obj,
        case CKO_CERTIFICATE:
                obj->type = GNUTLS_PKCS11_OBJ_X509_CRT;
                break;
+       case CKO_X_CERTIFICATE_EXTENSION:
+               obj->type = GNUTLS_PKCS11_OBJ_X509_CRT_EXTENSION;
+               break;
        case CKO_PUBLIC_KEY:
                obj->type = GNUTLS_PKCS11_OBJ_PUBKEY;
                break;
@@ -1503,8 +1506,7 @@ pkcs11_import_object(ck_object_handle_t obj, ck_object_class_t class,
        unsigned long category = 0;
        char label_tmp[PKCS11_LABEL_SIZE];
        char id_tmp[PKCS11_ID_SIZE];
-       uint8_t *cert_data = NULL;
-       gnutls_datum_t id, label, data;
+       gnutls_datum_t id, label, data = {NULL, 0};
 
        /* now figure out flags */
        fobj->flags = 0;
@@ -1571,7 +1573,6 @@ pkcs11_import_object(ck_object_handle_t obj, ck_object_class_t class,
                label.size = a[0].value_len;
        }
 
-
        a[0].type = CKA_ID;
        a[0].value = id_tmp;
        a[0].value_len = sizeof(id_tmp);
@@ -1589,24 +1590,11 @@ pkcs11_import_object(ck_object_handle_t obj, ck_object_class_t class,
        if (label.data == NULL && id.data == NULL)
                return gnutls_assert_val(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE);
 
-       cert_data = gnutls_malloc(MAX_CERT_SIZE);
-       if (cert_data == NULL) {
+       rv = pkcs11_get_attribute_avalue
+           (sinfo->module, sinfo->pks, obj, CKA_VALUE, &data);
+       if (rv != CKR_OK) {
                gnutls_assert();
-               return GNUTLS_E_MEMORY_ERROR;
-       }
-
-       a[0].type = CKA_VALUE;
-       a[0].value = cert_data;
-       a[0].value_len = MAX_CERT_SIZE;
-
-       rv = pkcs11_get_attribute_value
-           (sinfo->module, sinfo->pks, obj, a, 1);
-       if (rv == CKR_OK) {
-               data.data = a[0].value;
-               data.size = a[0].value_len;
-       } else {
-               data.data = NULL;
-               data.size = 0;
+               /* data will be null */
        }
 
        if (class == CKO_PUBLIC_KEY) {
@@ -1633,7 +1621,7 @@ pkcs11_import_object(ck_object_handle_t obj, ck_object_class_t class,
 
        ret = 0;
  cleanup:
-       gnutls_free(cert_data);
+       gnutls_free(data.data);
        return ret;
 }
 
@@ -2578,7 +2566,6 @@ find_objs_cb(struct pkcs11_session_info *sinfo,
                unsigned j;
                gnutls_datum_t id;
 
-               class = -1;
                for (j=0;j<count;j++) {
                        a[0].type = CKA_ID;
                        a[0].value = certid_tmp;
@@ -2593,7 +2580,6 @@ find_objs_cb(struct pkcs11_session_info *sinfo,
                                id.size = 0;
                        }
 
-
                        if (find_data->flags == GNUTLS_PKCS11_OBJ_ATTR_ALL ||
                            find_data->flags == GNUTLS_PKCS11_OBJ_ATTR_MATCH) {
                                a[0].type = CKA_CLASS;
@@ -3094,6 +3080,8 @@ const char *gnutls_pkcs11_type_get_name(gnutls_pkcs11_obj_type_t type)
                return "Secret key";
        case GNUTLS_PKCS11_OBJ_DATA:
                return "Data";
+       case GNUTLS_PKCS11_OBJ_X509_CRT_EXTENSION:
+               return "X.509 certificate extension";
        case GNUTLS_PKCS11_OBJ_UNKNOWN:
        default:
                return "Unknown";
@@ -3116,10 +3104,10 @@ find_cert_cb(struct pkcs11_session_info *sinfo,
        ck_object_handle_t obj;
        unsigned long count, a_vals;
        int found = 0, ret;
-       uint8_t *cert_data = NULL;
        struct find_cert_st *priv = input;
        char label_tmp[PKCS11_LABEL_SIZE];
        char id_tmp[PKCS11_ID_SIZE];
+       gnutls_datum_t data = {NULL, 0};
        unsigned tries, i, finalized;
        ck_bool_t trusted = 1;
 
@@ -3140,14 +3128,6 @@ find_cert_cb(struct pkcs11_session_info *sinfo,
                priv->serial.size == 0)
                return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
 
-       /* search the token for the key ID */
-
-       cert_data = gnutls_malloc(MAX_CERT_SIZE);
-       if (cert_data == NULL) {
-               gnutls_assert();
-               return GNUTLS_E_MEMORY_ERROR;
-       }
-
        /* Find objects with given class and type */
 
        if (priv->key_id.size > 0 && priv->dn.size > 0)
@@ -3234,28 +3214,37 @@ find_cert_cb(struct pkcs11_session_info *sinfo,
                                break;
                        }
 
-                       a[0].type = CKA_VALUE;
-                       a[0].value = cert_data;
-                       a[0].value_len = MAX_CERT_SIZE;
+                       a[0].type = CKA_LABEL;
+                       a[0].value = label_tmp;
+                       a[0].value_len = sizeof(label_tmp);
 
-                       a[1].type = CKA_LABEL;
-                       a[1].value = label_tmp;
-                       a[1].value_len = sizeof(label_tmp);
+                       a[1].type = CKA_ID;
+                       a[1].value = id_tmp;
+                       a[1].value_len = sizeof(id_tmp);
 
-                       a[2].type = CKA_ID;
-                       a[2].value = id_tmp;
-                       a[2].value_len = sizeof(id_tmp);
+                       /* data will contain the certificate */
+                       rv = pkcs11_get_attribute_avalue(sinfo->module, sinfo->pks, obj, CKA_VALUE, &data);
 
-                       if (pkcs11_get_attribute_value
+                       if (rv == CKR_OK && pkcs11_get_attribute_value
                            (sinfo->module, sinfo->pks, obj, a,
-                            3) == CKR_OK) {
-                               gnutls_datum_t id =
-                                   { a[2].value, a[2].value_len };
-                               gnutls_datum_t data =
-                                   { a[0].value, a[0].value_len };
+                            2) == CKR_OK) {
                                gnutls_datum_t label =
+                                   { a[0].value, a[0].value_len };
+                               gnutls_datum_t id =
                                    { a[1].value, a[1].value_len };
 
+                               if (priv->flags & GNUTLS_PKCS11_OBJ_FLAG_OVERWRITE_TRUSTMOD_EXT) {
+                                       gnutls_datum_t spki;
+                                       rv = pkcs11_get_attribute_avalue(sinfo->module, sinfo->pks, obj, CKA_PUBLIC_KEY_INFO, &spki);
+                                       if (rv == CKR_OK) {
+                                               ret = pkcs11_override_cert_exts(sinfo, &spki, &data);
+                                               if (ret < 0) {
+                                                       gnutls_assert();
+                                                       /* non fatal errors */
+                                               }
+                                       }
+                               }
+
                                if (priv->need_import != 0) {
                                        ret =
                                            pkcs11_obj_import(class, priv->obj,
@@ -3315,7 +3304,7 @@ find_cert_cb(struct pkcs11_session_info *sinfo,
        }
 
       cleanup:
-       gnutls_free(cert_data);
+       gnutls_free(data.data);
        if (finalized == 0)
                pkcs11_find_objects_final(sinfo);
 
index 4359ec0fc72c3f83e5ca2412b7bd4ea8f8656aab..9ff2d98bcfd29979d2979aa2dec956d409e424de 100644 (file)
@@ -33,6 +33,7 @@
 #include <pin.h>
 #include <pkcs11_int.h>
 #include <p11-kit/p11-kit.h>
+#include <p11-kit/pkcs11.h>
 #include <p11-kit/pin.h>
 
 ck_rv_t
@@ -104,6 +105,46 @@ pkcs11_get_attribute_value(struct ck_function_list * module,
        return (module)->C_GetAttributeValue(sess, object, templ, count);
 }
 
+/* Returns only a single attribute value, but allocates its data 
+ * Only the type needs to be set.
+ */
+ck_rv_t
+pkcs11_get_attribute_avalue(struct ck_function_list * module,
+                          ck_session_handle_t sess,
+                          ck_object_handle_t object,
+                          ck_attribute_type_t type,
+                          gnutls_datum_t *res)
+{
+       ck_rv_t rv;
+       struct ck_attribute templ;
+       void *t;
+
+       res->data = NULL;
+       res->size = 0;
+
+       templ.type = type;
+       templ.value = NULL;
+       templ.value_len = 0;
+       rv = (module)->C_GetAttributeValue(sess, object, &templ, 1);
+       if (rv == CKR_OK) {
+               if (templ.value_len == 0)
+                       return rv;
+
+               templ.type = type;
+               t = gnutls_malloc(templ.value_len);
+               if (t == NULL)
+                       return gnutls_assert_val(CKR_HOST_MEMORY);
+               templ.value = t;
+               rv = (module)->C_GetAttributeValue(sess, object, &templ, 1);
+               if (rv != CKR_OK) {
+                       gnutls_free(t);
+               }
+               res->data = t;
+               res->size = templ.value_len;
+       }
+       return rv;
+}
+
 ck_rv_t
 pkcs11_get_mechanism_list(struct ck_function_list * module,
                          ck_slot_id_t slot_id,
index bbd4cf2116d7f38f87d0cb0889bff6e67de4e493..3e932a95eac9023809bcad3dba02e61c5fda0238 100644 (file)
@@ -94,6 +94,8 @@ int pkcs11_read_pubkey(struct ck_function_list *module,
                       ck_session_handle_t pks, ck_object_handle_t obj,
                       ck_key_type_t key_type, gnutls_datum_t * pubkey);
 
+int pkcs11_override_cert_exts(struct pkcs11_session_info *sinfo, gnutls_datum_t *spki, gnutls_datum_t *der);
+
 int pkcs11_get_info(struct p11_kit_uri *info,
                    gnutls_pkcs11_obj_info_t itype, void *output,
                    size_t * output_size);
@@ -231,6 +233,13 @@ pkcs11_get_attribute_value(struct ck_function_list *module,
                           struct ck_attribute *templ,
                           unsigned long count);
 
+ck_rv_t
+pkcs11_get_attribute_avalue(struct ck_function_list * module,
+                          ck_session_handle_t sess,
+                          ck_object_handle_t object,
+                          ck_attribute_type_t type,
+                          gnutls_datum_t *res);
+
 ck_rv_t
 pkcs11_get_mechanism_list(struct ck_function_list *module,
                          ck_slot_id_t slot_id,
index 044984841f83e6d5993a974921da4b6334f07d44..48340a12c0fdace8a78db66fba1b1dde8700d6f4 100644 (file)
@@ -214,6 +214,7 @@ int _gnutls_copy_data(gnutls_datum_t* str, uint8_t *out, size_t *out_size);
 
 int _san_othername_to_virtual(const char *oid, size_t oid_size);
 
+int _gnutls_x509_decode_ext(const gnutls_datum_t *der, gnutls_x509_ext_st *out);
 int x509_crt_to_raw_pubkey(const gnutls_datum_t * cert,
                           gnutls_datum_t * rpubkey);
 
index bc6036f6fec50846303ad12a42645c7f73b899bd..f7a6ad338f2d4b5ef8a3c73048c82e90ceeb7255 100644 (file)
@@ -98,7 +98,7 @@ char str_ip[64];
 const char *p;
 unsigned non_ascii = 0, i;
 
-       if ((type == GNUTLS_SAN_DNSNAME
+       if ((type == GNUTLS_SAN_DNSNAME || type == GNUTLS_SAN_OTHERNAME_XMPP
             || type == GNUTLS_SAN_RFC822NAME
             || type == GNUTLS_SAN_URI) && sname != NULL && strlen(sname) != name->size) {
                adds(str,
@@ -154,6 +154,10 @@ unsigned non_ascii = 0, i;
        case GNUTLS_SAN_DN:
                addf(str,  _("%sdirectoryName: %.*s\n"), prefix, name->size, NON_NULL(name->data));
                break;
+
+       case GNUTLS_SAN_OTHERNAME_XMPP:
+               addf(str,  _("%sXMPP: %.*s\n"), prefix, name->size, NON_NULL(name->data));
+               break;
        default:
                addf(str,  _("%sUnknown name: "), prefix);
                _gnutls_buffer_hexprint(str, name->data, name->size);
@@ -161,7 +165,7 @@ unsigned non_ascii = 0, i;
        }
 }
 
-static void print_proxy(gnutls_buffer_st * str, gnutls_x509_crt_t cert)
+static void print_proxy(gnutls_buffer_st * str, gnutls_datum_t *der)
 {
        int pathlen;
        char *policyLanguage;
@@ -169,8 +173,7 @@ static void print_proxy(gnutls_buffer_st * str, gnutls_x509_crt_t cert)
        size_t npolicy;
        int err;
 
-       err = gnutls_x509_crt_get_proxy(cert, NULL,
-                                       &pathlen, &policyLanguage,
+       err = gnutls_x509_ext_import_proxy(der, &pathlen, &policyLanguage,
                                        &policy, &npolicy);
        if (err < 0) {
                addf(str, "error: get_proxy: %s\n", gnutls_strerror(err));
@@ -194,14 +197,16 @@ static void print_proxy(gnutls_buffer_st * str, gnutls_x509_crt_t cert)
                _gnutls_buffer_hexprint(str, policy, npolicy);
                adds(str, "\n");
        }
+       gnutls_free(policy);
+       gnutls_free(policyLanguage);
 }
 
 
-static void print_nc(gnutls_buffer_st * str, const char* prefix, gnutls_x509_crt_t cert)
+static void print_nc(gnutls_buffer_st * str, const char* prefix, gnutls_datum_t *der)
 {
        gnutls_x509_name_constraints_t nc;
        int ret;
-       unsigned critical, idx = 0;
+       unsigned idx = 0;
        gnutls_datum_t name;
        unsigned type;
        char new_prefix[16];
@@ -210,7 +215,7 @@ static void print_nc(gnutls_buffer_st * str, const char* prefix, gnutls_x509_crt
        if (ret < 0)
                return;
 
-       ret = gnutls_x509_crt_get_name_constraints(cert, nc, 0, &critical);
+       ret = gnutls_x509_ext_import_name_constraints(der, nc, 0);
        if (ret < 0)
                goto cleanup;
 
@@ -289,229 +294,97 @@ cleanup:
        gnutls_x509_aia_deinit(aia);
 }
 
-static void print_ski(gnutls_buffer_st * str, gnutls_x509_crt_t cert)
+static void print_ski(gnutls_buffer_st * str, gnutls_datum_t *der)
 {
-       char *buffer = NULL;
-       size_t size = 0;
+       gnutls_datum_t id = {NULL, 0};
        int err;
 
-       err =
-           gnutls_x509_crt_get_subject_key_id(cert, buffer, &size, NULL);
-       if (err != GNUTLS_E_SHORT_MEMORY_BUFFER) {
-               addf(str, "error: get_subject_key_id: %s\n",
-                    gnutls_strerror(err));
-               return;
-       }
-
-       buffer = gnutls_malloc(size);
-       if (!buffer) {
-               addf(str, "error: malloc: %s\n",
-                    gnutls_strerror(GNUTLS_E_MEMORY_ERROR));
-               return;
-       }
-
-       err =
-           gnutls_x509_crt_get_subject_key_id(cert, buffer, &size, NULL);
+       err = gnutls_x509_ext_import_subject_key_id(der, &id);
        if (err < 0) {
-               gnutls_free(buffer);
-               addf(str, "error: get_subject_key_id2: %s\n",
+               addf(str, "error: get_subject_key_id: %s\n",
                     gnutls_strerror(err));
                return;
        }
 
        adds(str, "\t\t\t");
-       _gnutls_buffer_hexprint(str, buffer, size);
+       _gnutls_buffer_hexprint(str, id.data, id.size);
        adds(str, "\n");
 
-       gnutls_free(buffer);
+       gnutls_free(id.data);
 }
 
-#define TYPE_CRL 1
 #define TYPE_CRT 2
 #define TYPE_CRQ 3
-#define TYPE_PUBKEY 4
-
-#define TYPE_CRT_SAN TYPE_CRT
-#define TYPE_CRQ_SAN TYPE_CRQ
-#define TYPE_CRT_IAN 4
 
 typedef union {
        gnutls_x509_crt_t crt;
        gnutls_x509_crq_t crq;
-       gnutls_x509_crl_t crl;
-       gnutls_pubkey_t pubkey;
 } cert_type_t;
 
 static void
-print_aki_gn_serial(gnutls_buffer_st * str, int type, cert_type_t cert)
+print_aki_gn_serial(gnutls_buffer_st * str, gnutls_x509_aki_t aki)
 {
-       char *buffer = NULL;
-       char serial[128];
-       size_t size = 0, serial_size = sizeof(serial);
+       gnutls_datum_t san, other_oid, serial;
        unsigned int alt_type;
-       gnutls_datum_t t;
        int err;
 
-       if (type == TYPE_CRT)
-               err =
-                   gnutls_x509_crt_get_authority_key_gn_serial(cert.crt,
-                                                               0, NULL,
-                                                               &size,
-                                                               &alt_type,
-                                                               serial,
-                                                               &serial_size,
-                                                               NULL);
-       else if (type == TYPE_CRL)
-               err =
-                   gnutls_x509_crl_get_authority_key_gn_serial(cert.crl,
-                                                               0, NULL,
-                                                               &size,
-                                                               &alt_type,
-                                                               serial,
-                                                               &serial_size,
-                                                               NULL);
-       else {
-               gnutls_assert();
-               return;
-       }
-
-       if (err != GNUTLS_E_SHORT_MEMORY_BUFFER) {
-               addf(str, "error: get_authority_key_gn_serial: %s\n",
-                    gnutls_strerror(err));
-               return;
-       }
-
-       buffer = gnutls_malloc(size);
-       if (!buffer) {
-               addf(str, "error: malloc: %s\n",
-                    gnutls_strerror(GNUTLS_E_MEMORY_ERROR));
-               return;
-       }
-
-       if (type == TYPE_CRT)
-               err =
-                   gnutls_x509_crt_get_authority_key_gn_serial(cert.crt,
-                                                               0, buffer,
-                                                               &size,
-                                                               &alt_type,
-                                                               serial,
-                                                               &serial_size,
-                                                               NULL);
-       else
-               err =
-                   gnutls_x509_crl_get_authority_key_gn_serial(cert.crl,
-                                                               0, buffer,
-                                                               &size,
-                                                               &alt_type,
-                                                               serial,
-                                                               &serial_size,
-                                                               NULL);
-
+       err =
+           gnutls_x509_aki_get_cert_issuer(aki,
+                                           0, &alt_type, &san, &other_oid, &serial);
        if (err < 0) {
-               gnutls_free(buffer);
-               addf(str, "error: get_authority_key_gn_serial2: %s\n",
+               addf(str, "error: gnutls_x509_aki_get_cert_issuer: %s\n",
                     gnutls_strerror(err));
                return;
        }
 
-       t.data = (void*)buffer;
-       t.size = size;
-       print_name(str, "\t\t\t", alt_type, &t);
+       print_name(str, "\t\t\t", alt_type, &san);
 
        adds(str, "\t\t\tserial: ");
-       _gnutls_buffer_hexprint(str, serial, serial_size);
+       _gnutls_buffer_hexprint(str, serial.data, serial.size);
        adds(str, "\n");
-
-       gnutls_free(buffer);
 }
 
-static void print_aki(gnutls_buffer_st * str, int type, cert_type_t cert)
+static void print_aki(gnutls_buffer_st * str, gnutls_datum_t *der)
 {
-       char *buffer = NULL;
-       size_t size = 0;
        int err;
+       gnutls_x509_aki_t aki;
+       gnutls_datum_t id;
 
-       if (type == TYPE_CRT)
-               err =
-                   gnutls_x509_crt_get_authority_key_id(cert.crt, buffer,
-                                                        &size, NULL);
-       else if (type == TYPE_CRL)
-               err =
-                   gnutls_x509_crl_get_authority_key_id(cert.crl, buffer,
-                                                        &size, NULL);
-       else {
-               gnutls_assert();
-               return;
-       }
-
-       if (err == GNUTLS_E_X509_UNSUPPORTED_EXTENSION) {
-               /* Check if an alternative name is there */
-               print_aki_gn_serial(str, type, cert);
+       err = gnutls_x509_aki_init(&aki);
+       if (err < 0) {
+               addf(str, "error: gnutls_x509_aki_init: %s\n",
+                    gnutls_strerror(err));
                return;
        }
 
-       if (err != GNUTLS_E_SHORT_MEMORY_BUFFER) {
-               addf(str, "error: get_authority_key_id: %s\n",
+       err = gnutls_x509_ext_import_authority_key_id(der, aki, 0);
+       if (err < 0) {
+               addf(str, "error: gnutls_x509_ext_import_authority_key_id: %s\n",
                     gnutls_strerror(err));
                return;
        }
 
-       buffer = gnutls_malloc(size);
-       if (!buffer) {
-               addf(str, "error: malloc: %s\n",
-                    gnutls_strerror(GNUTLS_E_MEMORY_ERROR));
+       err = gnutls_x509_aki_get_id(aki, &id);
+       if (err == GNUTLS_E_X509_UNSUPPORTED_EXTENSION) {
+               /* Check if an alternative name is there */
+               print_aki_gn_serial(str, aki);
                return;
-       }
-
-       if (type == TYPE_CRT)
-               err =
-                   gnutls_x509_crt_get_authority_key_id(cert.crt, buffer,
-                                                        &size, NULL);
-       else
-               err =
-                   gnutls_x509_crl_get_authority_key_id(cert.crl, buffer,
-                                                        &size, NULL);
-
-       if (err < 0) {
-               gnutls_free(buffer);
-               addf(str, "error: get_authority_key_id2: %s\n",
+       } else if (err < 0) {
+               addf(str, "error: gnutls_x509_aki_get_id: %s\n",
                     gnutls_strerror(err));
                return;
        }
-
+       
        adds(str, "\t\t\t");
-       _gnutls_buffer_hexprint(str, buffer, size);
+       _gnutls_buffer_hexprint(str, id.data, id.size);
        adds(str, "\n");
 
-       gnutls_free(buffer);
+       gnutls_x509_aki_deinit(aki);
 }
 
 static void
-print_key_usage(gnutls_buffer_st * str, const char *prefix, int type,
-               cert_type_t cert)
+print_key_usage2(gnutls_buffer_st * str, const char *prefix, unsigned int key_usage)
 {
-       unsigned int key_usage;
-       int err;
-
-       if (type == TYPE_CRT)
-               err =
-                   gnutls_x509_crt_get_key_usage(cert.crt, &key_usage,
-                                                 NULL);
-       else if (type == TYPE_CRQ)
-               err =
-                   gnutls_x509_crq_get_key_usage(cert.crq, &key_usage,
-                                                 NULL);
-       else if (type == TYPE_PUBKEY)
-               err = gnutls_pubkey_get_key_usage(cert.pubkey, &key_usage);
-       else
-               return;
-
-       if (err < 0) {
-               addf(str, "error: get_key_usage: %s\n",
-                    gnutls_strerror(err));
-               return;
-       }
-
        if (key_usage & GNUTLS_KEY_DIGITAL_SIGNATURE)
                addf(str, _("%sDigital signature.\n"), prefix);
        if (key_usage & GNUTLS_KEY_NON_REPUDIATION)
@@ -533,8 +406,23 @@ print_key_usage(gnutls_buffer_st * str, const char *prefix, int type,
 }
 
 static void
-print_private_key_usage_period(gnutls_buffer_st * str, const char *prefix,
-                              int type, cert_type_t cert)
+print_key_usage(gnutls_buffer_st * str, const char *prefix, gnutls_datum_t *der)
+{
+       unsigned int key_usage;
+       int err;
+
+       err = gnutls_x509_ext_import_key_usage(der, &key_usage);
+       if (err < 0) {
+               addf(str, "error: get_key_usage: %s\n",
+                    gnutls_strerror(err));
+               return;
+       }
+
+       print_key_usage2(str, prefix, key_usage);
+}
+
+static void
+print_private_key_usage_period(gnutls_buffer_st * str, const char *prefix, gnutls_datum_t *der)
 {
        time_t activation, expiration;
        int err;
@@ -542,21 +430,7 @@ print_private_key_usage_period(gnutls_buffer_st * str, const char *prefix,
        struct tm t;
        size_t max;
 
-       if (type == TYPE_CRT)
-               err =
-                   gnutls_x509_crt_get_private_key_usage_period(cert.crt,
-                                                                &activation,
-                                                                &expiration,
-                                                                NULL);
-       else if (type == TYPE_CRQ)
-               err =
-                   gnutls_x509_crq_get_private_key_usage_period(cert.crq,
-                                                                &activation,
-                                                                &expiration,
-                                                                NULL);
-       else
-               return;
-
+       err = gnutls_x509_ext_import_private_key_usage_period(der, &activation, &expiration);
        if (err < 0) {
                addf(str, "error: get_private_key_usage_period: %s\n",
                     gnutls_strerror(err));
@@ -585,166 +459,115 @@ print_private_key_usage_period(gnutls_buffer_st * str, const char *prefix,
 
 }
 
-static void print_crldist(gnutls_buffer_st * str, gnutls_x509_crt_t cert)
+static void print_crldist(gnutls_buffer_st * str, gnutls_datum_t *der)
 {
-       char *buffer = NULL;
-       size_t size;
-       gnutls_datum_t t;
        int err;
        int indx;
+       gnutls_x509_crl_dist_points_t dp;
+       unsigned int flags, type;
+       gnutls_datum_t dist;
+
+       err = gnutls_x509_crl_dist_points_init(&dp);
+       if (err < 0) {
+               addf(str, "error: gnutls_x509_crl_dist_points_init: %s\n",
+                    gnutls_strerror(err));
+               return;
+       }
+
+       err = gnutls_x509_ext_import_crl_dist_points(der, dp, 0);
+       if (err < 0) {
+               addf(str, "error: gnutls_x509_ext_import_crl_dist_points: %s\n",
+                    gnutls_strerror(err));
+               return;
+       }
 
        for (indx = 0;; indx++) {
-               size = 0;
                err =
-                   gnutls_x509_crt_get_crl_dist_points(cert, indx, buffer,
-                                                       &size, NULL, NULL);
+                   gnutls_x509_crl_dist_points_get(dp, indx, &type, &dist, &flags);
                if (err == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
                        return;
-               if (err != GNUTLS_E_SHORT_MEMORY_BUFFER) {
+               else if (err < 0) {
                        addf(str, "error: get_crl_dist_points: %s\n",
                             gnutls_strerror(err));
                        return;
                }
 
-               buffer = gnutls_malloc(size);
-               if (!buffer) {
-                       addf(str, "error: malloc: %s\n",
-                            gnutls_strerror(GNUTLS_E_MEMORY_ERROR));
-                       return;
-               }
-
-               err =
-                   gnutls_x509_crt_get_crl_dist_points(cert, indx, buffer,
-                                                       &size, NULL, NULL);
-               if (err < 0) {
-                       gnutls_free(buffer);
-                       addf(str, "error: get_crl_dist_points2: %s\n",
-                            gnutls_strerror(err));
-                       return;
-               }
-
-               t.data = (void*)buffer;
-               t.size = size;
-               print_name(str, "\t\t\t", err, &t);
-
-               gnutls_free(buffer);
+               print_name(str, "\t\t\t", type, &dist);
        }
 }
 
 static void
-print_key_purpose(gnutls_buffer_st * str, const char *prefix, int type,
-                 cert_type_t cert)
+print_key_purpose(gnutls_buffer_st * str, const char *prefix, gnutls_datum_t *der)
 {
        int indx;
-       char *buffer = NULL;
-       size_t size;
+       gnutls_datum_t oid;
+       char *p;
        int err;
+       gnutls_x509_key_purposes_t purposes;
+       
+       err = gnutls_x509_key_purpose_init(&purposes);
+       if (err < 0) {
+               addf(str, "error: gnutls_x509_key_purpose_init: %s\n",
+                    gnutls_strerror(err));
+               return;
+       }
 
-       for (indx = 0;; indx++) {
-               size = 0;
-               if (type == TYPE_CRT)
-                       err =
-                           gnutls_x509_crt_get_key_purpose_oid(cert.crt,
-                                                               indx,
-                                                               buffer,
-                                                               &size,
-                                                               NULL);
-               else if (type == TYPE_CRQ)
-                       err =
-                           gnutls_x509_crq_get_key_purpose_oid(cert.crq,
-                                                               indx,
-                                                               buffer,
-                                                               &size,
-                                                               NULL);
-               else
-                       return;
+       err = gnutls_x509_ext_import_key_purposes(der, purposes, 0);
+       if (err < 0) {
+               addf(str, "error: gnutls_x509_ext_import_key_purposes: %s\n",
+                    gnutls_strerror(err));
+               return;
+       }
 
+       for (indx = 0;; indx++) {
+               err = gnutls_x509_key_purpose_get(purposes, indx, &oid);
                if (err == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
                        return;
-               if (err != GNUTLS_E_SHORT_MEMORY_BUFFER) {
-                       addf(str, "error: get_key_purpose_oid: %s\n",
+               else if (err < GNUTLS_E_SHORT_MEMORY_BUFFER) {
+                       addf(str, "error: gnutls_x509_key_purpose_get: %s\n",
                             gnutls_strerror(err));
                        return;
                }
 
-               buffer = gnutls_malloc(size);
-               if (!buffer) {
-                       addf(str, "error: malloc: %s\n",
-                            gnutls_strerror(GNUTLS_E_MEMORY_ERROR));
-                       return;
-               }
-
-               if (type == TYPE_CRT)
-                       err =
-                           gnutls_x509_crt_get_key_purpose_oid(cert.crt,
-                                                               indx,
-                                                               buffer,
-                                                               &size,
-                                                               NULL);
-               else
-                       err =
-                           gnutls_x509_crq_get_key_purpose_oid(cert.crq,
-                                                               indx,
-                                                               buffer,
-                                                               &size,
-                                                               NULL);
-
-               if (err < 0) {
-                       gnutls_free(buffer);
-                       addf(str, "error: get_key_purpose_oid2: %s\n",
-                            gnutls_strerror(err));
-                       return;
-               }
-
-               if (strcmp(buffer, GNUTLS_KP_TLS_WWW_SERVER) == 0)
+               p = (void*)oid.data;
+               if (strcmp(p, GNUTLS_KP_TLS_WWW_SERVER) == 0)
                        addf(str, _("%s\t\t\tTLS WWW Server.\n"), prefix);
-               else if (strcmp(buffer, GNUTLS_KP_TLS_WWW_CLIENT) == 0)
+               else if (strcmp(p, GNUTLS_KP_TLS_WWW_CLIENT) == 0)
                        addf(str, _("%s\t\t\tTLS WWW Client.\n"), prefix);
-               else if (strcmp(buffer, GNUTLS_KP_CODE_SIGNING) == 0)
+               else if (strcmp(p, GNUTLS_KP_CODE_SIGNING) == 0)
                        addf(str, _("%s\t\t\tCode signing.\n"), prefix);
-               else if (strcmp(buffer, GNUTLS_KP_EMAIL_PROTECTION) == 0)
+               else if (strcmp(p, GNUTLS_KP_EMAIL_PROTECTION) == 0)
                        addf(str, _("%s\t\t\tEmail protection.\n"),
                             prefix);
-               else if (strcmp(buffer, GNUTLS_KP_TIME_STAMPING) == 0)
+               else if (strcmp(p, GNUTLS_KP_TIME_STAMPING) == 0)
                        addf(str, _("%s\t\t\tTime stamping.\n"), prefix);
-               else if (strcmp(buffer, GNUTLS_KP_OCSP_SIGNING) == 0)
+               else if (strcmp(p, GNUTLS_KP_OCSP_SIGNING) == 0)
                        addf(str, _("%s\t\t\tOCSP signing.\n"), prefix);
-               else if (strcmp(buffer, GNUTLS_KP_IPSEC_IKE) == 0)
+               else if (strcmp(p, GNUTLS_KP_IPSEC_IKE) == 0)
                        addf(str, _("%s\t\t\tIpsec IKE.\n"), prefix);
-               else if (strcmp(buffer, GNUTLS_KP_ANY) == 0)
+               else if (strcmp(p, GNUTLS_KP_ANY) == 0)
                        addf(str, _("%s\t\t\tAny purpose.\n"), prefix);
                else
-                       addf(str, "%s\t\t\t%s\n", prefix, buffer);
-
-               gnutls_free(buffer);
+                       addf(str, "%s\t\t\t%s\n", prefix, p);
        }
+       gnutls_x509_key_purpose_deinit(purposes);
 }
 
 static void
-print_basic(gnutls_buffer_st * str, const char *prefix, int type,
-           cert_type_t cert)
+print_basic(gnutls_buffer_st * str, const char *prefix, gnutls_datum_t *der)
 {
        int pathlen;
+       unsigned ca;
        int err;
 
-       if (type == TYPE_CRT)
-               err =
-                   gnutls_x509_crt_get_basic_constraints(cert.crt, NULL,
-                                                         NULL, &pathlen);
-       else if (type == TYPE_CRQ)
-               err =
-                   gnutls_x509_crq_get_basic_constraints(cert.crq, NULL,
-                                                         NULL, &pathlen);
-       else
-               return;
-
+       err = gnutls_x509_ext_import_basic_constraints(der, &ca, &pathlen);
        if (err < 0) {
                addf(str, "error: get_basic_constraints: %s\n",
                     gnutls_strerror(err));
                return;
        }
 
-       if (err == 0)
+       if (ca == 0)
                addf(str, _("%s\t\t\tCertificate Authority (CA): FALSE\n"),
                     prefix);
        else
@@ -758,187 +581,60 @@ print_basic(gnutls_buffer_st * str, const char *prefix, int type,
 
 
 static void
-print_altname(gnutls_buffer_st * str, const char *prefix,
-             unsigned int altname_type, cert_type_t cert)
+print_altname(gnutls_buffer_st * str, const char *prefix, gnutls_datum_t *der)
 {
        unsigned int altname_idx;
-       gnutls_datum_t t;
-       char *buffer;
-       size_t size;
+       gnutls_subject_alt_names_t names;
+       unsigned int type;
+       gnutls_datum_t san;
+       gnutls_datum_t othername;
        int err;
 
-       for (altname_idx = 0;; altname_idx++) {
+       err = gnutls_subject_alt_names_init(&names);
+       if (err < 0) {
+               addf(str, "error: gnutls_subject_alt_names_init: %s\n",
+                    gnutls_strerror(err));
+               return;
+       }
 
-               buffer = NULL;
-               size = 0;
-               if (altname_type == TYPE_CRT_SAN)
-                       err =
-                           gnutls_x509_crt_get_subject_alt_name(cert.crt,
-                                                                altname_idx,
-                                                                buffer,
-                                                                &size,
-                                                                NULL);
-               else if (altname_type == TYPE_CRQ_SAN)
-                       err =
-                           gnutls_x509_crq_get_subject_alt_name(cert.crq,
-                                                                altname_idx,
-                                                                buffer,
-                                                                &size,
-                                                                NULL,
-                                                                NULL);
-               else if (altname_type == TYPE_CRT_IAN)
-                       err =
-                           gnutls_x509_crt_get_issuer_alt_name(cert.crt,
-                                                               altname_idx,
-                                                               buffer,
-                                                               &size,
-                                                               NULL);
-               else
-                       return;
+       err = gnutls_x509_ext_import_subject_alt_names(der, names, 0);
+       if (err < 0) {
+               addf(str, "error: gnutls_x509_ext_import_subject_alt_names: %s\n",
+                    gnutls_strerror(err));
+               return;
+       }
 
+       for (altname_idx = 0;; altname_idx++) {
+               err = gnutls_subject_alt_names_get(names, altname_idx,
+                                                  &type, &san, &othername);
                if (err == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
                        break;
-               if (err < 0 && err != GNUTLS_E_SHORT_MEMORY_BUFFER) {
+               else if (err < 0) {
                        addf(str,
-                            "error: get_subject/issuer_alt_name: %s\n",
+                            "error: gnutls_subject_alt_names_get: %s\n",
                             gnutls_strerror(err));
                        return;
                }
 
-               buffer = gnutls_malloc(size);
-               if (!buffer) {
-                       addf(str, "error: malloc: %s\n",
-                            gnutls_strerror(GNUTLS_E_MEMORY_ERROR));
-                       return;
-               }
-
-               if (altname_type == TYPE_CRT_SAN) {
-                       err =
-                           gnutls_x509_crt_get_subject_alt_name(cert.crt,
-                                                                altname_idx,
-                                                                buffer,
-                                                                &size,
-                                                                NULL);
-               } else if (altname_type == TYPE_CRQ_SAN) {
-                       err =
-                           gnutls_x509_crq_get_subject_alt_name(cert.crq,
-                                                                altname_idx,
-                                                                buffer,
-                                                                &size,
-                                                                NULL,
-                                                                NULL);
-               } else if (altname_type == TYPE_CRT_IAN) {
-                       err =
-                           gnutls_x509_crt_get_issuer_alt_name(cert.crt,
-                                                               altname_idx,
-                                                               buffer,
-                                                               &size,
-                                                               NULL);
-               }
-               if (err < 0) {
-                       gnutls_free(buffer);
+               if (type == GNUTLS_SAN_OTHERNAME) {
                        addf(str,
-                            "error: get_subject/issuer_alt_name2: %s\n",
-                            gnutls_strerror(err));
-                       return;
-               }
-
-               if (err == GNUTLS_SAN_OTHERNAME) {
-                       char *oid = NULL;
-                       size_t oidsize;
-
-                       oidsize = 0;
-                       if (altname_type == TYPE_CRT_SAN)
-                               err =
-                                   gnutls_x509_crt_get_subject_alt_othername_oid
-                                   (cert.crt, altname_idx, oid, &oidsize);
-                       else if (altname_type == TYPE_CRQ_SAN)
-                               err =
-                                   gnutls_x509_crq_get_subject_alt_othername_oid
-                                   (cert.crq, altname_idx, oid, &oidsize);
-                       else if (altname_type == TYPE_CRT_IAN)
-                               err =
-                                   gnutls_x509_crt_get_issuer_alt_othername_oid
-                                   (cert.crt, altname_idx, oid, &oidsize);
-
-                       if (err != GNUTLS_E_SHORT_MEMORY_BUFFER) {
-                               gnutls_free(buffer);
-                               addf(str,
-                                    "error: get_subject/issuer_alt_othername_oid: %s (%d)\n",
-                                    gnutls_strerror(err), err);
-                               return;
-                       }
-
-                       oid = gnutls_malloc(oidsize);
-                       if (!oid) {
-                               gnutls_free(buffer);
-                               addf(str, "error: malloc: %s\n",
-                                    gnutls_strerror
-                                    (GNUTLS_E_MEMORY_ERROR));
-                               return;
-                       }
-
-                       if (altname_type == TYPE_CRT_SAN)
-                               err =
-                                   gnutls_x509_crt_get_subject_alt_othername_oid
-                                   (cert.crt, altname_idx, oid, &oidsize);
-                       else if (altname_type == TYPE_CRQ_SAN)
-                               err =
-                                   gnutls_x509_crq_get_subject_alt_othername_oid
-                                   (cert.crq, altname_idx, oid, &oidsize);
-                       else if (altname_type == TYPE_CRT_IAN)
-                               err =
-                                   gnutls_x509_crt_get_issuer_alt_othername_oid
-                                   (cert.crt, altname_idx, oid, &oidsize);
-
-                       if (err < 0) {
-                               gnutls_free(buffer);
-                               gnutls_free(oid);
-                               addf(str,
-                                    "error: get_subject_alt_othername_oid2: %s\n",
-                                    gnutls_strerror(err));
-                               return;
-                       }
-
-                       if (err == GNUTLS_SAN_OTHERNAME_XMPP) {
-                               if (strlen(buffer) != size) {
-                                       adds(str,
-                                            _
-                                            ("warning: altname contains an embedded NUL, "
-                                             "replacing with '!'\n"));
-                                       while (strlen(buffer) < size)
-                                               buffer[strlen(buffer)] =
-                                                   '!';
-                               }
-
-                               addf(str,
-                                    _("%s\t\t\tXMPP Address: %.*s\n"),
-                                    prefix, (int) size, buffer);
-                       } else {
-                               addf(str,
-                                    _("%s\t\t\totherName OID: %.*s\n"),
-                                    prefix, (int) oidsize, oid);
-                               addf(str, _("%s\t\t\totherName DER: "),
+                            _("%s\t\t\totherName OID: %.*s\n"),
+                            prefix, (int)othername.size, (char*)othername.data);
+                       addf(str, _("%s\t\t\totherName DER: "),
                                     prefix);
-                               _gnutls_buffer_hexprint(str, buffer, size);
-                               addf(str, _("\n%s\t\t\totherName ASCII: "),
+                       _gnutls_buffer_hexprint(str, san.data, san.size);
+                       addf(str, _("\n%s\t\t\totherName ASCII: "),
                                     prefix);
-                               _gnutls_buffer_asciiprint(str, buffer,
-                                                         size);
+                       _gnutls_buffer_asciiprint(str, (char*)san.data, san.size);
                                addf(str, "\n");
-                       }
-                       gnutls_free(oid);
                } else {
                        char pfx[16];
-                       t.data = (void*)buffer;
-                       t.size = size;
 
                        snprintf(pfx, sizeof(pfx), "%s\t\t\t", prefix);
-                       print_name(str, pfx, err, &t);
+                       print_name(str, pfx, type, &san);
                }
-
-               gnutls_free(buffer);
        }
+       gnutls_subject_alt_names_deinit(names);
 }
 
 static void
@@ -999,333 +695,308 @@ print_unique_ids(gnutls_buffer_st * str, const gnutls_x509_crt_t cert)
        }
 }
 
-static void
-print_extensions(gnutls_buffer_st * str, const char *prefix, int type,
-                cert_type_t cert)
+struct ext_indexes_st {
+       int san;
+       int ian;
+       int proxy;
+       int basic;
+       int keyusage;
+       int keypurpose;
+       int ski;
+       int aki, nc;
+       int crldist, pkey_usage_period;
+};
+
+static void print_extension(gnutls_buffer_st * str, const char *prefix,
+                           struct ext_indexes_st *idx, const char *oid,
+                           unsigned critical, gnutls_datum_t *der)
 {
-       unsigned i, j;
        int err;
-       int san_idx = 0;
-       int ian_idx = 0;
-       int proxy_idx = 0;
-       int basic_idx = 0;
-       int keyusage_idx = 0;
-       int keypurpose_idx = 0;
-       int ski_idx = 0;
-       int aki_idx = 0, nc_idx = 0;
-       int crldist_idx = 0, pkey_usage_period_idx = 0;
-       gnutls_datum_t der = {NULL, 0};
+       unsigned j;
        char pfx[16];
 
-       for (i = 0;; i++) {
-               char oid[MAX_OID_SIZE] = "";
-               size_t sizeof_oid = sizeof(oid);
-               unsigned int critical;
+       if (strcmp(oid, "2.5.29.19") == 0) {
+               if (idx->basic) {
+                       addf(str,
+                            "error: more than one basic constraint\n");
+               }
 
-               if (type == TYPE_CRT)
-                       err =
-                           gnutls_x509_crt_get_extension_info(cert.crt, i,
-                                                              oid,
-                                                              &sizeof_oid,
-                                                              &critical);
+               addf(str, _("%s\t\tBasic Constraints (%s):\n"),
+                    prefix,
+                    critical ? _("critical") : _("not critical"));
 
-               else if (type == TYPE_CRQ)
-                       err =
-                           gnutls_x509_crq_get_extension_info(cert.crq, i,
-                                                              oid,
-                                                              &sizeof_oid,
-                                                              &critical);
-               else {
-                       gnutls_assert();
+               print_basic(str, prefix, der);
+               idx->basic++;
+
+       } else if (strcmp(oid, "2.5.29.14") == 0) {
+               if (idx->ski) {
+                       addf(str,
+                            "error: more than one SKI extension\n");
+               }
+
+               addf(str,
+                    _("%s\t\tSubject Key Identifier (%s):\n"),
+                    prefix,
+                    critical ? _("critical") : _("not critical"));
+
+               print_ski(str, der);
+
+               idx->ski++;
+       } else if (strcmp(oid, "2.5.29.32") == 0) {
+               struct gnutls_x509_policy_st policy;
+               gnutls_x509_policies_t policies;
+               const char *name;
+               int x;
+
+               err = gnutls_x509_policies_init(&policies);
+               if (err < 0) {
+                       addf(str,
+                            "error: certificate policies: %s\n",
+                            gnutls_strerror(err));
                        return;
                }
 
+               err = gnutls_x509_ext_import_policies(der, policies, 0);
                if (err < 0) {
-                       if (err == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
-                               break;
-                       addf(str, "error: get_extension_info: %s\n",
+                       addf(str,
+                            "error: certificate policies import: %s\n",
                             gnutls_strerror(err));
-                       continue;
+                       return;
                }
 
-               if (i == 0)
-                       addf(str, _("%s\tExtensions:\n"), prefix);
+               for (x = 0;; x++) {
+                       err = gnutls_x509_policies_get(policies, x, &policy);
+                       if (err ==
+                           GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
+                               break;
 
-               if (strcmp(oid, "2.5.29.19") == 0) {
-                       if (basic_idx) {
+                       if (err < 0) {
                                addf(str,
-                                    "error: more than one basic constraint\n");
-                               continue;
+                                    "error: certificate policy: %s\n",
+                                    gnutls_strerror(err));
+                               break;
                        }
 
-                       addf(str, _("%s\t\tBasic Constraints (%s):\n"),
-                            prefix,
-                            critical ? _("critical") : _("not critical"));
-
-                       print_basic(str, prefix, type, cert);
-
-                       basic_idx++;
-               } else if (strcmp(oid, "2.5.29.14") == 0) {
-                       if (ski_idx) {
+                       if (x == 0)
                                addf(str,
-                                    "error: more than one SKI extension\n");
-                               continue;
+                                    "%s\t\tCertificate Policies (%s):\n",
+                                    prefix,
+                                    critical ? _("critical") :
+                                    _("not critical"));
+
+                       addf(str, "%s\t\t\t%s\n", prefix, policy.oid);
+                       for (j = 0; j < policy.qualifiers; j++) {
+                               if (policy.qualifier[j].type ==
+                                   GNUTLS_X509_QUALIFIER_URI)
+                                       name = "URI";
+                               else if (policy.qualifier[j].
+                                        type ==
+                                        GNUTLS_X509_QUALIFIER_NOTICE)
+                                       name = "Note";
+                               else
+                                       name = "Unknown qualifier";
+                               addf(str, "%s\t\t\t\t%s: %s\n",
+                                    prefix, name,
+                                    policy.qualifier[j].data);
                        }
+                       gnutls_x509_policy_release(&policy);
+               }
+               gnutls_x509_policies_deinit(policies);
+       } else if (strcmp(oid, "2.5.29.35") == 0) {
 
+               if (idx->aki) {
                        addf(str,
-                            _("%s\t\tSubject Key Identifier (%s):\n"),
-                            prefix,
-                            critical ? _("critical") : _("not critical"));
-
-                       if (type == TYPE_CRT)
-                               print_ski(str, cert.crt);
-
-                       ski_idx++;
-               } else if (strcmp(oid, "2.5.29.32") == 0) {
-                       struct gnutls_x509_policy_st policy;
-                       const char *name;
-                       int x;
-
-                       for (x = 0;; x++) {
-                               err =
-                                   gnutls_x509_crt_get_policy(cert.crt, x,
-                                                              &policy,
-                                                              &critical);
-                               if (err ==
-                                   GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
-                                       break;
-
-                               if (err < 0) {
-                                       addf(str,
-                                            "error: certificate policy: %s\n",
-                                            gnutls_strerror(err));
-                                       break;
-                               }
-
-                               if (x == 0)
-                                       addf(str,
-                                            "%s\t\tCertificate Policies (%s):\n",
-                                            prefix,
-                                            critical ? _("critical") :
-                                            _("not critical"));
-
-                               addf(str, "%s\t\t\t%s\n", prefix,
-                                    policy.oid);
-                               for (j = 0; j < policy.qualifiers; j++) {
-                                       if (policy.qualifier[j].type ==
-                                           GNUTLS_X509_QUALIFIER_URI)
-                                               name = "URI";
-                                       else if (policy.qualifier[j].
-                                                type ==
-                                                GNUTLS_X509_QUALIFIER_NOTICE)
-                                               name = "Note";
-                                       else
-                                               name = "Unknown qualifier";
-                                       addf(str, "%s\t\t\t\t%s: %s\n",
-                                            prefix, name,
-                                            policy.qualifier[j].data);
-                               }
+                            "error: more than one AKI extension\n");
+               }
 
-                               gnutls_x509_policy_release(&policy);
-                       }
-               } else if (strcmp(oid, "2.5.29.35") == 0) {
+               addf(str,
+                    _("%s\t\tAuthority Key Identifier (%s):\n"),
+                    prefix,
+                    critical ? _("critical") : _("not critical"));
 
-                       if (aki_idx) {
-                               addf(str,
-                                    "error: more than one AKI extension\n");
-                               continue;
-                       }
+               print_aki(str, der);
 
+               idx->aki++;
+       } else if (strcmp(oid, "2.5.29.15") == 0) {
+               if (idx->keyusage) {
                        addf(str,
-                            _("%s\t\tAuthority Key Identifier (%s):\n"),
-                            prefix,
-                            critical ? _("critical") : _("not critical"));
-
-                       if (type == TYPE_CRT)
-                               print_aki(str, TYPE_CRT, cert);
-
-                       aki_idx++;
-               } else if (strcmp(oid, "2.5.29.15") == 0) {
-                       if (keyusage_idx) {
-                               addf(str,
-                                    "error: more than one key usage extension\n");
-                               continue;
-                       }
+                            "error: more than one key usage extension\n");
+               }
 
-                       addf(str, _("%s\t\tKey Usage (%s):\n"), prefix,
+               addf(str, _("%s\t\tKey Usage (%s):\n"), prefix,
                             critical ? _("critical") : _("not critical"));
 
-                       snprintf(pfx, sizeof(pfx), "%s\t\t\t", prefix);
-                       print_key_usage(str, pfx, type, cert);
-
-                       keyusage_idx++;
-               } else if (strcmp(oid, "2.5.29.16") == 0) {
-                       if (pkey_usage_period_idx) {
-                               addf(str,
-                                    "error: more than one private key usage period extension\n");
-                               continue;
-                       }
+               snprintf(pfx, sizeof(pfx), "%s\t\t\t", prefix);
+               print_key_usage(str, pfx, der);
 
+               idx->keyusage++;
+       } else if (strcmp(oid, "2.5.29.16") == 0) {
+               if (idx->pkey_usage_period) {
                        addf(str,
-                            _("%s\t\tPrivate Key Usage Period (%s):\n"),
-                            prefix,
-                            critical ? _("critical") : _("not critical"));
-
-                       print_private_key_usage_period(str, prefix, type,
-                                                      cert);
-
-                       pkey_usage_period_idx++;
-               } else if (strcmp(oid, "2.5.29.37") == 0) {
-                       if (keypurpose_idx) {
-                               addf(str,
-                                    "error: more than one key purpose extension\n");
-                               continue;
-                       }
+                            "error: more than one private key usage period extension\n");
+               }
 
-                       addf(str, _("%s\t\tKey Purpose (%s):\n"), prefix,
-                            critical ? _("critical") : _("not critical"));
+               addf(str,
+                    _("%s\t\tPrivate Key Usage Period (%s):\n"),
+                    prefix,
+                    critical ? _("critical") : _("not critical"));
 
-                       print_key_purpose(str, prefix, type, cert);
-                       keypurpose_idx++;
-               } else if (strcmp(oid, "2.5.29.17") == 0) {
-                       if (san_idx) {
-                               addf(str,
-                                    "error: more than one SKI extension\n");
-                               continue;
-                       }
+               print_private_key_usage_period(str, prefix, der);
 
+               idx->pkey_usage_period++;
+       } else if (strcmp(oid, "2.5.29.37") == 0) {
+               if (idx->keypurpose) {
                        addf(str,
-                            _("%s\t\tSubject Alternative Name (%s):\n"),
-                            prefix,
-                            critical ? _("critical") : _("not critical"));
+                            "error: more than one key purpose extension\n");
+               }
 
-                       print_altname(str, prefix, type, cert);
+               addf(str, _("%s\t\tKey Purpose (%s):\n"), prefix,
+                    critical ? _("critical") : _("not critical"));
 
-                       san_idx++;
-               } else if (strcmp(oid, "2.5.29.18") == 0) {
-                       if (ian_idx) {
-                               addf(str,
-                                    "error: more than one Issuer AltName extension\n");
-                               continue;
-                       }
+               print_key_purpose(str, prefix, der);
+               idx->keypurpose++;
+       } else if (strcmp(oid, "2.5.29.17") == 0) {
+               if (idx->san) {
+                       addf(str,
+                            "error: more than one SKI extension\n");
+               }
 
+               addf(str,
+                    _("%s\t\tSubject Alternative Name (%s):\n"),
+                    prefix,
+                    critical ? _("critical") : _("not critical"));
+                       print_altname(str, prefix, der);
+               idx->san++;
+       } else if (strcmp(oid, "2.5.29.18") == 0) {
+               if (idx->ian) {
                        addf(str,
-                            _("%s\t\tIssuer Alternative Name (%s):\n"),
-                            prefix,
-                            critical ? _("critical") : _("not critical"));
+                            "error: more than one Issuer AltName extension\n");
+               }
 
-                       print_altname(str, prefix, TYPE_CRT_IAN, cert);
+               addf(str,
+                    _("%s\t\tIssuer Alternative Name (%s):\n"),
+                    prefix,
+                    critical ? _("critical") : _("not critical"));
 
-                       ian_idx++;
-               } else if (strcmp(oid, "2.5.29.31") == 0) {
-                       if (crldist_idx) {
-                               addf(str,
-                                    "error: more than one CRL distribution point\n");
-                               continue;
-                       }
+               print_altname(str, prefix, der);
 
+               idx->ian++;
+       } else if (strcmp(oid, "2.5.29.31") == 0) {
+               if (idx->crldist) {
                        addf(str,
-                            _("%s\t\tCRL Distribution points (%s):\n"),
-                            prefix,
-                            critical ? _("critical") : _("not critical"));
+                            "error: more than one CRL distribution point\n");
+               }
 
-                       if (type == TYPE_CRT)
-                               print_crldist(str, cert.crt);
-                       crldist_idx++;
-               } else if (strcmp(oid, "1.3.6.1.5.5.7.1.14") == 0) {
-                       if (proxy_idx) {
-                               addf(str,
-                                    "error: more than one proxy extension\n");
-                               continue;
-                       }
+               addf(str,
+                    _("%s\t\tCRL Distribution points (%s):\n"),
+                    prefix,
+                    critical ? _("critical") : _("not critical"));
 
+               print_crldist(str, der);
+               idx->crldist++;
+       } else if (strcmp(oid, "1.3.6.1.5.5.7.1.14") == 0) {
+               if (idx->proxy) {
                        addf(str,
+                            "error: more than one proxy extension\n");
+               }
+
+               addf(str,
                             _
-                            ("%s\t\tProxy Certificate Information (%s):\n"),
-                            prefix,
-                            critical ? _("critical") : _("not critical"));
+                    ("%s\t\tProxy Certificate Information (%s):\n"),
+                    prefix,
+                    critical ? _("critical") : _("not critical"));
 
-                       if (type == TYPE_CRT)
-                               print_proxy(str, cert.crt);
+               print_proxy(str, der);
 
-                       proxy_idx++;
-               } else if (strcmp(oid, "1.3.6.1.5.5.7.1.1") == 0) {
-                       addf(str, _("%s\t\tAuthority Information "
-                                   "Access (%s):\n"), prefix,
-                            critical ? _("critical") : _("not critical"));
+               idx->proxy++;
+       } else if (strcmp(oid, "1.3.6.1.5.5.7.1.1") == 0) {
+               addf(str, _("%s\t\tAuthority Information "
+                           "Access (%s):\n"), prefix,
+                    critical ? _("critical") : _("not critical"));
 
-                       if (type == TYPE_CRT)
-                               err =
-                                   gnutls_x509_crt_get_extension_data2
-                                   (cert.crt, i, &der);
-                       else if (type == TYPE_CRQ)
-                               err =
-                                   gnutls_x509_crq_get_extension_data2
-                                   (cert.crq, i, &der);
-                       else {
-                               gnutls_assert();
-                               return;
-                       }
+               print_aia(str, der);
+       } else if (strcmp(oid, "2.5.29.30") == 0) {
+               if (idx->nc) {
+                       addf(str,
+                            "error: more than one name constraints extension\n");
+               }
+               idx->nc++;
 
-                       if (err < 0) {
-                               addf(str,
-                                    "error: get_extension_data2: %s\n",
-                                    gnutls_strerror(err));
-                               continue;
-                       }
+               addf(str, _("%s\t\tName Constraints (%s):\n"), prefix,
+                    critical ? _("critical") : _("not critical"));
 
-                       print_aia(str, &der);
+               print_nc(str, prefix, der);
+       } else {
+               addf(str, _("%s\t\tUnknown extension %s (%s):\n"),
+                    prefix, oid,
+                    critical ? _("critical") : _("not critical"));
 
-                       _gnutls_free_datum(&der);
-               } else if (strcmp(oid, "2.5.29.30") == 0) {
-                       if (nc_idx) {
-                               addf(str,
-                                    "error: more than one name constraints extension\n");
-                               continue;
-                       }
-                       nc_idx++;
+               addf(str, _("%s\t\t\tASCII: "), prefix);
+               _gnutls_buffer_asciiprint(str, (char*)der->data, der->size);
 
-                       addf(str, _("%s\t\tName Constraints (%s):\n"), prefix,
-                            critical ? _("critical") : _("not critical"));
+               addf(str, "\n");
+               addf(str, _("%s\t\t\tHexdump: "), prefix);
+               _gnutls_buffer_hexprint(str, (char*)der->data, der->size);
+               adds(str, "\n");
+       }
+}
 
-                       if (type == TYPE_CRT)
-                               print_nc(str, prefix, cert.crt);
-               } else {
+static void
+print_extensions(gnutls_buffer_st * str, const char *prefix, int type,
+                cert_type_t cert)
+{
+       unsigned i;
+       int err;
+       gnutls_datum_t der = {NULL, 0};
+       struct ext_indexes_st idx;
 
-                       addf(str, _("%s\t\tUnknown extension %s (%s):\n"),
-                            prefix, oid,
-                            critical ? _("critical") : _("not critical"));
+       memset(&idx, 0, sizeof(idx));
 
-                       if (type == TYPE_CRT)
-                               err =
-                                   gnutls_x509_crt_get_extension_data2
-                                   (cert.crt, i, &der);
-                       else if (type == TYPE_CRQ)
-                               err =
-                                   gnutls_x509_crq_get_extension_data2
-                                   (cert.crq, i, &der);
-                       else {
-                               gnutls_assert();
-                               return;
-                       }
+       for (i = 0;; i++) {
+               char oid[MAX_OID_SIZE] = "";
+               size_t sizeof_oid = sizeof(oid);
+               unsigned int critical;
 
-                       if (err < 0) {
-                               addf(str,
-                                    "error: get_extension_data2: %s\n",
-                                    gnutls_strerror(err));
-                               continue;
-                       }
+               if (type == TYPE_CRT)
+                       err =
+                           gnutls_x509_crt_get_extension_info(cert.crt, i,
+                                                              oid,
+                                                              &sizeof_oid,
+                                                              &critical);
 
-                       addf(str, _("%s\t\t\tASCII: "), prefix);
-                       _gnutls_buffer_asciiprint(str, (char*)der.data, der.size);
-                       addf(str, "\n");
+               else if (type == TYPE_CRQ)
+                       err =
+                           gnutls_x509_crq_get_extension_info(cert.crq, i,
+                                                              oid,
+                                                              &sizeof_oid,
+                                                              &critical);
+               else {
+                       gnutls_assert();
+                       return;
+               }
 
-                       addf(str, _("%s\t\t\tHexdump: "), prefix);
-                       _gnutls_buffer_hexprint(str, (char*)der.data, der.size);
-                       adds(str, "\n");
+               if (err < 0) {
+                       if (err == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
+                               break;
+                       addf(str, "error: get_extension_info: %s\n",
+                            gnutls_strerror(err));
+                       continue;
+               }
+
+               if (i == 0)
+                       addf(str, _("%s\tExtensions:\n"), prefix);
 
-                       _gnutls_free_datum(&der);
+               if (type == TYPE_CRT)
+                       err = gnutls_x509_crt_get_extension_data2(cert.crt, i, &der);
+               else
+                       err = gnutls_x509_crq_get_extension_data2(cert.crq, i, &der);
+
+               if (err < 0) {
+                       der.data = NULL;
+                       der.size = 0;
                }
+
+               print_extension(str, prefix, &idx, oid, critical, &der);
        }
 }
 
@@ -1997,7 +1668,7 @@ static void print_oneline(gnutls_buffer_st * str, gnutls_x509_crt_t cert)
  * gnutls_x509_crt_print:
  * @cert: The structure to be printed
  * @format: Indicate the format to use
- * @out: Newly allocated datum with (0) terminated string.
+ * @out: Newly allocated datum with zero terminated string.
  *
  * This function will pretty print a X.509 certificate, suitable for
  * display to a human.
@@ -2222,7 +1893,7 @@ print_crl(gnutls_buffer_st * str, gnutls_x509_crl_t crl, int notsigned)
 
                                crl_nr++;
                        } else if (strcmp(oid, "2.5.29.35") == 0) {
-                               cert_type_t ccert;
+                               gnutls_datum_t der;
 
                                if (aki_idx) {
                                        addf(str,
@@ -2236,13 +1907,19 @@ print_crl(gnutls_buffer_st * str, gnutls_x509_crl_t crl, int notsigned)
                                     critical ? _("critical") :
                                     _("not critical"));
 
-                               ccert.crl = crl;
-                               print_aki(str, TYPE_CRL, ccert);
+                               err = gnutls_x509_crl_get_extension_data2(crl, i, &der);
+                               if (err < 0) {
+                                       addf(str,
+                                            "error: get_extension_data2: %s\n",
+                                            gnutls_strerror(err));
+                                       continue;
+                               }
+                               print_aki(str, &der);
+                               gnutls_free(der.data);
 
                                aki_idx++;
                        } else {
-                               char *buffer;
-                               size_t extlen = 0;
+                               gnutls_datum_t der;
 
                                addf(str,
                                     _("\t\tUnknown extension %s (%s):\n"),
@@ -2251,32 +1928,10 @@ print_crl(gnutls_buffer_st * str, gnutls_x509_crl_t crl, int notsigned)
                                     _("not critical"));
 
                                err =
-                                   gnutls_x509_crl_get_extension_data(crl,
-                                                                      i,
-                                                                      NULL,
-                                                                      &extlen);
-                               if (err < 0) {
-                                       addf(str,
-                                            "error: get_extension_data: %s\n",
-                                            gnutls_strerror(err));
-                                       continue;
-                               }
-
-                               buffer = gnutls_malloc(extlen);
-                               if (!buffer) {
-                                       addf(str, "error: malloc: %s\n",
-                                            gnutls_strerror
-                                            (GNUTLS_E_MEMORY_ERROR));
-                                       continue;
-                               }
-
-                               err =
-                                   gnutls_x509_crl_get_extension_data(crl,
+                                   gnutls_x509_crl_get_extension_data2(crl,
                                                                       i,
-                                                                      buffer,
-                                                                      &extlen);
+                                                                      &der);
                                if (err < 0) {
-                                       gnutls_free(buffer);
                                        addf(str,
                                             "error: get_extension_data2: %s\n",
                                             gnutls_strerror(err));
@@ -2284,16 +1939,14 @@ print_crl(gnutls_buffer_st * str, gnutls_x509_crl_t crl, int notsigned)
                                }
 
                                adds(str, _("\t\t\tASCII: "));
-                               _gnutls_buffer_asciiprint(str, buffer,
-                                                         extlen);
+                               _gnutls_buffer_asciiprint(str, (char*)der.data, der.size);
                                adds(str, "\n");
 
                                adds(str, _("\t\t\tHexdump: "));
-                               _gnutls_buffer_hexprint(str, buffer,
-                                                       extlen);
+                               _gnutls_buffer_hexprint(str, der.data, der.size);
                                adds(str, "\n");
 
-                               gnutls_free(buffer);
+                               gnutls_free(der.data);
                        }
                }
        }
@@ -2410,7 +2063,7 @@ print_crl(gnutls_buffer_st * str, gnutls_x509_crl_t crl, int notsigned)
  * gnutls_x509_crl_print:
  * @crl: The structure to be printed
  * @format: Indicate the format to use
- * @out: Newly allocated datum with (0) terminated string.
+ * @out: Newly allocated datum with zero terminated string.
  *
  * This function will pretty print a X.509 certificate revocation
  * list, suitable for display to a human.
@@ -2706,7 +2359,7 @@ static void print_crq_other(gnutls_buffer_st * str, gnutls_x509_crq_t crq)
  * gnutls_x509_crq_print:
  * @crq: The structure to be printed
  * @format: Indicate the format to use
- * @out: Newly allocated datum with (0) terminated string.
+ * @out: Newly allocated datum with zero terminated string.
  *
  * This function will pretty print a certificate request, suitable for
  * display to a human.
@@ -2754,9 +2407,6 @@ print_pubkey_other(gnutls_buffer_st * str, gnutls_pubkey_t pubkey,
        size_t size = sizeof(buffer);
        int ret;
        unsigned int usage;
-       cert_type_t ccert;
-
-       ccert.pubkey = pubkey;
 
        ret = gnutls_pubkey_get_key_usage(pubkey, &usage);
        if (ret < 0) {
@@ -2767,7 +2417,7 @@ print_pubkey_other(gnutls_buffer_st * str, gnutls_pubkey_t pubkey,
 
        adds(str, "\n");
        adds(str, _("Public Key Usage:\n"));
-       print_key_usage(str, "\t", TYPE_PUBKEY, ccert);
+       print_key_usage2(str, "\t", pubkey->key_usage);
 
        ret = gnutls_pubkey_get_key_id(pubkey, 0, buffer, &size);
        if (ret < 0) {
@@ -2785,7 +2435,7 @@ print_pubkey_other(gnutls_buffer_st * str, gnutls_pubkey_t pubkey,
  * gnutls_pubkey_print:
  * @pubkey: The structure to be printed
  * @format: Indicate the format to use
- * @out: Newly allocated datum with (0) terminated string.
+ * @out: Newly allocated datum with zero terminated string.
  *
  * This function will pretty print public key information, suitable for
  * display to a human.
@@ -2823,3 +2473,42 @@ gnutls_pubkey_print(gnutls_pubkey_t pubkey,
 
        return ret;
 }
+
+/**
+ * gnutls_x509_ext_print:
+ * @exts: The structures to be printed
+ * @exts_size: the number of available structures
+ * @format: Indicate the format to use
+ * @out: Newly allocated datum with zero terminated string.
+ *
+ * This function will pretty print X.509 certificate extensions, 
+ * suitable for display to a human.
+ *
+ * The output @out needs to be deallocated using gnutls_free().
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
+ *   negative error value.
+ **/
+int
+gnutls_x509_ext_print(gnutls_x509_ext_st *exts, unsigned int exts_size,
+                     gnutls_certificate_print_formats_t format,
+                     gnutls_datum_t * out)
+{
+       gnutls_buffer_st str;
+       struct ext_indexes_st idx;
+       int ret;
+       unsigned i;
+
+       memset(&idx, 0, sizeof(idx));
+       _gnutls_buffer_init(&str);
+
+       for (i=0;i<exts_size;i++)
+               print_extension(&str, "\t", &idx, (char*)exts[i].oid, exts[i].critical, &exts[i].data);
+
+       _gnutls_buffer_append_data(&str, "\x00", 1);
+
+       ret = _gnutls_buffer_to_datum(&str, out);
+       if (out->size > 0)
+               out->size--;
+       return ret;
+}
index afbc6e9951cc44555ff56a83f4f34afa86271ee3..5aeceefc9e12cd5a2966d92872b7b48877712d70 100644 (file)
@@ -702,7 +702,7 @@ void gnutls_x509_aki_deinit(gnutls_x509_aki_t aki)
  * @id: Will hold the identifier
  *
  * This function will return the key identifier as stored in
- * the @aki structure.
+ * the @aki structure. The identifier should be treated as constant.
  *
  * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, %GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
  * if the index is out of bounds, otherwise a negative error value.
@@ -1400,6 +1400,7 @@ int gnutls_x509_ext_export_basic_constraints(unsigned int ca, int pathlen,
  *
  * This function will return the information from a proxy certificate
  * extension. It reads the ProxyCertInfo X.509 extension (1.3.6.1.5.5.7.1.14).
+ * The @policyLanguage and @policy values must be deinitialized using gnutls_free() after use.
  *
  * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
  *   negative error value.
@@ -1467,6 +1468,7 @@ int gnutls_x509_ext_import_proxy(const gnutls_datum_t * ext, int *pathlen,
        } else {
                if (policy) {
                        *policy = (char *)value.data;
+                       value.data = NULL;
                }
                if (sizeof_policy)
                        *sizeof_policy = value.size;
@@ -3034,3 +3036,86 @@ int gnutls_x509_ext_export_key_purposes(gnutls_x509_key_purposes_t p,
        asn1_delete_structure(&c2);
        return ret;
 }
+
+/**
+ * gnutls_ext_deinit:
+ * @ext: The extensions structure
+ *
+ * This function will deinitialize an extensions structure.
+ *
+ * Since: 3.3.8
+ **/
+void gnutls_x509_ext_deinit(gnutls_x509_ext_st *ext)
+{
+       gnutls_free(ext->oid);
+       gnutls_free(ext->data.data);
+}
+
+int _gnutls_x509_decode_ext(const gnutls_datum_t *der, gnutls_x509_ext_st *out)
+{
+       ASN1_TYPE c2 = ASN1_TYPE_EMPTY;
+       char str_critical[10];
+       char oid[MAX_OID_SIZE];
+       int result, len, ret;
+
+       memset(out, 0, sizeof(*out));
+
+       /* decode der */
+       result = asn1_create_element(_gnutls_get_pkix(), "PKIX1.Extension", &c2);
+       if (result != ASN1_SUCCESS) {
+               gnutls_assert();
+               return _gnutls_asn2err(result);
+       }
+
+       result = asn1_der_decoding(&c2, der->data, der->size, NULL);
+       if (result != ASN1_SUCCESS) {
+               gnutls_assert();
+               ret = _gnutls_asn2err(result);
+               goto cleanup;
+       }
+
+       len = sizeof(oid)-1;
+       result = asn1_read_value(c2, "extnID", oid, &len);
+       if (result != ASN1_SUCCESS) {
+               gnutls_assert();
+               ret = _gnutls_asn2err(result);
+               goto cleanup;
+       }
+
+       len = sizeof(str_critical)-1;
+       result = asn1_read_value(c2, "critical", str_critical, &len);
+       if (result != ASN1_SUCCESS) {
+               gnutls_assert();
+               ret = _gnutls_asn2err(result);
+               goto cleanup;
+       }
+
+       if (str_critical[0] == 'T')
+               out->critical = 1;
+       else
+               out->critical = 0;
+
+       ret = _gnutls_x509_read_value(c2, "extnValue", &out->data);
+       if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE || ret == GNUTLS_E_ASN1_ELEMENT_NOT_FOUND) {
+               out->data.data = NULL;
+               out->data.size = 0;
+       } else if (ret < 0) {
+               gnutls_assert();
+               goto fail;
+       }
+
+       out->oid = gnutls_strdup(oid);
+       if (out->oid == NULL) {
+               ret = GNUTLS_E_MEMORY_ERROR;
+               goto fail;
+       }
+
+       ret = 0;
+       goto cleanup;
+ fail:
+       memset(out, 0, sizeof(*out));
+ cleanup:
+       asn1_delete_structure(&c2);
+       return ret;
+       
+}