[prev in list] [next in list] [prev in thread] [next in thread] 

List:       hostap
Subject:    [PATCH v3 1/1] hostapd: Add 'check_cert_subject' support
From:       jared.bents () rockwellcollins ! com
Date:       2019-02-28 19:39:50
Message-ID: 20190228193950.7878-1-jared.bents () rockwellcollins ! com
[Download RAW message or body]

From: Jared Bents <jared.bents@rockwellcollins.com>

This patch added 'check_cert_subject' support to match the value of
every field against the DN of the subject in the client certificate. If
the values do not match, the certificate verification will fail and will reject
the user.

This option allows hostapd to match every individual field in the right order,
also allow '*' character as a wildcard (e.g OU=Development*).

Note: Hostapd will match string up to 'wildcard' against the DN of the subject
in the client certificate for every individual field.

Signed-off-by: Paresh Chaudhary <paresh.chaudhary@rockwellcollins.com>

[v1->v2]: Update for hostapd 2.7 and some upstream feedback on v1
          - check_cert_subject made const
          - Move check_cert_subject into tls_data struct
          - Remove unnecessary conditional

[v2->v3]: - Move dn_cnt into tls_data struct
          - Update all tls_global_set_verify to include check_cert_subject

Signed-off-by: Jared Bents <jared.bents@rockwellcollins.com>
---
 hostapd/config_file.c     |   8 +
 hostapd/hostapd.conf      |  26 +++
 src/ap/ap_config.c        |   1 +
 src/ap/ap_config.h        |   1 +
 src/ap/authsrv.c          |   3 +-
 src/crypto/tls.h          |  25 ++-
 src/crypto/tls_gnutls.c   |   2 +-
 src/crypto/tls_internal.c |   2 +-
 src/crypto/tls_none.c     |   2 +-
 src/crypto/tls_openssl.c  | 348 +++++++++++++++++++++++++++++++++++++-
 src/crypto/tls_wolfssl.c  |   2 +-
 11 files changed, 412 insertions(+), 8 deletions(-)

diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index 70cad76d4..89ba39fc4 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -2525,6 +2525,14 @@ static int hostapd_config_fill(struct hostapd_config *conf,
 	} else if (os_strcmp(buf, "private_key_passwd") == 0) {
 		os_free(bss->private_key_passwd);
 		bss->private_key_passwd = os_strdup(pos);
+	} else if (os_strcmp(buf, "check_cert_subject") == 0) {
+		os_free(bss->check_cert_subject);
+		bss->check_cert_subject = os_strdup(pos);
+		if (!strlen(bss->check_cert_subject)) {
+			wpa_printf(MSG_ERROR, "Line %d: unknown check_cert_subject '%s'",
+				   line, pos);
+			return 1;
+		}
 	} else if (os_strcmp(buf, "check_crl") == 0) {
 		bss->check_crl = atoi(pos);
 	} else if (os_strcmp(buf, "check_crl_strict") == 0) {
diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf
index 57f0af7a0..09013756e 100644
--- a/hostapd/hostapd.conf
+++ b/hostapd/hostapd.conf
@@ -946,6 +946,32 @@ eap_server=0
 # 0 = do not reload CRLs (default)
 # crl_reload_interval = 300
 
+# If check_cert_subject is set, the value of every field will be checked
+# against the DN of the subject in the client certificate. If the values do
+# not match, the certificate verification will fail, rejecting the user.
+# This option allows hostapd to match every individual field in the right order
+# against the dn of the subject in the client certificate.
+# [
+# e.g, check_cert_subject=C=US/O=XX/OU=ABC/OU=XYZ/CN=1234, In this case,
+# hostapd will check every individual dn field of the subject in the client
+# certificate, If OU=XYZ comes first in terms of the order in the client certificate
+# (Dn field of client cert= C=US/O=XX/OU=XYZ/OU=ABC/CN=1234) dn field then
+# hostapd will reject client because the order of 'OU' is not matching the specified
+# string in 'check_cert_subject'.
+# ]
+# This option also allows '*' as a wildcard. This option has some limitation. It's
+# only work as per below example.
+# [
+# e.g, check_cert_subject=C=US/O=XX/OU=Production*, For example,
+# we have two clients and DN of the subject in the first client certificate is
+# (C=US/O=XX/OU=Production Unit) and dn of the subject in the second client is
+# (C=US/O=XX/OU=Production Factory). In this case, hostapd will allow both clients
+# because the value of 'OU' field in both clients certificate is matching with 'OU'
+# value in 'check_cert_subject' up to 'wildcard'.
+# ]
+# * (Allow all client e.g check_cert_subject = *)
+# check_cert_subject = string
+
 # TLS Session Lifetime in seconds
 # This can be used to allow TLS sessions to be cached and resumed with an
 # abbreviated handshake when using EAP-TLS/TTLS/PEAP.
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index cd55b574e..a30859e0c 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -595,6 +595,7 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
 	os_free(conf->server_cert);
 	os_free(conf->private_key);
 	os_free(conf->private_key_passwd);
+	os_free(conf->check_cert_subject);
 	os_free(conf->ocsp_stapling_response);
 	os_free(conf->ocsp_stapling_response_multi);
 	os_free(conf->dh_file);
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index 1edd072b3..f2d3c128a 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -392,6 +392,7 @@ struct hostapd_bss_config {
 	char *server_cert;
 	char *private_key;
 	char *private_key_passwd;
+	char *check_cert_subject;
 	int check_crl;
 	int check_crl_strict;
 	unsigned int crl_reload_interval;
diff --git a/src/ap/authsrv.c b/src/ap/authsrv.c
index 1bb3d9f6f..fcbe21c30 100644
--- a/src/ap/authsrv.c
+++ b/src/ap/authsrv.c
@@ -242,7 +242,8 @@ int authsrv_init(struct hostapd_data *hapd)
 
 		if (tls_global_set_verify(hapd->ssl_ctx,
 					  hapd->conf->check_crl,
-					  hapd->conf->check_crl_strict)) {
+					  hapd->conf->check_crl_strict,
+					  hapd->conf->check_cert_subject)) {
 			wpa_printf(MSG_ERROR, "Failed to enable check_crl");
 			authsrv_deinit(hapd);
 			return -1;
diff --git a/src/crypto/tls.h b/src/crypto/tls.h
index 413cccddc..f64024de4 100644
--- a/src/crypto/tls.h
+++ b/src/crypto/tls.h
@@ -25,6 +25,26 @@ enum tls_event {
 	TLS_ALERT
 };
 
+struct tls_dn_field_order_cnt {
+	uint8_t cn;
+	uint8_t c;
+	uint8_t l;
+	uint8_t st;
+	uint8_t o;
+	uint8_t ou;
+	uint8_t email;
+};
+
+enum digest_alg{
+	DIGEST_HASH_ALG_MD5,
+	DIGEST_HASH_ALG_SHA,
+	DIGEST_HASH_ALG_SHA1,
+	DIGEST_HASH_ALG_SHA224,
+	DIGEST_HASH_ALG_SHA256,
+	DIGEST_HASH_ALG_SHA384,
+	DIGEST_HASH_ALG_SHA512
+};
+
 /*
  * Note: These are used as identifier with external programs and as such, the
  * values must not be changed.
@@ -42,6 +62,7 @@ enum tls_fail_reason {
 	TLS_FAIL_DOMAIN_SUFFIX_MISMATCH = 9,
 	TLS_FAIL_DOMAIN_MISMATCH = 10,
 	TLS_FAIL_INSUFFICIENT_KEY_LEN = 11,
+	TLS_FAIL_DN_MISMATCH = 12
 };
 
 
@@ -329,10 +350,12 @@ int __must_check tls_global_set_params(
  * @check_crl: 0 = do not verify CRLs, 1 = verify CRL for the user certificate,
  * 2 = verify CRL for all certificates
  * @strict: 0 = allow CRL time errors, 1 = do not allow CRL time errors
+ * @check_cert_subject : Hostapd configuration 'check_cert_subject' string pointer
  * Returns: 0 on success, -1 on failure
  */
 int __must_check tls_global_set_verify(void *tls_ctx, int check_crl,
-				       int strict);
+				       int strict,
+				       const char *check_cert_subject);
 
 /**
  * tls_connection_set_verify - Set certificate verification options
diff --git a/src/crypto/tls_gnutls.c b/src/crypto/tls_gnutls.c
index 527d01ecf..0e34a5cb5 100644
--- a/src/crypto/tls_gnutls.c
+++ b/src/crypto/tls_gnutls.c
@@ -848,7 +848,7 @@ fail:
 }
 
 
-int tls_global_set_verify(void *ssl_ctx, int check_crl, int strict)
+int tls_global_set_verify(void *ssl_ctx, int check_crl, int strict, const char \
*check_cert_subject)  {
 	/* TODO */
 	return 0;
diff --git a/src/crypto/tls_internal.c b/src/crypto/tls_internal.c
index 57b3e632d..d81a9ff97 100644
--- a/src/crypto/tls_internal.c
+++ b/src/crypto/tls_internal.c
@@ -359,7 +359,7 @@ int tls_global_set_params(void *tls_ctx,
 }
 
 
-int tls_global_set_verify(void *tls_ctx, int check_crl, int strict)
+int tls_global_set_verify(void *tls_ctx, int check_crl, int strict, const char \
*check_cert_subject)  {
 	struct tls_global *global = tls_ctx;
 	global->check_crl = check_crl;
diff --git a/src/crypto/tls_none.c b/src/crypto/tls_none.c
index 108e9aa2e..8bf9faa24 100644
--- a/src/crypto/tls_none.c
+++ b/src/crypto/tls_none.c
@@ -72,7 +72,7 @@ int tls_global_set_params(void *tls_ctx,
 }
 
 
-int tls_global_set_verify(void *tls_ctx, int check_crl, int strict)
+int tls_global_set_verify(void *tls_ctx, int check_crl, int strict, const char \
*check_cert_subject)  {
 	return -1;
 }
diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c
index 18d76737e..e4f82c223 100644
--- a/src/crypto/tls_openssl.c
+++ b/src/crypto/tls_openssl.c
@@ -206,6 +206,7 @@ struct tls_context {
 	void *cb_ctx;
 	int cert_in_cb;
 	char *ocsp_stapling_response;
+	char *check_cert_subject;
 };
 
 static struct tls_context *tls_global = NULL;
@@ -219,6 +220,8 @@ struct tls_data {
 	char *ca_cert;
 	unsigned int crl_reload_interval;
 	struct os_reltime crl_last_reload;
+	char *client_cert_subject;
+	struct tls_dn_field_order_cnt *dn_cnt;
 };
 
 struct tls_connection {
@@ -1134,6 +1137,10 @@ void tls_deinit(void *ssl_ctx)
 		tls_global = NULL;
 	}
 
+	if(data->client_cert_subject) {
+		os_free(data->client_cert_subject);
+		data->client_cert_subject = NULL;
+	}
 	os_free(data);
 }
 
@@ -1526,6 +1533,8 @@ struct tls_connection * tls_connection_init(void *ssl_ctx)
 	struct os_reltime now;
 	struct tls_context *context = SSL_CTX_get_app_data(ssl);
 
+	tls_global->check_cert_subject = data->client_cert_subject;
+
 	/* Replace X509 store if it is time to update CRL. */
 	if (data->crl_reload_interval > 0 && os_get_reltime(&now) == 0 &&
 	    os_reltime_expired(&now, &data->crl_last_reload,
@@ -1548,6 +1557,7 @@ struct tls_connection * tls_connection_init(void *ssl_ctx)
 	if (conn == NULL)
 		return NULL;
 	conn->data = data;
+	conn->data->dn_cnt = os_zalloc(sizeof(struct tls_dn_field_order_cnt));
 	conn->ssl_ctx = ssl;
 	conn->ssl = SSL_new(ssl);
 	if (conn->ssl == NULL) {
@@ -1607,6 +1617,7 @@ void tls_connection_deinit(void *ssl_ctx, struct tls_connection \
*conn)  }
 	SSL_free(conn->ssl);
 	tls_engine_deinit(conn);
+	os_free(conn->data->dn_cnt);
 	os_free(conn->subject_match);
 	os_free(conn->altsubject_match);
 	os_free(conn->suffix_match);
@@ -1763,6 +1774,323 @@ static int domain_suffix_match(const u8 *val, size_t len, \
const char *match,  #endif /* CONFIG_NATIVE_WINDOWS */
 
 
+/**
+ * client_cert_fingerprint - print fingerprint of certificate
+ * @cert: Certificate
+ * @alg:  hash algorithm
+ * Returns: Return 1 on success and 0 on Failure
+*/
+static int client_cert_fingerprint(X509* cert, enum digest_alg alg)
+{
+
+	/* Maximum size of fingerprint with sha512 is 191 bytes,
+	so it's enough to hold fingerprint value for supported algorithm */
+	uint8_t fingerprint[192];
+	char fingerprint_string[192];
+	int ret = 0, i;
+	int pos = 0;
+	uint32_t len = sizeof(fingerprint);
+	uint32_t buflen = sizeof(fingerprint_string);
+
+	/* Init out buffers to zero */
+	os_memset(fingerprint, 0x00, sizeof(fingerprint));
+	os_memset(fingerprint_string, 0x00, sizeof(fingerprint_string));
+
+	switch (alg)
+	{
+		case DIGEST_HASH_ALG_MD5:
+			/* Get the digest */
+			ret = X509_digest(cert, EVP_md5(), fingerprint, &len);
+			break;
+		case DIGEST_HASH_ALG_SHA:
+			/* Get the digest */
+			ret = X509_digest(cert, EVP_sha(), fingerprint, &len);
+			break;
+		case DIGEST_HASH_ALG_SHA1:
+			/* Get the digest */
+			ret = X509_digest(cert, EVP_sha1(), fingerprint, &len);
+			break;
+		case DIGEST_HASH_ALG_SHA224:
+			/* Get the digest */
+			ret = X509_digest(cert, EVP_sha224(), fingerprint, &len);
+			break;
+		case DIGEST_HASH_ALG_SHA256:
+			/* Get the digest */
+			ret = X509_digest(cert, EVP_sha256(), fingerprint, &len);
+			break;
+		case DIGEST_HASH_ALG_SHA384:
+			/* Get the digest */
+			ret = X509_digest(cert, EVP_sha384(), fingerprint, &len);
+			break;
+		case DIGEST_HASH_ALG_SHA512:
+			/* Get the digest */
+			ret = X509_digest(cert, EVP_sha512(), fingerprint, &len);
+			break;
+		default:
+			wpa_printf(MSG_ERROR, "Unknown digest algorithm");
+			break;
+	}
+
+	if (ret != 1) {
+		wpa_printf(MSG_ERROR, "Cannot get digest from certificate");
+		return ret;
+	}
+
+
+	for(i = 0; i < len; ++i) {
+		if (i > 0) {
+			pos += snprintf(fingerprint_string + pos, buflen - pos, ":");
+		}
+		pos += snprintf(fingerprint_string + pos, buflen - pos, "%02X", fingerprint[i]);
+	}
+
+	wpa_printf(MSG_INFO,"Fingerprint: %s\n", fingerprint_string);
+
+	return ret;
+}
+
+
+/**
+ * match_dn_field - Match configuration DN field value with Certificate DN field \
value + * @cert: Certificate
+ * @nid:  NID of DN field
+ * @value DN field value which is passed from configuration file
+ *        e.g (If configuration have C=US and this argument will point to US)
+ * Returns: Return 1 on success and 0 on Failure
+ */
+static int match_dn_field(X509 *cert, int nid, char *value, struct \
tls_dn_field_order_cnt *dn_cnt) +{
+	int i = -1, ret = 1, len, config_dn_field_index = 0 ;
+	int match_index = 0;
+	X509_NAME *name;
+
+	len = os_strlen(value);
+	name = X509_get_subject_name(cert);
+
+	/* Assign incremented cnt for every field of DN to check DN field in
+	right order */
+	switch (nid)
+	{
+		case NID_commonName:
+			config_dn_field_index = dn_cnt->cn;
+			break;
+		case NID_countryName:
+			config_dn_field_index = dn_cnt->c;
+			break;
+		case NID_localityName:
+			config_dn_field_index = dn_cnt->l;
+			break;
+		case NID_stateOrProvinceName:
+			config_dn_field_index = dn_cnt->st;
+			break;
+		case NID_organizationName:
+			config_dn_field_index = dn_cnt->o;
+			break;
+		case NID_organizationalUnitName:
+			config_dn_field_index = dn_cnt->ou;
+			break;
+		case NID_pkcs9_emailAddress:
+			config_dn_field_index = dn_cnt->email;
+			break;
+		default:
+			wpa_printf(MSG_ERROR,
+				"TLS: Unknown NID '%d' in 'check_cert_subject' "
+				"option of hostapd configuration", nid);
+			return 0;
+	}
+
+	/* Fetch value based on NID */
+	for (;;) {
+		X509_NAME_ENTRY *e;
+		ASN1_STRING *cn;
+		i = X509_NAME_get_index_by_NID(name, nid, i);
+		if (i == -1) {
+			ret = 0;
+			break;
+		}
+		e = X509_NAME_get_entry(name, i);
+		if (e == NULL)
+			continue;
+
+		cn = X509_NAME_ENTRY_get_data(e);
+		if (cn == NULL)
+			continue;
+
+		match_index ++;
+
+		/* check for more than one dn field with same name */
+		if(match_index != config_dn_field_index)
+			continue;
+
+		/* Check wild card at the right end side*/
+		/* e.g. if OU=develop* mentioned in configuration file then hostapd will allow if \
the +		'OU' of the subject in the client certificate start with 'develop*' */
+		/* Same applicable for other field of DN*/
+		if( '*' == *(value + len - 1)) {
+		/* Compare actual certificate dn field value with configuration file dn field \
value upto specified length */ +			if (!os_strncasecmp(cn->data, value, len - 1)) {
+				ret = 1;
+				break;
+			} else {
+				wpa_printf(MSG_ERROR,
+					"TLS: Failed to match '%s' with "
+					"Certificate Distinguished Name '%s'",
+					value, ASN1_STRING_data(cn));
+				wpa_printf(MSG_INFO, "TLS: Please check hostapd configuration");
+				ret = 0;
+				break;
+			}
+		} else {
+		/* Compare actual certificate dn field value with configuration file dn field \
value */ +			if (!os_strcmp(cn->data, value)) {
+				ret = 1;
+				break;
+			} else {
+				wpa_printf(MSG_ERROR,
+					"TLS: Failed to match '%s' with "
+					"Certificate Distinguished Name '%s'",
+					value, ASN1_STRING_data(cn));
+				wpa_printf(MSG_INFO, "TLS: Please check hostapd configuration");
+				ret = 0;
+				break;
+			}
+		}
+	}
+
+	return ret;
+}
+
+
+/**
+ * get_value_from_field - Get value from DN field
+ * @cert: Certificate
+ * @field_str:  DN field string which is passed from configuration file (e.g C=US)
+ * Returns: Return 1 on success and 0 on Failure
+ */
+static int get_value_from_field(X509 *cert, char *field_str, struct \
tls_dn_field_order_cnt *dn_cnt) +{
+	int nid = -1, ret = 1;
+	char *temp, *dbg_dn;
+
+	temp = strtok(field_str,"=");
+
+	/* Compare all hostapd configuration DN field and assign nid based on that to
+	fetch correct value from certificate subject*/
+	if(strcmp(temp,"CN") == 0) {
+		nid = NID_commonName;
+		dn_cnt->cn++;
+	} else if(strcmp(temp,"C") == 0) {
+		nid = NID_countryName;
+		dn_cnt->c++;
+	} else if (strcmp(temp,"L") == 0) {
+		nid = NID_localityName;
+		dn_cnt->l++;
+	} else if (strcmp(temp,"ST") == 0) {
+		nid = NID_stateOrProvinceName;
+		dn_cnt->st++;
+	} else if (strcmp(temp,"O") == 0) {
+		nid = NID_organizationName;
+		dn_cnt->o++;
+	} else if (strcmp(temp,"OU") == 0) {
+		nid = NID_organizationalUnitName;
+		dn_cnt->ou++;
+	} else if (strcmp(temp,"emailAddress") == 0) {
+		nid = NID_pkcs9_emailAddress;
+		dn_cnt->email++;
+	} else if (strcmp(temp,"*") == 0) {
+		ret = 1;
+	} else {
+		wpa_printf(MSG_ERROR,
+			"TLS: Unknown field '%s' in 'check_cert_subject' "
+			"option of hostapd configuration", temp);
+		ret = 0;
+	}
+
+	dbg_dn = temp;
+	/* Check for correct NID */
+	if ( (nid >= NID_commonName && nid <= NID_organizationalUnitName) ||
+		nid == NID_pkcs9_emailAddress) {
+		temp = strtok (NULL,"=");
+		if (temp != NULL) {
+			ret = match_dn_field(cert, nid, temp, dn_cnt);
+		}
+		else {
+			ret = 0;
+			wpa_printf(MSG_ERROR,
+				"TLS:  Distinguished Name field '%s' value "
+				"is not defined in 'check_cert_subject'. "
+				"Please Check hostapd configuration file", dbg_dn);
+		}
+	}
+
+	return ret;
+}
+
+/**
+ * tls_match_dn_field - Match Certificate individual subject field with \
check_cert_subject + * @cert:   Certificate
+ * @match:  check_cert_subject string
+ * Returns: Return 1 on success and 0 on Failure
+*/
+static int tls_match_dn_field(X509 *cert, const char *match, struct \
tls_dn_field_order_cnt *dn_cnt) +{
+	int match_loop = 0, field_loop = 0, length, last_index = 0, len, ret = 1;
+	char *field = NULL;
+	char buf[2048] = {0}; /* NOTE: Print maximum 2048 bytes of subject and issuer */
+	enum digest_alg alg = DIGEST_HASH_ALG_SHA256; /* Default calculate certificate \
fingerprint with SHA256 algorithm */ +
+	os_memset(dn_cnt, 0, sizeof(struct tls_dn_field_order_cnt));
+	len = os_strlen(match);
+
+	/* Maximum length of each DN field is 128 character */
+	field = os_malloc(256);
+	if (field == NULL) {
+		wpa_printf(MSG_ERROR, "TLS: Failed to allocate memory");
+		return 0;
+	}
+	os_memset(field,0,256);
+
+	while ( match[match_loop] != '\0') {
+		/* Stop at '/' character */
+		if (match[match_loop] == '/') {
+			field[field_loop] = '\0';
+			if (strlen(field) > 0) {
+				if(!get_value_from_field(cert, field, dn_cnt)) {
+					ret = 0;
+					break;
+				}
+			}
+			os_memset(field,0,256);
+			field_loop = 0;
+			last_index = match_loop;
+			last_index++;
+		} else {
+			field[field_loop++] = match[match_loop];
+		}
+		match_loop++;
+	}
+	if (strlen(field) > 0 && ret != 0) {
+		strncpy(field, match+last_index, len - last_index);
+		if(!get_value_from_field(cert, field, dn_cnt))
+			ret = 0;
+	}
+	if(field != NULL)
+		os_free(field);
+
+	X509_NAME_oneline(X509_get_subject_name(cert), buf, sizeof(buf));
+	wpa_printf(MSG_INFO,"TLS: Certificate subject= %s\n", buf);
+	os_memset(buf,0,2048);
+	X509_NAME_oneline(X509_get_issuer_name(cert), buf, sizeof(buf));
+	wpa_printf(MSG_INFO,"TLS: Certificate issuer= %s\n", buf);
+	/* Return 0 only if client_cert_fingerprint function return failure code, otherwise
+	return 'tls_match_dn_field' function return code */
+	if(!client_cert_fingerprint(cert, alg))
+	ret = 0;
+
+	return ret;
+}
+
+
 static int tls_match_suffix(X509 *cert, const char *match, int full)
 {
 #ifdef CONFIG_NATIVE_WINDOWS
@@ -2127,6 +2455,14 @@ static int tls_verify_cb(int preverify_ok, X509_STORE_CTX \
*x509_ctx)  "err=%d (%s) ca_cert_verify=%d depth=%d buf='%s'",
 		   preverify_ok, err, err_str,
 		   conn->ca_cert_verify, depth, buf);
+	if (tls_global->check_cert_subject) {
+		if(depth == 0 && !tls_match_dn_field(err_cert,tls_global->check_cert_subject,conn->data->dn_cnt)) \
{ +			preverify_ok = 0;
+			openssl_tls_fail_event(conn, err_cert, err, depth, buf,
+					       "Distinguished Name",
+					       TLS_FAIL_DN_MISMATCH);
+		}
+	}
 	if (depth == 0 && match && os_strstr(buf, match) == NULL) {
 		wpa_printf(MSG_WARNING, "TLS: Subject '%s' did not "
 			   "match with '%s'", buf, match);
@@ -2473,12 +2809,20 @@ static int tls_global_ca_cert(struct tls_data *data, const \
char *ca_cert)  }
 
 
-int tls_global_set_verify(void *ssl_ctx, int check_crl, int strict)
+int tls_global_set_verify(void *ssl_ctx, int check_crl, int strict, const char \
*check_cert_subject)  {
 	int flags;
+	struct tls_data *data = ssl_ctx;
+
+	os_free(data->client_cert_subject);
+	data->client_cert_subject = NULL;
+	if (check_cert_subject) {
+		data->client_cert_subject = os_strdup(check_cert_subject);
+		if (data->client_cert_subject == NULL)
+			return -1;
+	}
 
 	if (check_crl) {
-		struct tls_data *data = ssl_ctx;
 		X509_STORE *cs = SSL_CTX_get_cert_store(data->ssl);
 		if (cs == NULL) {
 			tls_show_errors(MSG_INFO, __func__, "Failed to get "
diff --git a/src/crypto/tls_wolfssl.c b/src/crypto/tls_wolfssl.c
index b59622e5e..d270b527b 100644
--- a/src/crypto/tls_wolfssl.c
+++ b/src/crypto/tls_wolfssl.c
@@ -1549,7 +1549,7 @@ int tls_global_set_params(void *tls_ctx,
 }
 
 
-int tls_global_set_verify(void *tls_ctx, int check_crl, int strict)
+int tls_global_set_verify(void *tls_ctx, int check_crl, int strict, const char \
*check_cert_subject)  {
 	wpa_printf(MSG_DEBUG, "SSL: global set verify: %d", check_crl);
 
-- 
2.18.0


_______________________________________________
Hostap mailing list
Hostap@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/hostap


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic