HS20: Fix TrustRoot path for PolicyUpdate node in PPS MO
[mech_eap.git] / hs20 / client / osu_client.c
index 1a48592..e452aa7 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Hotspot 2.0 OSU client
- * Copyright (c) 2012-2013, Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2014, Qualcomm Atheros, Inc.
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -302,7 +302,12 @@ static int download_cert(struct hs20_osu_client *ctx, xml_node_t *params,
        xml_node_get_text_free(ctx->xml, hash);
 
        write_summary(ctx, "Download certificate from %s", url);
+       ctx->no_osu_cert_validation = 1;
+       http_ocsp_set(ctx->http, 1);
        res = http_download_file(ctx->http, url, TMP_CERT_DL_FILE, NULL);
+       http_ocsp_set(ctx->http,
+                     (ctx->workarounds & WORKAROUND_OCSP_OPTIONAL) ? 1 : 2);
+       ctx->no_osu_cert_validation = 0;
        xml_node_get_text_free(ctx->xml, url);
        if (res < 0)
                return -1;
@@ -392,9 +397,9 @@ static int cmd_dl_polupd_ca(struct hs20_osu_client *ctx, const char *pps_fname,
        }
 
        node = get_child_node(ctx->xml, pps,
-                             "PolicyUpdate/TrustRoot");
+                             "Policy/PolicyUpdate/TrustRoot");
        if (node == NULL) {
-               wpa_printf(MSG_INFO, "No PolicyUpdate/TrustRoot/CertURL found from PPS");
+               wpa_printf(MSG_INFO, "No Policy/PolicyUpdate/TrustRoot/CertURL found from PPS");
                xml_node_free(ctx->xml, pps);
                return -1;
        }
@@ -1993,7 +1998,7 @@ static struct osu_data * parse_osu_providers(const char *fname, size_t *count)
 
 
 static int osu_connect(struct hs20_osu_client *ctx, const char *bssid,
-                      const char *ssid, const char *url, const char *ca_fname,
+                      const char *ssid, const char *url,
                       unsigned int methods, int no_prod_assoc,
                       const char *osu_nai)
 {
@@ -2068,9 +2073,9 @@ static int osu_connect(struct hs20_osu_client *ctx, const char *bssid,
 
        ctx->no_reconnect = 1;
        if (methods & 0x02)
-               res = cmd_prov(ctx, url, ca_fname);
+               res = cmd_prov(ctx, url);
        else if (methods & 0x01)
-               res = cmd_oma_dm_prov(ctx, url, ca_fname);
+               res = cmd_oma_dm_prov(ctx, url);
 
        wpa_printf(MSG_INFO, "Remove OSU network connection");
        write_summary(ctx, "Remove OSU network connection");
@@ -2093,7 +2098,7 @@ static int osu_connect(struct hs20_osu_client *ctx, const char *bssid,
 
 
 static int cmd_osu_select(struct hs20_osu_client *ctx, const char *dir,
-                         int connect, const char *ca_fname, int no_prod_assoc,
+                         int connect, int no_prod_assoc,
                          const char *friendly_name)
 {
        char fname[255];
@@ -2264,14 +2269,14 @@ selected:
 
                if (connect == 2) {
                        if (last->methods & 0x02)
-                               ret = cmd_prov(ctx, last->url, ca_fname);
+                               ret = cmd_prov(ctx, last->url);
                        else if (last->methods & 0x01)
-                               ret = cmd_oma_dm_prov(ctx, last->url, ca_fname);
+                               ret = cmd_oma_dm_prov(ctx, last->url);
                        else
                                ret = -1;
                } else if (connect)
                        ret = osu_connect(ctx, last->bssid, last->osu_ssid,
-                                         last->url, ca_fname, last->methods,
+                                         last->url, last->methods,
                                          no_prod_assoc, last->osu_nai);
        } else
                ret = -1;
@@ -2282,8 +2287,8 @@ selected:
 }
 
 
-static int cmd_signup(struct hs20_osu_client *ctx, const char *ca_fname,
-                     int no_prod_assoc, const char *friendly_name)
+static int cmd_signup(struct hs20_osu_client *ctx, int no_prod_assoc,
+                     const char *friendly_name)
 {
        char dir[255];
        char fname[300], buf[400];
@@ -2334,13 +2339,12 @@ static int cmd_signup(struct hs20_osu_client *ctx, const char *ca_fname,
        }
        wpa_printf(MSG_INFO, "OSU provider fetch completed");
 
-       return cmd_osu_select(ctx, fname, 1, ca_fname, no_prod_assoc,
-                             friendly_name);
+       return cmd_osu_select(ctx, fname, 1, no_prod_assoc, friendly_name);
 }
 
 
-static void cmd_sub_rem(struct hs20_osu_client *ctx, const char *address,
-                       const char *pps_fname, const char *ca_fname)
+static int cmd_sub_rem(struct hs20_osu_client *ctx, const char *address,
+                      const char *pps_fname, const char *ca_fname)
 {
        xml_node_t *pps, *node;
        char pps_fname_buf[300];
@@ -2354,8 +2358,6 @@ static void cmd_sub_rem(struct hs20_osu_client *ctx, const char *address,
        char *client_key = NULL;
        int spp;
 
-       ctx->ca_fname = ca_fname;
-
        wpa_printf(MSG_INFO, "Subscription remediation requested with Server URL: %s",
                   address);
 
@@ -2369,12 +2371,12 @@ static void cmd_sub_rem(struct hs20_osu_client *ctx, const char *address,
                } else if (get_wpa_status(ctx->ifname, "provisioning_sp", buf,
                                          sizeof(buf)) < 0) {
                        wpa_printf(MSG_INFO, "Could not get provisioning Home SP FQDN from wpa_supplicant");
-                       return;
+                       return -1;
                }
                os_free(ctx->fqdn);
                ctx->fqdn = os_strdup(buf);
                if (ctx->fqdn == NULL)
-                       return;
+                       return -1;
                wpa_printf(MSG_INFO, "Home SP FQDN for current credential: %s",
                           buf);
                os_snprintf(pps_fname_buf, sizeof(pps_fname_buf),
@@ -2389,21 +2391,22 @@ static void cmd_sub_rem(struct hs20_osu_client *ctx, const char *address,
        if (!os_file_exists(pps_fname)) {
                wpa_printf(MSG_INFO, "PPS file '%s' does not exist or is not accessible",
                           pps_fname);
-               return;
+               return -1;
        }
        wpa_printf(MSG_INFO, "Using PPS file: %s", pps_fname);
 
        if (ca_fname && !os_file_exists(ca_fname)) {
                wpa_printf(MSG_INFO, "CA file '%s' does not exist or is not accessible",
                           ca_fname);
-               return;
+               return -1;
        }
        wpa_printf(MSG_INFO, "Using server trust root: %s", ca_fname);
+       ctx->ca_fname = ca_fname;
 
        pps = node_from_file(ctx->xml, pps_fname);
        if (pps == NULL) {
                wpa_printf(MSG_INFO, "Could not read PPS MO");
-               return;
+               return -1;
        }
 
        if (!ctx->fqdn) {
@@ -2411,18 +2414,18 @@ static void cmd_sub_rem(struct hs20_osu_client *ctx, const char *address,
                node = get_child_node(ctx->xml, pps, "HomeSP/FQDN");
                if (node == NULL) {
                        wpa_printf(MSG_INFO, "No HomeSP/FQDN found from PPS");
-                       return;
+                       return -1;
                }
                tmp = xml_node_get_text(ctx->xml, node);
                if (tmp == NULL) {
                        wpa_printf(MSG_INFO, "No HomeSP/FQDN text found from PPS");
-                       return;
+                       return -1;
                }
                ctx->fqdn = os_strdup(tmp);
                xml_node_get_text_free(ctx->xml, tmp);
                if (!ctx->fqdn) {
                        wpa_printf(MSG_INFO, "No FQDN known");
-                       return;
+                       return -1;
                }
        }
 
@@ -2471,7 +2474,7 @@ static void cmd_sub_rem(struct hs20_osu_client *ctx, const char *address,
        }
        if (!address) {
                wpa_printf(MSG_INFO, "Server URL not known");
-               return;
+               return -1;
        }
 
        write_summary(ctx, "Wait for IP address for subscriptiom remediation");
@@ -2482,18 +2485,19 @@ static void cmd_sub_rem(struct hs20_osu_client *ctx, const char *address,
        }
 
        if (spp)
-               spp_sub_rem(ctx, address, pps_fname, ca_fname,
+               spp_sub_rem(ctx, address, pps_fname,
                            client_cert, client_key,
                            cred_username, cred_password, pps);
        else
-               oma_dm_sub_rem(ctx, address, pps_fname, ca_fname,
+               oma_dm_sub_rem(ctx, address, pps_fname,
                               client_cert, client_key,
                               cred_username, cred_password, pps);
 
        xml_node_get_text_free(ctx->xml, sub_rem_uri);
        xml_node_get_text_free(ctx->xml, cred_username);
-       os_free(cred_password);
+       str_clear_free(cred_password);
        xml_node_free(ctx->xml, pps);
+       return 0;
 }
 
 
@@ -2555,6 +2559,7 @@ static int cmd_pol_upd(struct hs20_osu_client *ctx, const char *address,
                return -1;
        }
        wpa_printf(MSG_INFO, "Using server trust root: %s", ca_fname);
+       ctx->ca_fname = ca_fname;
 
        pps = node_from_file(ctx->xml, pps_fname);
        if (pps == NULL) {
@@ -2628,17 +2633,17 @@ static int cmd_pol_upd(struct hs20_osu_client *ctx, const char *address,
        }
 
        if (spp)
-               spp_pol_upd(ctx, address, pps_fname, ca_fname,
+               spp_pol_upd(ctx, address, pps_fname,
                            client_cert, client_key,
                            cred_username, cred_password, pps);
        else
-               oma_dm_pol_upd(ctx, address, pps_fname, ca_fname,
+               oma_dm_pol_upd(ctx, address, pps_fname,
                               client_cert, client_key,
                               cred_username, cred_password, pps);
 
        xml_node_get_text_free(ctx->xml, uri);
        xml_node_get_text_free(ctx->xml, cred_username);
-       os_free(cred_password);
+       str_clear_free(cred_password);
        xml_node_free(ctx->xml, pps);
 
        return 0;
@@ -2693,7 +2698,8 @@ static int osu_cert_cb(void *_ctx, struct http_cert *cert)
        int found;
        char *host = NULL;
 
-       wpa_printf(MSG_INFO, "osu_cert_cb");
+       wpa_printf(MSG_INFO, "osu_cert_cb(osu_cert_validation=%d)",
+                  !ctx->no_osu_cert_validation);
 
        host = get_hostname(ctx->server_url);
 
@@ -2737,7 +2743,8 @@ static int osu_cert_cb(void *_ctx, struct http_cert *cert)
                }
        }
 
-       for (j = 0; j < ctx->friendly_name_count; j++) {
+       for (j = 0; !ctx->no_osu_cert_validation &&
+                    j < ctx->friendly_name_count; j++) {
                int found = 0;
                for (i = 0; i < cert->num_othername; i++) {
                        if (os_strcmp(cert->othername[i].oid,
@@ -2776,7 +2783,7 @@ static int osu_cert_cb(void *_ctx, struct http_cert *cert)
                                  logo->hash, logo->hash_len);
        }
 
-       for (j = 0; j < ctx->icon_count; j++) {
+       for (j = 0; !ctx->no_osu_cert_validation && j < ctx->icon_count; j++) {
                int found = 0;
                char *name = ctx->icon_filename[j];
                size_t name_len = os_strlen(name);
@@ -2812,7 +2819,7 @@ static int osu_cert_cb(void *_ctx, struct http_cert *cert)
                }
        }
 
-       for (j = 0; j < ctx->icon_count; j++) {
+       for (j = 0; !ctx->no_osu_cert_validation && j < ctx->icon_count; j++) {
                int found = 0;
 
                for (i = 0; i < cert->num_logo; i++) {
@@ -2945,6 +2952,7 @@ static void usage(void)
               "- dl_polupd_ca <PPS> <CA file>\n"
               "- dl_aaa_ca <PPS> <CA file>\n"
               "- browser <URL>\n"
+              "- parse_cert <X.509 certificate (DER)>\n"
               "- osu_select <OSU info directory> [CA cert]\n");
 }
 
@@ -3059,10 +3067,11 @@ int main(int argc, char *argv[])
                if (argc - optind < 2)
                        wpa_printf(MSG_ERROR, "Server URL missing from command line");
                else
-                       cmd_sub_rem(&ctx, argv[optind + 1],
-                                   argc > optind + 2 ? argv[optind + 2] : NULL,
-                                   argc > optind + 3 ? argv[optind + 3] :
-                                   NULL);
+                       ret = cmd_sub_rem(&ctx, argv[optind + 1],
+                                         argc > optind + 2 ?
+                                         argv[optind + 2] : NULL,
+                                         argc > optind + 3 ?
+                                         argv[optind + 3] : NULL);
        } else if (strcmp(argv[optind], "pol_upd") == 0) {
                if (argc - optind < 2) {
                        usage();
@@ -3076,13 +3085,15 @@ int main(int argc, char *argv[])
                        usage();
                        exit(0);
                }
-               cmd_prov(&ctx, argv[optind + 1], argv[optind + 2]);
+               ctx.ca_fname = argv[optind + 2];
+               cmd_prov(&ctx, argv[optind + 1]);
        } else if (strcmp(argv[optind], "sim_prov") == 0) {
                if (argc - optind < 2) {
                        usage();
                        exit(0);
                }
-               cmd_sim_prov(&ctx, argv[optind + 1], argv[optind + 2]);
+               ctx.ca_fname = argv[optind + 2];
+               cmd_sim_prov(&ctx, argv[optind + 1]);
        } else if (strcmp(argv[optind], "dl_osu_ca") == 0) {
                if (argc - optind < 2) {
                        usage();
@@ -3106,13 +3117,11 @@ int main(int argc, char *argv[])
                        usage();
                        exit(0);
                }
-               cmd_osu_select(&ctx, argv[optind + 1], 2,
-                              argc > optind + 2 ? argv[optind + 2] : NULL,
-                              1, NULL);
+               ctx.ca_fname = argc > optind + 2 ? argv[optind + 2] : NULL;
+               cmd_osu_select(&ctx, argv[optind + 1], 2, 1, NULL);
        } else if (strcmp(argv[optind], "signup") == 0) {
-               ret = cmd_signup(&ctx,
-                                argc > optind + 1 ? argv[optind + 1] : NULL,
-                                no_prod_assoc, friendly_name);
+               ctx.ca_fname = argc > optind + 1 ? argv[optind + 1] : NULL;
+               ret = cmd_signup(&ctx, no_prod_assoc, friendly_name);
        } else if (strcmp(argv[optind], "set_pps") == 0) {
                if (argc - optind < 2) {
                        usage();
@@ -3130,14 +3139,15 @@ int main(int argc, char *argv[])
                        usage();
                        exit(0);
                }
-               cmd_oma_dm_prov(&ctx, argv[optind + 1], argv[optind + 2]);
+               ctx.ca_fname = argv[optind + 2];
+               cmd_oma_dm_prov(&ctx, argv[optind + 1]);
        } else if (strcmp(argv[optind], "oma_dm_sim_prov") == 0) {
                if (argc - optind < 2) {
                        usage();
                        exit(0);
                }
-               if (cmd_oma_dm_sim_prov(&ctx, argv[optind + 1],
-                                       argv[optind + 2]) < 0) {
+               ctx.ca_fname = argv[optind + 2];
+               if (cmd_oma_dm_sim_prov(&ctx, argv[optind + 1]) < 0) {
                        write_summary(&ctx, "Failed to complete OMA DM SIM provisioning");
                        return -1;
                }
@@ -3172,15 +3182,24 @@ int main(int argc, char *argv[])
                           argv[optind + 1]);
                ret = hs20_web_browser(argv[optind + 1]);
                wpa_printf(MSG_INFO, "Web browser result: %d", ret);
+       } else if (strcmp(argv[optind], "parse_cert") == 0) {
+               if (argc - optind < 2) {
+                       usage();
+                       exit(0);
+               }
+
+               wpa_debug_level = MSG_MSGDUMP;
+               http_parse_x509_certificate(ctx.http, argv[optind + 1]);
+               wpa_debug_level = MSG_INFO;
        } else {
                wpa_printf(MSG_INFO, "Unknown command '%s'", argv[optind]);
        }
 
+       deinit_ctx(&ctx);
        wpa_printf(MSG_DEBUG,
                   "===[hs20-osu-client END ]======================");
 
        wpa_debug_close_file();
-       deinit_ctx(&ctx);
 
        return ret;
 }