summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJeremy Harris <jgh146exb@wizmail.org>2014-05-05 16:53:48 +0100
committerJeremy Harris <jgh146exb@wizmail.org>2014-05-05 18:03:12 +0100
commit9e4dddbde4228e83fc7c882a4ef410ddbe0a6e79 (patch)
tree18671feab79ef894a2a905bbe808b153d706a711 /src
parent51424d0857ca09e1082aeacf177e2df6fea37eda (diff)
Extractors for subject-alternate-name, ocsp-uri, crl-uri return list. Bug 1358
Diffstat (limited to 'src')
-rw-r--r--src/src/expand.c37
-rw-r--r--src/src/functions.h22
-rw-r--r--src/src/tlscert-gnu.c193
-rw-r--r--src/src/tlscert-openssl.c89
4 files changed, 217 insertions, 124 deletions
diff --git a/src/src/expand.c b/src/src/expand.c
index 8f1b3d875..05b714a7f 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 8751a006e..566a32bd6 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 649e93a35..61b526a69 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 20ecbbc6c..53945a1e0 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