From 5e6194b6f402334299f25e76af8b743c1449b99b Mon Sep 17 00:00:00 2001
From: Kaspar Brand
Date: Wed, 30 Sep 2015 11:38:34 +0000
Subject: [PATCH] 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
---
CHANGES | 7 +++
docs/manual/mod/mod_ssl.xml | 2 +
modules/ssl/mod_ssl.c | 5 ++
modules/ssl/ssl_engine_vars.c | 38 +++++++++++---
modules/ssl/ssl_util_ssl.c | 95 ++++++++++++++++++++++++-----------
modules/ssl/ssl_util_ssl.h | 2 +-
6 files changed, 112 insertions(+), 37 deletions(-)
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);
--
2.40.0