diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index c69a1a536..af13e73ee 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -2476,6 +2476,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 425ec9a0a..83d2707f9 100644
--- a/hostapd/hostapd.conf
+++ b/hostapd/hostapd.conf
@@ -914,6 +914,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 a5655c673..06998268b 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -537,6 +537,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 19dd84aad..c9328cbe2 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -383,6 +383,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 4f2d418fb..bf1c986c0 100644
--- a/src/ap/authsrv.c
+++ b/src/ap/authsrv.c
@@ -238,7 +238,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 0a8d38c76..62a841937 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
 };
 
 
@@ -323,10 +344,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_openssl.c b/src/crypto/tls_openssl.c
index 77c77b36c..b3cbc952b 100644
--- a/src/crypto/tls_openssl.c
+++ b/src/crypto/tls_openssl.c
@@ -197,6 +197,7 @@ static int tls_add_ca_from_keystore_encoded(X509_STORE *ctx,
 
 static int tls_openssl_ref_count = 0;
 static int tls_ex_idx_session = -1;
+struct tls_dn_field_order_cnt dn_cnt = {0};
 
 struct tls_context {
 	void (*event_cb)(void *ctx, enum tls_event ev,
@@ -204,6 +205,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;
@@ -218,6 +220,7 @@ struct tls_data {
 	unsigned int crl_reload_interval;
 	unsigned int crl_last_reload;
 	X509_STORE   *old_x509_store;
+	char *client_cert_subject;
 };
 
 struct tls_connection {
@@ -1133,6 +1136,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);
 }
 
@@ -1511,6 +1518,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;
+
 	/* Get current time */
 	if (os_get_reltime(&now) < 0)
 		wpa_printf(MSG_ERROR,"Error getting relative time for crl reload");
@@ -1754,6 +1763,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)
+{
+	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)
+{
+	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);
+		}
+		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)
+{
+	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(dn_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)) {
+					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))
+			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
@@ -2118,6 +2444,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)) {
+			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);
@@ -2464,13 +2798,21 @@ 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 os_reltime now;
+	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 "
