User override of server certificate
Store server certificate hash and TOD policy from WPA3-Enterprise
connection attempts with sta_associate. Add support for dev_exec_action
ServerCertTrust,Accept argument. If TOD policy is in place for the
current network profile, reject that command; if TOD policy is not in
place, update network profile to use the last received server
certificate (from the last failed connection attempt) and try to
reconnect.
Signed-off-by: Jouni Malinen <jouni@codeaurora.org>
diff --git a/dev.c b/dev.c
index ada3f90..e70b7fa 100644
--- a/dev.c
+++ b/dev.c
@@ -67,11 +67,129 @@
}
+static enum sigma_cmd_result sta_server_cert_trust(struct sigma_dut *dut,
+ struct sigma_conn *conn,
+ const char *val)
+{
+ char buf[100];
+ struct wpa_ctrl *ctrl = NULL;
+ int e;
+ char resp[200];
+ int num_disconnected = 0;
+
+ strlcpy(resp, "ServerCertTrustResult,Accepted", sizeof(resp));
+
+ if (strcasecmp(val, "Accept") != 0) {
+ strlcpy(resp,
+ "ServerCertTrustResult,NotAccepted,Reason,Unsupported ServerCertTrust value",
+ sizeof(resp));
+ goto done;
+ }
+
+ if (!dut->server_cert_hash[0]) {
+ strlcpy(resp,
+ "ServerCertTrustResult,NotAccepted,Reason,No server certificate stored",
+ sizeof(resp));
+ goto done;
+ }
+
+ if (dut->sta_tod_policy) {
+ strlcpy(resp,
+ "ServerCertTrustResult,NotAccepted,Reason,TOD policy",
+ sizeof(resp));
+ goto done;
+ }
+
+ snprintf(buf, sizeof(buf), "hash://server/sha256/%s",
+ dut->server_cert_hash);
+ if (set_network_quoted(get_station_ifname(), dut->infra_network_id,
+ "ca_cert", buf) < 0) {
+ strlcpy(resp,
+ "ServerCertTrustResult,NotAccepted,Reason,Could not configure server certificate hash for the network profile",
+ sizeof(resp));
+ goto done;
+ }
+
+ wpa_command(get_station_ifname(), "DISCONNECT");
+ snprintf(buf, sizeof(buf), "SELECT_NETWORK %d", dut->infra_network_id);
+ if (wpa_command(get_station_ifname(), buf) < 0) {
+ sigma_dut_print(dut, DUT_MSG_INFO, "Failed to select "
+ "network id %d on %s",
+ dut->infra_network_id,
+ get_station_ifname());
+ strlcpy(resp,
+ "ServerCertTrustResult,Accepted,Result,Could not request reconnection",
+ sizeof(resp));
+ goto done;
+ }
+
+ ctrl = open_wpa_mon(get_station_ifname());
+ if (!ctrl)
+ goto done;
+
+ for (e = 0; e < 20; e++) {
+ const char *events[] = {
+ "CTRL-EVENT-EAP-TLS-CERT-ERROR",
+ "CTRL-EVENT-DISCONNECTED",
+ "CTRL-EVENT-CONNECTED",
+ NULL
+ };
+ char buf[1024];
+ int res;
+
+ res = get_wpa_cli_events(dut, ctrl, events, buf, sizeof(buf));
+ if (res < 0) {
+ strlcpy(resp,
+ "ServerCertTrustResult,Accepted,Result,Association did not complete",
+ sizeof(resp));
+ goto done;
+ }
+ sigma_dut_print(dut, DUT_MSG_DEBUG, "Connection event: %s",
+ buf);
+
+ if (strstr(buf, "CTRL-EVENT-EAP-TLS-CERT-ERROR")) {
+ strlcpy(resp,
+ "ServerCertTrustResult,Accepted,Result,TLS server certitficate validation failed with updated profile",
+ sizeof(resp));
+ goto done;
+ }
+
+ if (strstr(buf, "CTRL-EVENT-DISCONNECTED")) {
+ num_disconnected++;
+
+ if (num_disconnected > 2) {
+ strlcpy(resp,
+ "ServerCertTrustResult,Accepted,Result,Connection failed",
+ sizeof(resp));
+ goto done;
+ }
+ }
+
+ if (strstr(buf, "CTRL-EVENT-CONNECTED")) {
+ strlcpy(resp,
+ "ServerCertTrustResult,Accepted,Result,Connected",
+ sizeof(resp));
+ break;
+ }
+ }
+
+done:
+ if (ctrl) {
+ wpa_ctrl_detach(ctrl);
+ wpa_ctrl_close(ctrl);
+ }
+
+ send_resp(dut, conn, SIGMA_COMPLETE, resp);
+ return STATUS_SENT;
+}
+
+
static enum sigma_cmd_result cmd_dev_exec_action(struct sigma_dut *dut,
struct sigma_conn *conn,
struct sigma_cmd *cmd)
{
const char *program = get_param(cmd, "Program");
+ const char *val;
#ifdef MIRACAST
if (program && (strcasecmp(program, "WFD") == 0 ||
@@ -85,6 +203,10 @@
if (program && strcasecmp(program, "DPP") == 0)
return dpp_dev_exec_action(dut, conn, cmd);
+ val = get_param(cmd, "ServerCertTrust");
+ if (val)
+ return sta_server_cert_trust(dut, conn, val);
+
return ERROR_SEND_STATUS;
}