From 812a604525eef4993d6ed165d455c8309ae72c36 Mon Sep 17 00:00:00 2001 From: Jeremy Harris Date: Tue, 13 May 2014 22:02:51 +0100 Subject: [PATCH] Extractor for named RDN element types from a certificate DN field. --- doc/doc-docbook/spec.xfpt | 6 ++++ src/src/functions.h | 1 + src/src/tls.c | 62 +++++++++++++++++++++++++++++++++++++++ src/src/tlscert-gnu.c | 56 ++++++++++++++++------------------- src/src/tlscert-openssl.c | 6 ++-- test/confs/2002 | 1 + test/confs/2102 | 1 + test/log/2002 | 1 + test/log/2102 | 1 + 9 files changed, 102 insertions(+), 33 deletions(-) diff --git a/doc/doc-docbook/spec.xfpt b/doc/doc-docbook/spec.xfpt index 17c69a7a5..e85ba6629 100644 --- a/doc/doc-docbook/spec.xfpt +++ b/doc/doc-docbook/spec.xfpt @@ -8936,6 +8936,12 @@ output a Distinguished Name string which is not quite parseable by Exim as a comma-separated tagged list (the exceptions being elements containin commas). +RDN elements of a single type may be selected by +a modifier of the type label; if so the expansion +result is a list (newline-separated by default). +The separator may be changed by another modifer of +a right angle-bracket followed immediately by the new separator. +Recognised RDN type labels include "CN", "O", "OU" and "DC". Field values are generally presented in human-readable form. .wen diff --git a/src/src/functions.h b/src/src/functions.h index 792f3df4d..741b632a9 100644 --- a/src/src/functions.h +++ b/src/src/functions.h @@ -62,6 +62,7 @@ extern void tls_version_report(FILE *); #ifndef USE_GNUTLS extern BOOL tls_openssl_options_parse(uschar *, long *); #endif +extern uschar * tls_field_from_dn(uschar *, uschar *); #endif /*SUPPORT_TLS*/ diff --git a/src/src/tls.c b/src/src/tls.c index f0ac60308..75c46e9e4 100644 --- a/src/src/tls.c +++ b/src/src/tls.c @@ -196,4 +196,66 @@ modify_variable(US"tls_sni", &dest_tsp->sni); #endif } +/************************************************ +* TLS certificate name operations * +************************************************/ + +/* Convert an rfc4514 DN to an exim comma-sep list. +Backslashed commas need to be replaced by doublecomma +for Exim's list quoting. We modify the given string +inplace. +*/ + +static void +dn_to_list(uschar * dn) +{ +uschar * cp; +for (cp = dn; *cp; cp++) + if (cp[0] == '\\' && cp[1] == ',') + *cp++ = ','; +} + + +/* Extract fields of a given type from an RFC4514- +format Distinguished Name. Return an Exim list. +NOTE: We modify the supplied dn string during operation. + +Arguments: + dn Distinguished Name string + mod string containing optional list-sep and + field selector match, comma-separated +Return: + allocated string with list of matching fields, + field type stripped +*/ + +uschar * +tls_field_from_dn(uschar * dn, uschar * mod) +{ +int insep = ','; +uschar outsep = '\n'; +uschar * ele; +uschar * match = NULL; +int len; +uschar * list = NULL; + +while (ele = string_nextinlist(&mod, &insep, NULL, 0)) + if (ele[0] != '>') + match = ele; /* field tag to match */ + else if (ele[1]) + outsep = ele[1]; /* nondefault separator */ + +dn_to_list(dn); +insep = ','; +len = Ustrlen(match); +while (ele = string_nextinlist(&dn, &insep, NULL, 0)) + if (Ustrncmp(ele, match, len) == 0 && ele[len] == '=') + list = string_append_listele(list, outsep, ele+len+1); +return list; +} + + + +/* vi: aw ai sw=2 +*/ /* End of tls.c */ diff --git a/src/src/tlscert-gnu.c b/src/src/tlscert-gnu.c index 3d255ee96..085e05689 100644 --- a/src/src/tlscert-gnu.c +++ b/src/src/tlscert-gnu.c @@ -77,8 +77,8 @@ gnutls_global_deinit(); static uschar * g_err(const char * tag, const char * from, int gnutls_err) { -expand_string_message = string_sprintf(stderr, - "%s: %s fail: %s\n", from, tag, gnutls_strerror(gnutls_err)); +expand_string_message = string_sprintf("%s: %s fail: %s\n", + from, tag, gnutls_strerror(gnutls_err)); return NULL; } @@ -97,10 +97,19 @@ return len > 0 ? cp : NULL; uschar * tls_cert_issuer(void * cert, uschar * mod) { -uschar txt[256]; -size_t sz = sizeof(txt); -return ( gnutls_x509_crt_get_issuer_dn(cert, CS txt, &sz) == 0 ) - ? string_copy(txt) : NULL; +uschar * cp = NULL; +int ret; +size_t siz = 0; + +if ((ret = gnutls_x509_crt_get_issuer_dn(cert, cp, &siz)) + != GNUTLS_E_SHORT_MEMORY_BUFFER) + return g_err("gi0", __FUNCTION__, ret); + +cp = store_get(siz); +if ((ret = gnutls_x509_crt_get_issuer_dn(cert, cp, &siz)) < 0) + return g_err("gi1", __FUNCTION__, ret); + +return mod ? tls_field_from_dn(cp, mod) : cp; } uschar * @@ -143,20 +152,13 @@ uschar * cp3; size_t len = 0; int ret; -if ((ret = gnutls_x509_crt_get_signature((gnutls_x509_crt_t)cert, cp1, &len)) != - GNUTLS_E_SHORT_MEMORY_BUFFER) - { - fprintf(stderr, "%s: gs0 fail: %s\n", __FUNCTION__, gnutls_strerror(ret)); - return NULL; - } +if ((ret = gnutls_x509_crt_get_signature((gnutls_x509_crt_t)cert, cp1, &len)) + != GNUTLS_E_SHORT_MEMORY_BUFFER) + return g_err("gs0", __FUNCTION__, ret); cp1 = store_get(len*4+1); - if (gnutls_x509_crt_get_signature((gnutls_x509_crt_t)cert, cp1, &len) != 0) - { - fprintf(stderr, "%s: gs1 fail\n", __FUNCTION__); - return NULL; - } + return g_err("gs1", __FUNCTION__, ret); for(cp3 = cp2 = cp1+len; cp1 < cp2; cp3 += 3, cp1++) sprintf(cp3, "%.2x ", *cp1); @@ -180,23 +182,15 @@ uschar * cp = NULL; int ret; size_t siz = 0; -ret = gnutls_x509_crt_get_dn(cert, cp, &siz); -if (ret != GNUTLS_E_SHORT_MEMORY_BUFFER) - { - fprintf(stderr, "%s: gs0 fail: %s\n", __FUNCTION__, gnutls_strerror(ret)); - return NULL; - } +if ((ret = gnutls_x509_crt_get_dn(cert, cp, &siz)) + != GNUTLS_E_SHORT_MEMORY_BUFFER) + return g_err("gs0", __FUNCTION__, ret); cp = store_get(siz); +if ((ret = gnutls_x509_crt_get_dn(cert, cp, &siz)) < 0) + return g_err("gs1", __FUNCTION__, ret); -ret = gnutls_x509_crt_get_dn(cert, cp, &siz); -if (ret < 0) - { - fprintf(stderr, "%s: gs1 fail: %s\n", __FUNCTION__, gnutls_strerror(ret)); - return NULL; - } - -return cp; +return mod ? tls_field_from_dn(cp, mod) : cp; } uschar * diff --git a/src/src/tlscert-openssl.c b/src/src/tlscert-openssl.c index 9903f08f3..00a3cb555 100644 --- a/src/src/tlscert-openssl.c +++ b/src/src/tlscert-openssl.c @@ -111,7 +111,8 @@ return bio_string_copy(bp, len_good); uschar * tls_cert_issuer(void * cert, uschar * mod) { -return x509_name_copy(X509_get_issuer_name((X509 *)cert)); +uschar * cp = x509_name_copy(X509_get_issuer_name((X509 *)cert)); +return mod ? tls_field_from_dn(cp, mod) : cp; } uschar * @@ -170,7 +171,8 @@ return string_copy(US OBJ_nid2ln(X509_get_signature_type((X509 *)cert))); uschar * tls_cert_subject(void * cert, uschar * mod) { -return x509_name_copy(X509_get_subject_name((X509 *)cert)); +uschar * cp = x509_name_copy(X509_get_subject_name((X509 *)cert)); +return mod ? tls_field_from_dn(cp, mod) : cp; } uschar * diff --git a/test/confs/2002 b/test/confs/2002 index 178265d65..dc958ec38 100644 --- a/test/confs/2002 +++ b/test/confs/2002 @@ -51,6 +51,7 @@ check_recipient: logwrite = SR <${certextract {serial_number}{$tls_in_peercert}}> logwrite = SN <${certextract {subject} {$tls_in_peercert}}> logwrite = IN <${certextract {issuer} {$tls_in_peercert}}> + logwrite = IN/O <${certextract {issuer,O} {$tls_in_peercert}}> logwrite = NB <${certextract {notbefore} {$tls_in_peercert}}> logwrite = NA <${certextract {notafter} {$tls_in_peercert}}> logwrite = SA <${certextract {sig_algorithm}{$tls_in_peercert}}> diff --git a/test/confs/2102 b/test/confs/2102 index 3d5e51ae6..8879cd07d 100644 --- a/test/confs/2102 +++ b/test/confs/2102 @@ -52,6 +52,7 @@ check_recipient: logwrite = SR <${certextract {serial_number}{$tls_in_peercert}}> logwrite = SN <${certextract {subject} {$tls_in_peercert}}> logwrite = IN <${certextract {issuer} {$tls_in_peercert}}> + logwrite = IN/O <${certextract {issuer,O} {$tls_in_peercert}}> logwrite = NB <${certextract {notbefore} {$tls_in_peercert}}> logwrite = NA <${certextract {notafter} {$tls_in_peercert}}> logwrite = SA <${certextract {sig_algorithm}{$tls_in_peercert}}> diff --git a/test/log/2002 b/test/log/2002 index 6a5d0c899..1cfa6e875 100644 --- a/test/log/2002 +++ b/test/log/2002 @@ -12,6 +12,7 @@ 1999-03-02 09:44:33 SR 1999-03-02 09:44:33 SN 1999-03-02 09:44:33 IN +1999-03-02 09:44:33 IN/O 1999-03-02 09:44:33 NB 1999-03-02 09:44:33 NA 1999-03-02 09:44:33 SA diff --git a/test/log/2102 b/test/log/2102 index 57240408d..79c51d0df 100644 --- a/test/log/2102 +++ b/test/log/2102 @@ -13,6 +13,7 @@ 1999-03-02 09:44:33 SR 1999-03-02 09:44:33 SN 1999-03-02 09:44:33 IN +1999-03-02 09:44:33 IN/O 1999-03-02 09:44:33 NB 1999-03-02 09:44:33 NA 1999-03-02 09:44:33 SA -- 2.25.1