From: Kaspar Brand Date: Wed, 30 Sep 2015 11:38:34 +0000 (+0000) Subject: merge r1693792 from trunk X-Git-Tag: 2.4.17~58 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=5e6194b6f402334299f25e76af8b743c1449b99b;p=apache merge r1693792 from trunk Add support for extracting the msUPN and dnsSRV forms of subjectAltName entries of type "otherName" into SSL_{CLIENT,SERVER}_SAN_OTHER_{msUPN,dnsSRV}_n environment variables. Addresses PR 58020. * docs/manual/mod/mod_ssl.xml: add SSL_*_SAN_OTHER_*_n entries to the environment variables table * modules/ssl/ssl_engine_vars.c: add support for retrieving the SSL_{CLIENT,SERVER}_SAN_OTHER_{msUPN,dnsSRV}_n variables * modules/ssl/ssl_util_ssl.c: add parse_otherName_value, which currently recognizes the "msUPN" (1.3.6.1.4.1.311.20.2.3) and "id-on-dnsSRV" (1.3.6.1.5.5.7.8.7) otherName forms, and adapt modssl_X509_getSAN to take an optional otherName form argument for the GEN_OTHERNAME case * modules/ssl/ssl_util_ssl.h: adapt modssl_X509_getSAN prototype * modules/ssl/mod_ssl.c: register the id-on-dnsSRV otherName form OID (1.3.6.1.5.5.7.8.7) in OpenSSL's objects table Proposed by: kbrand Reviewed by: ylavic, jorton git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1706006 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/CHANGES b/CHANGES index 95adda0f6d..04c7362ba0 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,13 @@ -*- coding: utf-8 -*- Changes with Apache 2.4.17 + + *) mod_ssl: Add support for extracting the msUPN and dnsSRV forms + of subjectAltName entries of type "otherName" into + SSL_{CLIENT,SERVER}_SAN_OTHER_{msUPN,dnsSRV}_n environment + variables. Addresses PR 58020. [Jan Pazdziora , + Kaspar Brand] + *) mod_h2: added donated http/2 implementation to build system. Similar configuration options to mod_ssl. [Stefan Eissing] diff --git a/docs/manual/mod/mod_ssl.xml b/docs/manual/mod/mod_ssl.xml index 076f33653a..d6ea405a19 100644 --- a/docs/manual/mod/mod_ssl.xml +++ b/docs/manual/mod/mod_ssl.xml @@ -77,6 +77,7 @@ compatibility variables.

SSL_CLIENT_S_DN_x509 string Component of client's Subject DN SSL_CLIENT_SAN_Email_n string Client certificate's subjectAltName extension entries of type rfc822Name SSL_CLIENT_SAN_DNS_n string Client certificate's subjectAltName extension entries of type dNSName +SSL_CLIENT_SAN_OTHER_msUPN_n string Client certificate's subjectAltName extension entries of type otherName, Microsoft User Principal Name form (OID 1.3.6.1.4.1.311.20.2.3) SSL_CLIENT_I_DN string Issuer DN of client's certificate SSL_CLIENT_I_DN_x509 string Component of client's Issuer DN SSL_CLIENT_V_START string Validity of client's certificate (start time) @@ -93,6 +94,7 @@ compatibility variables.

SSL_SERVER_S_DN string Subject DN in server's certificate SSL_SERVER_SAN_Email_n string Server certificate's subjectAltName extension entries of type rfc822Name SSL_SERVER_SAN_DNS_n string Server certificate's subjectAltName extension entries of type dNSName +SSL_SERVER_SAN_OTHER_dnsSRV_n string Server certificate's subjectAltName extension entries of type otherName, SRVName form (OID 1.3.6.1.5.5.7.8.7, RFC 4985) SSL_SERVER_S_DN_x509 string Component of server's Subject DN SSL_SERVER_I_DN string Issuer DN of server's certificate SSL_SERVER_I_DN_x509 string Component of server's Issuer DN diff --git a/modules/ssl/mod_ssl.c b/modules/ssl/mod_ssl.c index 7d9b8a550c..567daf0a09 100644 --- a/modules/ssl/mod_ssl.c +++ b/modules/ssl/mod_ssl.c @@ -340,6 +340,11 @@ static int ssl_hook_pre_config(apr_pool_t *pconf, OpenSSL_add_all_algorithms(); OPENSSL_load_builtin_modules(); + if (OBJ_txt2nid("id-on-dnsSRV") == NID_undef) { + (void)OBJ_create("1.3.6.1.5.5.7.8.7", "id-on-dnsSRV", + "SRVName otherName form"); + } + /* * Let us cleanup the ssl library when the module is unloaded */ diff --git a/modules/ssl/ssl_engine_vars.c b/modules/ssl/ssl_engine_vars.c index 4fce7fc85d..0530eea4a3 100644 --- a/modules/ssl/ssl_engine_vars.c +++ b/modules/ssl/ssl_engine_vars.c @@ -594,6 +594,7 @@ static char *ssl_var_lookup_ssl_cert_dn(apr_pool_t *p, X509_NAME *xsname, char * static char *ssl_var_lookup_ssl_cert_san(apr_pool_t *p, X509 *xs, char *var) { int type, numlen; + const char *onf = NULL; apr_array_header_t *entries; if (strcEQn(var, "Email_", 6)) { @@ -604,6 +605,20 @@ static char *ssl_var_lookup_ssl_cert_san(apr_pool_t *p, X509 *xs, char *var) type = GEN_DNS; var += 4; } + else if (strcEQn(var, "OTHER_", 6)) { + type = GEN_OTHERNAME; + var += 6; + if (strEQn(var, "msUPN_", 6)) { + var += 6; + onf = "msUPN"; + } + else if (strEQn(var, "dnsSRV_", 7)) { + var += 7; + onf = "id-on-dnsSRV"; + } + else + return NULL; + } else return NULL; @@ -612,11 +627,11 @@ static char *ssl_var_lookup_ssl_cert_san(apr_pool_t *p, X509 *xs, char *var) if ((numlen < 1) || (numlen > 4) || (numlen != strlen(var))) return NULL; - if (modssl_X509_getSAN(p, xs, type, atoi(var), &entries)) - /* return the first entry from this 1-element array */ - return APR_ARRAY_IDX(entries, 0, char *); + if (modssl_X509_getSAN(p, xs, type, onf, atoi(var), &entries)) + /* return the first entry from this 1-element array */ + return APR_ARRAY_IDX(entries, 0, char *); else - return NULL; + return NULL; } static char *ssl_var_lookup_ssl_cert_valid(apr_pool_t *p, ASN1_TIME *tm) @@ -962,24 +977,31 @@ void modssl_var_extract_san_entries(apr_table_t *t, SSL *ssl, apr_pool_t *p) /* subjectAltName entries of the server certificate */ xs = SSL_get_certificate(ssl); if (xs) { - if (modssl_X509_getSAN(p, xs, GEN_EMAIL, -1, &entries)) { + if (modssl_X509_getSAN(p, xs, GEN_EMAIL, NULL, -1, &entries)) { extract_san_array(t, "SSL_SERVER_SAN_Email", entries, p); } - if (modssl_X509_getSAN(p, xs, GEN_DNS, -1, &entries)) { + if (modssl_X509_getSAN(p, xs, GEN_DNS, NULL, -1, &entries)) { extract_san_array(t, "SSL_SERVER_SAN_DNS", entries, p); } + if (modssl_X509_getSAN(p, xs, GEN_OTHERNAME, "id-on-dnsSRV", -1, + &entries)) { + extract_san_array(t, "SSL_SERVER_SAN_OTHER_dnsSRV", entries, p); + } /* no need to free xs (refcount does not increase) */ } /* subjectAltName entries of the client certificate */ xs = SSL_get_peer_certificate(ssl); if (xs) { - if (modssl_X509_getSAN(p, xs, GEN_EMAIL, -1, &entries)) { + if (modssl_X509_getSAN(p, xs, GEN_EMAIL, NULL, -1, &entries)) { extract_san_array(t, "SSL_CLIENT_SAN_Email", entries, p); } - if (modssl_X509_getSAN(p, xs, GEN_DNS, -1, &entries)) { + if (modssl_X509_getSAN(p, xs, GEN_DNS, NULL, -1, &entries)) { extract_san_array(t, "SSL_CLIENT_SAN_DNS", entries, p); } + if (modssl_X509_getSAN(p, xs, GEN_OTHERNAME, "msUPN", -1, &entries)) { + extract_san_array(t, "SSL_CLIENT_SAN_OTHER_msUPN", entries, p); + } X509_free(xs); } } diff --git a/modules/ssl/ssl_util_ssl.c b/modules/ssl/ssl_util_ssl.c index 1acda0d772..a7607c7349 100644 --- a/modules/ssl/ssl_util_ssl.c +++ b/modules/ssl/ssl_util_ssl.c @@ -252,19 +252,48 @@ char *modssl_X509_NAME_to_string(apr_pool_t *p, X509_NAME *dn, int maxlen) return result; } +static void parse_otherName_value(apr_pool_t *p, ASN1_TYPE *value, + const char *onf, apr_array_header_t **entries) +{ + const char *str; + int nid = onf ? OBJ_txt2nid(onf) : NID_undef; + + if (!value || (nid == NID_undef) || !*entries) + return; + + /* + * Currently supported otherName forms (values for "onf"): + * "msUPN" (1.3.6.1.4.1.311.20.2.3): Microsoft User Principal Name + * "id-on-dnsSRV" (1.3.6.1.5.5.7.8.7): SRVName, as specified in RFC 4985 + */ + if ((nid == NID_ms_upn) && (value->type == V_ASN1_UTF8STRING) && + (str = asn1_string_to_utf8(p, value->value.utf8string))) { + APR_ARRAY_PUSH(*entries, const char *) = str; + } else if (strEQ(onf, "id-on-dnsSRV") && + (value->type == V_ASN1_IA5STRING) && + (str = asn1_string_to_utf8(p, value->value.ia5string))) { + APR_ARRAY_PUSH(*entries, const char *) = str; + } +} + /* * Return an array of subjectAltName entries of type "type". If idx is -1, * return all entries of the given type, otherwise return an array consisting * of the n-th occurrence of that type only. Currently supported types: * GEN_EMAIL (rfc822Name) * GEN_DNS (dNSName) + * GEN_OTHERNAME (requires the otherName form ["onf"] argument to be supplied, + * see parse_otherName_value for the currently supported forms) */ -BOOL modssl_X509_getSAN(apr_pool_t *p, X509 *x509, int type, int idx, - apr_array_header_t **entries) +BOOL modssl_X509_getSAN(apr_pool_t *p, X509 *x509, int type, const char *onf, + int idx, apr_array_header_t **entries) { STACK_OF(GENERAL_NAME) *names; + int nid = onf ? OBJ_txt2nid(onf) : NID_undef; - if (!x509 || (type < GEN_OTHERNAME) || (type > GEN_RID) || (idx < -1) || + if (!x509 || (type < GEN_OTHERNAME) || + ((type == GEN_OTHERNAME) && (nid == NID_undef)) || + (type > GEN_RID) || (idx < -1) || !(*entries = apr_array_make(p, 0, sizeof(char *)))) { *entries = NULL; return FALSE; @@ -277,33 +306,43 @@ BOOL modssl_X509_getSAN(apr_pool_t *p, X509 *x509, int type, int idx, for (i = 0; i < sk_GENERAL_NAME_num(names); i++) { name = sk_GENERAL_NAME_value(names, i); - if (name->type == type) { - if ((idx == -1) || (n == idx)) { - switch (type) { - case GEN_EMAIL: - case GEN_DNS: - utf8str = asn1_string_to_utf8(p, name->d.ia5); - if (utf8str) { - APR_ARRAY_PUSH(*entries, const char *) = utf8str; - } - break; - default: - /* - * Not implemented right now: - * GEN_OTHERNAME (otherName) - * GEN_X400 (x400Address) - * GEN_DIRNAME (directoryName) - * GEN_EDIPARTY (ediPartyName) - * GEN_URI (uniformResourceIdentifier) - * GEN_IPADD (iPAddress) - * GEN_RID (registeredID) - */ - break; + + if (name->type != type) + continue; + + switch (type) { + case GEN_EMAIL: + case GEN_DNS: + if (((idx == -1) || (n == idx)) && + (utf8str = asn1_string_to_utf8(p, name->d.ia5))) { + APR_ARRAY_PUSH(*entries, const char *) = utf8str; + } + n++; + break; + case GEN_OTHERNAME: + if (OBJ_obj2nid(name->d.otherName->type_id) == nid) { + if (((idx == -1) || (n == idx))) { + parse_otherName_value(p, name->d.otherName->value, + onf, entries); } + n++; } - if ((idx != -1) && (n++ > idx)) - break; + break; + default: + /* + * Not implemented right now: + * GEN_X400 (x400Address) + * GEN_DIRNAME (directoryName) + * GEN_EDIPARTY (ediPartyName) + * GEN_URI (uniformResourceIdentifier) + * GEN_IPADD (iPAddress) + * GEN_RID (registeredID) + */ + break; } + + if ((idx != -1) && (n > idx)) + break; } sk_GENERAL_NAME_pop_free(names, GENERAL_NAME_free); @@ -320,7 +359,7 @@ static BOOL getIDs(apr_pool_t *p, X509 *x509, apr_array_header_t **ids) /* First, the DNS-IDs (dNSName entries in the subjectAltName extension) */ if (!x509 || - (modssl_X509_getSAN(p, x509, GEN_DNS, -1, ids) == FALSE && !*ids)) { + (modssl_X509_getSAN(p, x509, GEN_DNS, NULL, -1, ids) == FALSE && !*ids)) { *ids = NULL; return FALSE; } diff --git a/modules/ssl/ssl_util_ssl.h b/modules/ssl/ssl_util_ssl.h index c7c4a916a0..5f7483195c 100644 --- a/modules/ssl/ssl_util_ssl.h +++ b/modules/ssl/ssl_util_ssl.h @@ -65,7 +65,7 @@ int modssl_smart_shutdown(SSL *ssl); BOOL modssl_X509_getBC(X509 *, int *, int *); char *modssl_X509_NAME_ENTRY_to_string(apr_pool_t *p, X509_NAME_ENTRY *xsne); char *modssl_X509_NAME_to_string(apr_pool_t *, X509_NAME *, int); -BOOL modssl_X509_getSAN(apr_pool_t *, X509 *, int, int, apr_array_header_t **); +BOOL modssl_X509_getSAN(apr_pool_t *, X509 *, int, const char *, int, apr_array_header_t **); BOOL modssl_X509_match_name(apr_pool_t *, X509 *, const char *, BOOL, server_rec *); char *modssl_SSL_SESSION_id2sz(unsigned char *, int, char *, int);