]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
TLS client: Add support for validating server certificate hash
authorPali Rohár <pali.rohar@gmail.com>
Sun, 22 Nov 2015 01:02:56 +0000 (02:02 +0100)
committerJouni Malinen <j@w1.fi>
Sun, 29 Nov 2015 09:45:59 +0000 (11:45 +0200)
This commit adds support for "hash://server/sha256/cert_hash_in_hex"
scheme in ca_cert property for the internal TLS implementation.

Signed-off-by: Pali Rohár <pali.rohar@gmail.com>
src/tls/tlsv1_client_read.c
src/tls/tlsv1_cred.c
src/tls/tlsv1_cred.h

index 4fe95807af7bc804b0dcfb7630c4ba16bf365af3..48120b683030529ac5e89592235717ffd655cb1c 100644 (file)
@@ -364,10 +364,32 @@ static int tls_process_certificate(struct tlsv1_client *conn, u8 ct,
                pos += cert_len;
        }
 
-       if (conn->cred && conn->cred->ca_cert_verify &&
-           x509_certificate_chain_validate(conn->cred->trusted_certs, chain,
-                                           &reason, conn->disable_time_checks)
-           < 0) {
+       if (conn->cred && conn->cred->server_cert_only && chain) {
+               u8 hash[SHA256_MAC_LEN];
+               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,
+                             SHA256_MAC_LEN) != 0) {
+                       wpa_printf(MSG_DEBUG,
+                                  "TLSv1: Server certificate hash mismatch");
+                       wpa_hexdump(MSG_MSGDUMP, "TLSv1: SHA256 hash",
+                                   hash, SHA256_MAC_LEN);
+                       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) {
                int tls_reason;
                wpa_printf(MSG_DEBUG, "TLSv1: Server certificate chain "
                           "validation failed (reason=%d)", reason);
index fbac96511d31d92a5babdc11ee890c79f1b4295c..3ed21ec1c82a5ddcc58bcf02393c55a08ddaa5a1 100644 (file)
@@ -190,6 +190,34 @@ 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,
index b1e3e00bdf0a42e5b2e50c3de2d79aebcc44f102..ac72b8c228a1aeadf464630a6963857af4abc5fd 100644 (file)
@@ -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 */