diff --git a/doc/manpages/Makefile.am b/doc/manpages/Makefile.am index 4c0ff22..b894f7e 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 2a87cba..e61ef25 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 100ac67..2252464 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 854affb..10e5fc2 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 a65626b..afb0fc9 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 5538fb7..4779c64 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 0000000..ef99bae --- /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 + +#include +#include +#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, "address@hidden" ) != 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 (); +}