[PATCH 2/4] TLS client: Add support for validating server certificate

Pali Rohár pali.rohar at gmail.com
Sat Nov 21 17:02:56 PST 2015


This commit adds support for "hash://server/sha256/cert_hash_in_hex" scheme
in ca_cert property for internal TLS implementation.

Signed-off-by: Pali Rohár <pali.rohar at gmail.com>
---
 src/tls/tlsv1_client_read.c |   16 +++++++++++++++-
 src/tls/tlsv1_cred.c        |   25 +++++++++++++++++++++++++
 src/tls/tlsv1_cred.h        |    2 ++
 3 files changed, 42 insertions(+), 1 deletion(-)

diff --git a/src/tls/tlsv1_client_read.c b/src/tls/tlsv1_client_read.c
index 4fe9580..56973c3 100644
--- a/src/tls/tlsv1_client_read.c
+++ b/src/tls/tlsv1_client_read.c
@@ -364,7 +364,21 @@ static int tls_process_certificate(struct tlsv1_client *conn, u8 ct,
 		pos += cert_len;
 	}
 
-	if (conn->cred && conn->cred->ca_cert_verify &&
+	if (conn->cred && conn->cred->server_cert_only && chain) {
+		u8 hash[32];
+		char buf[128];
+		wpa_printf(MSG_DEBUG, "TLSv1: Validate server certificate hash");
+		x509_name_string(&chain->subject, buf, sizeof(buf));
+		wpa_printf(MSG_DEBUG, "TLSv1: 0: %s", buf);
+		if (sha256_vector(1, &chain->cert_start, &chain->cert_len, hash) < 0 ||
+		    os_memcmp(conn->cred->srv_cert_hash, hash, 32) != 0) {
+			wpa_printf(MSG_DEBUG, "TLSv1: Server certificate hash mismatch");
+			wpa_hexdump(MSG_MSGDUMP, "TLSv1: SHA256 hash", hash, 32);
+			tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_BAD_CERTIFICATE);
+			x509_certificate_chain_free(chain);
+			return -1;
+		}
+	} else if (conn->cred && conn->cred->ca_cert_verify &&
 	    x509_certificate_chain_validate(conn->cred->trusted_certs, chain,
 					    &reason, conn->disable_time_checks)
 	    < 0) {
diff --git a/src/tls/tlsv1_cred.c b/src/tls/tlsv1_cred.c
index fbac965..94a7246 100644
--- a/src/tls/tlsv1_cred.c
+++ b/src/tls/tlsv1_cred.c
@@ -190,6 +190,31 @@ int tlsv1_set_ca_cert(struct tlsv1_credentials *cred, const char *cert,
 		      const u8 *cert_blob, size_t cert_blob_len,
 		      const char *path)
 {
+	if (cert && os_strncmp(cert, "hash://", 7) == 0) {
+		const char *pos = cert + 7;
+		if (os_strncmp(pos, "server/sha256/", 14) != 0) {
+			wpa_printf(MSG_DEBUG, "TLSv1: Unsupported ca_cert "
+				   "hash value '%s'", cert);
+			return -1;
+		}
+		pos += 14;
+		if (os_strlen(pos) != 32 * 2) {
+			wpa_printf(MSG_DEBUG, "TLSv1: Unexpected SHA256 "
+				   "hash length in ca_cert '%s'", cert);
+			return -1;
+		}
+		if (hexstr2bin(pos, cred->srv_cert_hash, 32) < 0) {
+			wpa_printf(MSG_DEBUG, "TLSv1: Invalid SHA256 hash "
+				   "value in ca_cert '%s'", cert);
+			return -1;
+		}
+		cred->server_cert_only = 1;
+		cred->ca_cert_verify = 0;
+		wpa_printf(MSG_DEBUG, "TLSv1: Checking only server "
+			   "certificate match");
+		return 0;
+	}
+
 	cred->ca_cert_verify = cert || cert_blob || path;
 
 	if (tlsv1_set_cert_chain(&cred->trusted_certs, cert,
diff --git a/src/tls/tlsv1_cred.h b/src/tls/tlsv1_cred.h
index b1e3e00..ac72b8c 100644
--- a/src/tls/tlsv1_cred.h
+++ b/src/tls/tlsv1_cred.h
@@ -15,6 +15,8 @@ struct tlsv1_credentials {
 	struct crypto_private_key *key;
 
 	unsigned int ca_cert_verify:1;
+	unsigned int server_cert_only:1;
+	u8 srv_cert_hash[32];
 
 	/* Diffie-Hellman parameters */
 	u8 *dh_p; /* prime */
-- 
1.7.9.5




More information about the Hostap mailing list