summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrad Hards <bradh@frogmouth.net>2009-09-09 21:57:06 +1000
committerSimon Josefsson <simon@josefsson.org>2009-09-10 08:21:10 +0200
commit6d53cd6b1ef73cd239f29df42ca07c9d6f0cd107 (patch)
tree4392a001279fe58fb8e1ddd5df38dc9a1b2fe660
parent36db99c522b5edb2221e9fd23f53f63aacd43f9f (diff)
downloadgnutls-6d53cd6b1ef73cd239f29df42ca07c9d6f0cd107.tar.gz
Add X509 Issuer Altname functions
Signed-off-by: Simon Josefsson <simon@josefsson.org>
-rw-r--r--doc/manpages/Makefile.am3
-rw-r--r--lib/includes/gnutls/x509.h15
-rw-r--r--lib/libgnutls.map3
-rw-r--r--lib/x509/output.c90
-rw-r--r--lib/x509/x509.c143
-rw-r--r--tests/Makefile.am2
-rw-r--r--tests/x509_altname.c119
7 files changed, 336 insertions, 39 deletions
diff --git a/doc/manpages/Makefile.am b/doc/manpages/Makefile.am
index 4c0ff22762..b894f7e9e9 100644
--- a/doc/manpages/Makefile.am
+++ b/doc/manpages/Makefile.am
@@ -431,8 +431,11 @@ APIMANS += gnutls_x509_crt_get_subject_key_id.3
APIMANS += gnutls_x509_crt_get_authority_key_id.3
APIMANS += gnutls_x509_crt_get_pk_algorithm.3
APIMANS += gnutls_x509_crt_get_subject_alt_name.3
+APIMANS += gnutls_x509_crt_get_issuer_alt_name.3
APIMANS += gnutls_x509_crt_get_subject_alt_name2.3
+APIMANS += gnutls_x509_crt_get_issuer_alt_name2.3
APIMANS += gnutls_x509_crt_get_subject_alt_othername_oid.3
+APIMANS += gnutls_x509_crt_get_issuer_alt_othername_oid.3
APIMANS += gnutls_x509_crt_get_basic_constraints.3
APIMANS += gnutls_x509_crt_get_ca_status.3
APIMANS += gnutls_x509_crt_get_key_usage.3
diff --git a/lib/includes/gnutls/x509.h b/lib/includes/gnutls/x509.h
index 2a87cba7a2..e61ef25684 100644
--- a/lib/includes/gnutls/x509.h
+++ b/lib/includes/gnutls/x509.h
@@ -198,6 +198,21 @@ extern "C"
void *ret,
size_t * ret_size);
+ int gnutls_x509_crt_get_issuer_alt_name (gnutls_x509_crt_t cert,
+ unsigned int seq, void *ret,
+ size_t * ret_size,
+ unsigned int *critical);
+ int gnutls_x509_crt_get_issuer_alt_name2 (gnutls_x509_crt_t cert,
+ unsigned int seq, void *ret,
+ size_t * ret_size,
+ unsigned int *ret_type,
+ unsigned int *critical);
+
+ int gnutls_x509_crt_get_issuer_alt_othername_oid (gnutls_x509_crt_t cert,
+ unsigned int seq,
+ void *ret,
+ size_t * ret_size);
+
int gnutls_x509_crt_get_ca_status (gnutls_x509_crt_t cert,
unsigned int *critical);
int gnutls_x509_crt_get_basic_constraints (gnutls_x509_crt_t cert,
diff --git a/lib/libgnutls.map b/lib/libgnutls.map
index 100ac679f0..22524648bb 100644
--- a/lib/libgnutls.map
+++ b/lib/libgnutls.map
@@ -562,6 +562,9 @@ GNUTLS_2_8
gnutls_x509_crq_set_key_purpose_oid;
gnutls_x509_crq_set_key_usage;
gnutls_x509_crq_set_subject_alt_name;
+ gnutls_x509_crt_get_issuer_alt_name2;
+ gnutls_x509_crt_get_issuer_alt_name;
+ gnutls_x509_crt_get_issuer_alt_othername_oid;
gnutls_x509_crt_get_verify_algorithm;
gnutls_x509_crt_set_crq_extensions;
gnutls_x509_crt_verify_hash;
diff --git a/lib/x509/output.c b/lib/x509/output.c
index 854affb0ba..10e5fc21fc 100644
--- a/lib/x509/output.c
+++ b/lib/x509/output.c
@@ -212,6 +212,10 @@ print_ski (gnutls_string * str, gnutls_x509_crt_t cert)
#define TYPE_CRT 2
#define TYPE_CRQ 3
+#define TYPE_CRT_SAN TYPE_CRT
+#define TYPE_CRQ_SAN TYPE_CRQ
+#define TYPE_CRT_IAN 4
+
typedef union
{
gnutls_x509_crt_t crt;
@@ -510,27 +514,31 @@ print_basic (gnutls_string * str, const char *prefix, int type,
static void
-print_san (gnutls_string * str, const char *prefix, int type,
- cert_type_t cert)
+print_altname (gnutls_string * str, const char *prefix, int altname_type,
+ cert_type_t cert)
{
- unsigned int san_idx;
+ unsigned int altname_idx;
char str_ip[64];
char *p;
- for (san_idx = 0;; san_idx++)
+ for (altname_idx = 0;; altname_idx++)
{
char *buffer = NULL;
size_t size = 0;
int err;
- if (type == TYPE_CRT)
+ if (altname_type == TYPE_CRT_SAN)
err =
- gnutls_x509_crt_get_subject_alt_name (cert.crt, san_idx, buffer,
+ gnutls_x509_crt_get_subject_alt_name (cert.crt, altname_idx, buffer,
&size, NULL);
- else if (type == TYPE_CRQ)
+ else if (altname_type == TYPE_CRQ_SAN)
err =
- gnutls_x509_crq_get_subject_alt_name (cert.crq, san_idx, buffer,
+ 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;
@@ -538,7 +546,7 @@ print_san (gnutls_string * str, const char *prefix, int type,
break;
if (err != GNUTLS_E_SHORT_MEMORY_BUFFER)
{
- addf (str, "error: get_subject_alt_name: %s\n",
+ addf (str, "error: get_subject/issuer_alt_name: %s\n",
gnutls_strerror (err));
return;
}
@@ -551,19 +559,23 @@ print_san (gnutls_string * str, const char *prefix, int type,
return;
}
- if (type == TYPE_CRT)
+ if (altname_type == TYPE_CRT_SAN)
err =
- gnutls_x509_crt_get_subject_alt_name (cert.crt, san_idx, buffer,
+ gnutls_x509_crt_get_subject_alt_name (cert.crt, altname_idx, buffer,
&size, NULL);
- else if (type == TYPE_CRQ)
+ else if (altname_type == TYPE_CRQ_SAN)
err =
- gnutls_x509_crq_get_subject_alt_name (cert.crq, san_idx, buffer,
+ 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);
- addf (str, "error: get_subject_alt_name2: %s\n",
+ addf (str, "error: get_subject/issuer_alt_name2: %s\n",
gnutls_strerror (err));
return;
}
@@ -573,7 +585,7 @@ print_san (gnutls_string * str, const char *prefix, int type,
|| err == GNUTLS_SAN_URI) &&
strlen (buffer) != size)
{
- adds (str, _("warning: SAN contains an embedded NUL, "
+ adds (str, _("warning: altname contains an embedded NUL, "
"replacing with '!'\n"));
while (strlen (buffer) < size)
buffer[strlen (buffer)] = '!';
@@ -611,17 +623,20 @@ print_san (gnutls_string * str, const char *prefix, int type,
size_t oidsize;
oidsize = 0;
- if (type == TYPE_CRT)
+ if (altname_type == TYPE_CRT_SAN)
err = gnutls_x509_crt_get_subject_alt_othername_oid
- (cert.crt, san_idx, oid, &oidsize);
- else if (type == TYPE_CRQ)
+ (cert.crt, altname_idx, oid, &oidsize);
+ else if (altname_type == TYPE_CRQ_SAN)
err = gnutls_x509_crq_get_subject_alt_othername_oid
- (cert.crq, san_idx, oid, &oidsize);
+ (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_alt_othername_oid: %s\n",
+ addf (str, "error: get_subject/issuer_alt_othername_oid: %s\n",
gnutls_strerror (err));
return;
}
@@ -635,12 +650,16 @@ print_san (gnutls_string * str, const char *prefix, int type,
return;
}
- if (type == TYPE_CRT)
+ if (altname_type == TYPE_CRT_SAN)
err = gnutls_x509_crt_get_subject_alt_othername_oid
- (cert.crt, san_idx, oid, &oidsize);
- else if (type == TYPE_CRQ)
+ (cert.crt, altname_idx, oid, &oidsize);
+ else if (altname_type == TYPE_CRQ_SAN)
err = gnutls_x509_crq_get_subject_alt_othername_oid
- (cert.crq, san_idx, oid, &oidsize);
+ (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);
@@ -654,7 +673,7 @@ print_san (gnutls_string * str, const char *prefix, int type,
{
if (strlen (buffer) != size)
{
- adds (str, _("warning: SAN contains an embedded NUL, "
+ adds (str, _("warning: altname contains an embedded NUL, "
"replacing with '!'\n"));
while (strlen (buffer) < size)
buffer[strlen (buffer)] = '!';
@@ -678,7 +697,7 @@ print_san (gnutls_string * str, const char *prefix, int type,
break;
default:
- addf (str, "error: unknown SAN\n");
+ addf (str, "error: unknown altname\n");
break;
}
@@ -686,12 +705,14 @@ print_san (gnutls_string * str, const char *prefix, int type,
}
}
+
static void
print_extensions (gnutls_string * str, const char *prefix, int type,
cert_type_t cert)
{
int i, err;
int san_idx = 0;
+ int ian_idx = 0;
int proxy_idx = 0;
int basic_idx = 0;
int keyusage_idx = 0;
@@ -824,10 +845,25 @@ print_extensions (gnutls_string * str, const char *prefix, int type,
addf (str, _("%s\t\tSubject Alternative Name (%s):\n"), prefix,
critical ? _("critical") : _("not critical"));
- print_san (str, prefix, type, cert);
+ print_altname (str, prefix, type, cert);
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;
+ }
+
+ addf (str, _("%s\t\tIssuer Alternative Name (%s):\n"), prefix,
+ critical ? _("critical") : _("not critical"));
+
+ print_altname (str, prefix, TYPE_CRT_IAN, cert);
+
+ ian_idx++;
+ }
else if (strcmp (oid, "2.5.29.31") == 0)
{
if (crldist_idx)
diff --git a/lib/x509/x509.c b/lib/x509/x509.c
index a65626b9b3..afb0fc9671 100644
--- a/lib/x509/x509.c
+++ b/lib/x509/x509.c
@@ -1110,10 +1110,10 @@ _gnutls_parse_general_name (ASN1_TYPE src, const char *src_name,
}
static int
-get_subject_alt_name (gnutls_x509_crt_t cert,
- unsigned int seq, void *ret,
- size_t * ret_size, unsigned int *ret_type,
- unsigned int *critical, int othername_oid)
+get_alt_name(gnutls_x509_crt_t cert, const char *extension_id,
+ unsigned int seq, void *ret,
+ size_t * ret_size, unsigned int *ret_type,
+ unsigned int *critical, int othername_oid)
{
int result;
gnutls_datum_t dnsname;
@@ -1132,7 +1132,7 @@ get_subject_alt_name (gnutls_x509_crt_t cert,
*ret_size = 0;
if ((result =
- _gnutls_x509_crt_get_extension (cert, "2.5.29.17", 0, &dnsname,
+ _gnutls_x509_crt_get_extension (cert, extension_id, 0, &dnsname,
critical)) < 0)
{
return result;
@@ -1144,8 +1144,20 @@ get_subject_alt_name (gnutls_x509_crt_t cert,
return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
}
- result = asn1_create_element
- (_gnutls_get_pkix (), "PKIX1.SubjectAltName", &c2);
+ if (strcmp("2.5.29.17", extension_id) == 0)
+ {
+ result = asn1_create_element(_gnutls_get_pkix (), "PKIX1.SubjectAltName", &c2);
+ }
+ else if (strcmp("2.5.29.18", extension_id) == 0)
+ {
+ result = asn1_create_element(_gnutls_get_pkix (), "PKIX1.IssuerAltName", &c2);
+ }
+ else
+ {
+ gnutls_assert ();
+ return GNUTLS_E_INTERNAL_ERROR;
+ }
+
if (result != ASN1_SUCCESS)
{
gnutls_assert ();
@@ -1219,7 +1231,49 @@ gnutls_x509_crt_get_subject_alt_name (gnutls_x509_crt_t cert,
size_t * ret_size,
unsigned int *critical)
{
- return get_subject_alt_name (cert, seq, ret, ret_size, NULL, critical, 0);
+ return get_alt_name (cert, "2.5.29.17", seq, ret, ret_size, NULL, critical, 0);
+}
+
+/**
+ * gnutls_x509_crt_get_issuer_alt_name - Get certificate's issuer alternative name, if any
+ * @cert: should contain a #gnutls_x509_crt_t structure
+ * @seq: specifies the sequence number of the alt name (0 for the first one, 1 for the second etc.)
+ * @ret: is the place where the alternative name will be copied to
+ * @ret_size: holds the size of ret.
+ * @critical: will be non zero if the extension is marked as critical (may be null)
+ *
+ * This function will return the issuer alternative names, contained in the
+ * given certificate.
+ *
+ * This is specified in X509v3 Certificate Extensions. GNUTLS will
+ * return the Isssuer Alternative name (2.5.29.18), or a negative error code.
+ *
+ * When the SAN type is otherName, it will extract the data in the
+ * otherName's value field, and %GNUTLS_SAN_OTHERNAME is returned.
+ * You may use gnutls_x509_crt_get_subject_alt_othername_oid() to get
+ * the corresponding OID and the "virtual" SAN types (e.g.,
+ * %GNUTLS_SAN_OTHERNAME_XMPP).
+ *
+ * If an otherName OID is known, the data will be decoded. Otherwise
+ * the returned data will be DER encoded, and you will have to decode
+ * it yourself. Currently, only the RFC 3920 id-on-xmppAddr Issuer AltName
+ * is recognized.
+ *
+ * Returns: the alternative issuer name type on success, one of the
+ * enumerated #gnutls_x509_subject_alt_name_t. It will return
+ * %GNUTLS_E_SHORT_MEMORY_BUFFER if @ret_size is not large enough
+ * to hold the value. In that case @ret_size will be updated with
+ * the required size. If the certificate does not have an
+ * Alternative name with the specified sequence number then
+ * %GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE is returned.
+ **/
+int
+gnutls_x509_crt_get_issuer_alt_name (gnutls_x509_crt_t cert,
+ unsigned int seq, void *ret,
+ size_t * ret_size,
+ unsigned int *critical)
+{
+ return get_alt_name (cert, "2.5.29.18", seq, ret, ret_size, NULL, critical, 0);
}
/**
@@ -1253,8 +1307,41 @@ gnutls_x509_crt_get_subject_alt_name2 (gnutls_x509_crt_t cert,
unsigned int *ret_type,
unsigned int *critical)
{
- return get_subject_alt_name (cert, seq, ret, ret_size, ret_type, critical,
- 0);
+ return get_alt_name (cert, "2.5.29.17", seq, ret, ret_size, ret_type, critical, 0);
+}
+
+/**
+ * gnutls_x509_crt_get_issuer_alt_name2 - Get certificate issuer's alternative name, if any
+ * @cert: should contain a #gnutls_x509_crt_t structure
+ * @seq: specifies the sequence number of the alt name (0 for the first one, 1 for the second etc.)
+ * @ret: is the place where the alternative name will be copied to
+ * @ret_size: holds the size of ret.
+ * @ret_type: holds the type of the alternative name (one of gnutls_x509_subject_alt_name_t).
+ * @critical: will be non zero if the extension is marked as critical (may be null)
+ *
+ * This function will return the alternative names, contained in the
+ * given certificate. It is the same as
+ * gnutls_x509_crt_get_issuer_alt_name() except for the fact that it
+ * will return the type of the alternative name in @ret_type even if
+ * the function fails for some reason (i.e. the buffer provided is
+ * not enough).
+ *
+ * Returns: the alternative issuer name type on success, one of the
+ * enumerated #gnutls_x509_subject_alt_name_t. It will return
+ * %GNUTLS_E_SHORT_MEMORY_BUFFER if @ret_size is not large enough
+ * to hold the value. In that case @ret_size will be updated with
+ * the required size. If the certificate does not have an
+ * Alternative name with the specified sequence number then
+ * %GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE is returned.
+ **/
+int
+gnutls_x509_crt_get_issuer_alt_name2 (gnutls_x509_crt_t cert,
+ unsigned int seq, void *ret,
+ size_t * ret_size,
+ unsigned int *ret_type,
+ unsigned int *critical)
+{
+ return get_alt_name (cert, "2.5.29.18", seq, ret, ret_size, ret_type, critical, 0);
}
/**
@@ -1288,7 +1375,41 @@ gnutls_x509_crt_get_subject_alt_othername_oid (gnutls_x509_crt_t cert,
unsigned int seq,
void *ret, size_t * ret_size)
{
- return get_subject_alt_name (cert, seq, ret, ret_size, NULL, NULL, 1);
+ return get_alt_name (cert, "2.5.29.17", seq, ret, ret_size, NULL, NULL, 1);
+}
+
+/**
+ * gnutls_x509_crt_get_issuer_alt_othername_oid - Get Issuer AltName otherName OID
+ * @cert: should contain a #gnutls_x509_crt_t structure
+ * @seq: specifies the sequence number of the alt name (0 for the first one, 1 for the second etc.)
+ * @ret: is the place where the otherName OID will be copied to
+ * @ret_size: holds the size of ret.
+ *
+ * This function will extract the type OID of an otherName Subject
+ * Alternative Name, contained in the given certificate, and return
+ * the type as an enumerated element.
+ *
+ * This function is only useful if
+ * gnutls_x509_crt_get_issuer_alt_name() returned
+ * %GNUTLS_SAN_OTHERNAME.
+ *
+ * Returns: the alternative issuer name type on success, one of the
+ * enumerated gnutls_x509_subject_alt_name_t. For supported OIDs, it
+ * will return one of the virtual (GNUTLS_SAN_OTHERNAME_*) types,
+ * e.g. %GNUTLS_SAN_OTHERNAME_XMPP, and %GNUTLS_SAN_OTHERNAME for
+ * unknown OIDs. It will return %GNUTLS_E_SHORT_MEMORY_BUFFER if
+ * @ret_size is not large enough to hold the value. In that case
+ * @ret_size will be updated with the required size. If the
+ * certificate does not have an Alternative name with the specified
+ * sequence number and with the otherName type then
+ * %GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE is returned.
+ **/
+int
+gnutls_x509_crt_get_issuer_alt_othername_oid (gnutls_x509_crt_t cert,
+ unsigned int seq,
+ void *ret, size_t * ret_size)
+{
+ return get_alt_name (cert, "2.5.29.18", seq, ret, ret_size, NULL, NULL, 1);
}
/**
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 5538fb72dc..4779c646a2 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -58,7 +58,7 @@ ctests = simple gc set_pkcs12_cred certder mpi \
finished hostname-check cve-2008-4989 pkcs12_s2k chainverify \
crq_key_id x509sign-verify cve-2009-1415 cve-2009-1416 \
crq_apis init_roundtrip pkcs12_s2k_pem dn2 mini-eagain \
- nul-in-x509-names
+ nul-in-x509-names x509_altname
if ENABLE_OPENSSL
ctests += openssl
diff --git a/tests/x509_altname.c b/tests/x509_altname.c
new file mode 100644
index 0000000000..ef99bae377
--- /dev/null
+++ b/tests/x509_altname.c
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2006, 2007, 2008 Free Software Foundation
+ * Author: Simon Josefsson, Howard Chu
+ *
+ * This file is part of GNUTLS.
+ *
+ * GNUTLS is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GNUTLS is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNUTLS; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdio.h>
+
+#include <gnutls/gnutls.h>
+#include <gnutls/x509.h>
+#include "utils.h"
+
+static char pem[] =
+"-----BEGIN CERTIFICATE-----\n"
+"MIIE6zCCA9OgAwIBAgIBdjANBgkqhkiG9w0BAQUFADBQMQswCQYDVQQGEwJTRTEf\n"
+"MB0GA1UEChMWU3RvY2tob2xtcyB1bml2ZXJzaXRldDEgMB4GA1UEAxMXU3RvY2to\n"
+"b2xtIFVuaXZlcnNpdHkgQ0EwHhcNMDYwMzIyMDkxNTI4WhcNMDcwMzIyMDkxNTI4\n"
+"WjBDMQswCQYDVQQGEwJTRTEfMB0GA1UEChMWU3RvY2tob2xtcyB1bml2ZXJzaXRl\n"
+"dDETMBEGA1UEAxMKc2lwMS5zdS5zZTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkC\n"
+"gYEArUzXTD36ZK7CwZJH/faUNTcdaqM7JyiZsfrO703d7cT/bJ3wKxT8trOOh/Ou\n"
+"WwgGFX2+r7ykun3aIUXUuD13Yle/yHqH/4g9vWX7UeFCBlSI0tAxnlqt0QqlPgSd\n"
+"GLHcoO4PPyjon9jj0A/zpJGZHiRUCooo63YqE9MYfr5HBfkCAwEAAaOCAl8wggJb\n"
+"MAsGA1UdDwQEAwIF4DAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwHQYD\n"
+"VR0OBBYEFDpcXNHMLJ7fc/c72BtZseq4MDXFMH8GA1UdIwR4MHaAFJ4uMLo32VFE\n"
+"yZ2/GCHxvX7utYZIoVukWTBXMQswCQYDVQQGEwJTRTEYMBYGA1UEChMPVW1lYSBV\n"
+"bml2ZXJzaXR5MRMwEQYDVQQLEwpTd1VQS0ktUENBMRkwFwYDVQQDExBTd1VQS0kg\n"
+"UG9saWN5IENBggEQMDIGA1UdHwQrMCkwJ6AloCOGIWh0dHA6Ly9jYS5zdS5zZS8y\n"
+"MDA1LTEvY3JsLXYyLmNybDB5BgNVHSAEcjBwMG4GCCqFcCsCAQEBMGIwHwYIKwYB\n"
+"BQUHAgEWE2h0dHA6Ly9jYS5zdS5zZS9DUFMwPwYIKwYBBQUHAgIwMxoxTGltaXRl\n"
+"ZCBMaWFiaWxpdHksIHNlZSBodHRwOi8vd3d3LnN3dXBraS5zdS5zZS9DUDAkBgNV\n"
+"HRIEHTAbgQhjYUBzdS5zZYYPaHR0cDovL2NhLnN1LnNlMIG3BgNVHREEga8wgayC\n"
+"F2luY29taW5ncHJveHkuc2lwLnN1LnNlghhpbmNvbWluZ3Byb3h5MS5zaXAuc3Uu\n"
+"c2WCF291dGdvaW5ncHJveHkuc2lwLnN1LnNlghhvdXRnb2luZ3Byb3h5MS5zaXAu\n"
+"c3Uuc2WCDW91dC5zaXAuc3Uuc2WCE2FwcHNlcnZlci5zaXAuc3Uuc2WCFGFwcHNl\n"
+"cnZlcjEuc2lwLnN1LnNlggpzaXAxLnN1LnNlMA0GCSqGSIb3DQEBBQUAA4IBAQAR\n"
+"FYg7ytcph0E7WmvM44AN/8qru7tRX6aSFWrjLyVr/1Wk4prCK4y5JpfNw5dh9Z8f\n"
+"/gyFsr1iFsb6fS3nJTTd3fVlWRfcNCGIx5g8KuSb3u6f7VznkGOeiRMRESQc1G8B\n"
+"eh0zbdZS7BYO2g9EKlbGST5PwQnc4g9K7pqPyKSNVkzb60Nujg/+qYje7MCcN+ZR\n"
+"nUBo6U2NZ06/QEUFm+uUIhZ8IGM1gLehC7Q3G4+d4c38CDJxQnSPOgWiXuSvhhQm\n"
+"KDsbrKzRaeBRh5eEJbTkA8Dp0Emb0UrkRVhixeg97stxUcATAjdGljJ9MLnuHXnI\n"
+"7ihGdUfg5q/105vpsQpO\n"
+"-----END CERTIFICATE-----\n";
+
+#define MAX_DATA_SIZE 1024
+
+void
+doit (void)
+{
+ int ret;
+ gnutls_datum_t derCert = { pem, sizeof (pem) };
+ gnutls_x509_crt_t cert;
+ size_t data_len = MAX_DATA_SIZE;
+ char data[ MAX_DATA_SIZE ];
+ unsigned int critical = 0;
+ int alt_name_count = 0;
+
+ ret = gnutls_global_init ();
+ if (ret < 0)
+ fail ("init %d\n", ret);
+
+ ret = gnutls_x509_crt_init (&cert);
+ if (ret < 0)
+ fail ("crt_init %d\n", ret);
+
+ ret = gnutls_x509_crt_import (cert, &derCert, GNUTLS_X509_FMT_PEM);
+ if (ret < 0)
+ fail ("crt_import %d\n", ret);
+
+ for (alt_name_count = 0; ; ++alt_name_count) {
+ ret = gnutls_x509_crt_get_issuer_alt_name (cert, alt_name_count, data, &data_len, &critical);
+ if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
+ break;
+
+ if (ret < 0)
+ fail ("get_issuer_alt_name: %d\n", ret);
+
+ // TODO: print out / check results
+ if (GNUTLS_SAN_URI == ret) {
+ if (strcmp( data, "http://ca.su.se" ) != 0) {
+ fail("unexpected issuer GNUTLS_SAN_URI: %s\n", data);
+ }
+ } else if (GNUTLS_SAN_RFC822NAME == ret) {
+ if (strcmp( data, "ca@su.se" ) != 0) {
+ fail("unexpected issuer GNUTLS_SAN_RFC822NAME: %s\n", data);
+ }
+ } else {
+ fail("unexpected alt name type: %d\n", ret);
+ }
+ data_len = MAX_DATA_SIZE;
+ }
+
+ if (alt_name_count !=2) {
+ fail("unexpected number of alt names: %i\n", alt_name_count);
+ }
+
+ success ("done\n");
+
+ gnutls_x509_crt_deinit (cert);
+ gnutls_global_deinit ();
+}