Implemented callback in libeap/src/crypto to allow mech_eap / ID Selector to ask...
[mech_eap.git] / libeap / src / crypto / tls_openssl.c
index 0a8ae57..e82e949 100644 (file)
@@ -129,6 +129,9 @@ struct tls_connection {
        unsigned char client_random[SSL3_RANDOM_SIZE];
        unsigned char server_random[SSL3_RANDOM_SIZE];
 #endif
+
+    int (*validate_ca_cb)(int ok_so_far, X509* cert, void *ca_ctx);
+    void *validate_ca_ctx;
 };
 
 
@@ -145,7 +148,6 @@ static struct tls_context * tls_context_new(const struct tls_config *conf)
        return context;
 }
 
-
 #ifdef CONFIG_NO_STDOUT_DEBUG
 
 static void _tls_show_errors(void)
@@ -1591,20 +1593,36 @@ static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
        else if (depth == 2)
                conn->peer_issuer_issuer = err_cert;
 
+       wpa_printf(MSG_DEBUG, "TLS: tls_verify_cb(enter) - preverify_ok=%d "
+                  "err=%d (%s) ca_cert_verify=%d depth=%d buf='%s'",
+                  preverify_ok, err, X509_verify_cert_error_string(err),
+                  conn->ca_cert_verify, depth, buf);
+
+
        context = conn->context;
        match = conn->subject_match;
        altmatch = conn->altsubject_match;
        suffix_match = conn->suffix_match;
        domain_match = conn->domain_match;
 
-       if (!preverify_ok && !conn->ca_cert_verify)
-               preverify_ok = 1;
-       if (!preverify_ok && depth > 0 && conn->server_cert_only)
+       if (!preverify_ok && !conn->ca_cert_verify) {
+        if (conn->validate_ca_cb) {
+            preverify_ok = conn->validate_ca_cb(preverify_ok, err_cert, conn->validate_ca_ctx);
+            wpa_printf(MSG_DEBUG, "TLS: tls_verify_cb: validate_ca_cb returned %d", preverify_ok);
+        }
+        else {
+            preverify_ok = 1;
+            wpa_printf(MSG_DEBUG, "TLS: tls_verify_cb: allowing cert because !conn->ca_cert_verify\n");
+        }
+    }
+       if (!preverify_ok && depth > 0 && conn->server_cert_only) {
+        wpa_printf(MSG_DEBUG, "TLS: tls_verify_cb: allowing cert because depth > 0 && conn->server_cert_only\n");
                preverify_ok = 1;
+    }
        if (!preverify_ok && (conn->flags & TLS_CONN_DISABLE_TIME_CHECKS) &&
            (err == X509_V_ERR_CERT_HAS_EXPIRED ||
             err == X509_V_ERR_CERT_NOT_YET_VALID)) {
-               wpa_printf(MSG_DEBUG, "OpenSSL: Ignore certificate validity "
+               wpa_printf(MSG_DEBUG, "tls_verify_cb: OpenSSL: Ignore certificate validity "
                           "time mismatch");
                preverify_ok = 1;
        }
@@ -1620,7 +1638,7 @@ static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
                struct wpabuf *cert;
                cert = get_x509_cert(err_cert);
                if (!cert) {
-                       wpa_printf(MSG_DEBUG, "OpenSSL: Could not fetch "
+                       wpa_printf(MSG_DEBUG, "tls_verify_cb: OpenSSL: Could not fetch "
                                   "server certificate data");
                        preverify_ok = 0;
                } else {
@@ -1640,7 +1658,7 @@ static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
                                 * regardless of other problems.
                                 */
                                wpa_printf(MSG_DEBUG,
-                                          "OpenSSL: Ignore validation issues for a pinned server certificate");
+                                          "tls_verify_cb: OpenSSL: Ignore validation issues for a pinned server certificate");
                                preverify_ok = 1;
                        }
                        wpabuf_free(cert);
@@ -1649,7 +1667,7 @@ static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
 #endif /* CONFIG_SHA256 */
 
        if (!preverify_ok) {
-               wpa_printf(MSG_WARNING, "TLS: Certificate verification failed,"
+               wpa_printf(MSG_WARNING, "tls_verify_cb: TLS: Certificate verification failed,"
                           " error %d (%s) depth %d for '%s'", err, err_str,
                           depth, buf);
                openssl_tls_fail_event(conn, err_cert, err, depth, buf,
@@ -1657,12 +1675,12 @@ static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
                return preverify_ok;
        }
 
-       wpa_printf(MSG_DEBUG, "TLS: tls_verify_cb - preverify_ok=%d "
+       wpa_printf(MSG_DEBUG, "TLS: tls_verify_cb(exit) - preverify_ok=%d "
                   "err=%d (%s) ca_cert_verify=%d depth=%d buf='%s'",
                   preverify_ok, err, err_str,
                   conn->ca_cert_verify, depth, buf);
        if (depth == 0 && match && os_strstr(buf, match) == NULL) {
-               wpa_printf(MSG_WARNING, "TLS: Subject '%s' did not "
+               wpa_printf(MSG_WARNING, "tls_verify_cb: TLS: Subject '%s' did not "
                           "match with '%s'", buf, match);
                preverify_ok = 0;
                openssl_tls_fail_event(conn, err_cert, err, depth, buf,
@@ -1670,7 +1688,7 @@ static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
                                       TLS_FAIL_SUBJECT_MISMATCH);
        } else if (depth == 0 && altmatch &&
                   !tls_match_altsubject(err_cert, altmatch)) {
-               wpa_printf(MSG_WARNING, "TLS: altSubjectName match "
+               wpa_printf(MSG_WARNING, "tls_verify_cb: TLS: altSubjectName match "
                           "'%s' not found", altmatch);
                preverify_ok = 0;
                openssl_tls_fail_event(conn, err_cert, err, depth, buf,
@@ -1678,7 +1696,7 @@ static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
                                       TLS_FAIL_ALTSUBJECT_MISMATCH);
        } else if (depth == 0 && suffix_match &&
                   !tls_match_suffix(err_cert, suffix_match, 0)) {
-               wpa_printf(MSG_WARNING, "TLS: Domain suffix match '%s' not found",
+               wpa_printf(MSG_WARNING, "tls_verify_cb: TLS: Domain suffix match '%s' not found",
                           suffix_match);
                preverify_ok = 0;
                openssl_tls_fail_event(conn, err_cert, err, depth, buf,
@@ -1686,7 +1704,7 @@ static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
                                       TLS_FAIL_DOMAIN_SUFFIX_MISMATCH);
        } else if (depth == 0 && domain_match &&
                   !tls_match_suffix(err_cert, domain_match, 1)) {
-               wpa_printf(MSG_WARNING, "TLS: Domain match '%s' not found",
+               wpa_printf(MSG_WARNING, "tls_verify_cb: TLS: Domain match '%s' not found",
                           domain_match);
                preverify_ok = 0;
                openssl_tls_fail_event(conn, err_cert, err, depth, buf,
@@ -1696,7 +1714,7 @@ static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
                openssl_tls_cert_event(conn, err_cert, depth, buf);
 
        if (conn->cert_probe && preverify_ok && depth == 0) {
-               wpa_printf(MSG_DEBUG, "OpenSSL: Reject server certificate "
+               wpa_printf(MSG_DEBUG, "tls_verify_cb: OpenSSL: Reject server certificate "
                           "on probe-only run");
                preverify_ok = 0;
                openssl_tls_fail_event(conn, err_cert, err, depth, buf,
@@ -1746,9 +1764,11 @@ static int tls_load_ca_der(struct tls_data *data, const char *ca_cert)
 
 
 static int tls_connection_ca_cert(struct tls_data *data,
-                                 struct tls_connection *conn,
-                                 const char *ca_cert, const u8 *ca_cert_blob,
-                                 size_t ca_cert_blob_len, const char *ca_path)
+                                  struct tls_connection *conn,
+                                  const char *ca_cert, const u8 *ca_cert_blob,
+                                  size_t ca_cert_blob_len, const char *ca_path,
+                                  int (*validate_ca_cb)(int ok_so_far, X509* cert, void *ca_ctx),
+                                  void *validate_ca_ctx)
 {
        SSL_CTX *ssl_ctx = data->ssl;
        X509_STORE *store;
@@ -1770,7 +1790,7 @@ static int tls_connection_ca_cert(struct tls_data *data,
 
        if (ca_cert && os_strncmp(ca_cert, "probe://", 8) == 0) {
                wpa_printf(MSG_DEBUG, "OpenSSL: Probe for server certificate "
-                          "chain");
+                          "chain; setting conn->ca_cert_verify=0");
                conn->cert_probe = 1;
                conn->ca_cert_verify = 0;
                return 0;
@@ -1904,7 +1924,10 @@ static int tls_connection_ca_cert(struct tls_data *data,
        } else {
                /* No ca_cert configured - do not try to verify server
                 * certificate */
+               wpa_printf(MSG_DEBUG, "OpenSSL: tls_connection_ca_cert: No ca_cert; setting conn->ca_cert_verify=0");
                conn->ca_cert_verify = 0;
+        conn->validate_ca_cb = validate_ca_cb;
+        conn->validate_ca_ctx = validate_ca_ctx;
        }
 
        return 0;
@@ -2049,6 +2072,7 @@ int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
                               SSL_VERIFY_FAIL_IF_NO_PEER_CERT |
                               SSL_VERIFY_CLIENT_ONCE, tls_verify_cb);
        } else {
+               wpa_printf(MSG_DEBUG, "OpenSSL: tls_connection_set_verify: !verify_peer; setting conn->ca_cert_verify=0");
                conn->ca_cert_verify = 0;
                SSL_set_verify(conn->ssl, SSL_VERIFY_NONE, NULL);
        }
@@ -3838,11 +3862,14 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
        if (engine_id && ca_cert_id) {
                if (tls_connection_engine_ca_cert(data, conn, ca_cert_id))
                        return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED;
-       } else if (tls_connection_ca_cert(data, conn, params->ca_cert,
-                                         params->ca_cert_blob,
-                                         params->ca_cert_blob_len,
-                                         params->ca_path))
-               return -1;
+       } else {
+        if (tls_connection_ca_cert(data, conn, params->ca_cert,
+                                   params->ca_cert_blob,
+                                   params->ca_cert_blob_len,
+                                   params->ca_path, params->validate_ca_cb, 
+                                   params->validate_ca_ctx))
+            return -1;
+    }
 
        if (engine_id && cert_id) {
                if (tls_connection_engine_client_cert(conn, cert_id))