[exim-cvs] Extractors for subject-alternate-name, ocsp-uri, …

Etusivu
Poista viesti
Vastaa
Lähettäjä: Exim Git Commits Mailing List
Päiväys:  
Vastaanottaja: exim-cvs
Aihe: [exim-cvs] Extractors for subject-alternate-name, ocsp-uri, crl-uri return list. Bug 1358
Gitweb: http://git.exim.org/exim.git/commitdiff/9e4dddbde4228e83fc7c882a4ef410ddbe0a6e79
Commit:     9e4dddbde4228e83fc7c882a4ef410ddbe0a6e79
Parent:     51424d0857ca09e1082aeacf177e2df6fea37eda
Author:     Jeremy Harris <jgh146exb@???>
AuthorDate: Mon May 5 16:53:48 2014 +0100
Committer:  Jeremy Harris <jgh146exb@???>
CommitDate: Mon May 5 18:03:12 2014 +0100


    Extractors for subject-alternate-name, ocsp-uri, crl-uri return list.  Bug 1358
---
 doc/doc-docbook/spec.xfpt |   38 ++++++---
 src/src/expand.c          |   37 +++++----
 src/src/functions.h       |   22 +++---
 src/src/tlscert-gnu.c     |  193 +++++++++++++++++++++++++++++----------------
 src/src/tlscert-openssl.c |   89 ++++++++++++++-------
 test/confs/2002           |    4 +-
 test/confs/2102           |    4 +-
 test/confs/5750           |    4 +-
 test/confs/5760           |    4 +-
 test/log/2002             |    2 +-
 test/log/2102             |    2 +-
 test/log/5750             |    4 +-
 test/log/5760             |    2 +-
 13 files changed, 256 insertions(+), 149 deletions(-)


diff --git a/doc/doc-docbook/spec.xfpt b/doc/doc-docbook/spec.xfpt
index ec93675..6497157 100644
--- a/doc/doc-docbook/spec.xfpt
+++ b/doc/doc-docbook/spec.xfpt
@@ -8885,17 +8885,17 @@ The <&'certificate'&> must be a variable of type certificate.
 The field name is expanded and used to retrive the relevant field from
 the certificate.  Supported fields are:
 .display
-version
-serial_number
-subject
-issuer
-notbefore
-notafter
-signature_algorithm
-signature
-subject_altname
-ocsp_uri
-crl_uri
+&`version        `&
+&`serial_number  `&
+&`subject        `&
+&`issuer         `&
+&`notbefore      `&
+&`notafter       `&
+&`sig_algorithm  `&
+&`signature      `&
+&`subj_altname   `& tagged list
+&`ocsp_uri       `& list
+&`crl_uri        `& list
 .endd
 If the field is found,
 <&'string2'&> is expanded, and replaces the whole item;
@@ -8907,7 +8907,21 @@ If {<&'string3'&>} is omitted, the item is replaced by an empty string if the
 key is not found. If {<&'string2'&>} is also omitted, the value that was
 extracted is used.


-Field values are presented in human-readable form.
+Some field names take optional modifiers, appended and separated by commas.
+
+The field selectors marked as "list" above return a list,
+newline-separated by default,
+(embedded separator characters in elements are doubled).
+The separator may be changed by a modifier of
+a right angle-bracket followed immediately by the new separator.
+
+The field selectors marked as "tagged" above
+prefix each list element with a type string and an equals sign.
+Elements of only one type may be selected by a modifier
+which is one of "dns", "uri" or "mail";
+if so the elenment tags are omitted.
+
+Field values are generally presented in human-readable form.
.wen

.vitem "&*${dlfunc{*&<&'file'&>&*}{*&<&'function'&>&*}{*&<&'arg'&>&*}&&&
diff --git a/src/src/expand.c b/src/src/expand.c
index 8f1b3d8..05b714a 100644
--- a/src/src/expand.c
+++ b/src/src/expand.c
@@ -1185,26 +1185,28 @@ return string_nextinlist(&list, &sep, NULL, 0);


/* Certificate fields, by name. Worry about by-OID later */
+/* Names are chosen to not have common prefixes */

 #ifdef SUPPORT_TLS
 typedef struct
 {
 uschar * name;
-uschar * (*getfn)(void * cert);
+int      namelen;
+uschar * (*getfn)(void * cert, uschar * mod);
 } certfield;
 static certfield certfields[] =
 {            /* linear search; no special order */
-  { US"version",    &tls_cert_version },
-  { US"serial_number",    &tls_cert_serial_number },
-  { US"subject",    &tls_cert_subject },
-  { US"notbefore",    &tls_cert_not_before },
-  { US"notafter",    &tls_cert_not_after },
-  { US"issuer",        &tls_cert_issuer },
-  { US"signature",    &tls_cert_signature },
-  { US"signature_algorithm",    &tls_cert_signature_algorithm },
-  { US"subject_altname",    &tls_cert_subject_altname },
-  { US"ocsp_uri",    &tls_cert_ocsp_uri },
-  { US"crl_uri",    &tls_cert_crl_uri },
+  { US"version",     7,  &tls_cert_version },
+  { US"serial_number",     13, &tls_cert_serial_number },
+  { US"subject",     7,  &tls_cert_subject },
+  { US"notbefore",     9,  &tls_cert_not_before },
+  { US"notafter",     8,  &tls_cert_not_after },
+  { US"issuer",         6,  &tls_cert_issuer },
+  { US"signature",     9,  &tls_cert_signature },
+  { US"sig_algorithm",     13, &tls_cert_signature_algorithm },
+  { US"subj_altname",    12, &tls_cert_subject_altname },
+  { US"ocsp_uri",     8,  &tls_cert_ocsp_uri },
+  { US"crl_uri",     7,  &tls_cert_crl_uri },
 };


 static uschar *
@@ -1236,8 +1238,12 @@ if (*field >= '0' && *field <= '9')
 for(cp = certfields;
     cp < certfields + nelements(certfields);
     cp++)
-  if (Ustrcmp(cp->name, field) == 0)
-    return (*cp->getfn)( *(void **)vp->value );
+  if (Ustrncmp(cp->name, field, cp->namelen) == 0)
+    {
+    uschar * modifier = *(field += cp->namelen) == ','
+      ? ++field : NULL;
+    return (*cp->getfn)( *(void **)vp->value, modifier );
+    }


expand_string_message =
string_sprintf("bad field selector \"%s\" for certextract", field);
@@ -7007,7 +7013,6 @@ return 0;

#endif

-/*
- vi: aw ai sw=2
+/* vi: aw ai sw=2
 */
 /* End of expand.c */
diff --git a/src/src/functions.h b/src/src/functions.h
index 8751a00..566a32b 100644
--- a/src/src/functions.h
+++ b/src/src/functions.h
@@ -26,18 +26,18 @@ extern const char *
 extern const char *
                std_dh_prime_named(const uschar *);


-extern uschar * tls_cert_crl_uri(void *);
+extern uschar * tls_cert_crl_uri(void *, uschar * mod);
extern uschar * tls_cert_ext_by_oid(void *, uschar *, int);
-extern uschar * tls_cert_issuer(void *);
-extern uschar * tls_cert_not_before(void *);
-extern uschar * tls_cert_not_after(void *);
-extern uschar * tls_cert_ocsp_uri(void *);
-extern uschar * tls_cert_serial_number(void *);
-extern uschar * tls_cert_signature(void *);
-extern uschar * tls_cert_signature_algorithm(void *);
-extern uschar * tls_cert_subject(void *);
-extern uschar * tls_cert_subject_altname(void *);
-extern uschar * tls_cert_version(void *);
+extern uschar * tls_cert_issuer(void *, uschar * mod);
+extern uschar * tls_cert_not_before(void *, uschar * mod);
+extern uschar * tls_cert_not_after(void *, uschar * mod);
+extern uschar * tls_cert_ocsp_uri(void *, uschar * mod);
+extern uschar * tls_cert_serial_number(void *, uschar * mod);
+extern uschar * tls_cert_signature(void *, uschar * mod);
+extern uschar * tls_cert_signature_algorithm(void *, uschar * mod);
+extern uschar * tls_cert_subject(void *, uschar * mod);
+extern uschar * tls_cert_subject_altname(void *, uschar * mod);
+extern uschar * tls_cert_version(void *, uschar * mod);

 extern int     tls_client_start(int, host_item *, address_item *,
                  uschar *, uschar *, uschar *, uschar *, uschar *, uschar *,
diff --git a/src/src/tlscert-gnu.c b/src/src/tlscert-gnu.c
index 649e93a..61b526a 100644
--- a/src/src/tlscert-gnu.c
+++ b/src/src/tlscert-gnu.c
@@ -86,7 +86,7 @@ return len > 0 ? cp : NULL;
 /**/


uschar *
-tls_cert_issuer(void * cert)
+tls_cert_issuer(void * cert, uschar * mod)
{
uschar txt[256];
size_t sz = sizeof(txt);
@@ -95,21 +95,21 @@ return ( gnutls_x509_crt_get_issuer_dn(cert, CS txt, &sz) == 0 )
}

uschar *
-tls_cert_not_after(void * cert)
+tls_cert_not_after(void * cert, uschar * mod)
{
return time_copy(
gnutls_x509_crt_get_expiration_time((gnutls_x509_crt_t)cert));
}

uschar *
-tls_cert_not_before(void * cert)
+tls_cert_not_before(void * cert, uschar * mod)
{
return time_copy(
gnutls_x509_crt_get_activation_time((gnutls_x509_crt_t)cert));
}

uschar *
-tls_cert_serial_number(void * cert)
+tls_cert_serial_number(void * cert, uschar * mod)
{
uschar bin[50], txt[150];
size_t sz = sizeof(bin);
@@ -126,7 +126,7 @@ return string_copy(sp);
}

uschar *
-tls_cert_signature(void * cert)
+tls_cert_signature(void * cert, uschar * mod)
{
uschar * cp1;
uschar * cp2;
@@ -157,7 +157,7 @@ return cp2;
}

uschar *
-tls_cert_signature_algorithm(void * cert)
+tls_cert_signature_algorithm(void * cert, uschar * mod)
{
gnutls_sign_algorithm_t algo =
gnutls_x509_crt_get_signature_algorithm((gnutls_x509_crt_t)cert);
@@ -165,7 +165,7 @@ return algo < 0 ? NULL : string_copy(gnutls_sign_get_name(algo));
}

uschar *
-tls_cert_subject(void * cert)
+tls_cert_subject(void * cert, uschar * mod)
{
static uschar txt[256];
size_t sz = sizeof(txt);
@@ -174,7 +174,7 @@ return ( gnutls_x509_crt_get_dn(cert, CS txt, &sz) == 0 )
}

uschar *
-tls_cert_version(void * cert)
+tls_cert_version(void * cert, uschar * mod)
{
return string_sprintf("%d", gnutls_x509_crt_get_version(cert));
}
@@ -218,60 +218,106 @@ return cp2;
}

uschar *
-tls_cert_subject_altname(void * cert)
+tls_cert_subject_altname(void * cert, uschar * mod)
{
-uschar * cp = NULL;
-size_t siz = 0;
-unsigned int crit;
+uschar * list = NULL;
+int index;
+size_t siz;
int ret;
+uschar sep = '\n';
+uschar * tag = US"";
+uschar * ele;
+int match = -1;

-ret = gnutls_x509_crt_get_subject_alt_name ((gnutls_x509_crt_t)cert,
-  0, cp, &siz, &crit);
-switch(ret)
+while (mod)
   {
-  case GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE:
-    return NULL;
-  case GNUTLS_E_SHORT_MEMORY_BUFFER:
+  if (*mod == '>' && *++mod) sep = *mod++;
+  else if (Ustrcmp(mod, "dns")==0) { match = GNUTLS_SAN_DNSNAME; mod += 3; }
+  else if (Ustrcmp(mod, "uri")==0) { match = GNUTLS_SAN_URI; mod += 3; }
+  else if (Ustrcmp(mod, "mail")==0) { match = GNUTLS_SAN_RFC822NAME; mod += 4; }
+  else continue;
+
+  if (*mod++ != ',')
     break;
-  default:
-    expand_string_message = 
-      string_sprintf("%s: gs0 fail: %d %s\n", __FUNCTION__,
-    ret, gnutls_strerror(ret));
-    return NULL;
   }


-cp = store_get(siz+1);
-ret = gnutls_x509_crt_get_subject_alt_name ((gnutls_x509_crt_t)cert,
-  0, cp, &siz, &crit);
-if (ret < 0)
+for(index = 0;; index++)
   {
-  expand_string_message = 
-    string_sprintf("%s: gs1 fail: %d %s\n", __FUNCTION__,
-      ret, gnutls_strerror(ret));
-  return NULL;
+  siz = 0;
+  switch(ret = gnutls_x509_crt_get_subject_alt_name(
+    (gnutls_x509_crt_t)cert, index, NULL, &siz, NULL))
+    {
+    case GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE:
+      return list;    /* no more elements; normal exit */
+
+    case GNUTLS_E_SHORT_MEMORY_BUFFER:
+      break;
+
+    default:
+      expand_string_message = 
+    string_sprintf("%s: gs0 fail: %d %s\n", __FUNCTION__,
+      ret, gnutls_strerror(ret));
+      return NULL;
+    }
+
+  ele = store_get(siz+1);
+  if ((ret = gnutls_x509_crt_get_subject_alt_name(
+    (gnutls_x509_crt_t)cert, index, ele, &siz, NULL)) < 0)
+    {
+    expand_string_message = 
+      string_sprintf("%s: gs1 fail: %d %s\n", __FUNCTION__,
+    ret, gnutls_strerror(ret));
+    return NULL;
+    }
+  ele[siz] = '\0';
+
+  if (match != -1 && match != ret)
+    continue;
+  switch (ret)
+    {
+    case GNUTLS_SAN_DNSNAME:    tag = US"DNS";  break;
+    case GNUTLS_SAN_URI:        tag = US"URI";  break; 
+    case GNUTLS_SAN_RFC822NAME: tag = US"MAIL"; break;
+    default: continue;        /* ignore unrecognised types */
+    }
+  list = string_append_listele(list, sep, 
+          match == -1 ? string_sprintf("%s=%s", tag, ele) : ele);
   }
-cp[siz] = '\0';
-return cp;
+/*NOTREACHED*/
 }


 uschar *
-tls_cert_ocsp_uri(void * cert)
+tls_cert_ocsp_uri(void * cert, uschar * mod)
 {
 #if GNUTLS_VERSION_NUMBER >= 0x030000
 gnutls_datum_t uri;
-unsigned int crit;
-int ret = gnutls_x509_crt_get_authority_info_access((gnutls_x509_crt_t)cert,
-    0, GNUTLS_IA_OCSP_URI, &uri, &crit);
+int ret;
+uschar sep = '\n';
+int index;
+uschar * list = NULL;
+
+if (mod)
+  if (*mod == '>' && *++mod) sep = *mod++;


-if (ret >= 0)
-  return string_copyn(uri.data, uri.size);
+for(index = 0;; index++)
+  {
+  ret = gnutls_x509_crt_get_authority_info_access((gnutls_x509_crt_t)cert,
+      index, GNUTLS_IA_OCSP_URI, &uri, NULL);


-if (ret != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
-  expand_string_message = 
-    string_sprintf("%s: gai fail: %d %s\n", __FUNCTION__,
-      ret, gnutls_strerror(ret));
+  if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
+    return list;
+  if (ret < 0)
+    {
+    expand_string_message = 
+      string_sprintf("%s: gai fail: %d %s\n", __FUNCTION__,
+    ret, gnutls_strerror(ret));
+    return NULL;
+    }


-return NULL;
+  list = string_append_listele(list, sep,
+        string_copyn(uri.data, uri.size));
+  }
+/*NOTREACHED*/


#else

@@ -284,39 +330,48 @@ return NULL;
}

uschar *
-tls_cert_crl_uri(void * cert)
+tls_cert_crl_uri(void * cert, uschar * mod)
{
int ret;
-uschar * cp = NULL;
-size_t siz = 0;
+size_t siz;
+uschar sep = '\n';
+int index;
+uschar * list = NULL;
+uschar * ele;
+
+if (mod)
+ if (*mod == '>' && *++mod) sep = *mod++;

-ret = gnutls_x509_crt_get_crl_dist_points ((gnutls_x509_crt_t)cert,
-  0, cp, &siz, NULL, NULL);
-switch(ret)
+for(index = 0;; index++)
   {
-  case GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE:
-    return NULL;
-  case GNUTLS_E_SHORT_MEMORY_BUFFER:
-    break;
-  default:
+  siz = 0;
+  switch(ret = gnutls_x509_crt_get_crl_dist_points(
+    (gnutls_x509_crt_t)cert, index, NULL, &siz, NULL, NULL))
+    {
+    case GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE:
+      return list;
+    case GNUTLS_E_SHORT_MEMORY_BUFFER:
+      break;
+    default:
+      expand_string_message = 
+    string_sprintf("%s: gc0 fail: %d %s\n", __FUNCTION__,
+      ret, gnutls_strerror(ret));
+      return NULL;
+    }
+
+  ele = store_get(siz+1);
+  if ((ret = gnutls_x509_crt_get_crl_dist_points(
+    (gnutls_x509_crt_t)cert, index, ele, &siz, NULL, NULL)) < 0)
+    {
     expand_string_message = 
-      string_sprintf("%s: gc0 fail: %d %s\n", __FUNCTION__,
+      string_sprintf("%s: gc1 fail: %d %s\n", __FUNCTION__,
     ret, gnutls_strerror(ret));
     return NULL;
+    }
+  ele[siz] = '\0';
+  list = string_append_listele(list, sep, ele);
   }
-
-cp = store_get(siz+1);
-ret = gnutls_x509_crt_get_crl_dist_points ((gnutls_x509_crt_t)cert,
-  0, cp, &siz, NULL, NULL);
-if (ret < 0)
-  {
-  expand_string_message = 
-    string_sprintf("%s: gs1 fail: %d %s\n", __FUNCTION__,
-      ret, gnutls_strerror(ret));
-  return NULL;
-  }
-cp[siz] = '\0';
-return cp;
+/*NOTREACHED*/
 }



diff --git a/src/src/tlscert-openssl.c b/src/src/tlscert-openssl.c
index 20ecbbc..53945a1 100644
--- a/src/src/tlscert-openssl.c
+++ b/src/src/tlscert-openssl.c
@@ -109,25 +109,25 @@ return bio_string_copy(bp, len_good);
/**/

uschar *
-tls_cert_issuer(void * cert)
+tls_cert_issuer(void * cert, uschar * mod)
{
return x509_name_copy(X509_get_issuer_name((X509 *)cert));
}

uschar *
-tls_cert_not_before(void * cert)
+tls_cert_not_before(void * cert, uschar * mod)
{
return asn1_time_copy(X509_get_notBefore((X509 *)cert));
}

uschar *
-tls_cert_not_after(void * cert)
+tls_cert_not_after(void * cert, uschar * mod)
{
return asn1_time_copy(X509_get_notAfter((X509 *)cert));
}

 uschar *
-tls_cert_serial_number(void * cert)
+tls_cert_serial_number(void * cert, uschar * mod)
 {
 uschar txt[256];
 BIO * bp = BIO_new(BIO_s_mem());
@@ -142,7 +142,7 @@ return string_copynlc(txt, len);    /* lowercase */
 }


uschar *
-tls_cert_signature(void * cert)
+tls_cert_signature(void * cert, uschar * mod)
{
BIO * bp = BIO_new(BIO_s_mem());
uschar * cp = NULL;
@@ -162,19 +162,19 @@ return cp;
}

uschar *
-tls_cert_signature_algorithm(void * cert)
+tls_cert_signature_algorithm(void * cert, uschar * mod)
{
return string_copy(OBJ_nid2ln(X509_get_signature_type((X509 *)cert)));
}

uschar *
-tls_cert_subject(void * cert)
+tls_cert_subject(void * cert, uschar * mod)
{
return x509_name_copy(X509_get_subject_name((X509 *)cert));
}

uschar *
-tls_cert_version(void * cert)
+tls_cert_version(void * cert, uschar * mod)
{
return string_sprintf("%d", X509_get_version((X509 *)cert));
}
@@ -211,58 +211,86 @@ return cp3;
}

uschar *
-tls_cert_subject_altname(void * cert)
+tls_cert_subject_altname(void * cert, uschar * mod)
{
-uschar * cp;
+uschar * list = NULL;
STACK_OF(GENERAL_NAME) * san = (STACK_OF(GENERAL_NAME) *)
X509_get_ext_d2i((X509 *)cert, NID_subject_alt_name, NULL, NULL);
+uschar sep = '\n';
+uschar * tag = US"";
+uschar * ele;
+int match = -1;

if (!san) return NULL;

+while (mod)
+  {
+  if (*mod == '>' && *++mod) sep = *mod++;
+  else if (Ustrcmp(mod, "dns")==0) { match = GEN_DNS; mod += 3; }
+  else if (Ustrcmp(mod, "uri")==0) { match = GEN_URI; mod += 3; }
+  else if (Ustrcmp(mod, "mail")==0) { match = GEN_EMAIL; mod += 4; }
+  else continue;
+
+  if (*mod++ != ',')
+    break;
+  }
+
 while (sk_GENERAL_NAME_num(san) > 0)
   {
   GENERAL_NAME * namePart = sk_GENERAL_NAME_pop(san);
+  if (match != -1 && match != namePart->type)
+    continue;
   switch (namePart->type)
     {
+    case GEN_DNS:
+      tag = US"DNS";
+      ele = ASN1_STRING_data(namePart->d.dNSName);
+      break;
     case GEN_URI:
-      cp = string_sprintf("URI=%s",
-        ASN1_STRING_data(namePart->d.uniformResourceIdentifier));
-      return cp;
+      tag = US"URI";
+      ele = ASN1_STRING_data(namePart->d.uniformResourceIdentifier);
+      break;
     case GEN_EMAIL:
-      cp = string_sprintf("email=%s",
-        ASN1_STRING_data(namePart->d.rfc822Name));
-      return cp;
+      tag = US"MAIL";
+      ele = ASN1_STRING_data(namePart->d.rfc822Name);
+      break;
     default:
-      cp = string_sprintf("Unrecognisable");
-      return cp;
+      continue;    /* ignore unrecognised types */
     }
+  list = string_append_listele(list, sep,
+      match == -1 ? string_sprintf("%s=%s", tag, ele) : ele);
   }


-/* sk_GENERAL_NAME_pop_free(gen_names, GENERAL_NAME_free); ??? */
-return cp;
+sk_GENERAL_NAME_free(san);
+return list;
}

uschar *
-tls_cert_ocsp_uri(void * cert)
+tls_cert_ocsp_uri(void * cert, uschar * mod)
{
STACK_OF(ACCESS_DESCRIPTION) * ads = (STACK_OF(ACCESS_DESCRIPTION) *)
X509_get_ext_d2i((X509 *)cert, NID_info_access, NULL, NULL);
int adsnum = sk_ACCESS_DESCRIPTION_num(ads);
int i;
+uschar sep = '\n';
+uschar * list = NULL;
+
+if (mod)
+ if (*mod == '>' && *++mod) sep = *mod++;

for (i = 0; i < adsnum; i++)
{
ACCESS_DESCRIPTION * ad = sk_ACCESS_DESCRIPTION_value(ads, i);

   if (ad && OBJ_obj2nid(ad->method) == NID_ad_OCSP)
-    return string_copy( ASN1_STRING_data(ad->location->d.ia5) );
+    list = string_append_listele(list, sep,
+          ASN1_STRING_data(ad->location->d.ia5));
   }
-
-return NULL;
+return list;
 }


uschar *
-tls_cert_crl_uri(void * cert)
+tls_cert_crl_uri(void * cert, uschar * mod)
{
STACK_OF(DIST_POINT) * dps = (STACK_OF(DIST_POINT) *)
X509_get_ext_d2i((X509 *)cert, NID_crl_distribution_points,
@@ -270,6 +298,11 @@ STACK_OF(DIST_POINT) * dps = (STACK_OF(DIST_POINT) *)
DIST_POINT * dp;
int dpsnum = sk_DIST_POINT_num(dps);
int i;
+uschar sep = '\n';
+uschar * list = NULL;
+
+if (mod)
+ if (*mod == '>' && *++mod) sep = *mod++;

 if (dps) for (i = 0; i < dpsnum; i++)
   if ((dp = sk_DIST_POINT_value(dps, i)))
@@ -283,10 +316,10 @@ if (dps) for (i = 0; i < dpsnum; i++)
       if (  (np = sk_GENERAL_NAME_value(names, j))
      && np->type == GEN_URI
      )
-    return string_copy(ASN1_STRING_data(
-      np->d.uniformResourceIdentifier));
+    list = string_append_listele(list, sep,
+        ASN1_STRING_data(np->d.uniformResourceIdentifier));
     }
-return NULL;
+return list;
 }


 /* vi: aw ai sw=2
diff --git a/test/confs/2002 b/test/confs/2002
index b4d0348..9d7deb7 100644
--- a/test/confs/2002
+++ b/test/confs/2002
@@ -53,9 +53,9 @@ check_recipient:
           logwrite =  IN  <${certextract {issuer}    {$tls_in_peercert}}>
           logwrite =  NB  <${certextract {notbefore}    {$tls_in_peercert}}>
           logwrite =  NA  <${certextract {notafter}    {$tls_in_peercert}}>
-          logwrite =  SA  <${certextract {signature_algorithm}{$tls_in_peercert}}>
+          logwrite =  SA  <${certextract {sig_algorithm}{$tls_in_peercert}}>
           logwrite =  SG  <${certextract {signature}    {$tls_in_peercert}}>
-      logwrite =       ${certextract {subject_altname}{$tls_in_peercert} {SAN <$value>}{(no SAN)}}
+      logwrite =       ${certextract {subj_altname} {$tls_in_peercert} {SAN <$value>}{(no SAN)}}
 #      logwrite =       ${certextract {ocsp_uri}    {$tls_in_peercert} {OCU <$value>}{(no OCU)}}
       logwrite =       ${certextract {crl_uri}    {$tls_in_peercert} {CRU <$value>}{(no CRU)}}


diff --git a/test/confs/2102 b/test/confs/2102
index 5332801..27cb805 100644
--- a/test/confs/2102
+++ b/test/confs/2102
@@ -54,9 +54,9 @@ check_recipient:
           logwrite =  IN  <${certextract {issuer}    {$tls_in_peercert}}>
           logwrite =  NB  <${certextract {notbefore}    {$tls_in_peercert}}>
           logwrite =  NA  <${certextract {notafter}    {$tls_in_peercert}}>
-          logwrite =  SA  <${certextract {signature_algorithm}{$tls_in_peercert}}>
+          logwrite =  SA  <${certextract {sig_algorithm}{$tls_in_peercert}}>
           logwrite =  SG  <${certextract {signature}    {$tls_in_peercert}}>
-      logwrite =       ${certextract {subject_altname}{$tls_in_peercert} {SAN <$value>}{(no SAN)}}
+      logwrite =       ${certextract {subj_altname} {$tls_in_peercert} {SAN <$value>}{(no SAN)}}
       logwrite =       ${certextract {ocsp_uri}    {$tls_in_peercert} {OCU <$value>}{(no OCU)}}
       logwrite =       ${certextract {crl_uri}    {$tls_in_peercert} {CRU <$value>}{(no CRU)}}


diff --git a/test/confs/5750 b/test/confs/5750
index daff91b..a8ff603 100644
--- a/test/confs/5750
+++ b/test/confs/5750
@@ -45,9 +45,9 @@ logger:
          logwrite =  IN  <${certextract {issuer}    {$tls_out_peercert}}>
          logwrite =  NB  <${certextract {notbefore}    {$tls_out_peercert}}>
          logwrite =  NA  <${certextract {notafter}    {$tls_out_peercert}}>
-         logwrite =  SA  <${certextract {signature_algorithm}{$tls_out_peercert}}>
+         logwrite =  SA  <${certextract {sig_algorithm} {$tls_out_peercert}}>
          logwrite =  SG  <${certextract {signature}    {$tls_out_peercert}}>
-     logwrite =       ${certextract {subject_altname}{$tls_out_peercert}{SAN <$value>}{(no SAN)}}
+     logwrite =       ${certextract {subj_altname}  {$tls_out_peercert}{SAN <$value>}{(no SAN)}}
 #     logwrite =       ${certextract {ocsp_uri}    {$tls_out_peercert} {OCU <$value>}{(no OCU)}}
      logwrite =       ${certextract {crl_uri}    {$tls_out_peercert} {CRU <$value>}{(no CRU)}}


diff --git a/test/confs/5760 b/test/confs/5760
index 0e11ab0..e9868d1 100644
--- a/test/confs/5760
+++ b/test/confs/5760
@@ -45,9 +45,9 @@ logger:
          logwrite =  IN  <${certextract {issuer}    {$tls_out_peercert}}>
          logwrite =  NB  <${certextract {notbefore}    {$tls_out_peercert}}>
          logwrite =  NA  <${certextract {notafter}    {$tls_out_peercert}}>
-         logwrite =  SA  <${certextract {signature_algorithm}{$tls_out_peercert}}>
+         logwrite =  SA  <${certextract {sig_algorithm} {$tls_out_peercert}}>
          logwrite =  SG  <${certextract {signature}    {$tls_out_peercert}}>
-     logwrite =       ${certextract {subject_altname}{$tls_out_peercert}{SAN <$value>}{(no SAN)}}
+     logwrite = ${certextract {subj_altname,>;}{$tls_out_peercert}{SAN <$value>}{(no SAN)}}
      logwrite =       ${certextract {ocsp_uri}    {$tls_out_peercert} {OCU <$value>}{(no OCU)}}
      logwrite =       ${certextract {crl_uri}    {$tls_out_peercert} {CRU <$value>}{(no CRU)}}


diff --git a/test/log/2002 b/test/log/2002
index 50b7863..c4aa1d0 100644
--- a/test/log/2002
+++ b/test/log/2002
@@ -16,7 +16,7 @@
 1999-03-02 09:44:33 NA  <Jan  1 12:34:06 2038 GMT>
 1999-03-02 09:44:33 SA  <RSA-SHA>
 1999-03-02 09:44:33 SG  <6c 37 41 26 4d 5d f4 b5 31 10 67 ca fb 64 b6 22 98 62 f7 1e 95 7b 6c e6 74 47 21 f4 5e 89 36 3e b9 9c 8a c5 52 bb c4 af 12 93 26 3b d7 3d e0 56 71 1e 1d 21 20 02 ed f0 4e d5 5e 45 42 fd 3c 38 41 54 83 86 0b 3b bf c5 47 39 ff 15 ea 93 dc fd c7 3d 18 58 59 ca dd 2a d8 b9 f9 2f b9 76 93 f4 ae e3 91 56 80 2f 8c 04 2f ad 57 ef d2 51 19 f4 b4 ef 32 9c ac 3a 7c 0d b8 39 db b1 e3 30 73 1a>
-1999-03-02 09:44:33 SAN <server2.example.com>
+1999-03-02 09:44:33 SAN <DNS=server2.example.com>
 1999-03-02 09:44:33 CRU <http://crl.example.com/latest.crl>
 1999-03-02 09:44:33 10HmaZ-0005vi-00 <= CALLER@??? H=[ip4.ip4.ip4.ip4] P=smtps X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 DN="CN=server2.example.com" S=sss
 1999-03-02 09:44:33 Start queue run: pid=pppp -qf
diff --git a/test/log/2102 b/test/log/2102
index 6e0713f..e5bf8f6 100644
--- a/test/log/2102
+++ b/test/log/2102
@@ -17,7 +17,7 @@
 1999-03-02 09:44:33 NA  <Jan  1 12:34:06 2038 GMT>
 1999-03-02 09:44:33 SA  <undefined>
 1999-03-02 09:44:33 SG  <    Signature Algorithm: sha1WithRSAEncryption\n         6c:37:41:26:4d:5d:f4:b5:31:10:67:ca:fb:64:b6:22:98:62:\n         f7:1e:95:7b:6c:e6:74:47:21:f4:5e:89:36:3e:b9:9c:8a:c5:\n         52:bb:c4:af:12:93:26:3b:d7:3d:e0:56:71:1e:1d:21:20:02:\n         ed:f0:4e:d5:5e:45:42:fd:3c:38:41:54:83:86:0b:3b:bf:c5:\n         47:39:ff:15:ea:93:dc:fd:c7:3d:18:58:59:ca:dd:2a:d8:b9:\n         f9:2f:b9:76:93:f4:ae:e3:91:56:80:2f:8c:04:2f:ad:57:ef:\n         d2:51:19:f4:b4:ef:32:9c:ac:3a:7c:0d:b8:39:db:b1:e3:30:\n         73:1a\n>
-1999-03-02 09:44:33 SAN <Unrecognisable>
+1999-03-02 09:44:33 SAN <DNS=server2.example.com>
 1999-03-02 09:44:33 OCU <http://oscp/example.com/>
 1999-03-02 09:44:33 CRU <http://crl.example.com/latest.crl>
 1999-03-02 09:44:33 10HmaZ-0005vi-00 <= CALLER@??? H=[ip4.ip4.ip4.ip4] P=smtps X=TLSv1:AES256-SHA:256 DN="/CN=server2.example.com" S=sss
diff --git a/test/log/5750 b/test/log/5750
index c3c77a6..8456246 100644
--- a/test/log/5750
+++ b/test/log/5750
@@ -12,7 +12,7 @@
 1999-03-02 09:44:33 10HmaX-0005vi-00 NA  <Jan  1 12:34:05 2038 GMT>
 1999-03-02 09:44:33 10HmaX-0005vi-00 SA  <RSA-SHA>
 1999-03-02 09:44:33 10HmaX-0005vi-00 SG  <56 3a a4 3c cb eb b8 27 c2 90 08 74 13 88 dc 48 c6 b5 2c e5 26 be 5b 91 d4 67 e7 3c 49 12 d7 47 30 df 98 db 58 ed 18 a8 7d 4b db 97 48 f5 5c 7f 70 b9 37 63 33 f1 24 62 72 92 60 f5 6e da b6 bc 73 c8 c2 dc d6 95 9a bd 16 16 a2 ef 0a f1 d7 41 68 f6 ad 98 5a d0 ff d9 1b 51 9f 59 ce 2f 3d 84 d0 ee e8 2b eb 9b 32 1a 0e 02 3e cc 30 89 44 09 2a 75 81 46 a7 b6 ed 7d 41 eb 5a 63 fa 9c 58 ef>
-1999-03-02 09:44:33 10HmaX-0005vi-00 SAN <alternatename.server1.example.com>
+1999-03-02 09:44:33 10HmaX-0005vi-00 SAN <DNS=alternatename.server1.example.com\nDNS=alternatename2.server1.example.com\nDNS=server1.example.com>
 1999-03-02 09:44:33 10HmaX-0005vi-00 CRU <http://crl.example.com/latest.crl>
 1999-03-02 09:44:33 10HmaX-0005vi-00 TLS session failure: delivering unencrypted to 127.0.0.1 [127.0.0.1] (not in hosts_require_tls)
 1999-03-02 09:44:33 10HmaX-0005vi-00 => bad@??? R=client T=send_to_server H=127.0.0.1 [127.0.0.1] C="250 OK id=10HmaZ-0005vi-00"
@@ -31,7 +31,7 @@
 1999-03-02 09:44:33 10HmaY-0005vi-00 NA  <Jan  1 12:34:05 2038 GMT>
 1999-03-02 09:44:33 10HmaY-0005vi-00 SA  <RSA-SHA>
 1999-03-02 09:44:33 10HmaY-0005vi-00 SG  <56 3a a4 3c cb eb b8 27 c2 90 08 74 13 88 dc 48 c6 b5 2c e5 26 be 5b 91 d4 67 e7 3c 49 12 d7 47 30 df 98 db 58 ed 18 a8 7d 4b db 97 48 f5 5c 7f 70 b9 37 63 33 f1 24 62 72 92 60 f5 6e da b6 bc 73 c8 c2 dc d6 95 9a bd 16 16 a2 ef 0a f1 d7 41 68 f6 ad 98 5a d0 ff d9 1b 51 9f 59 ce 2f 3d 84 d0 ee e8 2b eb 9b 32 1a 0e 02 3e cc 30 89 44 09 2a 75 81 46 a7 b6 ed 7d 41 eb 5a 63 fa 9c 58 ef>
-1999-03-02 09:44:33 10HmaY-0005vi-00 SAN <alternatename.server1.example.com>
+1999-03-02 09:44:33 10HmaY-0005vi-00 SAN <DNS=alternatename.server1.example.com\nDNS=alternatename2.server1.example.com\nDNS=server1.example.com>
 1999-03-02 09:44:33 10HmaY-0005vi-00 CRU <http://crl.example.com/latest.crl>
 1999-03-02 09:44:33 10HmaY-0005vi-00 Completed
 1999-03-02 09:44:33 End queue run: pid=pppp -qf
diff --git a/test/log/5760 b/test/log/5760
index 0b74e24..a59190f 100644
--- a/test/log/5760
+++ b/test/log/5760
@@ -33,7 +33,7 @@
 1999-03-02 09:44:33 10HmaY-0005vi-00 NA  <Jan  1 12:34:05 2038 GMT>
 1999-03-02 09:44:33 10HmaY-0005vi-00 SA  <undefined>
 1999-03-02 09:44:33 10HmaY-0005vi-00 SG  <    Signature Algorithm: sha1WithRSAEncryption\n         56:3a:a4:3c:cb:eb:b8:27:c2:90:08:74:13:88:dc:48:c6:b5:\n         2c:e5:26:be:5b:91:d4:67:e7:3c:49:12:d7:47:30:df:98:db:\n         58:ed:18:a8:7d:4b:db:97:48:f5:5c:7f:70:b9:37:63:33:f1:\n         24:62:72:92:60:f5:6e:da:b6:bc:73:c8:c2:dc:d6:95:9a:bd:\n         16:16:a2:ef:0a:f1:d7:41:68:f6:ad:98:5a:d0:ff:d9:1b:51:\n         9f:59:ce:2f:3d:84:d0:ee:e8:2b:eb:9b:32:1a:0e:02:3e:cc:\n         30:89:44:09:2a:75:81:46:a7:b6:ed:7d:41:eb:5a:63:fa:9c:\n         58:ef\n>
-1999-03-02 09:44:33 10HmaY-0005vi-00 SAN <Unrecognisable>
+1999-03-02 09:44:33 10HmaY-0005vi-00 SAN <DNS=server1.example.com;DNS=alternatename2.server1.example.com;DNS=alternatename.server1.example.com>
 1999-03-02 09:44:33 10HmaY-0005vi-00 OCU <http://oscp/example.com/>
 1999-03-02 09:44:33 10HmaY-0005vi-00 CRU <http://crl.example.com/latest.crl>
 1999-03-02 09:44:33 10HmaY-0005vi-00 Completed