[patch] Request for review - X509 Issuer Altname handling

View: New views
9 Messages — Rating Filter:   Alert me  

[patch] Request for review - X509 Issuer Altname handling

by Bugzilla from bradh@frogmouth.net :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi,

This patch (which I submit as a request for review / feedback) implements
support for getting issuer altname. It is based on the equivalent subject
altname code.

[I'll submit it again for incorporation after my papers get worked through]

Brad

[x509_issuer_altname-2009-08-05.patch]

diff --git a/doc/manpages/Makefile.am b/doc/manpages/Makefile.am
index b50a487..c7fbe21 100644
--- a/doc/manpages/Makefile.am
+++ b/doc/manpages/Makefile.am
@@ -428,8 +428,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 73dc6aa..887fef5 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 38200bb..27617d3 100644
--- a/lib/x509/output.c
+++ b/lib/x509/output.c
@@ -655,6 +655,148 @@ print_san (gnutls_string * str, const char *prefix, int type,
 }
 
 static void
+print_ian (gnutls_string * str, const char *prefix, int type,
+   cert_type_t cert)
+{
+  unsigned int ian_idx;
+  char str_ip[64];
+  char *p;
+
+  for (ian_idx = 0;; ian_idx++)
+    {
+      char *buffer = NULL;
+      size_t size = 0;
+      int err;
+
+      if (type == TYPE_CRT)
+ err =
+  gnutls_x509_crt_get_issuer_alt_name (cert.crt, ian_idx, buffer,
+ &size, NULL);
+      else
+ return;
+
+      if (err == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
+ break;
+      if (err != GNUTLS_E_SHORT_MEMORY_BUFFER)
+ {
+  addf (str, "error: get_issuer_alt_name: %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_issuer_alt_name (cert.crt, ian_idx, buffer,
+ &size, NULL);
+
+      if (err < 0)
+ {
+  gnutls_free (buffer);
+  addf (str, "error: get_issuer_alt_name2: %s\n",
+ gnutls_strerror (err));
+  return;
+ }
+
+      switch (err)
+ {
+ case GNUTLS_SAN_DNSNAME:
+  addf (str, "%s\t\t\tDNSname: %.*s\n", prefix, (int) size, buffer);
+  break;
+
+ case GNUTLS_SAN_RFC822NAME:
+  addf (str, "%s\t\t\tRFC822name: %.*s\n", prefix, (int) size, buffer);
+  break;
+
+ case GNUTLS_SAN_URI:
+  addf (str, "%s\t\t\tURI: %.*s\n", prefix, (int) size, buffer);
+  break;
+
+ case GNUTLS_SAN_IPADDRESS:
+  p = ip_to_string (buffer, size, str_ip, sizeof (str_ip));
+  if (p == NULL)
+    p = ERROR_STR;
+  addf (str, "%s\t\t\tIPAddress: %s\n", prefix, p);
+  break;
+
+ case GNUTLS_SAN_DN:
+  addf (str, "%s\t\t\tdirectoryName: %.*s\n", prefix,
+ (int) size, buffer);
+  break;
+
+ case GNUTLS_SAN_OTHERNAME:
+  {
+    char *oid = NULL;
+    size_t oidsize;
+
+    oidsize = 0;
+    if (type == TYPE_CRT)
+      err = gnutls_x509_crt_get_issuer_alt_othername_oid
+ (cert.crt, ian_idx, oid, &oidsize);
+
+    if (err != GNUTLS_E_SHORT_MEMORY_BUFFER)
+      {
+ gnutls_free (buffer);
+ addf (str, "error: get_issuer_alt_othername_oid: %s\n",
+      gnutls_strerror (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 (type == TYPE_CRT)
+      err = gnutls_x509_crt_get_issuer_alt_othername_oid
+ (cert.crt, ian_idx, oid, &oidsize);
+    if (err < 0)
+      {
+ gnutls_free (buffer);
+ gnutls_free (oid);
+ addf (str, "error: get_issuer_alt_othername_oid2: %s\n",
+      gnutls_strerror (err));
+ return;
+      }
+
+    if (err == GNUTLS_SAN_OTHERNAME_XMPP)
+      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: "), prefix);
+ hexprint (str, buffer, size);
+ addf (str, _("\n%s\t\t\totherName ASCII: "), prefix);
+ asciiprint (str, buffer, size);
+ addf (str, "\n");
+      }
+    gnutls_free (oid);
+  }
+  break;
+
+ default:
+  addf (str, "error: unknown Issuer AltName\n");
+  break;
+ }
+
+      gnutls_free (buffer);
+    }
+}
+
+static void
 print_extensions (gnutls_string * str, const char *prefix, int type,
   cert_type_t cert)
 {
@@ -666,6 +808,7 @@ print_extensions (gnutls_string * str, const char *prefix, int type,
       size_t sizeof_oid = sizeof (oid);
       int critical;
       size_t san_idx = 0;
+      size_t ian_idx = 0;
       size_t proxy_idx = 0;
       size_t basic_idx = 0;
       size_t keyusage_idx = 0;
@@ -796,6 +939,21 @@ print_extensions (gnutls_string * str, const char *prefix, int type,
 
   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_ian (str, prefix, type, 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 048ff89..103253d 100644
--- a/lib/x509/x509.c
+++ b/lib/x509/x509.c
@@ -1079,10 +1079,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;
@@ -1101,7 +1101,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;
@@ -1113,8 +1113,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 ();
@@ -1188,7 +1200,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);
 }
 
 /**
@@ -1222,8 +1276,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);
 }
 
 /**
@@ -1257,7 +1344,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 63b2497..9125366 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 rfc2231-escape-test
+ nul-in-x509-names x509_altname
 
 if ENABLE_OPENSSL
 ctests +=  openssl


_______________________________________________
Gnutls-devel mailing list
Gnutls-devel@...
http://lists.gnu.org/mailman/listinfo/gnutls-devel

Re: [patch] Request for review - X509 Issuer Altname handling

by Nikos Mavrogiannopoulos :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Brad Hards wrote:
> Hi,
>
> This patch (which I submit as a request for review / feedback) implements
> support for getting issuer altname. It is based on the equivalent subject
> altname code.

No comments. Looks nice to me!

regards,
Nikos


_______________________________________________
Gnutls-devel mailing list
Gnutls-devel@...
http://lists.gnu.org/mailman/listinfo/gnutls-devel

Re: [patch] Request for review - X509 Issuer Altname handling

by Simon Josefsson-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Brad Hards <bradh@...> writes:

> Hi,
>
> This patch (which I submit as a request for review / feedback) implements
> support for getting issuer altname. It is based on the equivalent subject
> altname code.

It looks fine to me.  I wonder why that have been missing...  The
self-test x509_altname was missing from your patch though?

> [I'll submit it again for incorporation after my papers get worked through]

Please do, otherwise I'm likely to forget about it.

/Simon


_______________________________________________
Gnutls-devel mailing list
Gnutls-devel@...
http://lists.gnu.org/mailman/listinfo/gnutls-devel

Re: [patch] Request for review - X509 Issuer Altname handling

by Bugzilla from bradh@frogmouth.net :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Friday 07 August 2009 01:14:46 Simon Josefsson wrote:

> Brad Hards <bradh@...> writes:
> > This patch (which I submit as a request for review / feedback) implements
> > support for getting issuer altname. It is based on the equivalent subject
> > altname code.
>
> It looks fine to me.  I wonder why that have been missing...  The
> self-test x509_altname was missing from your patch though?
>
> > [I'll submit it again for incorporation after my papers get worked
> > through]
I got the confirmation on my papers today.

I've updated the patch to include the self-test. It is otherwise unchanged.

Brad

[x509_issuer_altname-2009-09-04.patch]

diff --git a/doc/manpages/Makefile.am b/doc/manpages/Makefile.am
index b50a487..c7fbe21 100644
--- a/doc/manpages/Makefile.am
+++ b/doc/manpages/Makefile.am
@@ -428,8 +428,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 73dc6aa..887fef5 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 e170a9b..c8fdbe1 100644
--- a/lib/x509/output.c
+++ b/lib/x509/output.c
@@ -687,6 +687,148 @@ print_san (gnutls_string * str, const char *prefix, int type,
 }
 
 static void
+print_ian (gnutls_string * str, const char *prefix, int type,
+   cert_type_t cert)
+{
+  unsigned int ian_idx;
+  char str_ip[64];
+  char *p;
+
+  for (ian_idx = 0;; ian_idx++)
+    {
+      char *buffer = NULL;
+      size_t size = 0;
+      int err;
+
+      if (type == TYPE_CRT)
+ err =
+  gnutls_x509_crt_get_issuer_alt_name (cert.crt, ian_idx, buffer,
+ &size, NULL);
+      else
+ return;
+
+      if (err == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
+ break;
+      if (err != GNUTLS_E_SHORT_MEMORY_BUFFER)
+ {
+  addf (str, "error: get_issuer_alt_name: %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_issuer_alt_name (cert.crt, ian_idx, buffer,
+ &size, NULL);
+
+      if (err < 0)
+ {
+  gnutls_free (buffer);
+  addf (str, "error: get_issuer_alt_name2: %s\n",
+ gnutls_strerror (err));
+  return;
+ }
+
+      switch (err)
+ {
+ case GNUTLS_SAN_DNSNAME:
+  addf (str, "%s\t\t\tDNSname: %.*s\n", prefix, (int) size, buffer);
+  break;
+
+ case GNUTLS_SAN_RFC822NAME:
+  addf (str, "%s\t\t\tRFC822name: %.*s\n", prefix, (int) size, buffer);
+  break;
+
+ case GNUTLS_SAN_URI:
+  addf (str, "%s\t\t\tURI: %.*s\n", prefix, (int) size, buffer);
+  break;
+
+ case GNUTLS_SAN_IPADDRESS:
+  p = ip_to_string (buffer, size, str_ip, sizeof (str_ip));
+  if (p == NULL)
+    p = ERROR_STR;
+  addf (str, "%s\t\t\tIPAddress: %s\n", prefix, p);
+  break;
+
+ case GNUTLS_SAN_DN:
+  addf (str, "%s\t\t\tdirectoryName: %.*s\n", prefix,
+ (int) size, buffer);
+  break;
+
+ case GNUTLS_SAN_OTHERNAME:
+  {
+    char *oid = NULL;
+    size_t oidsize;
+
+    oidsize = 0;
+    if (type == TYPE_CRT)
+      err = gnutls_x509_crt_get_issuer_alt_othername_oid
+ (cert.crt, ian_idx, oid, &oidsize);
+
+    if (err != GNUTLS_E_SHORT_MEMORY_BUFFER)
+      {
+ gnutls_free (buffer);
+ addf (str, "error: get_issuer_alt_othername_oid: %s\n",
+      gnutls_strerror (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 (type == TYPE_CRT)
+      err = gnutls_x509_crt_get_issuer_alt_othername_oid
+ (cert.crt, ian_idx, oid, &oidsize);
+    if (err < 0)
+      {
+ gnutls_free (buffer);
+ gnutls_free (oid);
+ addf (str, "error: get_issuer_alt_othername_oid2: %s\n",
+      gnutls_strerror (err));
+ return;
+      }
+
+    if (err == GNUTLS_SAN_OTHERNAME_XMPP)
+      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: "), prefix);
+ hexprint (str, buffer, size);
+ addf (str, _("\n%s\t\t\totherName ASCII: "), prefix);
+ asciiprint (str, buffer, size);
+ addf (str, "\n");
+      }
+    gnutls_free (oid);
+  }
+  break;
+
+ default:
+  addf (str, "error: unknown Issuer AltName\n");
+  break;
+ }
+
+      gnutls_free (buffer);
+    }
+}
+
+static void
 print_extensions (gnutls_string * str, const char *prefix, int type,
   cert_type_t cert)
 {
@@ -698,6 +840,7 @@ print_extensions (gnutls_string * str, const char *prefix, int type,
       size_t sizeof_oid = sizeof (oid);
       int critical;
       size_t san_idx = 0;
+      size_t ian_idx = 0;
       size_t proxy_idx = 0;
       size_t basic_idx = 0;
       size_t keyusage_idx = 0;
@@ -828,6 +971,21 @@ print_extensions (gnutls_string * str, const char *prefix, int type,
 
   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_ian (str, prefix, type, 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 048ff89..103253d 100644
--- a/lib/x509/x509.c
+++ b/lib/x509/x509.c
@@ -1079,10 +1079,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;
@@ -1101,7 +1101,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;
@@ -1113,8 +1113,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 ();
@@ -1188,7 +1200,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);
 }
 
 /**
@@ -1222,8 +1276,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);
 }
 
 /**
@@ -1257,7 +1344,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


_______________________________________________
Gnutls-devel mailing list
Gnutls-devel@...
http://lists.gnu.org/mailman/listinfo/gnutls-devel

Re: [patch] Request for review - X509 Issuer Altname handling

by Simon Josefsson-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Brad Hards <bradh@...> writes:

> I've updated the patch to include the self-test. It is otherwise unchanged.

Thank you!  It looks fine except one nit:

The code duplication between print_san and print_ian worries me, and the
print_san code has been changed since you made the patch so they are not
in sync with your patch.  Could you instead generalize print_san into a
print_an function that takes an additional parameter indicating whether
it is printing a SAN or IAN?

With that change, it is ready to go in.

/Simon


_______________________________________________
Gnutls-devel mailing list
Gnutls-devel@...
http://lists.gnu.org/mailman/listinfo/gnutls-devel

Re: [patch] Request for review - X509 Issuer Altname handling

by Bugzilla from bradh@frogmouth.net :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Tuesday 08 September 2009 01:59:09 Simon Josefsson wrote:

> Brad Hards <bradh@...> writes:
> > I've updated the patch to include the self-test. It is otherwise
> > unchanged.
>
> Thank you!  It looks fine except one nit:
>
> The code duplication between print_san and print_ian worries me, and the
> print_san code has been changed since you made the patch so they are not
> in sync with your patch.  Could you instead generalize print_san into a
> print_an function that takes an additional parameter indicating whether
> it is printing a SAN or IAN?
>
> With that change, it is ready to go in.
It isn't an easy refactoring, but I'm working on it.

During the review, I note that the altname is sanitised if the type is
GNUTLS_SAN_DNSNAME, GNUTLS_SAN_RFC822NAME or GNUTLS_SAN_URI.

Should we also sanitise GNUTLS_SAN_DN ?

Brad


_______________________________________________
Gnutls-devel mailing list
Gnutls-devel@...
http://lists.gnu.org/mailman/listinfo/gnutls-devel

Re: [patch] Request for review - X509 Issuer Altname handling

by Simon Josefsson-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Brad Hards <bradh@...> writes:

> On Tuesday 08 September 2009 01:59:09 Simon Josefsson wrote:
>> Brad Hards <bradh@...> writes:
>> > I've updated the patch to include the self-test. It is otherwise
>> > unchanged.
>>
>> Thank you!  It looks fine except one nit:
>>
>> The code duplication between print_san and print_ian worries me, and the
>> print_san code has been changed since you made the patch so they are not
>> in sync with your patch.  Could you instead generalize print_san into a
>> print_an function that takes an additional parameter indicating whether
>> it is printing a SAN or IAN?
>>
>> With that change, it is ready to go in.
> It isn't an easy refactoring, but I'm working on it.

Thanks -- a 'bool san' variable, and if-conditions for each gnutls
function call to SAN/IAN functions should suffice.

> During the review, I note that the altname is sanitised if the type is
> GNUTLS_SAN_DNSNAME, GNUTLS_SAN_RFC822NAME or GNUTLS_SAN_URI.
>
> Should we also sanitise GNUTLS_SAN_DN ?

DN's should already be sanitized (they should be in LDAP encoded form),
although I don't have any test certificates for this.  Anyway, it is
best to not touch anything else in your patch, to avoid mixing separate
issues in the same patch.

/Simon


_______________________________________________
Gnutls-devel mailing list
Gnutls-devel@...
http://lists.gnu.org/mailman/listinfo/gnutls-devel

Re: [patch] Request for review - X509 Issuer Altname handling

by Bugzilla from bradh@frogmouth.net :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Tuesday 08 September 2009 20:49:31 Simon Josefsson wrote:
> Brad Hards <bradh@...> writes:
> > It isn't an easy refactoring, but I'm working on it.
>
> Thanks -- a 'bool san' variable, and if-conditions for each gnutls
> function call to SAN/IAN functions should suffice.
OK, I was thinking about a more complex cleanup. In the end, I changed the way
the type argument works (so we don't basically have two bools to drive the
three cases).

See attached.

Brad

[x509_issuer_altname-2009-09-09.patch]

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 <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@..." ) != 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 ();
+}


_______________________________________________
Gnutls-devel mailing list
Gnutls-devel@...
http://lists.gnu.org/mailman/listinfo/gnutls-devel

Re: [patch] Request for review - X509 Issuer Altname handling

by Simon Josefsson-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Brad Hards <bradh@...> writes:

> On Tuesday 08 September 2009 20:49:31 Simon Josefsson wrote:
>> Brad Hards <bradh@...> writes:
>> > It isn't an easy refactoring, but I'm working on it.
>>
>> Thanks -- a 'bool san' variable, and if-conditions for each gnutls
>> function call to SAN/IAN functions should suffice.
> OK, I was thinking about a more complex cleanup. In the end, I changed the way
> the type argument works (so we don't basically have two bools to drive the
> three cases).

Thank you, that's better than my suggestion.  Pushed, will release it
next.

/Simon


_______________________________________________
Gnutls-devel mailing list
Gnutls-devel@...
http://lists.gnu.org/mailman/listinfo/gnutls-devel