15b9c547cSRui Paulo /* 25b9c547cSRui Paulo * Hotspot 2.0 OSU client 35b9c547cSRui Paulo * Copyright (c) 2012-2014, Qualcomm Atheros, Inc. 45b9c547cSRui Paulo * 55b9c547cSRui Paulo * This software may be distributed under the terms of the BSD license. 65b9c547cSRui Paulo * See README for more details. 75b9c547cSRui Paulo */ 85b9c547cSRui Paulo 95b9c547cSRui Paulo #include "includes.h" 105b9c547cSRui Paulo #include <time.h> 115b9c547cSRui Paulo #include <sys/stat.h> 125b9c547cSRui Paulo #ifdef ANDROID 135b9c547cSRui Paulo #include "private/android_filesystem_config.h" 145b9c547cSRui Paulo #endif /* ANDROID */ 155b9c547cSRui Paulo 165b9c547cSRui Paulo #include "common.h" 175b9c547cSRui Paulo #include "utils/browser.h" 185b9c547cSRui Paulo #include "utils/base64.h" 195b9c547cSRui Paulo #include "utils/xml-utils.h" 205b9c547cSRui Paulo #include "utils/http-utils.h" 215b9c547cSRui Paulo #include "common/wpa_ctrl.h" 225b9c547cSRui Paulo #include "common/wpa_helpers.h" 235b9c547cSRui Paulo #include "eap_common/eap_defs.h" 245b9c547cSRui Paulo #include "crypto/crypto.h" 255b9c547cSRui Paulo #include "crypto/sha256.h" 265b9c547cSRui Paulo #include "osu_client.h" 275b9c547cSRui Paulo 28325151a3SRui Paulo const char *spp_xsd_fname = "spp.xsd"; 29325151a3SRui Paulo 305b9c547cSRui Paulo 315b9c547cSRui Paulo void write_result(struct hs20_osu_client *ctx, const char *fmt, ...) 325b9c547cSRui Paulo { 335b9c547cSRui Paulo va_list ap; 345b9c547cSRui Paulo FILE *f; 355b9c547cSRui Paulo char buf[500]; 365b9c547cSRui Paulo 375b9c547cSRui Paulo va_start(ap, fmt); 385b9c547cSRui Paulo vsnprintf(buf, sizeof(buf), fmt, ap); 395b9c547cSRui Paulo va_end(ap); 405b9c547cSRui Paulo write_summary(ctx, "%s", buf); 415b9c547cSRui Paulo 425b9c547cSRui Paulo if (!ctx->result_file) 435b9c547cSRui Paulo return; 445b9c547cSRui Paulo 455b9c547cSRui Paulo f = fopen(ctx->result_file, "w"); 465b9c547cSRui Paulo if (f == NULL) 475b9c547cSRui Paulo return; 485b9c547cSRui Paulo 495b9c547cSRui Paulo va_start(ap, fmt); 505b9c547cSRui Paulo vfprintf(f, fmt, ap); 515b9c547cSRui Paulo va_end(ap); 525b9c547cSRui Paulo fprintf(f, "\n"); 535b9c547cSRui Paulo fclose(f); 545b9c547cSRui Paulo } 555b9c547cSRui Paulo 565b9c547cSRui Paulo 575b9c547cSRui Paulo void write_summary(struct hs20_osu_client *ctx, const char *fmt, ...) 585b9c547cSRui Paulo { 595b9c547cSRui Paulo va_list ap; 605b9c547cSRui Paulo FILE *f; 615b9c547cSRui Paulo 625b9c547cSRui Paulo if (!ctx->summary_file) 635b9c547cSRui Paulo return; 645b9c547cSRui Paulo 655b9c547cSRui Paulo f = fopen(ctx->summary_file, "a"); 665b9c547cSRui Paulo if (f == NULL) 675b9c547cSRui Paulo return; 685b9c547cSRui Paulo 695b9c547cSRui Paulo va_start(ap, fmt); 705b9c547cSRui Paulo vfprintf(f, fmt, ap); 715b9c547cSRui Paulo va_end(ap); 725b9c547cSRui Paulo fprintf(f, "\n"); 735b9c547cSRui Paulo fclose(f); 745b9c547cSRui Paulo } 755b9c547cSRui Paulo 765b9c547cSRui Paulo 775b9c547cSRui Paulo void debug_dump_node(struct hs20_osu_client *ctx, const char *title, 785b9c547cSRui Paulo xml_node_t *node) 795b9c547cSRui Paulo { 805b9c547cSRui Paulo char *str = xml_node_to_str(ctx->xml, node); 815b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "[hs20] %s: '%s'", title, str); 825b9c547cSRui Paulo free(str); 835b9c547cSRui Paulo } 845b9c547cSRui Paulo 855b9c547cSRui Paulo 865b9c547cSRui Paulo static int valid_fqdn(const char *fqdn) 875b9c547cSRui Paulo { 885b9c547cSRui Paulo const char *pos; 895b9c547cSRui Paulo 905b9c547cSRui Paulo /* TODO: could make this more complete.. */ 915b9c547cSRui Paulo if (strchr(fqdn, '.') == 0 || strlen(fqdn) > 255) 925b9c547cSRui Paulo return 0; 935b9c547cSRui Paulo for (pos = fqdn; *pos; pos++) { 945b9c547cSRui Paulo if (*pos >= 'a' && *pos <= 'z') 955b9c547cSRui Paulo continue; 965b9c547cSRui Paulo if (*pos >= 'A' && *pos <= 'Z') 975b9c547cSRui Paulo continue; 985b9c547cSRui Paulo if (*pos >= '0' && *pos <= '9') 995b9c547cSRui Paulo continue; 1005b9c547cSRui Paulo if (*pos == '-' || *pos == '.' || *pos == '_') 1015b9c547cSRui Paulo continue; 1025b9c547cSRui Paulo return 0; 1035b9c547cSRui Paulo } 1045b9c547cSRui Paulo return 1; 1055b9c547cSRui Paulo } 1065b9c547cSRui Paulo 1075b9c547cSRui Paulo 10885732ac8SCy Schubert static int android_update_permission(const char *path, mode_t mode) 10985732ac8SCy Schubert { 11085732ac8SCy Schubert #ifdef ANDROID 11185732ac8SCy Schubert /* we need to change file/folder permission for Android */ 11285732ac8SCy Schubert 11385732ac8SCy Schubert if (!path) { 11485732ac8SCy Schubert wpa_printf(MSG_ERROR, "file path null"); 11585732ac8SCy Schubert return -1; 11685732ac8SCy Schubert } 11785732ac8SCy Schubert 11885732ac8SCy Schubert /* Allow processes running with Group ID as AID_WIFI, 11985732ac8SCy Schubert * to read files from SP, SP/<fqdn>, Cert and osu-info directories */ 1204bc52338SCy Schubert if (lchown(path, -1, AID_WIFI)) { 1214bc52338SCy Schubert wpa_printf(MSG_INFO, "CTRL: Could not lchown directory: %s", 12285732ac8SCy Schubert strerror(errno)); 12385732ac8SCy Schubert return -1; 12485732ac8SCy Schubert } 12585732ac8SCy Schubert 12685732ac8SCy Schubert if (chmod(path, mode) < 0) { 12785732ac8SCy Schubert wpa_printf(MSG_INFO, "CTRL: Could not chmod directory: %s", 12885732ac8SCy Schubert strerror(errno)); 12985732ac8SCy Schubert return -1; 13085732ac8SCy Schubert } 13185732ac8SCy Schubert #endif /* ANDROID */ 13285732ac8SCy Schubert 13385732ac8SCy Schubert return 0; 13485732ac8SCy Schubert } 13585732ac8SCy Schubert 13685732ac8SCy Schubert 1375b9c547cSRui Paulo int osu_get_certificate(struct hs20_osu_client *ctx, xml_node_t *getcert) 1385b9c547cSRui Paulo { 1395b9c547cSRui Paulo xml_node_t *node; 1405b9c547cSRui Paulo char *url, *user = NULL, *pw = NULL; 1415b9c547cSRui Paulo char *proto; 1425b9c547cSRui Paulo int ret = -1; 1435b9c547cSRui Paulo 1445b9c547cSRui Paulo proto = xml_node_get_attr_value(ctx->xml, getcert, 1455b9c547cSRui Paulo "enrollmentProtocol"); 1465b9c547cSRui Paulo if (!proto) 1475b9c547cSRui Paulo return -1; 1485b9c547cSRui Paulo wpa_printf(MSG_INFO, "getCertificate - enrollmentProtocol=%s", proto); 1495b9c547cSRui Paulo write_summary(ctx, "getCertificate - enrollmentProtocol=%s", proto); 1505b9c547cSRui Paulo if (os_strcasecmp(proto, "EST") != 0) { 1515b9c547cSRui Paulo wpa_printf(MSG_INFO, "Unsupported enrollmentProtocol"); 1525b9c547cSRui Paulo xml_node_get_attr_value_free(ctx->xml, proto); 1535b9c547cSRui Paulo return -1; 1545b9c547cSRui Paulo } 1555b9c547cSRui Paulo xml_node_get_attr_value_free(ctx->xml, proto); 1565b9c547cSRui Paulo 1575b9c547cSRui Paulo node = get_node(ctx->xml, getcert, "enrollmentServerURI"); 1585b9c547cSRui Paulo if (node == NULL) { 1595b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not find enrollmentServerURI node"); 1605b9c547cSRui Paulo xml_node_get_attr_value_free(ctx->xml, proto); 1615b9c547cSRui Paulo return -1; 1625b9c547cSRui Paulo } 1635b9c547cSRui Paulo url = xml_node_get_text(ctx->xml, node); 1645b9c547cSRui Paulo if (url == NULL) { 1655b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not get URL text"); 1665b9c547cSRui Paulo return -1; 1675b9c547cSRui Paulo } 1685b9c547cSRui Paulo wpa_printf(MSG_INFO, "enrollmentServerURI: %s", url); 1695b9c547cSRui Paulo write_summary(ctx, "enrollmentServerURI: %s", url); 1705b9c547cSRui Paulo 1715b9c547cSRui Paulo node = get_node(ctx->xml, getcert, "estUserID"); 1725b9c547cSRui Paulo if (node == NULL && !ctx->client_cert_present) { 1735b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not find estUserID node"); 1745b9c547cSRui Paulo goto fail; 1755b9c547cSRui Paulo } 1765b9c547cSRui Paulo if (node) { 1775b9c547cSRui Paulo user = xml_node_get_text(ctx->xml, node); 1785b9c547cSRui Paulo if (user == NULL) { 1795b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not get estUserID text"); 1805b9c547cSRui Paulo goto fail; 1815b9c547cSRui Paulo } 1825b9c547cSRui Paulo wpa_printf(MSG_INFO, "estUserID: %s", user); 1835b9c547cSRui Paulo write_summary(ctx, "estUserID: %s", user); 1845b9c547cSRui Paulo } 1855b9c547cSRui Paulo 1865b9c547cSRui Paulo node = get_node(ctx->xml, getcert, "estPassword"); 1875b9c547cSRui Paulo if (node == NULL && !ctx->client_cert_present) { 1885b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not find estPassword node"); 1895b9c547cSRui Paulo goto fail; 1905b9c547cSRui Paulo } 1915b9c547cSRui Paulo if (node) { 1925b9c547cSRui Paulo pw = xml_node_get_base64_text(ctx->xml, node, NULL); 1935b9c547cSRui Paulo if (pw == NULL) { 1945b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not get estPassword text"); 1955b9c547cSRui Paulo goto fail; 1965b9c547cSRui Paulo } 1975b9c547cSRui Paulo wpa_printf(MSG_INFO, "estPassword: %s", pw); 1985b9c547cSRui Paulo } 1995b9c547cSRui Paulo 2005b9c547cSRui Paulo mkdir("Cert", S_IRWXU); 20185732ac8SCy Schubert android_update_permission("Cert", S_IRWXU | S_IRWXG); 20285732ac8SCy Schubert 2035b9c547cSRui Paulo if (est_load_cacerts(ctx, url) < 0 || 2045b9c547cSRui Paulo est_build_csr(ctx, url) < 0 || 2055b9c547cSRui Paulo est_simple_enroll(ctx, url, user, pw) < 0) 2065b9c547cSRui Paulo goto fail; 2075b9c547cSRui Paulo 2085b9c547cSRui Paulo ret = 0; 2095b9c547cSRui Paulo fail: 2105b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, url); 2115b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, user); 2125b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, pw); 2135b9c547cSRui Paulo 2145b9c547cSRui Paulo return ret; 2155b9c547cSRui Paulo } 2165b9c547cSRui Paulo 2175b9c547cSRui Paulo 2185b9c547cSRui Paulo static int process_est_cert(struct hs20_osu_client *ctx, xml_node_t *cert, 2195b9c547cSRui Paulo const char *fqdn) 2205b9c547cSRui Paulo { 2215b9c547cSRui Paulo u8 digest1[SHA256_MAC_LEN], digest2[SHA256_MAC_LEN]; 2225b9c547cSRui Paulo char *der, *pem; 2235b9c547cSRui Paulo size_t der_len, pem_len; 2245b9c547cSRui Paulo char *fingerprint; 2255b9c547cSRui Paulo char buf[200]; 2265b9c547cSRui Paulo 2275b9c547cSRui Paulo wpa_printf(MSG_INFO, "PPS for certificate credential - fqdn=%s", fqdn); 2285b9c547cSRui Paulo 2295b9c547cSRui Paulo fingerprint = xml_node_get_text(ctx->xml, cert); 2305b9c547cSRui Paulo if (fingerprint == NULL) 2315b9c547cSRui Paulo return -1; 2325b9c547cSRui Paulo if (hexstr2bin(fingerprint, digest1, SHA256_MAC_LEN) < 0) { 2335b9c547cSRui Paulo wpa_printf(MSG_INFO, "Invalid SHA256 hash value"); 2345b9c547cSRui Paulo write_result(ctx, "Invalid client certificate SHA256 hash value in PPS"); 2355b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, fingerprint); 2365b9c547cSRui Paulo return -1; 2375b9c547cSRui Paulo } 2385b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, fingerprint); 2395b9c547cSRui Paulo 2405b9c547cSRui Paulo der = os_readfile("Cert/est_cert.der", &der_len); 2415b9c547cSRui Paulo if (der == NULL) { 2425b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not find client certificate from EST"); 2435b9c547cSRui Paulo write_result(ctx, "Could not find client certificate from EST"); 2445b9c547cSRui Paulo return -1; 2455b9c547cSRui Paulo } 2465b9c547cSRui Paulo 2475b9c547cSRui Paulo if (sha256_vector(1, (const u8 **) &der, &der_len, digest2) < 0) { 2485b9c547cSRui Paulo os_free(der); 2495b9c547cSRui Paulo return -1; 2505b9c547cSRui Paulo } 2515b9c547cSRui Paulo os_free(der); 2525b9c547cSRui Paulo 2535b9c547cSRui Paulo if (os_memcmp(digest1, digest2, sizeof(digest1)) != 0) { 2545b9c547cSRui Paulo wpa_printf(MSG_INFO, "Client certificate from EST does not match fingerprint from PPS MO"); 2555b9c547cSRui Paulo write_result(ctx, "Client certificate from EST does not match fingerprint from PPS MO"); 2565b9c547cSRui Paulo return -1; 2575b9c547cSRui Paulo } 2585b9c547cSRui Paulo 2595b9c547cSRui Paulo wpa_printf(MSG_INFO, "Client certificate from EST matches PPS MO"); 2605b9c547cSRui Paulo unlink("Cert/est_cert.der"); 2615b9c547cSRui Paulo 2625b9c547cSRui Paulo os_snprintf(buf, sizeof(buf), "SP/%s/client-ca.pem", fqdn); 2635b9c547cSRui Paulo if (rename("Cert/est-cacerts.pem", buf) < 0) { 2645b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not move est-cacerts.pem to client-ca.pem: %s", 2655b9c547cSRui Paulo strerror(errno)); 2665b9c547cSRui Paulo return -1; 2675b9c547cSRui Paulo } 2685b9c547cSRui Paulo pem = os_readfile(buf, &pem_len); 2695b9c547cSRui Paulo 2705b9c547cSRui Paulo os_snprintf(buf, sizeof(buf), "SP/%s/client-cert.pem", fqdn); 2715b9c547cSRui Paulo if (rename("Cert/est_cert.pem", buf) < 0) { 2725b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not move est_cert.pem to client-cert.pem: %s", 2735b9c547cSRui Paulo strerror(errno)); 2745b9c547cSRui Paulo os_free(pem); 2755b9c547cSRui Paulo return -1; 2765b9c547cSRui Paulo } 2775b9c547cSRui Paulo 2785b9c547cSRui Paulo if (pem) { 2795b9c547cSRui Paulo FILE *f = fopen(buf, "a"); 2805b9c547cSRui Paulo if (f) { 2815b9c547cSRui Paulo fwrite(pem, pem_len, 1, f); 2825b9c547cSRui Paulo fclose(f); 2835b9c547cSRui Paulo } 2845b9c547cSRui Paulo os_free(pem); 2855b9c547cSRui Paulo } 2865b9c547cSRui Paulo 2875b9c547cSRui Paulo os_snprintf(buf, sizeof(buf), "SP/%s/client-key.pem", fqdn); 2885b9c547cSRui Paulo if (rename("Cert/privkey-plain.pem", buf) < 0) { 2895b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not move privkey-plain.pem to client-key.pem: %s", 2905b9c547cSRui Paulo strerror(errno)); 2915b9c547cSRui Paulo return -1; 2925b9c547cSRui Paulo } 2935b9c547cSRui Paulo 2945b9c547cSRui Paulo unlink("Cert/est-req.b64"); 2955b9c547cSRui Paulo unlink("Cert/est-req.pem"); 2965b9c547cSRui Paulo rmdir("Cert"); 2975b9c547cSRui Paulo 2985b9c547cSRui Paulo return 0; 2995b9c547cSRui Paulo } 3005b9c547cSRui Paulo 3015b9c547cSRui Paulo 3025b9c547cSRui Paulo #define TMP_CERT_DL_FILE "tmp-cert-download" 3035b9c547cSRui Paulo 3045b9c547cSRui Paulo static int download_cert(struct hs20_osu_client *ctx, xml_node_t *params, 3055b9c547cSRui Paulo const char *fname) 3065b9c547cSRui Paulo { 3075b9c547cSRui Paulo xml_node_t *url_node, *hash_node; 3085b9c547cSRui Paulo char *url, *hash; 3095b9c547cSRui Paulo char *cert; 3105b9c547cSRui Paulo size_t len; 3115b9c547cSRui Paulo u8 digest1[SHA256_MAC_LEN], digest2[SHA256_MAC_LEN]; 3125b9c547cSRui Paulo int res; 313*c1d255d3SCy Schubert char *b64; 3145b9c547cSRui Paulo FILE *f; 3155b9c547cSRui Paulo 3165b9c547cSRui Paulo url_node = get_node(ctx->xml, params, "CertURL"); 3175b9c547cSRui Paulo hash_node = get_node(ctx->xml, params, "CertSHA256Fingerprint"); 3185b9c547cSRui Paulo if (url_node == NULL || hash_node == NULL) 3195b9c547cSRui Paulo return -1; 3205b9c547cSRui Paulo url = xml_node_get_text(ctx->xml, url_node); 3215b9c547cSRui Paulo hash = xml_node_get_text(ctx->xml, hash_node); 3225b9c547cSRui Paulo if (url == NULL || hash == NULL) { 3235b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, url); 3245b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, hash); 3255b9c547cSRui Paulo return -1; 3265b9c547cSRui Paulo } 3275b9c547cSRui Paulo 3285b9c547cSRui Paulo wpa_printf(MSG_INFO, "CertURL: %s", url); 3295b9c547cSRui Paulo wpa_printf(MSG_INFO, "SHA256 hash: %s", hash); 3305b9c547cSRui Paulo 3315b9c547cSRui Paulo if (hexstr2bin(hash, digest1, SHA256_MAC_LEN) < 0) { 3325b9c547cSRui Paulo wpa_printf(MSG_INFO, "Invalid SHA256 hash value"); 3335b9c547cSRui Paulo write_result(ctx, "Invalid SHA256 hash value for downloaded certificate"); 3345b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, hash); 3355b9c547cSRui Paulo return -1; 3365b9c547cSRui Paulo } 3375b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, hash); 3385b9c547cSRui Paulo 3395b9c547cSRui Paulo write_summary(ctx, "Download certificate from %s", url); 3405b9c547cSRui Paulo ctx->no_osu_cert_validation = 1; 3415b9c547cSRui Paulo http_ocsp_set(ctx->http, 1); 3425b9c547cSRui Paulo res = http_download_file(ctx->http, url, TMP_CERT_DL_FILE, NULL); 3435b9c547cSRui Paulo http_ocsp_set(ctx->http, 3445b9c547cSRui Paulo (ctx->workarounds & WORKAROUND_OCSP_OPTIONAL) ? 1 : 2); 3455b9c547cSRui Paulo ctx->no_osu_cert_validation = 0; 3465b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, url); 3475b9c547cSRui Paulo if (res < 0) 3485b9c547cSRui Paulo return -1; 3495b9c547cSRui Paulo 3505b9c547cSRui Paulo cert = os_readfile(TMP_CERT_DL_FILE, &len); 3515b9c547cSRui Paulo remove(TMP_CERT_DL_FILE); 3525b9c547cSRui Paulo if (cert == NULL) 3535b9c547cSRui Paulo return -1; 3545b9c547cSRui Paulo 3555b9c547cSRui Paulo if (sha256_vector(1, (const u8 **) &cert, &len, digest2) < 0) { 3565b9c547cSRui Paulo os_free(cert); 3575b9c547cSRui Paulo return -1; 3585b9c547cSRui Paulo } 3595b9c547cSRui Paulo 3605b9c547cSRui Paulo if (os_memcmp(digest1, digest2, sizeof(digest1)) != 0) { 3615b9c547cSRui Paulo wpa_printf(MSG_INFO, "Downloaded certificate fingerprint did not match"); 3625b9c547cSRui Paulo write_result(ctx, "Downloaded certificate fingerprint did not match"); 3635b9c547cSRui Paulo os_free(cert); 3645b9c547cSRui Paulo return -1; 3655b9c547cSRui Paulo } 3665b9c547cSRui Paulo 367*c1d255d3SCy Schubert b64 = base64_encode(cert, len, NULL); 3685b9c547cSRui Paulo os_free(cert); 3695b9c547cSRui Paulo if (b64 == NULL) 3705b9c547cSRui Paulo return -1; 3715b9c547cSRui Paulo 3725b9c547cSRui Paulo f = fopen(fname, "wb"); 3735b9c547cSRui Paulo if (f == NULL) { 3745b9c547cSRui Paulo os_free(b64); 3755b9c547cSRui Paulo return -1; 3765b9c547cSRui Paulo } 3775b9c547cSRui Paulo 3785b9c547cSRui Paulo fprintf(f, "-----BEGIN CERTIFICATE-----\n" 3795b9c547cSRui Paulo "%s" 3805b9c547cSRui Paulo "-----END CERTIFICATE-----\n", 3815b9c547cSRui Paulo b64); 3825b9c547cSRui Paulo 3835b9c547cSRui Paulo os_free(b64); 3845b9c547cSRui Paulo fclose(f); 3855b9c547cSRui Paulo 3865b9c547cSRui Paulo wpa_printf(MSG_INFO, "Downloaded certificate into %s and validated fingerprint", 3875b9c547cSRui Paulo fname); 3885b9c547cSRui Paulo write_summary(ctx, "Downloaded certificate into %s and validated fingerprint", 3895b9c547cSRui Paulo fname); 3905b9c547cSRui Paulo 3915b9c547cSRui Paulo return 0; 3925b9c547cSRui Paulo } 3935b9c547cSRui Paulo 3945b9c547cSRui Paulo 3955b9c547cSRui Paulo static int cmd_dl_osu_ca(struct hs20_osu_client *ctx, const char *pps_fname, 3965b9c547cSRui Paulo const char *ca_fname) 3975b9c547cSRui Paulo { 3985b9c547cSRui Paulo xml_node_t *pps, *node; 3995b9c547cSRui Paulo int ret; 4005b9c547cSRui Paulo 4015b9c547cSRui Paulo pps = node_from_file(ctx->xml, pps_fname); 4025b9c547cSRui Paulo if (pps == NULL) { 4035b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not read or parse '%s'", pps_fname); 4045b9c547cSRui Paulo return -1; 4055b9c547cSRui Paulo } 4065b9c547cSRui Paulo 4075b9c547cSRui Paulo node = get_child_node(ctx->xml, pps, 4085b9c547cSRui Paulo "SubscriptionUpdate/TrustRoot"); 4095b9c547cSRui Paulo if (node == NULL) { 4105b9c547cSRui Paulo wpa_printf(MSG_INFO, "No SubscriptionUpdate/TrustRoot/CertURL found from PPS"); 4115b9c547cSRui Paulo xml_node_free(ctx->xml, pps); 4125b9c547cSRui Paulo return -1; 4135b9c547cSRui Paulo } 4145b9c547cSRui Paulo 4155b9c547cSRui Paulo ret = download_cert(ctx, node, ca_fname); 4165b9c547cSRui Paulo xml_node_free(ctx->xml, pps); 4175b9c547cSRui Paulo 4185b9c547cSRui Paulo return ret; 4195b9c547cSRui Paulo } 4205b9c547cSRui Paulo 4215b9c547cSRui Paulo 4225b9c547cSRui Paulo static int cmd_dl_polupd_ca(struct hs20_osu_client *ctx, const char *pps_fname, 4235b9c547cSRui Paulo const char *ca_fname) 4245b9c547cSRui Paulo { 4255b9c547cSRui Paulo xml_node_t *pps, *node; 4265b9c547cSRui Paulo int ret; 4275b9c547cSRui Paulo 4285b9c547cSRui Paulo pps = node_from_file(ctx->xml, pps_fname); 4295b9c547cSRui Paulo if (pps == NULL) { 4305b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not read or parse '%s'", pps_fname); 4315b9c547cSRui Paulo return -1; 4325b9c547cSRui Paulo } 4335b9c547cSRui Paulo 4345b9c547cSRui Paulo node = get_child_node(ctx->xml, pps, 4355b9c547cSRui Paulo "Policy/PolicyUpdate/TrustRoot"); 4365b9c547cSRui Paulo if (node == NULL) { 4375b9c547cSRui Paulo wpa_printf(MSG_INFO, "No Policy/PolicyUpdate/TrustRoot/CertURL found from PPS"); 4385b9c547cSRui Paulo xml_node_free(ctx->xml, pps); 43985732ac8SCy Schubert return -2; 4405b9c547cSRui Paulo } 4415b9c547cSRui Paulo 4425b9c547cSRui Paulo ret = download_cert(ctx, node, ca_fname); 4435b9c547cSRui Paulo xml_node_free(ctx->xml, pps); 4445b9c547cSRui Paulo 4455b9c547cSRui Paulo return ret; 4465b9c547cSRui Paulo } 4475b9c547cSRui Paulo 4485b9c547cSRui Paulo 4495b9c547cSRui Paulo static int cmd_dl_aaa_ca(struct hs20_osu_client *ctx, const char *pps_fname, 4505b9c547cSRui Paulo const char *ca_fname) 4515b9c547cSRui Paulo { 4525b9c547cSRui Paulo xml_node_t *pps, *node, *aaa; 4535b9c547cSRui Paulo int ret; 4545b9c547cSRui Paulo 4555b9c547cSRui Paulo pps = node_from_file(ctx->xml, pps_fname); 4565b9c547cSRui Paulo if (pps == NULL) { 4575b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not read or parse '%s'", pps_fname); 4585b9c547cSRui Paulo return -1; 4595b9c547cSRui Paulo } 4605b9c547cSRui Paulo 4615b9c547cSRui Paulo node = get_child_node(ctx->xml, pps, 4625b9c547cSRui Paulo "AAAServerTrustRoot"); 4635b9c547cSRui Paulo if (node == NULL) { 4645b9c547cSRui Paulo wpa_printf(MSG_INFO, "No AAAServerTrustRoot/CertURL found from PPS"); 4655b9c547cSRui Paulo xml_node_free(ctx->xml, pps); 46685732ac8SCy Schubert return -2; 4675b9c547cSRui Paulo } 4685b9c547cSRui Paulo 4695b9c547cSRui Paulo aaa = xml_node_first_child(ctx->xml, node); 4705b9c547cSRui Paulo if (aaa == NULL) { 4715b9c547cSRui Paulo wpa_printf(MSG_INFO, "No AAAServerTrustRoot/CertURL found from PPS"); 4725b9c547cSRui Paulo xml_node_free(ctx->xml, pps); 4735b9c547cSRui Paulo return -1; 4745b9c547cSRui Paulo } 4755b9c547cSRui Paulo 4765b9c547cSRui Paulo ret = download_cert(ctx, aaa, ca_fname); 4775b9c547cSRui Paulo xml_node_free(ctx->xml, pps); 4785b9c547cSRui Paulo 4795b9c547cSRui Paulo return ret; 4805b9c547cSRui Paulo } 4815b9c547cSRui Paulo 4825b9c547cSRui Paulo 4835b9c547cSRui Paulo static int download_trust_roots(struct hs20_osu_client *ctx, 4845b9c547cSRui Paulo const char *pps_fname) 4855b9c547cSRui Paulo { 4865b9c547cSRui Paulo char *dir, *pos; 4875b9c547cSRui Paulo char fname[300]; 48885732ac8SCy Schubert int ret, ret1; 4895b9c547cSRui Paulo 4905b9c547cSRui Paulo dir = os_strdup(pps_fname); 4915b9c547cSRui Paulo if (dir == NULL) 4925b9c547cSRui Paulo return -1; 4935b9c547cSRui Paulo pos = os_strrchr(dir, '/'); 4945b9c547cSRui Paulo if (pos == NULL) { 4955b9c547cSRui Paulo os_free(dir); 4965b9c547cSRui Paulo return -1; 4975b9c547cSRui Paulo } 4985b9c547cSRui Paulo *pos = '\0'; 4995b9c547cSRui Paulo 5005b9c547cSRui Paulo snprintf(fname, sizeof(fname), "%s/ca.pem", dir); 5015b9c547cSRui Paulo ret = cmd_dl_osu_ca(ctx, pps_fname, fname); 5025b9c547cSRui Paulo snprintf(fname, sizeof(fname), "%s/polupd-ca.pem", dir); 50385732ac8SCy Schubert ret1 = cmd_dl_polupd_ca(ctx, pps_fname, fname); 50485732ac8SCy Schubert if (ret == 0 && ret1 == -1) 50585732ac8SCy Schubert ret = -1; 5065b9c547cSRui Paulo snprintf(fname, sizeof(fname), "%s/aaa-ca.pem", dir); 50785732ac8SCy Schubert ret1 = cmd_dl_aaa_ca(ctx, pps_fname, fname); 50885732ac8SCy Schubert if (ret == 0 && ret1 == -1) 50985732ac8SCy Schubert ret = -1; 5105b9c547cSRui Paulo 5115b9c547cSRui Paulo os_free(dir); 5125b9c547cSRui Paulo 5135b9c547cSRui Paulo return ret; 5145b9c547cSRui Paulo } 5155b9c547cSRui Paulo 5165b9c547cSRui Paulo 5175b9c547cSRui Paulo static int server_dnsname_suffix_match(struct hs20_osu_client *ctx, 5185b9c547cSRui Paulo const char *fqdn) 5195b9c547cSRui Paulo { 5205b9c547cSRui Paulo size_t match_len, len, i; 5215b9c547cSRui Paulo const char *val; 5225b9c547cSRui Paulo 5235b9c547cSRui Paulo match_len = os_strlen(fqdn); 5245b9c547cSRui Paulo 5255b9c547cSRui Paulo for (i = 0; i < ctx->server_dnsname_count; i++) { 5265b9c547cSRui Paulo wpa_printf(MSG_INFO, 5275b9c547cSRui Paulo "Checking suffix match against server dNSName %s", 5285b9c547cSRui Paulo ctx->server_dnsname[i]); 5295b9c547cSRui Paulo val = ctx->server_dnsname[i]; 5305b9c547cSRui Paulo len = os_strlen(val); 5315b9c547cSRui Paulo 5325b9c547cSRui Paulo if (match_len > len) 5335b9c547cSRui Paulo continue; 5345b9c547cSRui Paulo 5355b9c547cSRui Paulo if (os_strncasecmp(val + len - match_len, fqdn, match_len) != 0) 5365b9c547cSRui Paulo continue; /* no match */ 5375b9c547cSRui Paulo 5385b9c547cSRui Paulo if (match_len == len) 5395b9c547cSRui Paulo return 1; /* exact match */ 5405b9c547cSRui Paulo 5415b9c547cSRui Paulo if (val[len - match_len - 1] == '.') 5425b9c547cSRui Paulo return 1; /* full label match completes suffix match */ 5435b9c547cSRui Paulo 5445b9c547cSRui Paulo /* Reject due to incomplete label match */ 5455b9c547cSRui Paulo } 5465b9c547cSRui Paulo 5475b9c547cSRui Paulo /* None of the dNSName(s) matched */ 5485b9c547cSRui Paulo return 0; 5495b9c547cSRui Paulo } 5505b9c547cSRui Paulo 5515b9c547cSRui Paulo 5525b9c547cSRui Paulo int hs20_add_pps_mo(struct hs20_osu_client *ctx, const char *uri, 5535b9c547cSRui Paulo xml_node_t *add_mo, char *fname, size_t fname_len) 5545b9c547cSRui Paulo { 5555b9c547cSRui Paulo char *str; 5565b9c547cSRui Paulo char *fqdn, *pos; 5575b9c547cSRui Paulo xml_node_t *tnds, *mo, *cert; 5585b9c547cSRui Paulo const char *name; 5595b9c547cSRui Paulo int ret; 5605b9c547cSRui Paulo 5615b9c547cSRui Paulo if (strncmp(uri, "./Wi-Fi/", 8) != 0) { 5625b9c547cSRui Paulo wpa_printf(MSG_INFO, "Unsupported location for addMO to add PPS MO: '%s'", 5635b9c547cSRui Paulo uri); 5645b9c547cSRui Paulo write_result(ctx, "Unsupported location for addMO to add PPS MO: '%s'", 5655b9c547cSRui Paulo uri); 5665b9c547cSRui Paulo return -1; 5675b9c547cSRui Paulo } 5685b9c547cSRui Paulo 5695b9c547cSRui Paulo fqdn = strdup(uri + 8); 5705b9c547cSRui Paulo if (fqdn == NULL) 5715b9c547cSRui Paulo return -1; 5725b9c547cSRui Paulo pos = strchr(fqdn, '/'); 5735b9c547cSRui Paulo if (pos) { 5745b9c547cSRui Paulo if (os_strcasecmp(pos, "/PerProviderSubscription") != 0) { 5755b9c547cSRui Paulo wpa_printf(MSG_INFO, "Unsupported location for addMO to add PPS MO (extra directory): '%s'", 5765b9c547cSRui Paulo uri); 5775b9c547cSRui Paulo write_result(ctx, "Unsupported location for addMO to " 5785b9c547cSRui Paulo "add PPS MO (extra directory): '%s'", uri); 579325151a3SRui Paulo free(fqdn); 5805b9c547cSRui Paulo return -1; 5815b9c547cSRui Paulo } 5825b9c547cSRui Paulo *pos = '\0'; /* remove trailing slash and PPS node name */ 5835b9c547cSRui Paulo } 5845b9c547cSRui Paulo wpa_printf(MSG_INFO, "SP FQDN: %s", fqdn); 5855b9c547cSRui Paulo 5865b9c547cSRui Paulo if (!server_dnsname_suffix_match(ctx, fqdn)) { 587325151a3SRui Paulo wpa_printf(MSG_INFO, 588325151a3SRui Paulo "FQDN '%s' for new PPS MO did not have suffix match with server's dNSName values, count: %d", 589325151a3SRui Paulo fqdn, (int) ctx->server_dnsname_count); 5905b9c547cSRui Paulo write_result(ctx, "FQDN '%s' for new PPS MO did not have suffix match with server's dNSName values", 5915b9c547cSRui Paulo fqdn); 5925b9c547cSRui Paulo free(fqdn); 5935b9c547cSRui Paulo return -1; 5945b9c547cSRui Paulo } 5955b9c547cSRui Paulo 5965b9c547cSRui Paulo if (!valid_fqdn(fqdn)) { 5975b9c547cSRui Paulo wpa_printf(MSG_INFO, "Invalid FQDN '%s'", fqdn); 5985b9c547cSRui Paulo write_result(ctx, "Invalid FQDN '%s'", fqdn); 5995b9c547cSRui Paulo free(fqdn); 6005b9c547cSRui Paulo return -1; 6015b9c547cSRui Paulo } 6025b9c547cSRui Paulo 6035b9c547cSRui Paulo mkdir("SP", S_IRWXU); 6045b9c547cSRui Paulo snprintf(fname, fname_len, "SP/%s", fqdn); 6055b9c547cSRui Paulo if (mkdir(fname, S_IRWXU) < 0) { 6065b9c547cSRui Paulo if (errno != EEXIST) { 6075b9c547cSRui Paulo int err = errno; 6085b9c547cSRui Paulo wpa_printf(MSG_INFO, "mkdir(%s) failed: %s", 6095b9c547cSRui Paulo fname, strerror(err)); 6105b9c547cSRui Paulo free(fqdn); 6115b9c547cSRui Paulo return -1; 6125b9c547cSRui Paulo } 6135b9c547cSRui Paulo } 6145b9c547cSRui Paulo 6154bc52338SCy Schubert android_update_permission("SP", S_IRWXU | S_IRWXG); 6164bc52338SCy Schubert android_update_permission(fname, S_IRWXU | S_IRWXG); 6175b9c547cSRui Paulo 6185b9c547cSRui Paulo snprintf(fname, fname_len, "SP/%s/pps.xml", fqdn); 6195b9c547cSRui Paulo 6205b9c547cSRui Paulo if (os_file_exists(fname)) { 6215b9c547cSRui Paulo wpa_printf(MSG_INFO, "PPS file '%s' exists - reject addMO", 6225b9c547cSRui Paulo fname); 6235b9c547cSRui Paulo write_result(ctx, "PPS file '%s' exists - reject addMO", 6245b9c547cSRui Paulo fname); 6255b9c547cSRui Paulo free(fqdn); 6265b9c547cSRui Paulo return -2; 6275b9c547cSRui Paulo } 6285b9c547cSRui Paulo wpa_printf(MSG_INFO, "Using PPS file: %s", fname); 6295b9c547cSRui Paulo 6305b9c547cSRui Paulo str = xml_node_get_text(ctx->xml, add_mo); 6315b9c547cSRui Paulo if (str == NULL) { 6325b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not extract MO text"); 6335b9c547cSRui Paulo free(fqdn); 6345b9c547cSRui Paulo return -1; 6355b9c547cSRui Paulo } 6365b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "[hs20] addMO text: '%s'", str); 6375b9c547cSRui Paulo 6385b9c547cSRui Paulo tnds = xml_node_from_buf(ctx->xml, str); 6395b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, str); 6405b9c547cSRui Paulo if (tnds == NULL) { 6415b9c547cSRui Paulo wpa_printf(MSG_INFO, "[hs20] Could not parse addMO text"); 6425b9c547cSRui Paulo free(fqdn); 6435b9c547cSRui Paulo return -1; 6445b9c547cSRui Paulo } 6455b9c547cSRui Paulo 6465b9c547cSRui Paulo mo = tnds_to_mo(ctx->xml, tnds); 6475b9c547cSRui Paulo if (mo == NULL) { 6485b9c547cSRui Paulo wpa_printf(MSG_INFO, "[hs20] Could not parse addMO TNDS text"); 6495b9c547cSRui Paulo free(fqdn); 6505b9c547cSRui Paulo return -1; 6515b9c547cSRui Paulo } 6525b9c547cSRui Paulo 6535b9c547cSRui Paulo debug_dump_node(ctx, "Parsed TNDS", mo); 6545b9c547cSRui Paulo 6555b9c547cSRui Paulo name = xml_node_get_localname(ctx->xml, mo); 6565b9c547cSRui Paulo if (os_strcasecmp(name, "PerProviderSubscription") != 0) { 6575b9c547cSRui Paulo wpa_printf(MSG_INFO, "[hs20] Unexpected PPS MO root node name '%s'", 6585b9c547cSRui Paulo name); 6595b9c547cSRui Paulo free(fqdn); 6605b9c547cSRui Paulo return -1; 6615b9c547cSRui Paulo } 6625b9c547cSRui Paulo 6635b9c547cSRui Paulo cert = get_child_node(ctx->xml, mo, 6645b9c547cSRui Paulo "Credential/DigitalCertificate/" 6655b9c547cSRui Paulo "CertSHA256Fingerprint"); 6665b9c547cSRui Paulo if (cert && process_est_cert(ctx, cert, fqdn) < 0) { 6675b9c547cSRui Paulo xml_node_free(ctx->xml, mo); 6685b9c547cSRui Paulo free(fqdn); 6695b9c547cSRui Paulo return -1; 6705b9c547cSRui Paulo } 6715b9c547cSRui Paulo free(fqdn); 6725b9c547cSRui Paulo 6735b9c547cSRui Paulo if (node_to_file(ctx->xml, fname, mo) < 0) { 6745b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not write MO to file"); 6755b9c547cSRui Paulo xml_node_free(ctx->xml, mo); 6765b9c547cSRui Paulo return -1; 6775b9c547cSRui Paulo } 6785b9c547cSRui Paulo xml_node_free(ctx->xml, mo); 6795b9c547cSRui Paulo 6805b9c547cSRui Paulo wpa_printf(MSG_INFO, "A new PPS MO added as '%s'", fname); 6815b9c547cSRui Paulo write_summary(ctx, "A new PPS MO added as '%s'", fname); 6825b9c547cSRui Paulo 6835b9c547cSRui Paulo ret = download_trust_roots(ctx, fname); 6845b9c547cSRui Paulo if (ret < 0) { 6855b9c547cSRui Paulo wpa_printf(MSG_INFO, "Remove invalid PPS MO file"); 6865b9c547cSRui Paulo write_summary(ctx, "Remove invalid PPS MO file"); 6875b9c547cSRui Paulo unlink(fname); 6885b9c547cSRui Paulo } 6895b9c547cSRui Paulo 6905b9c547cSRui Paulo return ret; 6915b9c547cSRui Paulo } 6925b9c547cSRui Paulo 6935b9c547cSRui Paulo 6945b9c547cSRui Paulo int update_pps_file(struct hs20_osu_client *ctx, const char *pps_fname, 6955b9c547cSRui Paulo xml_node_t *pps) 6965b9c547cSRui Paulo { 6975b9c547cSRui Paulo char *str; 6985b9c547cSRui Paulo FILE *f; 6995b9c547cSRui Paulo char backup[300]; 7005b9c547cSRui Paulo 7015b9c547cSRui Paulo if (ctx->client_cert_present) { 7025b9c547cSRui Paulo xml_node_t *cert; 7035b9c547cSRui Paulo cert = get_child_node(ctx->xml, pps, 7045b9c547cSRui Paulo "Credential/DigitalCertificate/" 7055b9c547cSRui Paulo "CertSHA256Fingerprint"); 7065b9c547cSRui Paulo if (cert && os_file_exists("Cert/est_cert.der") && 7075b9c547cSRui Paulo process_est_cert(ctx, cert, ctx->fqdn) < 0) { 7085b9c547cSRui Paulo wpa_printf(MSG_INFO, "EST certificate update processing failed on PPS MO update"); 7095b9c547cSRui Paulo return -1; 7105b9c547cSRui Paulo } 7115b9c547cSRui Paulo } 7125b9c547cSRui Paulo 7135b9c547cSRui Paulo wpa_printf(MSG_INFO, "Updating PPS MO %s", pps_fname); 7145b9c547cSRui Paulo 7155b9c547cSRui Paulo str = xml_node_to_str(ctx->xml, pps); 7165b9c547cSRui Paulo if (str == NULL) { 7175b9c547cSRui Paulo wpa_printf(MSG_ERROR, "No node found"); 7185b9c547cSRui Paulo return -1; 7195b9c547cSRui Paulo } 7205b9c547cSRui Paulo wpa_printf(MSG_MSGDUMP, "[hs20] Updated PPS: '%s'", str); 7215b9c547cSRui Paulo 7225b9c547cSRui Paulo snprintf(backup, sizeof(backup), "%s.bak", pps_fname); 7235b9c547cSRui Paulo rename(pps_fname, backup); 7245b9c547cSRui Paulo f = fopen(pps_fname, "w"); 7255b9c547cSRui Paulo if (f == NULL) { 7265b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not write PPS"); 7275b9c547cSRui Paulo rename(backup, pps_fname); 7285b9c547cSRui Paulo free(str); 7295b9c547cSRui Paulo return -1; 7305b9c547cSRui Paulo } 7315b9c547cSRui Paulo fprintf(f, "%s\n", str); 7325b9c547cSRui Paulo fclose(f); 7335b9c547cSRui Paulo 7345b9c547cSRui Paulo free(str); 7355b9c547cSRui Paulo 7365b9c547cSRui Paulo return 0; 7375b9c547cSRui Paulo } 7385b9c547cSRui Paulo 7395b9c547cSRui Paulo 7405b9c547cSRui Paulo void get_user_pw(struct hs20_osu_client *ctx, xml_node_t *pps, 7415b9c547cSRui Paulo const char *alt_loc, char **user, char **pw) 7425b9c547cSRui Paulo { 7435b9c547cSRui Paulo xml_node_t *node; 7445b9c547cSRui Paulo 7455b9c547cSRui Paulo node = get_child_node(ctx->xml, pps, 7465b9c547cSRui Paulo "Credential/UsernamePassword/Username"); 7475b9c547cSRui Paulo if (node) 7485b9c547cSRui Paulo *user = xml_node_get_text(ctx->xml, node); 7495b9c547cSRui Paulo 7505b9c547cSRui Paulo node = get_child_node(ctx->xml, pps, 7515b9c547cSRui Paulo "Credential/UsernamePassword/Password"); 7525b9c547cSRui Paulo if (node) 7535b9c547cSRui Paulo *pw = xml_node_get_base64_text(ctx->xml, node, NULL); 7545b9c547cSRui Paulo 7555b9c547cSRui Paulo node = get_child_node(ctx->xml, pps, alt_loc); 7565b9c547cSRui Paulo if (node) { 7575b9c547cSRui Paulo xml_node_t *a; 7585b9c547cSRui Paulo a = get_node(ctx->xml, node, "Username"); 7595b9c547cSRui Paulo if (a) { 7605b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, *user); 7615b9c547cSRui Paulo *user = xml_node_get_text(ctx->xml, a); 7625b9c547cSRui Paulo wpa_printf(MSG_INFO, "Use OSU username '%s'", *user); 7635b9c547cSRui Paulo } 7645b9c547cSRui Paulo 7655b9c547cSRui Paulo a = get_node(ctx->xml, node, "Password"); 7665b9c547cSRui Paulo if (a) { 7675b9c547cSRui Paulo free(*pw); 7685b9c547cSRui Paulo *pw = xml_node_get_base64_text(ctx->xml, a, NULL); 7695b9c547cSRui Paulo wpa_printf(MSG_INFO, "Use OSU password"); 7705b9c547cSRui Paulo } 7715b9c547cSRui Paulo } 7725b9c547cSRui Paulo } 7735b9c547cSRui Paulo 7745b9c547cSRui Paulo 7755b9c547cSRui Paulo /* Remove old credentials based on HomeSP/FQDN */ 7765b9c547cSRui Paulo static void remove_sp_creds(struct hs20_osu_client *ctx, const char *fqdn) 7775b9c547cSRui Paulo { 7785b9c547cSRui Paulo char cmd[300]; 7795b9c547cSRui Paulo os_snprintf(cmd, sizeof(cmd), "REMOVE_CRED provisioning_sp=%s", fqdn); 7805b9c547cSRui Paulo if (wpa_command(ctx->ifname, cmd) < 0) 7815b9c547cSRui Paulo wpa_printf(MSG_INFO, "Failed to remove old credential(s)"); 7825b9c547cSRui Paulo } 7835b9c547cSRui Paulo 7845b9c547cSRui Paulo 7855b9c547cSRui Paulo static void set_pps_cred_policy_spe(struct hs20_osu_client *ctx, int id, 7865b9c547cSRui Paulo xml_node_t *spe) 7875b9c547cSRui Paulo { 7885b9c547cSRui Paulo xml_node_t *ssid; 7895b9c547cSRui Paulo char *txt; 7905b9c547cSRui Paulo 7915b9c547cSRui Paulo ssid = get_node(ctx->xml, spe, "SSID"); 7925b9c547cSRui Paulo if (ssid == NULL) 7935b9c547cSRui Paulo return; 7945b9c547cSRui Paulo txt = xml_node_get_text(ctx->xml, ssid); 7955b9c547cSRui Paulo if (txt == NULL) 7965b9c547cSRui Paulo return; 7975b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "- Policy/SPExclusionList/<X+>/SSID = %s", txt); 7985b9c547cSRui Paulo if (set_cred_quoted(ctx->ifname, id, "excluded_ssid", txt) < 0) 7995b9c547cSRui Paulo wpa_printf(MSG_INFO, "Failed to set cred excluded_ssid"); 8005b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, txt); 8015b9c547cSRui Paulo } 8025b9c547cSRui Paulo 8035b9c547cSRui Paulo 8045b9c547cSRui Paulo static void set_pps_cred_policy_spel(struct hs20_osu_client *ctx, int id, 8055b9c547cSRui Paulo xml_node_t *spel) 8065b9c547cSRui Paulo { 8075b9c547cSRui Paulo xml_node_t *child; 8085b9c547cSRui Paulo 8095b9c547cSRui Paulo xml_node_for_each_child(ctx->xml, child, spel) { 8105b9c547cSRui Paulo xml_node_for_each_check(ctx->xml, child); 8115b9c547cSRui Paulo set_pps_cred_policy_spe(ctx, id, child); 8125b9c547cSRui Paulo } 8135b9c547cSRui Paulo } 8145b9c547cSRui Paulo 8155b9c547cSRui Paulo 8165b9c547cSRui Paulo static void set_pps_cred_policy_prp(struct hs20_osu_client *ctx, int id, 8175b9c547cSRui Paulo xml_node_t *prp) 8185b9c547cSRui Paulo { 8195b9c547cSRui Paulo xml_node_t *node; 8205b9c547cSRui Paulo char *txt = NULL, *pos; 8215b9c547cSRui Paulo char *prio, *country_buf = NULL; 8225b9c547cSRui Paulo const char *country; 8235b9c547cSRui Paulo char val[200]; 8245b9c547cSRui Paulo int priority; 8255b9c547cSRui Paulo 8265b9c547cSRui Paulo node = get_node(ctx->xml, prp, "Priority"); 8275b9c547cSRui Paulo if (node == NULL) 8285b9c547cSRui Paulo return; 8295b9c547cSRui Paulo prio = xml_node_get_text(ctx->xml, node); 8305b9c547cSRui Paulo if (prio == NULL) 8315b9c547cSRui Paulo return; 8325b9c547cSRui Paulo wpa_printf(MSG_INFO, "- Policy/PreferredRoamingPartnerList/<X+>/Priority = %s", 8335b9c547cSRui Paulo prio); 8345b9c547cSRui Paulo priority = atoi(prio); 8355b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, prio); 8365b9c547cSRui Paulo 8375b9c547cSRui Paulo node = get_node(ctx->xml, prp, "Country"); 8385b9c547cSRui Paulo if (node) { 8395b9c547cSRui Paulo country_buf = xml_node_get_text(ctx->xml, node); 8405b9c547cSRui Paulo if (country_buf == NULL) 8415b9c547cSRui Paulo return; 8425b9c547cSRui Paulo country = country_buf; 8435b9c547cSRui Paulo wpa_printf(MSG_INFO, "- Policy/PreferredRoamingPartnerList/<X+>/Country = %s", 8445b9c547cSRui Paulo country); 8455b9c547cSRui Paulo } else { 8465b9c547cSRui Paulo country = "*"; 8475b9c547cSRui Paulo } 8485b9c547cSRui Paulo 8495b9c547cSRui Paulo node = get_node(ctx->xml, prp, "FQDN_Match"); 8505b9c547cSRui Paulo if (node == NULL) 8515b9c547cSRui Paulo goto out; 8525b9c547cSRui Paulo txt = xml_node_get_text(ctx->xml, node); 8535b9c547cSRui Paulo if (txt == NULL) 8545b9c547cSRui Paulo goto out; 8555b9c547cSRui Paulo wpa_printf(MSG_INFO, "- Policy/PreferredRoamingPartnerList/<X+>/FQDN_Match = %s", 8565b9c547cSRui Paulo txt); 8575b9c547cSRui Paulo pos = strrchr(txt, ','); 8585b9c547cSRui Paulo if (pos == NULL) 8595b9c547cSRui Paulo goto out; 8605b9c547cSRui Paulo *pos++ = '\0'; 8615b9c547cSRui Paulo 8625b9c547cSRui Paulo snprintf(val, sizeof(val), "%s,%d,%d,%s", txt, 8635b9c547cSRui Paulo strcmp(pos, "includeSubdomains") != 0, priority, country); 8645b9c547cSRui Paulo if (set_cred_quoted(ctx->ifname, id, "roaming_partner", val) < 0) 8655b9c547cSRui Paulo wpa_printf(MSG_INFO, "Failed to set cred roaming_partner"); 8665b9c547cSRui Paulo out: 8675b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, country_buf); 8685b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, txt); 8695b9c547cSRui Paulo } 8705b9c547cSRui Paulo 8715b9c547cSRui Paulo 8725b9c547cSRui Paulo static void set_pps_cred_policy_prpl(struct hs20_osu_client *ctx, int id, 8735b9c547cSRui Paulo xml_node_t *prpl) 8745b9c547cSRui Paulo { 8755b9c547cSRui Paulo xml_node_t *child; 8765b9c547cSRui Paulo 8775b9c547cSRui Paulo xml_node_for_each_child(ctx->xml, child, prpl) { 8785b9c547cSRui Paulo xml_node_for_each_check(ctx->xml, child); 8795b9c547cSRui Paulo set_pps_cred_policy_prp(ctx, id, child); 8805b9c547cSRui Paulo } 8815b9c547cSRui Paulo } 8825b9c547cSRui Paulo 8835b9c547cSRui Paulo 8845b9c547cSRui Paulo static void set_pps_cred_policy_min_backhaul(struct hs20_osu_client *ctx, int id, 8855b9c547cSRui Paulo xml_node_t *min_backhaul) 8865b9c547cSRui Paulo { 8875b9c547cSRui Paulo xml_node_t *node; 8885b9c547cSRui Paulo char *type, *dl = NULL, *ul = NULL; 8895b9c547cSRui Paulo int home; 8905b9c547cSRui Paulo 8915b9c547cSRui Paulo node = get_node(ctx->xml, min_backhaul, "NetworkType"); 8925b9c547cSRui Paulo if (node == NULL) { 8935b9c547cSRui Paulo wpa_printf(MSG_INFO, "Ignore MinBackhaulThreshold without mandatory NetworkType node"); 8945b9c547cSRui Paulo return; 8955b9c547cSRui Paulo } 8965b9c547cSRui Paulo 8975b9c547cSRui Paulo type = xml_node_get_text(ctx->xml, node); 8985b9c547cSRui Paulo if (type == NULL) 8995b9c547cSRui Paulo return; 9005b9c547cSRui Paulo wpa_printf(MSG_INFO, "- Policy/MinBackhaulThreshold/<X+>/NetworkType = %s", 9015b9c547cSRui Paulo type); 9025b9c547cSRui Paulo if (os_strcasecmp(type, "home") == 0) 9035b9c547cSRui Paulo home = 1; 9045b9c547cSRui Paulo else if (os_strcasecmp(type, "roaming") == 0) 9055b9c547cSRui Paulo home = 0; 9065b9c547cSRui Paulo else { 9075b9c547cSRui Paulo wpa_printf(MSG_INFO, "Ignore MinBackhaulThreshold with invalid NetworkType"); 9085b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, type); 9095b9c547cSRui Paulo return; 9105b9c547cSRui Paulo } 9115b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, type); 9125b9c547cSRui Paulo 9135b9c547cSRui Paulo node = get_node(ctx->xml, min_backhaul, "DLBandwidth"); 9145b9c547cSRui Paulo if (node) 9155b9c547cSRui Paulo dl = xml_node_get_text(ctx->xml, node); 9165b9c547cSRui Paulo 9175b9c547cSRui Paulo node = get_node(ctx->xml, min_backhaul, "ULBandwidth"); 9185b9c547cSRui Paulo if (node) 9195b9c547cSRui Paulo ul = xml_node_get_text(ctx->xml, node); 9205b9c547cSRui Paulo 9215b9c547cSRui Paulo if (dl == NULL && ul == NULL) { 9225b9c547cSRui Paulo wpa_printf(MSG_INFO, "Ignore MinBackhaulThreshold without either DLBandwidth or ULBandwidth nodes"); 9235b9c547cSRui Paulo return; 9245b9c547cSRui Paulo } 9255b9c547cSRui Paulo 9265b9c547cSRui Paulo if (dl) 9275b9c547cSRui Paulo wpa_printf(MSG_INFO, "- Policy/MinBackhaulThreshold/<X+>/DLBandwidth = %s", 9285b9c547cSRui Paulo dl); 9295b9c547cSRui Paulo if (ul) 9305b9c547cSRui Paulo wpa_printf(MSG_INFO, "- Policy/MinBackhaulThreshold/<X+>/ULBandwidth = %s", 9315b9c547cSRui Paulo ul); 9325b9c547cSRui Paulo 9335b9c547cSRui Paulo if (home) { 9345b9c547cSRui Paulo if (dl && 9355b9c547cSRui Paulo set_cred(ctx->ifname, id, "min_dl_bandwidth_home", dl) < 0) 9365b9c547cSRui Paulo wpa_printf(MSG_INFO, "Failed to set cred bandwidth limit"); 9375b9c547cSRui Paulo if (ul && 9385b9c547cSRui Paulo set_cred(ctx->ifname, id, "min_ul_bandwidth_home", ul) < 0) 9395b9c547cSRui Paulo wpa_printf(MSG_INFO, "Failed to set cred bandwidth limit"); 9405b9c547cSRui Paulo } else { 9415b9c547cSRui Paulo if (dl && 9425b9c547cSRui Paulo set_cred(ctx->ifname, id, "min_dl_bandwidth_roaming", dl) < 9435b9c547cSRui Paulo 0) 9445b9c547cSRui Paulo wpa_printf(MSG_INFO, "Failed to set cred bandwidth limit"); 9455b9c547cSRui Paulo if (ul && 9465b9c547cSRui Paulo set_cred(ctx->ifname, id, "min_ul_bandwidth_roaming", ul) < 9475b9c547cSRui Paulo 0) 9485b9c547cSRui Paulo wpa_printf(MSG_INFO, "Failed to set cred bandwidth limit"); 9495b9c547cSRui Paulo } 9505b9c547cSRui Paulo 9515b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, dl); 9525b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, ul); 9535b9c547cSRui Paulo } 9545b9c547cSRui Paulo 9555b9c547cSRui Paulo 9565b9c547cSRui Paulo static void set_pps_cred_policy_min_backhaul_list(struct hs20_osu_client *ctx, 9575b9c547cSRui Paulo int id, xml_node_t *node) 9585b9c547cSRui Paulo { 9595b9c547cSRui Paulo xml_node_t *child; 9605b9c547cSRui Paulo 9615b9c547cSRui Paulo wpa_printf(MSG_INFO, "- Policy/MinBackhaulThreshold"); 9625b9c547cSRui Paulo 9635b9c547cSRui Paulo xml_node_for_each_child(ctx->xml, child, node) { 9645b9c547cSRui Paulo xml_node_for_each_check(ctx->xml, child); 9655b9c547cSRui Paulo set_pps_cred_policy_min_backhaul(ctx, id, child); 9665b9c547cSRui Paulo } 9675b9c547cSRui Paulo } 9685b9c547cSRui Paulo 9695b9c547cSRui Paulo 9705b9c547cSRui Paulo static void set_pps_cred_policy_update(struct hs20_osu_client *ctx, int id, 9715b9c547cSRui Paulo xml_node_t *node) 9725b9c547cSRui Paulo { 9735b9c547cSRui Paulo wpa_printf(MSG_INFO, "- Policy/PolicyUpdate"); 9745b9c547cSRui Paulo /* Not used in wpa_supplicant */ 9755b9c547cSRui Paulo } 9765b9c547cSRui Paulo 9775b9c547cSRui Paulo 9785b9c547cSRui Paulo static void set_pps_cred_policy_required_proto_port(struct hs20_osu_client *ctx, 9795b9c547cSRui Paulo int id, xml_node_t *tuple) 9805b9c547cSRui Paulo { 9815b9c547cSRui Paulo xml_node_t *node; 9825b9c547cSRui Paulo char *proto, *port; 9835b9c547cSRui Paulo char *buf; 9845b9c547cSRui Paulo size_t buflen; 9855b9c547cSRui Paulo 9865b9c547cSRui Paulo node = get_node(ctx->xml, tuple, "IPProtocol"); 9875b9c547cSRui Paulo if (node == NULL) { 9885b9c547cSRui Paulo wpa_printf(MSG_INFO, "Ignore RequiredProtoPortTuple without mandatory IPProtocol node"); 9895b9c547cSRui Paulo return; 9905b9c547cSRui Paulo } 9915b9c547cSRui Paulo 9925b9c547cSRui Paulo proto = xml_node_get_text(ctx->xml, node); 9935b9c547cSRui Paulo if (proto == NULL) 9945b9c547cSRui Paulo return; 9955b9c547cSRui Paulo 9965b9c547cSRui Paulo wpa_printf(MSG_INFO, "- Policy/RequiredProtoPortTuple/<X+>/IPProtocol = %s", 9975b9c547cSRui Paulo proto); 9985b9c547cSRui Paulo 9995b9c547cSRui Paulo node = get_node(ctx->xml, tuple, "PortNumber"); 10005b9c547cSRui Paulo port = node ? xml_node_get_text(ctx->xml, node) : NULL; 10015b9c547cSRui Paulo if (port) { 10025b9c547cSRui Paulo wpa_printf(MSG_INFO, "- Policy/RequiredProtoPortTuple/<X+>/PortNumber = %s", 10035b9c547cSRui Paulo port); 10045b9c547cSRui Paulo buflen = os_strlen(proto) + os_strlen(port) + 10; 10055b9c547cSRui Paulo buf = os_malloc(buflen); 10065b9c547cSRui Paulo if (buf) 10075b9c547cSRui Paulo os_snprintf(buf, buflen, "%s:%s", proto, port); 10085b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, port); 10095b9c547cSRui Paulo } else { 10105b9c547cSRui Paulo buflen = os_strlen(proto) + 10; 10115b9c547cSRui Paulo buf = os_malloc(buflen); 10125b9c547cSRui Paulo if (buf) 10135b9c547cSRui Paulo os_snprintf(buf, buflen, "%s", proto); 10145b9c547cSRui Paulo } 10155b9c547cSRui Paulo 10165b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, proto); 10175b9c547cSRui Paulo 10185b9c547cSRui Paulo if (buf == NULL) 10195b9c547cSRui Paulo return; 10205b9c547cSRui Paulo 10215b9c547cSRui Paulo if (set_cred(ctx->ifname, id, "req_conn_capab", buf) < 0) 10225b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not set req_conn_capab"); 10235b9c547cSRui Paulo 10245b9c547cSRui Paulo os_free(buf); 10255b9c547cSRui Paulo } 10265b9c547cSRui Paulo 10275b9c547cSRui Paulo 10285b9c547cSRui Paulo static void set_pps_cred_policy_required_proto_ports(struct hs20_osu_client *ctx, 10295b9c547cSRui Paulo int id, xml_node_t *node) 10305b9c547cSRui Paulo { 10315b9c547cSRui Paulo xml_node_t *child; 10325b9c547cSRui Paulo 10335b9c547cSRui Paulo wpa_printf(MSG_INFO, "- Policy/RequiredProtoPortTuple"); 10345b9c547cSRui Paulo 10355b9c547cSRui Paulo xml_node_for_each_child(ctx->xml, child, node) { 10365b9c547cSRui Paulo xml_node_for_each_check(ctx->xml, child); 10375b9c547cSRui Paulo set_pps_cred_policy_required_proto_port(ctx, id, child); 10385b9c547cSRui Paulo } 10395b9c547cSRui Paulo } 10405b9c547cSRui Paulo 10415b9c547cSRui Paulo 10425b9c547cSRui Paulo static void set_pps_cred_policy_max_bss_load(struct hs20_osu_client *ctx, int id, 10435b9c547cSRui Paulo xml_node_t *node) 10445b9c547cSRui Paulo { 10455b9c547cSRui Paulo char *str = xml_node_get_text(ctx->xml, node); 10465b9c547cSRui Paulo if (str == NULL) 10475b9c547cSRui Paulo return; 10485b9c547cSRui Paulo wpa_printf(MSG_INFO, "- Policy/MaximumBSSLoadValue - %s", str); 10495b9c547cSRui Paulo if (set_cred(ctx->ifname, id, "max_bss_load", str) < 0) 10505b9c547cSRui Paulo wpa_printf(MSG_INFO, "Failed to set cred max_bss_load limit"); 10515b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, str); 10525b9c547cSRui Paulo } 10535b9c547cSRui Paulo 10545b9c547cSRui Paulo 10555b9c547cSRui Paulo static void set_pps_cred_policy(struct hs20_osu_client *ctx, int id, 10565b9c547cSRui Paulo xml_node_t *node) 10575b9c547cSRui Paulo { 10585b9c547cSRui Paulo xml_node_t *child; 10595b9c547cSRui Paulo const char *name; 10605b9c547cSRui Paulo 10615b9c547cSRui Paulo wpa_printf(MSG_INFO, "- Policy"); 10625b9c547cSRui Paulo 10635b9c547cSRui Paulo xml_node_for_each_child(ctx->xml, child, node) { 10645b9c547cSRui Paulo xml_node_for_each_check(ctx->xml, child); 10655b9c547cSRui Paulo name = xml_node_get_localname(ctx->xml, child); 10665b9c547cSRui Paulo if (os_strcasecmp(name, "PreferredRoamingPartnerList") == 0) 10675b9c547cSRui Paulo set_pps_cred_policy_prpl(ctx, id, child); 10685b9c547cSRui Paulo else if (os_strcasecmp(name, "MinBackhaulThreshold") == 0) 10695b9c547cSRui Paulo set_pps_cred_policy_min_backhaul_list(ctx, id, child); 10705b9c547cSRui Paulo else if (os_strcasecmp(name, "PolicyUpdate") == 0) 10715b9c547cSRui Paulo set_pps_cred_policy_update(ctx, id, child); 10725b9c547cSRui Paulo else if (os_strcasecmp(name, "SPExclusionList") == 0) 10735b9c547cSRui Paulo set_pps_cred_policy_spel(ctx, id, child); 10745b9c547cSRui Paulo else if (os_strcasecmp(name, "RequiredProtoPortTuple") == 0) 10755b9c547cSRui Paulo set_pps_cred_policy_required_proto_ports(ctx, id, child); 10765b9c547cSRui Paulo else if (os_strcasecmp(name, "MaximumBSSLoadValue") == 0) 10775b9c547cSRui Paulo set_pps_cred_policy_max_bss_load(ctx, id, child); 10785b9c547cSRui Paulo else 10795b9c547cSRui Paulo wpa_printf(MSG_INFO, "Unknown Policy node '%s'", name); 10805b9c547cSRui Paulo } 10815b9c547cSRui Paulo } 10825b9c547cSRui Paulo 10835b9c547cSRui Paulo 10845b9c547cSRui Paulo static void set_pps_cred_priority(struct hs20_osu_client *ctx, int id, 10855b9c547cSRui Paulo xml_node_t *node) 10865b9c547cSRui Paulo { 10875b9c547cSRui Paulo char *str = xml_node_get_text(ctx->xml, node); 10885b9c547cSRui Paulo if (str == NULL) 10895b9c547cSRui Paulo return; 10905b9c547cSRui Paulo wpa_printf(MSG_INFO, "- CredentialPriority = %s", str); 10915b9c547cSRui Paulo if (set_cred(ctx->ifname, id, "sp_priority", str) < 0) 10925b9c547cSRui Paulo wpa_printf(MSG_INFO, "Failed to set cred sp_priority"); 10935b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, str); 10945b9c547cSRui Paulo } 10955b9c547cSRui Paulo 10965b9c547cSRui Paulo 10975b9c547cSRui Paulo static void set_pps_cred_aaa_server_trust_root(struct hs20_osu_client *ctx, 10985b9c547cSRui Paulo int id, xml_node_t *node) 10995b9c547cSRui Paulo { 11005b9c547cSRui Paulo wpa_printf(MSG_INFO, "- AAAServerTrustRoot - TODO"); 11015b9c547cSRui Paulo } 11025b9c547cSRui Paulo 11035b9c547cSRui Paulo 11045b9c547cSRui Paulo static void set_pps_cred_sub_update(struct hs20_osu_client *ctx, int id, 11055b9c547cSRui Paulo xml_node_t *node) 11065b9c547cSRui Paulo { 11075b9c547cSRui Paulo wpa_printf(MSG_INFO, "- SubscriptionUpdate"); 11085b9c547cSRui Paulo /* not used within wpa_supplicant */ 11095b9c547cSRui Paulo } 11105b9c547cSRui Paulo 11115b9c547cSRui Paulo 11125b9c547cSRui Paulo static void set_pps_cred_home_sp_network_id(struct hs20_osu_client *ctx, 11135b9c547cSRui Paulo int id, xml_node_t *node) 11145b9c547cSRui Paulo { 11155b9c547cSRui Paulo xml_node_t *ssid_node, *hessid_node; 11165b9c547cSRui Paulo char *ssid, *hessid; 11175b9c547cSRui Paulo 11185b9c547cSRui Paulo ssid_node = get_node(ctx->xml, node, "SSID"); 11195b9c547cSRui Paulo if (ssid_node == NULL) { 11205b9c547cSRui Paulo wpa_printf(MSG_INFO, "Ignore HomeSP/NetworkID without mandatory SSID node"); 11215b9c547cSRui Paulo return; 11225b9c547cSRui Paulo } 11235b9c547cSRui Paulo 11245b9c547cSRui Paulo hessid_node = get_node(ctx->xml, node, "HESSID"); 11255b9c547cSRui Paulo 11265b9c547cSRui Paulo ssid = xml_node_get_text(ctx->xml, ssid_node); 11275b9c547cSRui Paulo if (ssid == NULL) 11285b9c547cSRui Paulo return; 11295b9c547cSRui Paulo hessid = hessid_node ? xml_node_get_text(ctx->xml, hessid_node) : NULL; 11305b9c547cSRui Paulo 11315b9c547cSRui Paulo wpa_printf(MSG_INFO, "- HomeSP/NetworkID/<X+>/SSID = %s", ssid); 11325b9c547cSRui Paulo if (hessid) 11335b9c547cSRui Paulo wpa_printf(MSG_INFO, "- HomeSP/NetworkID/<X+>/HESSID = %s", 11345b9c547cSRui Paulo hessid); 11355b9c547cSRui Paulo 11365b9c547cSRui Paulo /* TODO: Configure to wpa_supplicant */ 11375b9c547cSRui Paulo 11385b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, ssid); 11395b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, hessid); 11405b9c547cSRui Paulo } 11415b9c547cSRui Paulo 11425b9c547cSRui Paulo 11435b9c547cSRui Paulo static void set_pps_cred_home_sp_network_ids(struct hs20_osu_client *ctx, 11445b9c547cSRui Paulo int id, xml_node_t *node) 11455b9c547cSRui Paulo { 11465b9c547cSRui Paulo xml_node_t *child; 11475b9c547cSRui Paulo 11485b9c547cSRui Paulo wpa_printf(MSG_INFO, "- HomeSP/NetworkID"); 11495b9c547cSRui Paulo 11505b9c547cSRui Paulo xml_node_for_each_child(ctx->xml, child, node) { 11515b9c547cSRui Paulo xml_node_for_each_check(ctx->xml, child); 11525b9c547cSRui Paulo set_pps_cred_home_sp_network_id(ctx, id, child); 11535b9c547cSRui Paulo } 11545b9c547cSRui Paulo } 11555b9c547cSRui Paulo 11565b9c547cSRui Paulo 11575b9c547cSRui Paulo static void set_pps_cred_home_sp_friendly_name(struct hs20_osu_client *ctx, 11585b9c547cSRui Paulo int id, xml_node_t *node) 11595b9c547cSRui Paulo { 11605b9c547cSRui Paulo char *str = xml_node_get_text(ctx->xml, node); 11615b9c547cSRui Paulo if (str == NULL) 11625b9c547cSRui Paulo return; 11635b9c547cSRui Paulo wpa_printf(MSG_INFO, "- HomeSP/FriendlyName = %s", str); 11645b9c547cSRui Paulo /* not used within wpa_supplicant(?) */ 11655b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, str); 11665b9c547cSRui Paulo } 11675b9c547cSRui Paulo 11685b9c547cSRui Paulo 11695b9c547cSRui Paulo static void set_pps_cred_home_sp_icon_url(struct hs20_osu_client *ctx, 11705b9c547cSRui Paulo int id, xml_node_t *node) 11715b9c547cSRui Paulo { 11725b9c547cSRui Paulo char *str = xml_node_get_text(ctx->xml, node); 11735b9c547cSRui Paulo if (str == NULL) 11745b9c547cSRui Paulo return; 11755b9c547cSRui Paulo wpa_printf(MSG_INFO, "- HomeSP/IconURL = %s", str); 11765b9c547cSRui Paulo /* not used within wpa_supplicant */ 11775b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, str); 11785b9c547cSRui Paulo } 11795b9c547cSRui Paulo 11805b9c547cSRui Paulo 11815b9c547cSRui Paulo static void set_pps_cred_home_sp_fqdn(struct hs20_osu_client *ctx, int id, 11825b9c547cSRui Paulo xml_node_t *node) 11835b9c547cSRui Paulo { 11845b9c547cSRui Paulo char *str = xml_node_get_text(ctx->xml, node); 11855b9c547cSRui Paulo if (str == NULL) 11865b9c547cSRui Paulo return; 11875b9c547cSRui Paulo wpa_printf(MSG_INFO, "- HomeSP/FQDN = %s", str); 11885b9c547cSRui Paulo if (set_cred_quoted(ctx->ifname, id, "domain", str) < 0) 11895b9c547cSRui Paulo wpa_printf(MSG_INFO, "Failed to set cred domain"); 11905b9c547cSRui Paulo if (set_cred_quoted(ctx->ifname, id, "domain_suffix_match", str) < 0) 11915b9c547cSRui Paulo wpa_printf(MSG_INFO, "Failed to set cred domain_suffix_match"); 11925b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, str); 11935b9c547cSRui Paulo } 11945b9c547cSRui Paulo 11955b9c547cSRui Paulo 11965b9c547cSRui Paulo static void set_pps_cred_home_sp_oi(struct hs20_osu_client *ctx, int id, 11975b9c547cSRui Paulo xml_node_t *node) 11985b9c547cSRui Paulo { 11995b9c547cSRui Paulo xml_node_t *child; 12005b9c547cSRui Paulo const char *name; 12015b9c547cSRui Paulo char *homeoi = NULL; 12025b9c547cSRui Paulo int required = 0; 12035b9c547cSRui Paulo char *str; 12045b9c547cSRui Paulo 12055b9c547cSRui Paulo xml_node_for_each_child(ctx->xml, child, node) { 12065b9c547cSRui Paulo xml_node_for_each_check(ctx->xml, child); 12075b9c547cSRui Paulo name = xml_node_get_localname(ctx->xml, child); 12085b9c547cSRui Paulo if (strcasecmp(name, "HomeOI") == 0 && !homeoi) { 12095b9c547cSRui Paulo homeoi = xml_node_get_text(ctx->xml, child); 12105b9c547cSRui Paulo wpa_printf(MSG_INFO, "- HomeSP/HomeOIList/<X+>/HomeOI = %s", 12115b9c547cSRui Paulo homeoi); 12125b9c547cSRui Paulo } else if (strcasecmp(name, "HomeOIRequired") == 0) { 12135b9c547cSRui Paulo str = xml_node_get_text(ctx->xml, child); 12145b9c547cSRui Paulo wpa_printf(MSG_INFO, "- HomeSP/HomeOIList/<X+>/HomeOIRequired = '%s'", 12155b9c547cSRui Paulo str); 12165b9c547cSRui Paulo if (str == NULL) 12175b9c547cSRui Paulo continue; 12185b9c547cSRui Paulo required = strcasecmp(str, "true") == 0; 12195b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, str); 12205b9c547cSRui Paulo } else 12215b9c547cSRui Paulo wpa_printf(MSG_INFO, "Unknown HomeOIList node '%s'", 12225b9c547cSRui Paulo name); 12235b9c547cSRui Paulo } 12245b9c547cSRui Paulo 12255b9c547cSRui Paulo if (homeoi == NULL) { 12265b9c547cSRui Paulo wpa_printf(MSG_INFO, "- HomeSP/HomeOIList/<X+> without HomeOI ignored"); 12275b9c547cSRui Paulo return; 12285b9c547cSRui Paulo } 12295b9c547cSRui Paulo 12305b9c547cSRui Paulo wpa_printf(MSG_INFO, "- HomeSP/HomeOIList/<X+> '%s' required=%d", 12315b9c547cSRui Paulo homeoi, required); 12325b9c547cSRui Paulo 12335b9c547cSRui Paulo if (required) { 12345b9c547cSRui Paulo if (set_cred(ctx->ifname, id, "required_roaming_consortium", 12355b9c547cSRui Paulo homeoi) < 0) 12365b9c547cSRui Paulo wpa_printf(MSG_INFO, "Failed to set cred required_roaming_consortium"); 12375b9c547cSRui Paulo } else { 123885732ac8SCy Schubert if (set_cred(ctx->ifname, id, "roaming_consortium", homeoi) < 0) 12395b9c547cSRui Paulo wpa_printf(MSG_INFO, "Failed to set cred roaming_consortium"); 12405b9c547cSRui Paulo } 12415b9c547cSRui Paulo 12425b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, homeoi); 12435b9c547cSRui Paulo } 12445b9c547cSRui Paulo 12455b9c547cSRui Paulo 12465b9c547cSRui Paulo static void set_pps_cred_home_sp_oi_list(struct hs20_osu_client *ctx, int id, 12475b9c547cSRui Paulo xml_node_t *node) 12485b9c547cSRui Paulo { 12495b9c547cSRui Paulo xml_node_t *child; 12505b9c547cSRui Paulo 12515b9c547cSRui Paulo wpa_printf(MSG_INFO, "- HomeSP/HomeOIList"); 12525b9c547cSRui Paulo 12535b9c547cSRui Paulo xml_node_for_each_child(ctx->xml, child, node) { 12545b9c547cSRui Paulo xml_node_for_each_check(ctx->xml, child); 12555b9c547cSRui Paulo set_pps_cred_home_sp_oi(ctx, id, child); 12565b9c547cSRui Paulo } 12575b9c547cSRui Paulo } 12585b9c547cSRui Paulo 12595b9c547cSRui Paulo 12605b9c547cSRui Paulo static void set_pps_cred_home_sp_other_partner(struct hs20_osu_client *ctx, 12615b9c547cSRui Paulo int id, xml_node_t *node) 12625b9c547cSRui Paulo { 12635b9c547cSRui Paulo xml_node_t *child; 12645b9c547cSRui Paulo const char *name; 12655b9c547cSRui Paulo char *fqdn = NULL; 12665b9c547cSRui Paulo 12675b9c547cSRui Paulo xml_node_for_each_child(ctx->xml, child, node) { 12685b9c547cSRui Paulo xml_node_for_each_check(ctx->xml, child); 12695b9c547cSRui Paulo name = xml_node_get_localname(ctx->xml, child); 12705b9c547cSRui Paulo if (os_strcasecmp(name, "FQDN") == 0 && !fqdn) { 12715b9c547cSRui Paulo fqdn = xml_node_get_text(ctx->xml, child); 12725b9c547cSRui Paulo wpa_printf(MSG_INFO, "- HomeSP/OtherHomePartners/<X+>/FQDN = %s", 12735b9c547cSRui Paulo fqdn); 12745b9c547cSRui Paulo } else 12755b9c547cSRui Paulo wpa_printf(MSG_INFO, "Unknown OtherHomePartners node '%s'", 12765b9c547cSRui Paulo name); 12775b9c547cSRui Paulo } 12785b9c547cSRui Paulo 12795b9c547cSRui Paulo if (fqdn == NULL) { 12805b9c547cSRui Paulo wpa_printf(MSG_INFO, "- HomeSP/OtherHomePartners/<X+> without FQDN ignored"); 12815b9c547cSRui Paulo return; 12825b9c547cSRui Paulo } 12835b9c547cSRui Paulo 12845b9c547cSRui Paulo if (set_cred_quoted(ctx->ifname, id, "domain", fqdn) < 0) 12855b9c547cSRui Paulo wpa_printf(MSG_INFO, "Failed to set cred domain for OtherHomePartners node"); 12865b9c547cSRui Paulo 12875b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, fqdn); 12885b9c547cSRui Paulo } 12895b9c547cSRui Paulo 12905b9c547cSRui Paulo 12915b9c547cSRui Paulo static void set_pps_cred_home_sp_other_partners(struct hs20_osu_client *ctx, 12925b9c547cSRui Paulo int id, 12935b9c547cSRui Paulo xml_node_t *node) 12945b9c547cSRui Paulo { 12955b9c547cSRui Paulo xml_node_t *child; 12965b9c547cSRui Paulo 12975b9c547cSRui Paulo wpa_printf(MSG_INFO, "- HomeSP/OtherHomePartners"); 12985b9c547cSRui Paulo 12995b9c547cSRui Paulo xml_node_for_each_child(ctx->xml, child, node) { 13005b9c547cSRui Paulo xml_node_for_each_check(ctx->xml, child); 13015b9c547cSRui Paulo set_pps_cred_home_sp_other_partner(ctx, id, child); 13025b9c547cSRui Paulo } 13035b9c547cSRui Paulo } 13045b9c547cSRui Paulo 13055b9c547cSRui Paulo 13065b9c547cSRui Paulo static void set_pps_cred_home_sp_roaming_consortium_oi( 13075b9c547cSRui Paulo struct hs20_osu_client *ctx, int id, xml_node_t *node) 13085b9c547cSRui Paulo { 13095b9c547cSRui Paulo char *str = xml_node_get_text(ctx->xml, node); 13105b9c547cSRui Paulo if (str == NULL) 13115b9c547cSRui Paulo return; 13125b9c547cSRui Paulo wpa_printf(MSG_INFO, "- HomeSP/RoamingConsortiumOI = %s", str); 131385732ac8SCy Schubert if (set_cred_quoted(ctx->ifname, id, "roaming_consortiums", 131485732ac8SCy Schubert str) < 0) 131585732ac8SCy Schubert wpa_printf(MSG_INFO, "Failed to set cred roaming_consortiums"); 13165b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, str); 13175b9c547cSRui Paulo } 13185b9c547cSRui Paulo 13195b9c547cSRui Paulo 13205b9c547cSRui Paulo static void set_pps_cred_home_sp(struct hs20_osu_client *ctx, int id, 13215b9c547cSRui Paulo xml_node_t *node) 13225b9c547cSRui Paulo { 13235b9c547cSRui Paulo xml_node_t *child; 13245b9c547cSRui Paulo const char *name; 13255b9c547cSRui Paulo 13265b9c547cSRui Paulo wpa_printf(MSG_INFO, "- HomeSP"); 13275b9c547cSRui Paulo 13285b9c547cSRui Paulo xml_node_for_each_child(ctx->xml, child, node) { 13295b9c547cSRui Paulo xml_node_for_each_check(ctx->xml, child); 13305b9c547cSRui Paulo name = xml_node_get_localname(ctx->xml, child); 13315b9c547cSRui Paulo if (os_strcasecmp(name, "NetworkID") == 0) 13325b9c547cSRui Paulo set_pps_cred_home_sp_network_ids(ctx, id, child); 13335b9c547cSRui Paulo else if (os_strcasecmp(name, "FriendlyName") == 0) 13345b9c547cSRui Paulo set_pps_cred_home_sp_friendly_name(ctx, id, child); 13355b9c547cSRui Paulo else if (os_strcasecmp(name, "IconURL") == 0) 13365b9c547cSRui Paulo set_pps_cred_home_sp_icon_url(ctx, id, child); 13375b9c547cSRui Paulo else if (os_strcasecmp(name, "FQDN") == 0) 13385b9c547cSRui Paulo set_pps_cred_home_sp_fqdn(ctx, id, child); 13395b9c547cSRui Paulo else if (os_strcasecmp(name, "HomeOIList") == 0) 13405b9c547cSRui Paulo set_pps_cred_home_sp_oi_list(ctx, id, child); 13415b9c547cSRui Paulo else if (os_strcasecmp(name, "OtherHomePartners") == 0) 13425b9c547cSRui Paulo set_pps_cred_home_sp_other_partners(ctx, id, child); 13435b9c547cSRui Paulo else if (os_strcasecmp(name, "RoamingConsortiumOI") == 0) 13445b9c547cSRui Paulo set_pps_cred_home_sp_roaming_consortium_oi(ctx, id, 13455b9c547cSRui Paulo child); 13465b9c547cSRui Paulo else 13475b9c547cSRui Paulo wpa_printf(MSG_INFO, "Unknown HomeSP node '%s'", name); 13485b9c547cSRui Paulo } 13495b9c547cSRui Paulo } 13505b9c547cSRui Paulo 13515b9c547cSRui Paulo 13525b9c547cSRui Paulo static void set_pps_cred_sub_params(struct hs20_osu_client *ctx, int id, 13535b9c547cSRui Paulo xml_node_t *node) 13545b9c547cSRui Paulo { 13555b9c547cSRui Paulo wpa_printf(MSG_INFO, "- SubscriptionParameters"); 13565b9c547cSRui Paulo /* not used within wpa_supplicant */ 13575b9c547cSRui Paulo } 13585b9c547cSRui Paulo 13595b9c547cSRui Paulo 13605b9c547cSRui Paulo static void set_pps_cred_creation_date(struct hs20_osu_client *ctx, int id, 13615b9c547cSRui Paulo xml_node_t *node) 13625b9c547cSRui Paulo { 13635b9c547cSRui Paulo char *str = xml_node_get_text(ctx->xml, node); 13645b9c547cSRui Paulo if (str == NULL) 13655b9c547cSRui Paulo return; 13665b9c547cSRui Paulo wpa_printf(MSG_INFO, "- Credential/CreationDate = %s", str); 13675b9c547cSRui Paulo /* not used within wpa_supplicant */ 13685b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, str); 13695b9c547cSRui Paulo } 13705b9c547cSRui Paulo 13715b9c547cSRui Paulo 13725b9c547cSRui Paulo static void set_pps_cred_expiration_date(struct hs20_osu_client *ctx, int id, 13735b9c547cSRui Paulo xml_node_t *node) 13745b9c547cSRui Paulo { 13755b9c547cSRui Paulo char *str = xml_node_get_text(ctx->xml, node); 13765b9c547cSRui Paulo if (str == NULL) 13775b9c547cSRui Paulo return; 13785b9c547cSRui Paulo wpa_printf(MSG_INFO, "- Credential/ExpirationDate = %s", str); 13795b9c547cSRui Paulo /* not used within wpa_supplicant */ 13805b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, str); 13815b9c547cSRui Paulo } 13825b9c547cSRui Paulo 13835b9c547cSRui Paulo 13845b9c547cSRui Paulo static void set_pps_cred_username(struct hs20_osu_client *ctx, int id, 13855b9c547cSRui Paulo xml_node_t *node) 13865b9c547cSRui Paulo { 13875b9c547cSRui Paulo char *str = xml_node_get_text(ctx->xml, node); 13885b9c547cSRui Paulo if (str == NULL) 13895b9c547cSRui Paulo return; 13905b9c547cSRui Paulo wpa_printf(MSG_INFO, "- Credential/UsernamePassword/Username = %s", 13915b9c547cSRui Paulo str); 13925b9c547cSRui Paulo if (set_cred_quoted(ctx->ifname, id, "username", str) < 0) 13935b9c547cSRui Paulo wpa_printf(MSG_INFO, "Failed to set cred username"); 13945b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, str); 13955b9c547cSRui Paulo } 13965b9c547cSRui Paulo 13975b9c547cSRui Paulo 13985b9c547cSRui Paulo static void set_pps_cred_password(struct hs20_osu_client *ctx, int id, 13995b9c547cSRui Paulo xml_node_t *node) 14005b9c547cSRui Paulo { 14015b9c547cSRui Paulo int len, i; 14025b9c547cSRui Paulo char *pw, *hex, *pos, *end; 14035b9c547cSRui Paulo 14045b9c547cSRui Paulo pw = xml_node_get_base64_text(ctx->xml, node, &len); 14055b9c547cSRui Paulo if (pw == NULL) 14065b9c547cSRui Paulo return; 14075b9c547cSRui Paulo 14085b9c547cSRui Paulo wpa_printf(MSG_INFO, "- Credential/UsernamePassword/Password = %s", pw); 14095b9c547cSRui Paulo 14105b9c547cSRui Paulo hex = malloc(len * 2 + 1); 14115b9c547cSRui Paulo if (hex == NULL) { 14125b9c547cSRui Paulo free(pw); 14135b9c547cSRui Paulo return; 14145b9c547cSRui Paulo } 14155b9c547cSRui Paulo end = hex + len * 2 + 1; 14165b9c547cSRui Paulo pos = hex; 14175b9c547cSRui Paulo for (i = 0; i < len; i++) { 14185b9c547cSRui Paulo snprintf(pos, end - pos, "%02x", pw[i]); 14195b9c547cSRui Paulo pos += 2; 14205b9c547cSRui Paulo } 14215b9c547cSRui Paulo free(pw); 14225b9c547cSRui Paulo 14235b9c547cSRui Paulo if (set_cred(ctx->ifname, id, "password", hex) < 0) 14245b9c547cSRui Paulo wpa_printf(MSG_INFO, "Failed to set cred password"); 14255b9c547cSRui Paulo free(hex); 14265b9c547cSRui Paulo } 14275b9c547cSRui Paulo 14285b9c547cSRui Paulo 14295b9c547cSRui Paulo static void set_pps_cred_machine_managed(struct hs20_osu_client *ctx, int id, 14305b9c547cSRui Paulo xml_node_t *node) 14315b9c547cSRui Paulo { 14325b9c547cSRui Paulo char *str = xml_node_get_text(ctx->xml, node); 14335b9c547cSRui Paulo if (str == NULL) 14345b9c547cSRui Paulo return; 14355b9c547cSRui Paulo wpa_printf(MSG_INFO, "- Credential/UsernamePassword/MachineManaged = %s", 14365b9c547cSRui Paulo str); 14375b9c547cSRui Paulo /* not used within wpa_supplicant */ 14385b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, str); 14395b9c547cSRui Paulo } 14405b9c547cSRui Paulo 14415b9c547cSRui Paulo 14425b9c547cSRui Paulo static void set_pps_cred_soft_token_app(struct hs20_osu_client *ctx, int id, 14435b9c547cSRui Paulo xml_node_t *node) 14445b9c547cSRui Paulo { 14455b9c547cSRui Paulo char *str = xml_node_get_text(ctx->xml, node); 14465b9c547cSRui Paulo if (str == NULL) 14475b9c547cSRui Paulo return; 14485b9c547cSRui Paulo wpa_printf(MSG_INFO, "- Credential/UsernamePassword/SoftTokenApp = %s", 14495b9c547cSRui Paulo str); 14505b9c547cSRui Paulo /* not used within wpa_supplicant */ 14515b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, str); 14525b9c547cSRui Paulo } 14535b9c547cSRui Paulo 14545b9c547cSRui Paulo 14555b9c547cSRui Paulo static void set_pps_cred_able_to_share(struct hs20_osu_client *ctx, int id, 14565b9c547cSRui Paulo xml_node_t *node) 14575b9c547cSRui Paulo { 14585b9c547cSRui Paulo char *str = xml_node_get_text(ctx->xml, node); 14595b9c547cSRui Paulo if (str == NULL) 14605b9c547cSRui Paulo return; 14615b9c547cSRui Paulo wpa_printf(MSG_INFO, "- Credential/UsernamePassword/AbleToShare = %s", 14625b9c547cSRui Paulo str); 14635b9c547cSRui Paulo /* not used within wpa_supplicant */ 14645b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, str); 14655b9c547cSRui Paulo } 14665b9c547cSRui Paulo 14675b9c547cSRui Paulo 146885732ac8SCy Schubert static void set_pps_cred_eap_method_eap_type(struct hs20_osu_client *ctx, 146985732ac8SCy Schubert int id, xml_node_t *node) 147085732ac8SCy Schubert { 147185732ac8SCy Schubert char *str = xml_node_get_text(ctx->xml, node); 147285732ac8SCy Schubert int type; 147385732ac8SCy Schubert const char *eap_method = NULL; 147485732ac8SCy Schubert 147585732ac8SCy Schubert if (!str) 147685732ac8SCy Schubert return; 147785732ac8SCy Schubert wpa_printf(MSG_INFO, 147885732ac8SCy Schubert "- Credential/UsernamePassword/EAPMethod/EAPType = %s", str); 147985732ac8SCy Schubert type = atoi(str); 148085732ac8SCy Schubert switch (type) { 148185732ac8SCy Schubert case EAP_TYPE_TLS: 148285732ac8SCy Schubert eap_method = "TLS"; 148385732ac8SCy Schubert break; 148485732ac8SCy Schubert case EAP_TYPE_TTLS: 148585732ac8SCy Schubert eap_method = "TTLS"; 148685732ac8SCy Schubert break; 148785732ac8SCy Schubert case EAP_TYPE_PEAP: 148885732ac8SCy Schubert eap_method = "PEAP"; 148985732ac8SCy Schubert break; 149085732ac8SCy Schubert case EAP_TYPE_PWD: 149185732ac8SCy Schubert eap_method = "PWD"; 149285732ac8SCy Schubert break; 149385732ac8SCy Schubert } 149485732ac8SCy Schubert xml_node_get_text_free(ctx->xml, str); 149585732ac8SCy Schubert if (!eap_method) { 149685732ac8SCy Schubert wpa_printf(MSG_INFO, "Unknown EAPType value"); 149785732ac8SCy Schubert return; 149885732ac8SCy Schubert } 149985732ac8SCy Schubert 150085732ac8SCy Schubert if (set_cred(ctx->ifname, id, "eap", eap_method) < 0) 150185732ac8SCy Schubert wpa_printf(MSG_INFO, "Failed to set cred eap"); 150285732ac8SCy Schubert } 150385732ac8SCy Schubert 150485732ac8SCy Schubert 150585732ac8SCy Schubert static void set_pps_cred_eap_method_inner_method(struct hs20_osu_client *ctx, 150685732ac8SCy Schubert int id, xml_node_t *node) 150785732ac8SCy Schubert { 150885732ac8SCy Schubert char *str = xml_node_get_text(ctx->xml, node); 150985732ac8SCy Schubert const char *phase2 = NULL; 151085732ac8SCy Schubert 151185732ac8SCy Schubert if (!str) 151285732ac8SCy Schubert return; 151385732ac8SCy Schubert wpa_printf(MSG_INFO, 151485732ac8SCy Schubert "- Credential/UsernamePassword/EAPMethod/InnerMethod = %s", 151585732ac8SCy Schubert str); 151685732ac8SCy Schubert if (os_strcmp(str, "PAP") == 0) 151785732ac8SCy Schubert phase2 = "auth=PAP"; 151885732ac8SCy Schubert else if (os_strcmp(str, "CHAP") == 0) 151985732ac8SCy Schubert phase2 = "auth=CHAP"; 152085732ac8SCy Schubert else if (os_strcmp(str, "MS-CHAP") == 0) 152185732ac8SCy Schubert phase2 = "auth=MSCHAP"; 152285732ac8SCy Schubert else if (os_strcmp(str, "MS-CHAP-V2") == 0) 152385732ac8SCy Schubert phase2 = "auth=MSCHAPV2"; 152485732ac8SCy Schubert xml_node_get_text_free(ctx->xml, str); 152585732ac8SCy Schubert if (!phase2) { 152685732ac8SCy Schubert wpa_printf(MSG_INFO, "Unknown InnerMethod value"); 152785732ac8SCy Schubert return; 152885732ac8SCy Schubert } 152985732ac8SCy Schubert 153085732ac8SCy Schubert if (set_cred_quoted(ctx->ifname, id, "phase2", phase2) < 0) 153185732ac8SCy Schubert wpa_printf(MSG_INFO, "Failed to set cred phase2"); 153285732ac8SCy Schubert } 153385732ac8SCy Schubert 153485732ac8SCy Schubert 15355b9c547cSRui Paulo static void set_pps_cred_eap_method(struct hs20_osu_client *ctx, int id, 15365b9c547cSRui Paulo xml_node_t *node) 15375b9c547cSRui Paulo { 153885732ac8SCy Schubert xml_node_t *child; 153985732ac8SCy Schubert const char *name; 154085732ac8SCy Schubert 154185732ac8SCy Schubert wpa_printf(MSG_INFO, "- Credential/UsernamePassword/EAPMethod"); 154285732ac8SCy Schubert 154385732ac8SCy Schubert xml_node_for_each_child(ctx->xml, child, node) { 154485732ac8SCy Schubert xml_node_for_each_check(ctx->xml, child); 154585732ac8SCy Schubert name = xml_node_get_localname(ctx->xml, child); 154685732ac8SCy Schubert if (os_strcasecmp(name, "EAPType") == 0) 154785732ac8SCy Schubert set_pps_cred_eap_method_eap_type(ctx, id, child); 154885732ac8SCy Schubert else if (os_strcasecmp(name, "InnerMethod") == 0) 154985732ac8SCy Schubert set_pps_cred_eap_method_inner_method(ctx, id, child); 155085732ac8SCy Schubert else 155185732ac8SCy Schubert wpa_printf(MSG_INFO, "Unknown Credential/UsernamePassword/EAPMethod node '%s'", 155285732ac8SCy Schubert name); 155385732ac8SCy Schubert } 15545b9c547cSRui Paulo } 15555b9c547cSRui Paulo 15565b9c547cSRui Paulo 15575b9c547cSRui Paulo static void set_pps_cred_username_password(struct hs20_osu_client *ctx, int id, 15585b9c547cSRui Paulo xml_node_t *node) 15595b9c547cSRui Paulo { 15605b9c547cSRui Paulo xml_node_t *child; 15615b9c547cSRui Paulo const char *name; 15625b9c547cSRui Paulo 15635b9c547cSRui Paulo wpa_printf(MSG_INFO, "- Credential/UsernamePassword"); 15645b9c547cSRui Paulo 15655b9c547cSRui Paulo xml_node_for_each_child(ctx->xml, child, node) { 15665b9c547cSRui Paulo xml_node_for_each_check(ctx->xml, child); 15675b9c547cSRui Paulo name = xml_node_get_localname(ctx->xml, child); 15685b9c547cSRui Paulo if (os_strcasecmp(name, "Username") == 0) 15695b9c547cSRui Paulo set_pps_cred_username(ctx, id, child); 15705b9c547cSRui Paulo else if (os_strcasecmp(name, "Password") == 0) 15715b9c547cSRui Paulo set_pps_cred_password(ctx, id, child); 15725b9c547cSRui Paulo else if (os_strcasecmp(name, "MachineManaged") == 0) 15735b9c547cSRui Paulo set_pps_cred_machine_managed(ctx, id, child); 15745b9c547cSRui Paulo else if (os_strcasecmp(name, "SoftTokenApp") == 0) 15755b9c547cSRui Paulo set_pps_cred_soft_token_app(ctx, id, child); 15765b9c547cSRui Paulo else if (os_strcasecmp(name, "AbleToShare") == 0) 15775b9c547cSRui Paulo set_pps_cred_able_to_share(ctx, id, child); 15785b9c547cSRui Paulo else if (os_strcasecmp(name, "EAPMethod") == 0) 15795b9c547cSRui Paulo set_pps_cred_eap_method(ctx, id, child); 15805b9c547cSRui Paulo else 15815b9c547cSRui Paulo wpa_printf(MSG_INFO, "Unknown Credential/UsernamePassword node '%s'", 15825b9c547cSRui Paulo name); 15835b9c547cSRui Paulo } 15845b9c547cSRui Paulo } 15855b9c547cSRui Paulo 15865b9c547cSRui Paulo 15875b9c547cSRui Paulo static void set_pps_cred_digital_cert(struct hs20_osu_client *ctx, int id, 15885b9c547cSRui Paulo xml_node_t *node, const char *fqdn) 15895b9c547cSRui Paulo { 15905b9c547cSRui Paulo char buf[200], dir[200]; 1591206b73d0SCy Schubert int res; 15925b9c547cSRui Paulo 15935b9c547cSRui Paulo wpa_printf(MSG_INFO, "- Credential/DigitalCertificate"); 15945b9c547cSRui Paulo 15955b9c547cSRui Paulo if (getcwd(dir, sizeof(dir)) == NULL) 15965b9c547cSRui Paulo return; 15975b9c547cSRui Paulo 15985b9c547cSRui Paulo /* TODO: could build username from Subject of Subject AltName */ 15995b9c547cSRui Paulo if (set_cred_quoted(ctx->ifname, id, "username", "cert") < 0) { 16005b9c547cSRui Paulo wpa_printf(MSG_INFO, "Failed to set username"); 16015b9c547cSRui Paulo } 16025b9c547cSRui Paulo 1603206b73d0SCy Schubert res = os_snprintf(buf, sizeof(buf), "%s/SP/%s/client-cert.pem", dir, 1604206b73d0SCy Schubert fqdn); 1605206b73d0SCy Schubert if (os_snprintf_error(sizeof(buf), res)) 1606206b73d0SCy Schubert return; 16075b9c547cSRui Paulo if (os_file_exists(buf)) { 16085b9c547cSRui Paulo if (set_cred_quoted(ctx->ifname, id, "client_cert", buf) < 0) { 16095b9c547cSRui Paulo wpa_printf(MSG_INFO, "Failed to set client_cert"); 16105b9c547cSRui Paulo } 16115b9c547cSRui Paulo } 16125b9c547cSRui Paulo 1613206b73d0SCy Schubert res = os_snprintf(buf, sizeof(buf), "%s/SP/%s/client-key.pem", dir, 1614206b73d0SCy Schubert fqdn); 1615206b73d0SCy Schubert if (os_snprintf_error(sizeof(buf), res)) 1616206b73d0SCy Schubert return; 16175b9c547cSRui Paulo if (os_file_exists(buf)) { 16185b9c547cSRui Paulo if (set_cred_quoted(ctx->ifname, id, "private_key", buf) < 0) { 16195b9c547cSRui Paulo wpa_printf(MSG_INFO, "Failed to set private_key"); 16205b9c547cSRui Paulo } 16215b9c547cSRui Paulo } 16225b9c547cSRui Paulo } 16235b9c547cSRui Paulo 16245b9c547cSRui Paulo 16255b9c547cSRui Paulo static void set_pps_cred_realm(struct hs20_osu_client *ctx, int id, 16265b9c547cSRui Paulo xml_node_t *node, const char *fqdn, int sim) 16275b9c547cSRui Paulo { 16285b9c547cSRui Paulo char *str = xml_node_get_text(ctx->xml, node); 16295b9c547cSRui Paulo char buf[200], dir[200]; 1630206b73d0SCy Schubert int res; 16315b9c547cSRui Paulo 16325b9c547cSRui Paulo if (str == NULL) 16335b9c547cSRui Paulo return; 16345b9c547cSRui Paulo 16355b9c547cSRui Paulo wpa_printf(MSG_INFO, "- Credential/Realm = %s", str); 16365b9c547cSRui Paulo if (set_cred_quoted(ctx->ifname, id, "realm", str) < 0) 16375b9c547cSRui Paulo wpa_printf(MSG_INFO, "Failed to set cred realm"); 16385b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, str); 16395b9c547cSRui Paulo 16405b9c547cSRui Paulo if (sim) 16415b9c547cSRui Paulo return; 16425b9c547cSRui Paulo 16435b9c547cSRui Paulo if (getcwd(dir, sizeof(dir)) == NULL) 16445b9c547cSRui Paulo return; 1645206b73d0SCy Schubert res = os_snprintf(buf, sizeof(buf), "%s/SP/%s/aaa-ca.pem", dir, fqdn); 1646206b73d0SCy Schubert if (os_snprintf_error(sizeof(buf), res)) 1647206b73d0SCy Schubert return; 16485b9c547cSRui Paulo if (os_file_exists(buf)) { 16495b9c547cSRui Paulo if (set_cred_quoted(ctx->ifname, id, "ca_cert", buf) < 0) { 16505b9c547cSRui Paulo wpa_printf(MSG_INFO, "Failed to set CA cert"); 16515b9c547cSRui Paulo } 16525b9c547cSRui Paulo } 16535b9c547cSRui Paulo } 16545b9c547cSRui Paulo 16555b9c547cSRui Paulo 16565b9c547cSRui Paulo static void set_pps_cred_check_aaa_cert_status(struct hs20_osu_client *ctx, 16575b9c547cSRui Paulo int id, xml_node_t *node) 16585b9c547cSRui Paulo { 16595b9c547cSRui Paulo char *str = xml_node_get_text(ctx->xml, node); 16605b9c547cSRui Paulo 16615b9c547cSRui Paulo if (str == NULL) 16625b9c547cSRui Paulo return; 16635b9c547cSRui Paulo 16645b9c547cSRui Paulo wpa_printf(MSG_INFO, "- Credential/CheckAAAServerCertStatus = %s", str); 16655b9c547cSRui Paulo if (os_strcasecmp(str, "true") == 0 && 16665b9c547cSRui Paulo set_cred(ctx->ifname, id, "ocsp", "2") < 0) 16675b9c547cSRui Paulo wpa_printf(MSG_INFO, "Failed to set cred ocsp"); 16685b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, str); 16695b9c547cSRui Paulo } 16705b9c547cSRui Paulo 16715b9c547cSRui Paulo 16725b9c547cSRui Paulo static void set_pps_cred_sim(struct hs20_osu_client *ctx, int id, 16735b9c547cSRui Paulo xml_node_t *sim, xml_node_t *realm) 16745b9c547cSRui Paulo { 16755b9c547cSRui Paulo xml_node_t *node; 16765b9c547cSRui Paulo char *imsi, *eaptype, *str, buf[20]; 16775b9c547cSRui Paulo int type; 16785b9c547cSRui Paulo int mnc_len = 3; 16795b9c547cSRui Paulo size_t imsi_len; 16805b9c547cSRui Paulo 16815b9c547cSRui Paulo node = get_node(ctx->xml, sim, "EAPType"); 16825b9c547cSRui Paulo if (node == NULL) { 16835b9c547cSRui Paulo wpa_printf(MSG_INFO, "No SIM/EAPType node in credential"); 16845b9c547cSRui Paulo return; 16855b9c547cSRui Paulo } 16865b9c547cSRui Paulo eaptype = xml_node_get_text(ctx->xml, node); 16875b9c547cSRui Paulo if (eaptype == NULL) { 16885b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not extract SIM/EAPType"); 16895b9c547cSRui Paulo return; 16905b9c547cSRui Paulo } 16915b9c547cSRui Paulo wpa_printf(MSG_INFO, " - Credential/SIM/EAPType = %s", eaptype); 16925b9c547cSRui Paulo type = atoi(eaptype); 16935b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, eaptype); 16945b9c547cSRui Paulo 16955b9c547cSRui Paulo switch (type) { 16965b9c547cSRui Paulo case EAP_TYPE_SIM: 16975b9c547cSRui Paulo if (set_cred(ctx->ifname, id, "eap", "SIM") < 0) 16985b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not set eap=SIM"); 16995b9c547cSRui Paulo break; 17005b9c547cSRui Paulo case EAP_TYPE_AKA: 17015b9c547cSRui Paulo if (set_cred(ctx->ifname, id, "eap", "AKA") < 0) 17025b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not set eap=SIM"); 17035b9c547cSRui Paulo break; 17045b9c547cSRui Paulo case EAP_TYPE_AKA_PRIME: 17055b9c547cSRui Paulo if (set_cred(ctx->ifname, id, "eap", "AKA'") < 0) 17065b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not set eap=SIM"); 17075b9c547cSRui Paulo break; 17085b9c547cSRui Paulo default: 17095b9c547cSRui Paulo wpa_printf(MSG_INFO, "Unsupported SIM/EAPType %d", type); 17105b9c547cSRui Paulo return; 17115b9c547cSRui Paulo } 17125b9c547cSRui Paulo 17135b9c547cSRui Paulo node = get_node(ctx->xml, sim, "IMSI"); 17145b9c547cSRui Paulo if (node == NULL) { 17155b9c547cSRui Paulo wpa_printf(MSG_INFO, "No SIM/IMSI node in credential"); 17165b9c547cSRui Paulo return; 17175b9c547cSRui Paulo } 17185b9c547cSRui Paulo imsi = xml_node_get_text(ctx->xml, node); 17195b9c547cSRui Paulo if (imsi == NULL) { 17205b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not extract SIM/IMSI"); 17215b9c547cSRui Paulo return; 17225b9c547cSRui Paulo } 17235b9c547cSRui Paulo wpa_printf(MSG_INFO, " - Credential/SIM/IMSI = %s", imsi); 17245b9c547cSRui Paulo imsi_len = os_strlen(imsi); 17255b9c547cSRui Paulo if (imsi_len < 7 || imsi_len + 2 > sizeof(buf)) { 17265b9c547cSRui Paulo wpa_printf(MSG_INFO, "Invalid IMSI length"); 17275b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, imsi); 17285b9c547cSRui Paulo return; 17295b9c547cSRui Paulo } 17305b9c547cSRui Paulo 17315b9c547cSRui Paulo str = xml_node_get_text(ctx->xml, node); 17325b9c547cSRui Paulo if (str) { 17335b9c547cSRui Paulo char *pos; 17345b9c547cSRui Paulo pos = os_strstr(str, "mnc"); 17355b9c547cSRui Paulo if (pos && os_strlen(pos) >= 6) { 17365b9c547cSRui Paulo if (os_strncmp(imsi + 3, pos + 3, 3) == 0) 17375b9c547cSRui Paulo mnc_len = 3; 17385b9c547cSRui Paulo else if (os_strncmp(imsi + 3, pos + 4, 2) == 0) 17395b9c547cSRui Paulo mnc_len = 2; 17405b9c547cSRui Paulo } 17415b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, str); 17425b9c547cSRui Paulo } 17435b9c547cSRui Paulo 17445b9c547cSRui Paulo os_memcpy(buf, imsi, 3 + mnc_len); 17455b9c547cSRui Paulo buf[3 + mnc_len] = '-'; 17465b9c547cSRui Paulo os_strlcpy(buf + 3 + mnc_len + 1, imsi + 3 + mnc_len, 17475b9c547cSRui Paulo sizeof(buf) - 3 - mnc_len - 1); 17485b9c547cSRui Paulo 17495b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, imsi); 17505b9c547cSRui Paulo 17515b9c547cSRui Paulo if (set_cred_quoted(ctx->ifname, id, "imsi", buf) < 0) 17525b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not set IMSI"); 17535b9c547cSRui Paulo 17545b9c547cSRui Paulo if (set_cred_quoted(ctx->ifname, id, "milenage", 17555b9c547cSRui Paulo "90dca4eda45b53cf0f12d7c9c3bc6a89:" 17565b9c547cSRui Paulo "cb9cccc4b9258e6dca4760379fb82581:000000000123") < 17575b9c547cSRui Paulo 0) 17585b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not set Milenage parameters"); 17595b9c547cSRui Paulo } 17605b9c547cSRui Paulo 17615b9c547cSRui Paulo 17625b9c547cSRui Paulo static void set_pps_cred_credential(struct hs20_osu_client *ctx, int id, 17635b9c547cSRui Paulo xml_node_t *node, const char *fqdn) 17645b9c547cSRui Paulo { 17655b9c547cSRui Paulo xml_node_t *child, *sim, *realm; 17665b9c547cSRui Paulo const char *name; 17675b9c547cSRui Paulo 17685b9c547cSRui Paulo wpa_printf(MSG_INFO, "- Credential"); 17695b9c547cSRui Paulo 17705b9c547cSRui Paulo sim = get_node(ctx->xml, node, "SIM"); 17715b9c547cSRui Paulo realm = get_node(ctx->xml, node, "Realm"); 17725b9c547cSRui Paulo 17735b9c547cSRui Paulo xml_node_for_each_child(ctx->xml, child, node) { 17745b9c547cSRui Paulo xml_node_for_each_check(ctx->xml, child); 17755b9c547cSRui Paulo name = xml_node_get_localname(ctx->xml, child); 17765b9c547cSRui Paulo if (os_strcasecmp(name, "CreationDate") == 0) 17775b9c547cSRui Paulo set_pps_cred_creation_date(ctx, id, child); 17785b9c547cSRui Paulo else if (os_strcasecmp(name, "ExpirationDate") == 0) 17795b9c547cSRui Paulo set_pps_cred_expiration_date(ctx, id, child); 17805b9c547cSRui Paulo else if (os_strcasecmp(name, "UsernamePassword") == 0) 17815b9c547cSRui Paulo set_pps_cred_username_password(ctx, id, child); 17825b9c547cSRui Paulo else if (os_strcasecmp(name, "DigitalCertificate") == 0) 17835b9c547cSRui Paulo set_pps_cred_digital_cert(ctx, id, child, fqdn); 17845b9c547cSRui Paulo else if (os_strcasecmp(name, "Realm") == 0) 17855b9c547cSRui Paulo set_pps_cred_realm(ctx, id, child, fqdn, sim != NULL); 17865b9c547cSRui Paulo else if (os_strcasecmp(name, "CheckAAAServerCertStatus") == 0) 17875b9c547cSRui Paulo set_pps_cred_check_aaa_cert_status(ctx, id, child); 17885b9c547cSRui Paulo else if (os_strcasecmp(name, "SIM") == 0) 17895b9c547cSRui Paulo set_pps_cred_sim(ctx, id, child, realm); 17905b9c547cSRui Paulo else 17915b9c547cSRui Paulo wpa_printf(MSG_INFO, "Unknown Credential node '%s'", 17925b9c547cSRui Paulo name); 17935b9c547cSRui Paulo } 17945b9c547cSRui Paulo } 17955b9c547cSRui Paulo 17965b9c547cSRui Paulo 17975b9c547cSRui Paulo static void set_pps_credential(struct hs20_osu_client *ctx, int id, 17985b9c547cSRui Paulo xml_node_t *cred, const char *fqdn) 17995b9c547cSRui Paulo { 18005b9c547cSRui Paulo xml_node_t *child; 18015b9c547cSRui Paulo const char *name; 18025b9c547cSRui Paulo 18035b9c547cSRui Paulo xml_node_for_each_child(ctx->xml, child, cred) { 18045b9c547cSRui Paulo xml_node_for_each_check(ctx->xml, child); 18055b9c547cSRui Paulo name = xml_node_get_localname(ctx->xml, child); 18065b9c547cSRui Paulo if (os_strcasecmp(name, "Policy") == 0) 18075b9c547cSRui Paulo set_pps_cred_policy(ctx, id, child); 18085b9c547cSRui Paulo else if (os_strcasecmp(name, "CredentialPriority") == 0) 18095b9c547cSRui Paulo set_pps_cred_priority(ctx, id, child); 18105b9c547cSRui Paulo else if (os_strcasecmp(name, "AAAServerTrustRoot") == 0) 18115b9c547cSRui Paulo set_pps_cred_aaa_server_trust_root(ctx, id, child); 18125b9c547cSRui Paulo else if (os_strcasecmp(name, "SubscriptionUpdate") == 0) 18135b9c547cSRui Paulo set_pps_cred_sub_update(ctx, id, child); 18145b9c547cSRui Paulo else if (os_strcasecmp(name, "HomeSP") == 0) 18155b9c547cSRui Paulo set_pps_cred_home_sp(ctx, id, child); 18165b9c547cSRui Paulo else if (os_strcasecmp(name, "SubscriptionParameters") == 0) 18175b9c547cSRui Paulo set_pps_cred_sub_params(ctx, id, child); 18185b9c547cSRui Paulo else if (os_strcasecmp(name, "Credential") == 0) 18195b9c547cSRui Paulo set_pps_cred_credential(ctx, id, child, fqdn); 18205b9c547cSRui Paulo else 18215b9c547cSRui Paulo wpa_printf(MSG_INFO, "Unknown credential node '%s'", 18225b9c547cSRui Paulo name); 18235b9c547cSRui Paulo } 18245b9c547cSRui Paulo } 18255b9c547cSRui Paulo 18265b9c547cSRui Paulo 18275b9c547cSRui Paulo static void set_pps(struct hs20_osu_client *ctx, xml_node_t *pps, 18285b9c547cSRui Paulo const char *fqdn) 18295b9c547cSRui Paulo { 18305b9c547cSRui Paulo xml_node_t *child; 18315b9c547cSRui Paulo const char *name; 18325b9c547cSRui Paulo int id; 18335b9c547cSRui Paulo char *update_identifier = NULL; 18345b9c547cSRui Paulo 18355b9c547cSRui Paulo /* 18365b9c547cSRui Paulo * TODO: Could consider more complex mechanism that would remove 18375b9c547cSRui Paulo * credentials only if there are changes in the information sent to 18385b9c547cSRui Paulo * wpa_supplicant. 18395b9c547cSRui Paulo */ 18405b9c547cSRui Paulo remove_sp_creds(ctx, fqdn); 18415b9c547cSRui Paulo 18425b9c547cSRui Paulo xml_node_for_each_child(ctx->xml, child, pps) { 18435b9c547cSRui Paulo xml_node_for_each_check(ctx->xml, child); 18445b9c547cSRui Paulo name = xml_node_get_localname(ctx->xml, child); 18455b9c547cSRui Paulo if (os_strcasecmp(name, "UpdateIdentifier") == 0) { 18465b9c547cSRui Paulo update_identifier = xml_node_get_text(ctx->xml, child); 18475b9c547cSRui Paulo if (update_identifier) { 18485b9c547cSRui Paulo wpa_printf(MSG_INFO, "- UpdateIdentifier = %s", 18495b9c547cSRui Paulo update_identifier); 18505b9c547cSRui Paulo break; 18515b9c547cSRui Paulo } 18525b9c547cSRui Paulo } 18535b9c547cSRui Paulo } 18545b9c547cSRui Paulo 18555b9c547cSRui Paulo xml_node_for_each_child(ctx->xml, child, pps) { 18565b9c547cSRui Paulo xml_node_for_each_check(ctx->xml, child); 18575b9c547cSRui Paulo name = xml_node_get_localname(ctx->xml, child); 18585b9c547cSRui Paulo if (os_strcasecmp(name, "UpdateIdentifier") == 0) 18595b9c547cSRui Paulo continue; 18605b9c547cSRui Paulo id = add_cred(ctx->ifname); 18615b9c547cSRui Paulo if (id < 0) { 18625b9c547cSRui Paulo wpa_printf(MSG_INFO, "Failed to add credential to wpa_supplicant"); 18635b9c547cSRui Paulo write_summary(ctx, "Failed to add credential to wpa_supplicant"); 18645b9c547cSRui Paulo break; 18655b9c547cSRui Paulo } 18665b9c547cSRui Paulo write_summary(ctx, "Add a credential to wpa_supplicant"); 18675b9c547cSRui Paulo if (update_identifier && 18685b9c547cSRui Paulo set_cred(ctx->ifname, id, "update_identifier", 18695b9c547cSRui Paulo update_identifier) < 0) 18705b9c547cSRui Paulo wpa_printf(MSG_INFO, "Failed to set update_identifier"); 18715b9c547cSRui Paulo if (set_cred_quoted(ctx->ifname, id, "provisioning_sp", fqdn) < 18725b9c547cSRui Paulo 0) 18735b9c547cSRui Paulo wpa_printf(MSG_INFO, "Failed to set provisioning_sp"); 18745b9c547cSRui Paulo wpa_printf(MSG_INFO, "credential localname: '%s'", name); 18755b9c547cSRui Paulo set_pps_credential(ctx, id, child, fqdn); 18765b9c547cSRui Paulo ctx->pps_cred_set = 1; 18775b9c547cSRui Paulo } 18785b9c547cSRui Paulo 18795b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, update_identifier); 18805b9c547cSRui Paulo } 18815b9c547cSRui Paulo 18825b9c547cSRui Paulo 18835b9c547cSRui Paulo void cmd_set_pps(struct hs20_osu_client *ctx, const char *pps_fname) 18845b9c547cSRui Paulo { 18855b9c547cSRui Paulo xml_node_t *pps; 18865b9c547cSRui Paulo const char *fqdn; 18875b9c547cSRui Paulo char *fqdn_buf = NULL, *pos; 18885b9c547cSRui Paulo 18895b9c547cSRui Paulo pps = node_from_file(ctx->xml, pps_fname); 18905b9c547cSRui Paulo if (pps == NULL) { 18915b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not read or parse '%s'", pps_fname); 18925b9c547cSRui Paulo return; 18935b9c547cSRui Paulo } 18945b9c547cSRui Paulo 18955b9c547cSRui Paulo fqdn = os_strstr(pps_fname, "SP/"); 18965b9c547cSRui Paulo if (fqdn) { 18975b9c547cSRui Paulo fqdn_buf = os_strdup(fqdn + 3); 18985b9c547cSRui Paulo if (fqdn_buf == NULL) 18995b9c547cSRui Paulo return; 19005b9c547cSRui Paulo pos = os_strchr(fqdn_buf, '/'); 19015b9c547cSRui Paulo if (pos) 19025b9c547cSRui Paulo *pos = '\0'; 19035b9c547cSRui Paulo fqdn = fqdn_buf; 19045b9c547cSRui Paulo } else 19055b9c547cSRui Paulo fqdn = "wi-fi.org"; 19065b9c547cSRui Paulo 19075b9c547cSRui Paulo wpa_printf(MSG_INFO, "Set PPS MO info to wpa_supplicant - SP FQDN %s", 19085b9c547cSRui Paulo fqdn); 19095b9c547cSRui Paulo set_pps(ctx, pps, fqdn); 19105b9c547cSRui Paulo 19115b9c547cSRui Paulo os_free(fqdn_buf); 19125b9c547cSRui Paulo xml_node_free(ctx->xml, pps); 19135b9c547cSRui Paulo } 19145b9c547cSRui Paulo 19155b9c547cSRui Paulo 19165b9c547cSRui Paulo static int cmd_get_fqdn(struct hs20_osu_client *ctx, const char *pps_fname) 19175b9c547cSRui Paulo { 19185b9c547cSRui Paulo xml_node_t *pps, *node; 19195b9c547cSRui Paulo char *fqdn = NULL; 19205b9c547cSRui Paulo 19215b9c547cSRui Paulo pps = node_from_file(ctx->xml, pps_fname); 19225b9c547cSRui Paulo if (pps == NULL) { 19235b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not read or parse '%s'", pps_fname); 19245b9c547cSRui Paulo return -1; 19255b9c547cSRui Paulo } 19265b9c547cSRui Paulo 19275b9c547cSRui Paulo node = get_child_node(ctx->xml, pps, "HomeSP/FQDN"); 19285b9c547cSRui Paulo if (node) 19295b9c547cSRui Paulo fqdn = xml_node_get_text(ctx->xml, node); 19305b9c547cSRui Paulo 19315b9c547cSRui Paulo xml_node_free(ctx->xml, pps); 19325b9c547cSRui Paulo 19335b9c547cSRui Paulo if (fqdn) { 19345b9c547cSRui Paulo FILE *f = fopen("pps-fqdn", "w"); 19355b9c547cSRui Paulo if (f) { 19365b9c547cSRui Paulo fprintf(f, "%s", fqdn); 19375b9c547cSRui Paulo fclose(f); 19385b9c547cSRui Paulo } 19395b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, fqdn); 19405b9c547cSRui Paulo return 0; 19415b9c547cSRui Paulo } 19425b9c547cSRui Paulo 19435b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, fqdn); 19445b9c547cSRui Paulo return -1; 19455b9c547cSRui Paulo } 19465b9c547cSRui Paulo 19475b9c547cSRui Paulo 19485b9c547cSRui Paulo static void cmd_to_tnds(struct hs20_osu_client *ctx, const char *in_fname, 19495b9c547cSRui Paulo const char *out_fname, const char *urn, int use_path) 19505b9c547cSRui Paulo { 19515b9c547cSRui Paulo xml_node_t *mo, *node; 19525b9c547cSRui Paulo 19535b9c547cSRui Paulo mo = node_from_file(ctx->xml, in_fname); 19545b9c547cSRui Paulo if (mo == NULL) { 19555b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not read or parse '%s'", in_fname); 19565b9c547cSRui Paulo return; 19575b9c547cSRui Paulo } 19585b9c547cSRui Paulo 19595b9c547cSRui Paulo node = mo_to_tnds(ctx->xml, mo, use_path, urn, NULL); 19605b9c547cSRui Paulo if (node) { 19615b9c547cSRui Paulo node_to_file(ctx->xml, out_fname, node); 19625b9c547cSRui Paulo xml_node_free(ctx->xml, node); 19635b9c547cSRui Paulo } 19645b9c547cSRui Paulo 19655b9c547cSRui Paulo xml_node_free(ctx->xml, mo); 19665b9c547cSRui Paulo } 19675b9c547cSRui Paulo 19685b9c547cSRui Paulo 19695b9c547cSRui Paulo static void cmd_from_tnds(struct hs20_osu_client *ctx, const char *in_fname, 19705b9c547cSRui Paulo const char *out_fname) 19715b9c547cSRui Paulo { 19725b9c547cSRui Paulo xml_node_t *tnds, *mo; 19735b9c547cSRui Paulo 19745b9c547cSRui Paulo tnds = node_from_file(ctx->xml, in_fname); 19755b9c547cSRui Paulo if (tnds == NULL) { 19765b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not read or parse '%s'", in_fname); 19775b9c547cSRui Paulo return; 19785b9c547cSRui Paulo } 19795b9c547cSRui Paulo 19805b9c547cSRui Paulo mo = tnds_to_mo(ctx->xml, tnds); 19815b9c547cSRui Paulo if (mo) { 19825b9c547cSRui Paulo node_to_file(ctx->xml, out_fname, mo); 19835b9c547cSRui Paulo xml_node_free(ctx->xml, mo); 19845b9c547cSRui Paulo } 19855b9c547cSRui Paulo 19865b9c547cSRui Paulo xml_node_free(ctx->xml, tnds); 19875b9c547cSRui Paulo } 19885b9c547cSRui Paulo 19895b9c547cSRui Paulo 19905b9c547cSRui Paulo struct osu_icon { 19915b9c547cSRui Paulo int id; 19925b9c547cSRui Paulo char lang[4]; 19935b9c547cSRui Paulo char mime_type[256]; 19945b9c547cSRui Paulo char filename[256]; 19955b9c547cSRui Paulo }; 19965b9c547cSRui Paulo 19975b9c547cSRui Paulo struct osu_data { 19985b9c547cSRui Paulo char bssid[20]; 19995b9c547cSRui Paulo char url[256]; 20005b9c547cSRui Paulo unsigned int methods; 20015b9c547cSRui Paulo char osu_ssid[33]; 200285732ac8SCy Schubert char osu_ssid2[33]; 20035b9c547cSRui Paulo char osu_nai[256]; 200485732ac8SCy Schubert char osu_nai2[256]; 20055b9c547cSRui Paulo struct osu_lang_text friendly_name[MAX_OSU_VALS]; 20065b9c547cSRui Paulo size_t friendly_name_count; 20075b9c547cSRui Paulo struct osu_lang_text serv_desc[MAX_OSU_VALS]; 20085b9c547cSRui Paulo size_t serv_desc_count; 20095b9c547cSRui Paulo struct osu_icon icon[MAX_OSU_VALS]; 20105b9c547cSRui Paulo size_t icon_count; 20115b9c547cSRui Paulo }; 20125b9c547cSRui Paulo 20135b9c547cSRui Paulo 20145b9c547cSRui Paulo static struct osu_data * parse_osu_providers(const char *fname, size_t *count) 20155b9c547cSRui Paulo { 20165b9c547cSRui Paulo FILE *f; 20175b9c547cSRui Paulo char buf[1000]; 20185b9c547cSRui Paulo struct osu_data *osu = NULL, *last = NULL; 20195b9c547cSRui Paulo size_t osu_count = 0; 20205b9c547cSRui Paulo char *pos, *end; 20215b9c547cSRui Paulo 20225b9c547cSRui Paulo f = fopen(fname, "r"); 20235b9c547cSRui Paulo if (f == NULL) { 20245b9c547cSRui Paulo wpa_printf(MSG_ERROR, "Could not open %s", fname); 20255b9c547cSRui Paulo return NULL; 20265b9c547cSRui Paulo } 20275b9c547cSRui Paulo 20285b9c547cSRui Paulo while (fgets(buf, sizeof(buf), f)) { 20295b9c547cSRui Paulo pos = strchr(buf, '\n'); 20305b9c547cSRui Paulo if (pos) 20315b9c547cSRui Paulo *pos = '\0'; 20325b9c547cSRui Paulo 20335b9c547cSRui Paulo if (strncmp(buf, "OSU-PROVIDER ", 13) == 0) { 20345b9c547cSRui Paulo last = realloc(osu, (osu_count + 1) * sizeof(*osu)); 20355b9c547cSRui Paulo if (last == NULL) 20365b9c547cSRui Paulo break; 20375b9c547cSRui Paulo osu = last; 20385b9c547cSRui Paulo last = &osu[osu_count++]; 20395b9c547cSRui Paulo memset(last, 0, sizeof(*last)); 20405b9c547cSRui Paulo snprintf(last->bssid, sizeof(last->bssid), "%s", 20415b9c547cSRui Paulo buf + 13); 20425b9c547cSRui Paulo continue; 20435b9c547cSRui Paulo } 20445b9c547cSRui Paulo if (!last) 20455b9c547cSRui Paulo continue; 20465b9c547cSRui Paulo 20475b9c547cSRui Paulo if (strncmp(buf, "uri=", 4) == 0) { 20485b9c547cSRui Paulo snprintf(last->url, sizeof(last->url), "%s", buf + 4); 20495b9c547cSRui Paulo continue; 20505b9c547cSRui Paulo } 20515b9c547cSRui Paulo 20525b9c547cSRui Paulo if (strncmp(buf, "methods=", 8) == 0) { 20535b9c547cSRui Paulo last->methods = strtol(buf + 8, NULL, 16); 20545b9c547cSRui Paulo continue; 20555b9c547cSRui Paulo } 20565b9c547cSRui Paulo 20575b9c547cSRui Paulo if (strncmp(buf, "osu_ssid=", 9) == 0) { 20585b9c547cSRui Paulo snprintf(last->osu_ssid, sizeof(last->osu_ssid), 20595b9c547cSRui Paulo "%s", buf + 9); 20605b9c547cSRui Paulo continue; 20615b9c547cSRui Paulo } 20625b9c547cSRui Paulo 206385732ac8SCy Schubert if (strncmp(buf, "osu_ssid2=", 10) == 0) { 206485732ac8SCy Schubert snprintf(last->osu_ssid2, sizeof(last->osu_ssid2), 206585732ac8SCy Schubert "%s", buf + 10); 206685732ac8SCy Schubert continue; 206785732ac8SCy Schubert } 206885732ac8SCy Schubert 20695b9c547cSRui Paulo if (os_strncmp(buf, "osu_nai=", 8) == 0) { 20705b9c547cSRui Paulo os_snprintf(last->osu_nai, sizeof(last->osu_nai), 20715b9c547cSRui Paulo "%s", buf + 8); 20725b9c547cSRui Paulo continue; 20735b9c547cSRui Paulo } 20745b9c547cSRui Paulo 207585732ac8SCy Schubert if (os_strncmp(buf, "osu_nai2=", 9) == 0) { 207685732ac8SCy Schubert os_snprintf(last->osu_nai2, sizeof(last->osu_nai2), 207785732ac8SCy Schubert "%s", buf + 9); 207885732ac8SCy Schubert continue; 207985732ac8SCy Schubert } 208085732ac8SCy Schubert 20815b9c547cSRui Paulo if (strncmp(buf, "friendly_name=", 14) == 0) { 20825b9c547cSRui Paulo struct osu_lang_text *txt; 20835b9c547cSRui Paulo if (last->friendly_name_count == MAX_OSU_VALS) 20845b9c547cSRui Paulo continue; 20855b9c547cSRui Paulo pos = strchr(buf + 14, ':'); 20865b9c547cSRui Paulo if (pos == NULL) 20875b9c547cSRui Paulo continue; 20885b9c547cSRui Paulo *pos++ = '\0'; 20895b9c547cSRui Paulo txt = &last->friendly_name[last->friendly_name_count++]; 20905b9c547cSRui Paulo snprintf(txt->lang, sizeof(txt->lang), "%s", buf + 14); 20915b9c547cSRui Paulo snprintf(txt->text, sizeof(txt->text), "%s", pos); 20925b9c547cSRui Paulo } 20935b9c547cSRui Paulo 20945b9c547cSRui Paulo if (strncmp(buf, "desc=", 5) == 0) { 20955b9c547cSRui Paulo struct osu_lang_text *txt; 20965b9c547cSRui Paulo if (last->serv_desc_count == MAX_OSU_VALS) 20975b9c547cSRui Paulo continue; 20985b9c547cSRui Paulo pos = strchr(buf + 5, ':'); 20995b9c547cSRui Paulo if (pos == NULL) 21005b9c547cSRui Paulo continue; 21015b9c547cSRui Paulo *pos++ = '\0'; 21025b9c547cSRui Paulo txt = &last->serv_desc[last->serv_desc_count++]; 21035b9c547cSRui Paulo snprintf(txt->lang, sizeof(txt->lang), "%s", buf + 5); 21045b9c547cSRui Paulo snprintf(txt->text, sizeof(txt->text), "%s", pos); 21055b9c547cSRui Paulo } 21065b9c547cSRui Paulo 21075b9c547cSRui Paulo if (strncmp(buf, "icon=", 5) == 0) { 21085b9c547cSRui Paulo struct osu_icon *icon; 21095b9c547cSRui Paulo if (last->icon_count == MAX_OSU_VALS) 21105b9c547cSRui Paulo continue; 21115b9c547cSRui Paulo icon = &last->icon[last->icon_count++]; 21125b9c547cSRui Paulo icon->id = atoi(buf + 5); 21135b9c547cSRui Paulo pos = strchr(buf, ':'); 21145b9c547cSRui Paulo if (pos == NULL) 21155b9c547cSRui Paulo continue; 21165b9c547cSRui Paulo pos = strchr(pos + 1, ':'); 21175b9c547cSRui Paulo if (pos == NULL) 21185b9c547cSRui Paulo continue; 21195b9c547cSRui Paulo pos = strchr(pos + 1, ':'); 21205b9c547cSRui Paulo if (pos == NULL) 21215b9c547cSRui Paulo continue; 21225b9c547cSRui Paulo pos++; 21235b9c547cSRui Paulo end = strchr(pos, ':'); 21245b9c547cSRui Paulo if (!end) 21255b9c547cSRui Paulo continue; 21265b9c547cSRui Paulo *end = '\0'; 21275b9c547cSRui Paulo snprintf(icon->lang, sizeof(icon->lang), "%s", pos); 21285b9c547cSRui Paulo pos = end + 1; 21295b9c547cSRui Paulo 21305b9c547cSRui Paulo end = strchr(pos, ':'); 21315b9c547cSRui Paulo if (end) 21325b9c547cSRui Paulo *end = '\0'; 21335b9c547cSRui Paulo snprintf(icon->mime_type, sizeof(icon->mime_type), 21345b9c547cSRui Paulo "%s", pos); 21355b9c547cSRui Paulo if (!pos) 21365b9c547cSRui Paulo continue; 21375b9c547cSRui Paulo pos = end + 1; 21385b9c547cSRui Paulo 21395b9c547cSRui Paulo end = strchr(pos, ':'); 21405b9c547cSRui Paulo if (end) 21415b9c547cSRui Paulo *end = '\0'; 21425b9c547cSRui Paulo snprintf(icon->filename, sizeof(icon->filename), 21435b9c547cSRui Paulo "%s", pos); 21445b9c547cSRui Paulo continue; 21455b9c547cSRui Paulo } 21465b9c547cSRui Paulo } 21475b9c547cSRui Paulo 21485b9c547cSRui Paulo fclose(f); 21495b9c547cSRui Paulo 21505b9c547cSRui Paulo *count = osu_count; 21515b9c547cSRui Paulo return osu; 21525b9c547cSRui Paulo } 21535b9c547cSRui Paulo 21545b9c547cSRui Paulo 21555b9c547cSRui Paulo static int osu_connect(struct hs20_osu_client *ctx, const char *bssid, 215685732ac8SCy Schubert const char *ssid, const char *ssid2, const char *url, 21575b9c547cSRui Paulo unsigned int methods, int no_prod_assoc, 215885732ac8SCy Schubert const char *osu_nai, const char *osu_nai2) 21595b9c547cSRui Paulo { 21605b9c547cSRui Paulo int id; 21615b9c547cSRui Paulo const char *ifname = ctx->ifname; 21625b9c547cSRui Paulo char buf[200]; 21635b9c547cSRui Paulo struct wpa_ctrl *mon; 21645b9c547cSRui Paulo int res; 21655b9c547cSRui Paulo 216685732ac8SCy Schubert if (ssid2 && ssid2[0] == '\0') 216785732ac8SCy Schubert ssid2 = NULL; 216885732ac8SCy Schubert 216985732ac8SCy Schubert if (ctx->osu_ssid) { 217085732ac8SCy Schubert if (os_strcmp(ssid, ctx->osu_ssid) == 0) { 217185732ac8SCy Schubert wpa_printf(MSG_DEBUG, 217285732ac8SCy Schubert "Enforced OSU SSID matches ANQP info"); 217385732ac8SCy Schubert ssid2 = NULL; 217485732ac8SCy Schubert } else if (ssid2 && os_strcmp(ssid2, ctx->osu_ssid) == 0) { 217585732ac8SCy Schubert wpa_printf(MSG_DEBUG, 217685732ac8SCy Schubert "Enforced OSU SSID matches RSN[OSEN] info"); 217785732ac8SCy Schubert ssid = ssid2; 217885732ac8SCy Schubert } else { 217985732ac8SCy Schubert wpa_printf(MSG_INFO, "Enforced OSU SSID did not match"); 218085732ac8SCy Schubert write_summary(ctx, "Enforced OSU SSID did not match"); 218185732ac8SCy Schubert return -1; 218285732ac8SCy Schubert } 218385732ac8SCy Schubert } 218485732ac8SCy Schubert 21855b9c547cSRui Paulo id = add_network(ifname); 21865b9c547cSRui Paulo if (id < 0) 21875b9c547cSRui Paulo return -1; 21885b9c547cSRui Paulo if (set_network_quoted(ifname, id, "ssid", ssid) < 0) 21895b9c547cSRui Paulo return -1; 219085732ac8SCy Schubert if (ssid2) 219185732ac8SCy Schubert osu_nai = osu_nai2; 21925b9c547cSRui Paulo if (osu_nai && os_strlen(osu_nai) > 0) { 21935b9c547cSRui Paulo char dir[255], fname[300]; 21945b9c547cSRui Paulo if (getcwd(dir, sizeof(dir)) == NULL) 21955b9c547cSRui Paulo return -1; 21965b9c547cSRui Paulo os_snprintf(fname, sizeof(fname), "%s/osu-ca.pem", dir); 21975b9c547cSRui Paulo 219885732ac8SCy Schubert if (ssid2 && set_network_quoted(ifname, id, "ssid", ssid2) < 0) 219985732ac8SCy Schubert return -1; 220085732ac8SCy Schubert 22015b9c547cSRui Paulo if (set_network(ifname, id, "proto", "OSEN") < 0 || 22025b9c547cSRui Paulo set_network(ifname, id, "key_mgmt", "OSEN") < 0 || 22035b9c547cSRui Paulo set_network(ifname, id, "pairwise", "CCMP") < 0 || 220485732ac8SCy Schubert set_network(ifname, id, "group", "GTK_NOT_USED CCMP") < 0 || 22055b9c547cSRui Paulo set_network(ifname, id, "eap", "WFA-UNAUTH-TLS") < 0 || 22065b9c547cSRui Paulo set_network(ifname, id, "ocsp", "2") < 0 || 22075b9c547cSRui Paulo set_network_quoted(ifname, id, "identity", osu_nai) < 0 || 22085b9c547cSRui Paulo set_network_quoted(ifname, id, "ca_cert", fname) < 0) 22095b9c547cSRui Paulo return -1; 221085732ac8SCy Schubert } else if (ssid2) { 221185732ac8SCy Schubert wpa_printf(MSG_INFO, "No OSU_NAI set for RSN[OSEN]"); 221285732ac8SCy Schubert write_summary(ctx, "No OSU_NAI set for RSN[OSEN]"); 221385732ac8SCy Schubert return -1; 22145b9c547cSRui Paulo } else { 22155b9c547cSRui Paulo if (set_network(ifname, id, "key_mgmt", "NONE") < 0) 22165b9c547cSRui Paulo return -1; 22175b9c547cSRui Paulo } 22185b9c547cSRui Paulo 22195b9c547cSRui Paulo mon = open_wpa_mon(ifname); 22205b9c547cSRui Paulo if (mon == NULL) 22215b9c547cSRui Paulo return -1; 22225b9c547cSRui Paulo 22235b9c547cSRui Paulo wpa_printf(MSG_INFO, "Associate with OSU SSID"); 22245b9c547cSRui Paulo write_summary(ctx, "Associate with OSU SSID"); 22255b9c547cSRui Paulo snprintf(buf, sizeof(buf), "SELECT_NETWORK %d", id); 22265b9c547cSRui Paulo if (wpa_command(ifname, buf) < 0) 22275b9c547cSRui Paulo return -1; 22285b9c547cSRui Paulo 22295b9c547cSRui Paulo res = get_wpa_cli_event(mon, "CTRL-EVENT-CONNECTED", 22305b9c547cSRui Paulo buf, sizeof(buf)); 22315b9c547cSRui Paulo 22325b9c547cSRui Paulo wpa_ctrl_detach(mon); 22335b9c547cSRui Paulo wpa_ctrl_close(mon); 22345b9c547cSRui Paulo 22355b9c547cSRui Paulo if (res < 0) { 2236*c1d255d3SCy Schubert wpa_printf(MSG_INFO, "Could not connect to OSU network"); 22375b9c547cSRui Paulo write_summary(ctx, "Could not connect to OSU network"); 22385b9c547cSRui Paulo wpa_printf(MSG_INFO, "Remove OSU network connection"); 22395b9c547cSRui Paulo snprintf(buf, sizeof(buf), "REMOVE_NETWORK %d", id); 22405b9c547cSRui Paulo wpa_command(ifname, buf); 22415b9c547cSRui Paulo return -1; 22425b9c547cSRui Paulo } 22435b9c547cSRui Paulo 22445b9c547cSRui Paulo write_summary(ctx, "Waiting for IP address for subscription registration"); 22455b9c547cSRui Paulo if (wait_ip_addr(ifname, 15) < 0) { 22465b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not get IP address for WLAN - try connection anyway"); 22475b9c547cSRui Paulo } 22485b9c547cSRui Paulo 22495b9c547cSRui Paulo if (no_prod_assoc) { 22505b9c547cSRui Paulo if (res < 0) 22515b9c547cSRui Paulo return -1; 22525b9c547cSRui Paulo wpa_printf(MSG_INFO, "No production connection used for testing purposes"); 22535b9c547cSRui Paulo write_summary(ctx, "No production connection used for testing purposes"); 22545b9c547cSRui Paulo return 0; 22555b9c547cSRui Paulo } 22565b9c547cSRui Paulo 22575b9c547cSRui Paulo ctx->no_reconnect = 1; 2258325151a3SRui Paulo if (methods & 0x02) { 2259325151a3SRui Paulo wpa_printf(MSG_DEBUG, "Calling cmd_prov from osu_connect"); 22605b9c547cSRui Paulo res = cmd_prov(ctx, url); 2261325151a3SRui Paulo } else if (methods & 0x01) { 2262325151a3SRui Paulo wpa_printf(MSG_DEBUG, 2263325151a3SRui Paulo "Calling cmd_oma_dm_prov from osu_connect"); 22645b9c547cSRui Paulo res = cmd_oma_dm_prov(ctx, url); 2265325151a3SRui Paulo } 22665b9c547cSRui Paulo 22675b9c547cSRui Paulo wpa_printf(MSG_INFO, "Remove OSU network connection"); 22685b9c547cSRui Paulo write_summary(ctx, "Remove OSU network connection"); 22695b9c547cSRui Paulo snprintf(buf, sizeof(buf), "REMOVE_NETWORK %d", id); 22705b9c547cSRui Paulo wpa_command(ifname, buf); 22715b9c547cSRui Paulo 22725b9c547cSRui Paulo if (res < 0) 22735b9c547cSRui Paulo return -1; 22745b9c547cSRui Paulo 22755b9c547cSRui Paulo wpa_printf(MSG_INFO, "Requesting reconnection with updated configuration"); 22765b9c547cSRui Paulo write_summary(ctx, "Requesting reconnection with updated configuration"); 22775b9c547cSRui Paulo if (wpa_command(ctx->ifname, "INTERWORKING_SELECT auto") < 0) { 22785b9c547cSRui Paulo wpa_printf(MSG_INFO, "Failed to request wpa_supplicant to reconnect"); 22795b9c547cSRui Paulo write_summary(ctx, "Failed to request wpa_supplicant to reconnect"); 22805b9c547cSRui Paulo return -1; 22815b9c547cSRui Paulo } 22825b9c547cSRui Paulo 22835b9c547cSRui Paulo return 0; 22845b9c547cSRui Paulo } 22855b9c547cSRui Paulo 22865b9c547cSRui Paulo 22875b9c547cSRui Paulo static int cmd_osu_select(struct hs20_osu_client *ctx, const char *dir, 22885b9c547cSRui Paulo int connect, int no_prod_assoc, 22895b9c547cSRui Paulo const char *friendly_name) 22905b9c547cSRui Paulo { 22915b9c547cSRui Paulo char fname[255]; 22925b9c547cSRui Paulo FILE *f; 22935b9c547cSRui Paulo struct osu_data *osu = NULL, *last = NULL; 229485732ac8SCy Schubert size_t osu_count = 0, i, j; 22955b9c547cSRui Paulo int ret; 22965b9c547cSRui Paulo 22975b9c547cSRui Paulo write_summary(ctx, "OSU provider selection"); 22985b9c547cSRui Paulo 22995b9c547cSRui Paulo if (dir == NULL) { 23005b9c547cSRui Paulo wpa_printf(MSG_INFO, "Missing dir parameter to osu_select"); 23015b9c547cSRui Paulo return -1; 23025b9c547cSRui Paulo } 23035b9c547cSRui Paulo 23045b9c547cSRui Paulo snprintf(fname, sizeof(fname), "%s/osu-providers.txt", dir); 23055b9c547cSRui Paulo osu = parse_osu_providers(fname, &osu_count); 23065b9c547cSRui Paulo if (osu == NULL) { 2307325151a3SRui Paulo wpa_printf(MSG_INFO, "Could not find any OSU providers from %s", 23085b9c547cSRui Paulo fname); 23095b9c547cSRui Paulo write_result(ctx, "No OSU providers available"); 23105b9c547cSRui Paulo return -1; 23115b9c547cSRui Paulo } 23125b9c547cSRui Paulo 23135b9c547cSRui Paulo if (friendly_name) { 23145b9c547cSRui Paulo for (i = 0; i < osu_count; i++) { 23155b9c547cSRui Paulo last = &osu[i]; 23165b9c547cSRui Paulo for (j = 0; j < last->friendly_name_count; j++) { 23175b9c547cSRui Paulo if (os_strcmp(last->friendly_name[j].text, 23185b9c547cSRui Paulo friendly_name) == 0) 23195b9c547cSRui Paulo break; 23205b9c547cSRui Paulo } 23215b9c547cSRui Paulo if (j < last->friendly_name_count) 23225b9c547cSRui Paulo break; 23235b9c547cSRui Paulo } 23245b9c547cSRui Paulo if (i == osu_count) { 23255b9c547cSRui Paulo wpa_printf(MSG_INFO, "Requested operator friendly name '%s' not found in the list of available providers", 23265b9c547cSRui Paulo friendly_name); 23275b9c547cSRui Paulo write_summary(ctx, "Requested operator friendly name '%s' not found in the list of available providers", 23285b9c547cSRui Paulo friendly_name); 23295b9c547cSRui Paulo free(osu); 23305b9c547cSRui Paulo return -1; 23315b9c547cSRui Paulo } 23325b9c547cSRui Paulo 23335b9c547cSRui Paulo wpa_printf(MSG_INFO, "OSU Provider selected based on requested operator friendly name '%s'", 23345b9c547cSRui Paulo friendly_name); 23355b9c547cSRui Paulo write_summary(ctx, "OSU Provider selected based on requested operator friendly name '%s'", 23365b9c547cSRui Paulo friendly_name); 23375b9c547cSRui Paulo ret = i + 1; 23385b9c547cSRui Paulo goto selected; 23395b9c547cSRui Paulo } 23405b9c547cSRui Paulo 23415b9c547cSRui Paulo snprintf(fname, sizeof(fname), "%s/osu-providers.html", dir); 23425b9c547cSRui Paulo f = fopen(fname, "w"); 23435b9c547cSRui Paulo if (f == NULL) { 23445b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not open %s", fname); 23455b9c547cSRui Paulo free(osu); 23465b9c547cSRui Paulo return -1; 23475b9c547cSRui Paulo } 23485b9c547cSRui Paulo 23495b9c547cSRui Paulo fprintf(f, "<html><head>" 23505b9c547cSRui Paulo "<meta http-equiv=\"Content-type\" content=\"text/html; " 23515b9c547cSRui Paulo "charset=utf-8\"<title>Select service operator</title>" 23525b9c547cSRui Paulo "</head><body><h1>Select service operator</h1>\n"); 23535b9c547cSRui Paulo 23545b9c547cSRui Paulo if (osu_count == 0) 23555b9c547cSRui Paulo fprintf(f, "No online signup available\n"); 23565b9c547cSRui Paulo 23575b9c547cSRui Paulo for (i = 0; i < osu_count; i++) { 23585b9c547cSRui Paulo last = &osu[i]; 23595b9c547cSRui Paulo #ifdef ANDROID 23605b9c547cSRui Paulo fprintf(f, "<p>\n" 23615b9c547cSRui Paulo "<a href=\"http://localhost:12345/osu/%d\">" 23625b9c547cSRui Paulo "<table><tr><td>", (int) i + 1); 23635b9c547cSRui Paulo #else /* ANDROID */ 23645b9c547cSRui Paulo fprintf(f, "<p>\n" 23655b9c547cSRui Paulo "<a href=\"osu://%d\">" 23665b9c547cSRui Paulo "<table><tr><td>", (int) i + 1); 23675b9c547cSRui Paulo #endif /* ANDROID */ 23685b9c547cSRui Paulo for (j = 0; j < last->icon_count; j++) { 23695b9c547cSRui Paulo fprintf(f, "<img src=\"osu-icon-%d.%s\">\n", 23705b9c547cSRui Paulo last->icon[j].id, 23715b9c547cSRui Paulo strcasecmp(last->icon[j].mime_type, 23725b9c547cSRui Paulo "image/png") == 0 ? "png" : "icon"); 23735b9c547cSRui Paulo } 23745b9c547cSRui Paulo fprintf(f, "<td>"); 23755b9c547cSRui Paulo for (j = 0; j < last->friendly_name_count; j++) { 23765b9c547cSRui Paulo fprintf(f, "<small>[%s]</small> %s<br>\n", 23775b9c547cSRui Paulo last->friendly_name[j].lang, 23785b9c547cSRui Paulo last->friendly_name[j].text); 23795b9c547cSRui Paulo } 23805b9c547cSRui Paulo fprintf(f, "<tr><td colspan=2>"); 23815b9c547cSRui Paulo for (j = 0; j < last->serv_desc_count; j++) { 23825b9c547cSRui Paulo fprintf(f, "<small>[%s]</small> %s<br>\n", 23835b9c547cSRui Paulo last->serv_desc[j].lang, 23845b9c547cSRui Paulo last->serv_desc[j].text); 23855b9c547cSRui Paulo } 23865b9c547cSRui Paulo fprintf(f, "</table></a><br><small>BSSID: %s<br>\n" 23875b9c547cSRui Paulo "SSID: %s<br>\n", 23885b9c547cSRui Paulo last->bssid, last->osu_ssid); 238985732ac8SCy Schubert if (last->osu_ssid2[0]) 239085732ac8SCy Schubert fprintf(f, "SSID2: %s<br>\n", last->osu_ssid2); 2391780fb4a2SCy Schubert if (last->osu_nai[0]) 23925b9c547cSRui Paulo fprintf(f, "NAI: %s<br>\n", last->osu_nai); 239385732ac8SCy Schubert if (last->osu_nai2[0]) 239485732ac8SCy Schubert fprintf(f, "NAI2: %s<br>\n", last->osu_nai2); 23955b9c547cSRui Paulo fprintf(f, "URL: %s<br>\n" 23965b9c547cSRui Paulo "methods:%s%s<br>\n" 23975b9c547cSRui Paulo "</small></p>\n", 23985b9c547cSRui Paulo last->url, 23995b9c547cSRui Paulo last->methods & 0x01 ? " OMA-DM" : "", 24005b9c547cSRui Paulo last->methods & 0x02 ? " SOAP-XML-SPP" : ""); 24015b9c547cSRui Paulo } 24025b9c547cSRui Paulo 24035b9c547cSRui Paulo fprintf(f, "</body></html>\n"); 24045b9c547cSRui Paulo 24055b9c547cSRui Paulo fclose(f); 24065b9c547cSRui Paulo 24075b9c547cSRui Paulo snprintf(fname, sizeof(fname), "file://%s/osu-providers.html", dir); 24085b9c547cSRui Paulo write_summary(ctx, "Start web browser with OSU provider selection page"); 2409*c1d255d3SCy Schubert ret = hs20_web_browser(fname, 0); 24105b9c547cSRui Paulo 24115b9c547cSRui Paulo selected: 24125b9c547cSRui Paulo if (ret > 0 && (size_t) ret <= osu_count) { 24135b9c547cSRui Paulo char *data; 24145b9c547cSRui Paulo size_t data_len; 24155b9c547cSRui Paulo 24165b9c547cSRui Paulo wpa_printf(MSG_INFO, "Selected OSU id=%d", ret); 24175b9c547cSRui Paulo last = &osu[ret - 1]; 24185b9c547cSRui Paulo ret = 0; 24195b9c547cSRui Paulo wpa_printf(MSG_INFO, "BSSID: %s", last->bssid); 24205b9c547cSRui Paulo wpa_printf(MSG_INFO, "SSID: %s", last->osu_ssid); 242185732ac8SCy Schubert if (last->osu_ssid2[0]) 242285732ac8SCy Schubert wpa_printf(MSG_INFO, "SSID2: %s", last->osu_ssid2); 24235b9c547cSRui Paulo wpa_printf(MSG_INFO, "URL: %s", last->url); 24245b9c547cSRui Paulo write_summary(ctx, "Selected OSU provider id=%d BSSID=%s SSID=%s URL=%s", 24255b9c547cSRui Paulo ret, last->bssid, last->osu_ssid, last->url); 24265b9c547cSRui Paulo 24275b9c547cSRui Paulo ctx->friendly_name_count = last->friendly_name_count; 24285b9c547cSRui Paulo for (j = 0; j < last->friendly_name_count; j++) { 24295b9c547cSRui Paulo wpa_printf(MSG_INFO, "FRIENDLY_NAME: [%s]%s", 24305b9c547cSRui Paulo last->friendly_name[j].lang, 24315b9c547cSRui Paulo last->friendly_name[j].text); 24325b9c547cSRui Paulo os_strlcpy(ctx->friendly_name[j].lang, 24335b9c547cSRui Paulo last->friendly_name[j].lang, 24345b9c547cSRui Paulo sizeof(ctx->friendly_name[j].lang)); 24355b9c547cSRui Paulo os_strlcpy(ctx->friendly_name[j].text, 24365b9c547cSRui Paulo last->friendly_name[j].text, 24375b9c547cSRui Paulo sizeof(ctx->friendly_name[j].text)); 24385b9c547cSRui Paulo } 24395b9c547cSRui Paulo 24405b9c547cSRui Paulo ctx->icon_count = last->icon_count; 24415b9c547cSRui Paulo for (j = 0; j < last->icon_count; j++) { 24425b9c547cSRui Paulo char fname[256]; 24435b9c547cSRui Paulo 24445b9c547cSRui Paulo os_snprintf(fname, sizeof(fname), "%s/osu-icon-%d.%s", 24455b9c547cSRui Paulo dir, last->icon[j].id, 24465b9c547cSRui Paulo strcasecmp(last->icon[j].mime_type, 24475b9c547cSRui Paulo "image/png") == 0 ? 24485b9c547cSRui Paulo "png" : "icon"); 24495b9c547cSRui Paulo wpa_printf(MSG_INFO, "ICON: %s (%s)", 24505b9c547cSRui Paulo fname, last->icon[j].filename); 24515b9c547cSRui Paulo os_strlcpy(ctx->icon_filename[j], 24525b9c547cSRui Paulo last->icon[j].filename, 24535b9c547cSRui Paulo sizeof(ctx->icon_filename[j])); 24545b9c547cSRui Paulo 24555b9c547cSRui Paulo data = os_readfile(fname, &data_len); 24565b9c547cSRui Paulo if (data) { 24575b9c547cSRui Paulo sha256_vector(1, (const u8 **) &data, &data_len, 24585b9c547cSRui Paulo ctx->icon_hash[j]); 24595b9c547cSRui Paulo os_free(data); 24605b9c547cSRui Paulo } 24615b9c547cSRui Paulo } 24625b9c547cSRui Paulo 24635b9c547cSRui Paulo if (connect == 2) { 2464325151a3SRui Paulo if (last->methods & 0x02) { 2465325151a3SRui Paulo wpa_printf(MSG_DEBUG, 2466325151a3SRui Paulo "Calling cmd_prov from cmd_osu_select"); 24675b9c547cSRui Paulo ret = cmd_prov(ctx, last->url); 2468325151a3SRui Paulo } else if (last->methods & 0x01) { 2469325151a3SRui Paulo wpa_printf(MSG_DEBUG, 2470325151a3SRui Paulo "Calling cmd_oma_dm_prov from cmd_osu_select"); 24715b9c547cSRui Paulo ret = cmd_oma_dm_prov(ctx, last->url); 2472325151a3SRui Paulo } else { 2473325151a3SRui Paulo wpa_printf(MSG_DEBUG, 2474325151a3SRui Paulo "No supported OSU provisioning method"); 24755b9c547cSRui Paulo ret = -1; 2476325151a3SRui Paulo } 247785732ac8SCy Schubert } else if (connect) { 24785b9c547cSRui Paulo ret = osu_connect(ctx, last->bssid, last->osu_ssid, 247985732ac8SCy Schubert last->osu_ssid2, 24805b9c547cSRui Paulo last->url, last->methods, 248185732ac8SCy Schubert no_prod_assoc, last->osu_nai, 248285732ac8SCy Schubert last->osu_nai2); 248385732ac8SCy Schubert } 24845b9c547cSRui Paulo } else 24855b9c547cSRui Paulo ret = -1; 24865b9c547cSRui Paulo 24875b9c547cSRui Paulo free(osu); 24885b9c547cSRui Paulo 24895b9c547cSRui Paulo return ret; 24905b9c547cSRui Paulo } 24915b9c547cSRui Paulo 24925b9c547cSRui Paulo 24935b9c547cSRui Paulo static int cmd_signup(struct hs20_osu_client *ctx, int no_prod_assoc, 24945b9c547cSRui Paulo const char *friendly_name) 24955b9c547cSRui Paulo { 24965b9c547cSRui Paulo char dir[255]; 24975b9c547cSRui Paulo char fname[300], buf[400]; 24985b9c547cSRui Paulo struct wpa_ctrl *mon; 24995b9c547cSRui Paulo const char *ifname; 25005b9c547cSRui Paulo int res; 25015b9c547cSRui Paulo 25025b9c547cSRui Paulo ifname = ctx->ifname; 25035b9c547cSRui Paulo 25045b9c547cSRui Paulo if (getcwd(dir, sizeof(dir)) == NULL) 25055b9c547cSRui Paulo return -1; 25065b9c547cSRui Paulo 25075b9c547cSRui Paulo snprintf(fname, sizeof(fname), "%s/osu-info", dir); 2508780fb4a2SCy Schubert if (mkdir(fname, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) < 0 && 2509780fb4a2SCy Schubert errno != EEXIST) { 25105b9c547cSRui Paulo wpa_printf(MSG_INFO, "mkdir(%s) failed: %s", 25115b9c547cSRui Paulo fname, strerror(errno)); 25125b9c547cSRui Paulo return -1; 25135b9c547cSRui Paulo } 25145b9c547cSRui Paulo 251585732ac8SCy Schubert android_update_permission(fname, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); 2516780fb4a2SCy Schubert 25175b9c547cSRui Paulo snprintf(buf, sizeof(buf), "SET osu_dir %s", fname); 25185b9c547cSRui Paulo if (wpa_command(ifname, buf) < 0) { 25195b9c547cSRui Paulo wpa_printf(MSG_INFO, "Failed to configure osu_dir to wpa_supplicant"); 25205b9c547cSRui Paulo return -1; 25215b9c547cSRui Paulo } 25225b9c547cSRui Paulo 25235b9c547cSRui Paulo mon = open_wpa_mon(ifname); 25245b9c547cSRui Paulo if (mon == NULL) 25255b9c547cSRui Paulo return -1; 25265b9c547cSRui Paulo 25275b9c547cSRui Paulo wpa_printf(MSG_INFO, "Starting OSU fetch"); 25285b9c547cSRui Paulo write_summary(ctx, "Starting OSU provider information fetch"); 25295b9c547cSRui Paulo if (wpa_command(ifname, "FETCH_OSU") < 0) { 25305b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not start OSU fetch"); 25315b9c547cSRui Paulo wpa_ctrl_detach(mon); 25325b9c547cSRui Paulo wpa_ctrl_close(mon); 25335b9c547cSRui Paulo return -1; 25345b9c547cSRui Paulo } 25355b9c547cSRui Paulo res = get_wpa_cli_event(mon, "OSU provider fetch completed", 25365b9c547cSRui Paulo buf, sizeof(buf)); 25375b9c547cSRui Paulo 25385b9c547cSRui Paulo wpa_ctrl_detach(mon); 25395b9c547cSRui Paulo wpa_ctrl_close(mon); 25405b9c547cSRui Paulo 25415b9c547cSRui Paulo if (res < 0) { 25425b9c547cSRui Paulo wpa_printf(MSG_INFO, "OSU fetch did not complete"); 25435b9c547cSRui Paulo write_summary(ctx, "OSU fetch did not complete"); 25445b9c547cSRui Paulo return -1; 25455b9c547cSRui Paulo } 25465b9c547cSRui Paulo wpa_printf(MSG_INFO, "OSU provider fetch completed"); 25475b9c547cSRui Paulo 25485b9c547cSRui Paulo return cmd_osu_select(ctx, fname, 1, no_prod_assoc, friendly_name); 25495b9c547cSRui Paulo } 25505b9c547cSRui Paulo 25515b9c547cSRui Paulo 25525b9c547cSRui Paulo static int cmd_sub_rem(struct hs20_osu_client *ctx, const char *address, 25535b9c547cSRui Paulo const char *pps_fname, const char *ca_fname) 25545b9c547cSRui Paulo { 25555b9c547cSRui Paulo xml_node_t *pps, *node; 25565b9c547cSRui Paulo char pps_fname_buf[300]; 25575b9c547cSRui Paulo char ca_fname_buf[200]; 25585b9c547cSRui Paulo char *cred_username = NULL; 25595b9c547cSRui Paulo char *cred_password = NULL; 25605b9c547cSRui Paulo char *sub_rem_uri = NULL; 25615b9c547cSRui Paulo char client_cert_buf[200]; 25625b9c547cSRui Paulo char *client_cert = NULL; 25635b9c547cSRui Paulo char client_key_buf[200]; 25645b9c547cSRui Paulo char *client_key = NULL; 25655b9c547cSRui Paulo int spp; 25665b9c547cSRui Paulo 25675b9c547cSRui Paulo wpa_printf(MSG_INFO, "Subscription remediation requested with Server URL: %s", 25685b9c547cSRui Paulo address); 25695b9c547cSRui Paulo 25705b9c547cSRui Paulo if (!pps_fname) { 25715b9c547cSRui Paulo char buf[256]; 25725b9c547cSRui Paulo wpa_printf(MSG_INFO, "Determining PPS file based on Home SP information"); 25735b9c547cSRui Paulo if (os_strncmp(address, "fqdn=", 5) == 0) { 25745b9c547cSRui Paulo wpa_printf(MSG_INFO, "Use requested FQDN from command line"); 25755b9c547cSRui Paulo os_snprintf(buf, sizeof(buf), "%s", address + 5); 25765b9c547cSRui Paulo address = NULL; 25775b9c547cSRui Paulo } else if (get_wpa_status(ctx->ifname, "provisioning_sp", buf, 25785b9c547cSRui Paulo sizeof(buf)) < 0) { 25795b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not get provisioning Home SP FQDN from wpa_supplicant"); 25805b9c547cSRui Paulo return -1; 25815b9c547cSRui Paulo } 25825b9c547cSRui Paulo os_free(ctx->fqdn); 25835b9c547cSRui Paulo ctx->fqdn = os_strdup(buf); 25845b9c547cSRui Paulo if (ctx->fqdn == NULL) 25855b9c547cSRui Paulo return -1; 25865b9c547cSRui Paulo wpa_printf(MSG_INFO, "Home SP FQDN for current credential: %s", 25875b9c547cSRui Paulo buf); 25885b9c547cSRui Paulo os_snprintf(pps_fname_buf, sizeof(pps_fname_buf), 25895b9c547cSRui Paulo "SP/%s/pps.xml", ctx->fqdn); 25905b9c547cSRui Paulo pps_fname = pps_fname_buf; 25915b9c547cSRui Paulo 25925b9c547cSRui Paulo os_snprintf(ca_fname_buf, sizeof(ca_fname_buf), "SP/%s/ca.pem", 25935b9c547cSRui Paulo ctx->fqdn); 25945b9c547cSRui Paulo ca_fname = ca_fname_buf; 25955b9c547cSRui Paulo } 25965b9c547cSRui Paulo 25975b9c547cSRui Paulo if (!os_file_exists(pps_fname)) { 25985b9c547cSRui Paulo wpa_printf(MSG_INFO, "PPS file '%s' does not exist or is not accessible", 25995b9c547cSRui Paulo pps_fname); 26005b9c547cSRui Paulo return -1; 26015b9c547cSRui Paulo } 26025b9c547cSRui Paulo wpa_printf(MSG_INFO, "Using PPS file: %s", pps_fname); 26035b9c547cSRui Paulo 26045b9c547cSRui Paulo if (ca_fname && !os_file_exists(ca_fname)) { 26055b9c547cSRui Paulo wpa_printf(MSG_INFO, "CA file '%s' does not exist or is not accessible", 26065b9c547cSRui Paulo ca_fname); 26075b9c547cSRui Paulo return -1; 26085b9c547cSRui Paulo } 26095b9c547cSRui Paulo wpa_printf(MSG_INFO, "Using server trust root: %s", ca_fname); 26105b9c547cSRui Paulo ctx->ca_fname = ca_fname; 26115b9c547cSRui Paulo 26125b9c547cSRui Paulo pps = node_from_file(ctx->xml, pps_fname); 26135b9c547cSRui Paulo if (pps == NULL) { 26145b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not read PPS MO"); 26155b9c547cSRui Paulo return -1; 26165b9c547cSRui Paulo } 26175b9c547cSRui Paulo 26185b9c547cSRui Paulo if (!ctx->fqdn) { 26195b9c547cSRui Paulo char *tmp; 26205b9c547cSRui Paulo node = get_child_node(ctx->xml, pps, "HomeSP/FQDN"); 26215b9c547cSRui Paulo if (node == NULL) { 26225b9c547cSRui Paulo wpa_printf(MSG_INFO, "No HomeSP/FQDN found from PPS"); 26235b9c547cSRui Paulo return -1; 26245b9c547cSRui Paulo } 26255b9c547cSRui Paulo tmp = xml_node_get_text(ctx->xml, node); 26265b9c547cSRui Paulo if (tmp == NULL) { 26275b9c547cSRui Paulo wpa_printf(MSG_INFO, "No HomeSP/FQDN text found from PPS"); 26285b9c547cSRui Paulo return -1; 26295b9c547cSRui Paulo } 26305b9c547cSRui Paulo ctx->fqdn = os_strdup(tmp); 26315b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, tmp); 26325b9c547cSRui Paulo if (!ctx->fqdn) { 26335b9c547cSRui Paulo wpa_printf(MSG_INFO, "No FQDN known"); 26345b9c547cSRui Paulo return -1; 26355b9c547cSRui Paulo } 26365b9c547cSRui Paulo } 26375b9c547cSRui Paulo 26385b9c547cSRui Paulo node = get_child_node(ctx->xml, pps, 26395b9c547cSRui Paulo "SubscriptionUpdate/UpdateMethod"); 26405b9c547cSRui Paulo if (node) { 26415b9c547cSRui Paulo char *tmp; 26425b9c547cSRui Paulo tmp = xml_node_get_text(ctx->xml, node); 26435b9c547cSRui Paulo if (tmp && os_strcasecmp(tmp, "OMA-DM-ClientInitiated") == 0) 26445b9c547cSRui Paulo spp = 0; 26455b9c547cSRui Paulo else 26465b9c547cSRui Paulo spp = 1; 26475b9c547cSRui Paulo } else { 26485b9c547cSRui Paulo wpa_printf(MSG_INFO, "No UpdateMethod specified - assume SPP"); 26495b9c547cSRui Paulo spp = 1; 26505b9c547cSRui Paulo } 26515b9c547cSRui Paulo 26525b9c547cSRui Paulo get_user_pw(ctx, pps, "SubscriptionUpdate/UsernamePassword", 26535b9c547cSRui Paulo &cred_username, &cred_password); 26545b9c547cSRui Paulo if (cred_username) 26555b9c547cSRui Paulo wpa_printf(MSG_INFO, "Using username: %s", cred_username); 26565b9c547cSRui Paulo if (cred_password) 26575b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "Using password: %s", cred_password); 26585b9c547cSRui Paulo 26595b9c547cSRui Paulo if (cred_username == NULL && cred_password == NULL && 26605b9c547cSRui Paulo get_child_node(ctx->xml, pps, "Credential/DigitalCertificate")) { 26615b9c547cSRui Paulo wpa_printf(MSG_INFO, "Using client certificate"); 26625b9c547cSRui Paulo os_snprintf(client_cert_buf, sizeof(client_cert_buf), 26635b9c547cSRui Paulo "SP/%s/client-cert.pem", ctx->fqdn); 26645b9c547cSRui Paulo client_cert = client_cert_buf; 26655b9c547cSRui Paulo os_snprintf(client_key_buf, sizeof(client_key_buf), 26665b9c547cSRui Paulo "SP/%s/client-key.pem", ctx->fqdn); 26675b9c547cSRui Paulo client_key = client_key_buf; 26685b9c547cSRui Paulo ctx->client_cert_present = 1; 26695b9c547cSRui Paulo } 26705b9c547cSRui Paulo 26715b9c547cSRui Paulo node = get_child_node(ctx->xml, pps, "SubscriptionUpdate/URI"); 26725b9c547cSRui Paulo if (node) { 26735b9c547cSRui Paulo sub_rem_uri = xml_node_get_text(ctx->xml, node); 26745b9c547cSRui Paulo if (sub_rem_uri && 26755b9c547cSRui Paulo (!address || os_strcmp(address, sub_rem_uri) != 0)) { 26765b9c547cSRui Paulo wpa_printf(MSG_INFO, "Override sub rem URI based on PPS: %s", 26775b9c547cSRui Paulo sub_rem_uri); 26785b9c547cSRui Paulo address = sub_rem_uri; 26795b9c547cSRui Paulo } 26805b9c547cSRui Paulo } 26815b9c547cSRui Paulo if (!address) { 26825b9c547cSRui Paulo wpa_printf(MSG_INFO, "Server URL not known"); 26835b9c547cSRui Paulo return -1; 26845b9c547cSRui Paulo } 26855b9c547cSRui Paulo 26865b9c547cSRui Paulo write_summary(ctx, "Wait for IP address for subscriptiom remediation"); 26875b9c547cSRui Paulo wpa_printf(MSG_INFO, "Wait for IP address before starting subscription remediation"); 26885b9c547cSRui Paulo 26895b9c547cSRui Paulo if (wait_ip_addr(ctx->ifname, 15) < 0) { 26905b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not get IP address for WLAN - try connection anyway"); 26915b9c547cSRui Paulo } 26925b9c547cSRui Paulo 26935b9c547cSRui Paulo if (spp) 26945b9c547cSRui Paulo spp_sub_rem(ctx, address, pps_fname, 26955b9c547cSRui Paulo client_cert, client_key, 26965b9c547cSRui Paulo cred_username, cred_password, pps); 26975b9c547cSRui Paulo else 26985b9c547cSRui Paulo oma_dm_sub_rem(ctx, address, pps_fname, 26995b9c547cSRui Paulo client_cert, client_key, 27005b9c547cSRui Paulo cred_username, cred_password, pps); 27015b9c547cSRui Paulo 27025b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, sub_rem_uri); 27035b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, cred_username); 27045b9c547cSRui Paulo str_clear_free(cred_password); 27055b9c547cSRui Paulo xml_node_free(ctx->xml, pps); 27065b9c547cSRui Paulo return 0; 27075b9c547cSRui Paulo } 27085b9c547cSRui Paulo 27095b9c547cSRui Paulo 27105b9c547cSRui Paulo static int cmd_pol_upd(struct hs20_osu_client *ctx, const char *address, 27115b9c547cSRui Paulo const char *pps_fname, const char *ca_fname) 27125b9c547cSRui Paulo { 27135b9c547cSRui Paulo xml_node_t *pps; 27145b9c547cSRui Paulo xml_node_t *node; 27155b9c547cSRui Paulo char pps_fname_buf[300]; 27165b9c547cSRui Paulo char ca_fname_buf[200]; 27175b9c547cSRui Paulo char *uri = NULL; 27185b9c547cSRui Paulo char *cred_username = NULL; 27195b9c547cSRui Paulo char *cred_password = NULL; 27205b9c547cSRui Paulo char client_cert_buf[200]; 27215b9c547cSRui Paulo char *client_cert = NULL; 27225b9c547cSRui Paulo char client_key_buf[200]; 27235b9c547cSRui Paulo char *client_key = NULL; 27245b9c547cSRui Paulo int spp; 27255b9c547cSRui Paulo 27265b9c547cSRui Paulo wpa_printf(MSG_INFO, "Policy update requested"); 27275b9c547cSRui Paulo 27285b9c547cSRui Paulo if (!pps_fname) { 27295b9c547cSRui Paulo char buf[256]; 2730206b73d0SCy Schubert int res; 2731206b73d0SCy Schubert 27325b9c547cSRui Paulo wpa_printf(MSG_INFO, "Determining PPS file based on Home SP information"); 2733780fb4a2SCy Schubert if (address && os_strncmp(address, "fqdn=", 5) == 0) { 27345b9c547cSRui Paulo wpa_printf(MSG_INFO, "Use requested FQDN from command line"); 27355b9c547cSRui Paulo os_snprintf(buf, sizeof(buf), "%s", address + 5); 27365b9c547cSRui Paulo address = NULL; 27375b9c547cSRui Paulo } else if (get_wpa_status(ctx->ifname, "provisioning_sp", buf, 27385b9c547cSRui Paulo sizeof(buf)) < 0) { 27395b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not get provisioning Home SP FQDN from wpa_supplicant"); 27405b9c547cSRui Paulo return -1; 27415b9c547cSRui Paulo } 27425b9c547cSRui Paulo os_free(ctx->fqdn); 27435b9c547cSRui Paulo ctx->fqdn = os_strdup(buf); 27445b9c547cSRui Paulo if (ctx->fqdn == NULL) 27455b9c547cSRui Paulo return -1; 27465b9c547cSRui Paulo wpa_printf(MSG_INFO, "Home SP FQDN for current credential: %s", 27475b9c547cSRui Paulo buf); 27485b9c547cSRui Paulo os_snprintf(pps_fname_buf, sizeof(pps_fname_buf), 27495b9c547cSRui Paulo "SP/%s/pps.xml", ctx->fqdn); 27505b9c547cSRui Paulo pps_fname = pps_fname_buf; 27515b9c547cSRui Paulo 2752206b73d0SCy Schubert res = os_snprintf(ca_fname_buf, sizeof(ca_fname_buf), 2753206b73d0SCy Schubert "SP/%s/ca.pem", buf); 2754206b73d0SCy Schubert if (os_snprintf_error(sizeof(ca_fname_buf), res)) { 2755206b73d0SCy Schubert os_free(ctx->fqdn); 2756206b73d0SCy Schubert ctx->fqdn = NULL; 2757206b73d0SCy Schubert return -1; 2758206b73d0SCy Schubert } 27595b9c547cSRui Paulo ca_fname = ca_fname_buf; 27605b9c547cSRui Paulo } 27615b9c547cSRui Paulo 27625b9c547cSRui Paulo if (!os_file_exists(pps_fname)) { 27635b9c547cSRui Paulo wpa_printf(MSG_INFO, "PPS file '%s' does not exist or is not accessible", 27645b9c547cSRui Paulo pps_fname); 27655b9c547cSRui Paulo return -1; 27665b9c547cSRui Paulo } 27675b9c547cSRui Paulo wpa_printf(MSG_INFO, "Using PPS file: %s", pps_fname); 27685b9c547cSRui Paulo 27695b9c547cSRui Paulo if (ca_fname && !os_file_exists(ca_fname)) { 27705b9c547cSRui Paulo wpa_printf(MSG_INFO, "CA file '%s' does not exist or is not accessible", 27715b9c547cSRui Paulo ca_fname); 27725b9c547cSRui Paulo return -1; 27735b9c547cSRui Paulo } 27745b9c547cSRui Paulo wpa_printf(MSG_INFO, "Using server trust root: %s", ca_fname); 27755b9c547cSRui Paulo ctx->ca_fname = ca_fname; 27765b9c547cSRui Paulo 27775b9c547cSRui Paulo pps = node_from_file(ctx->xml, pps_fname); 27785b9c547cSRui Paulo if (pps == NULL) { 27795b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not read PPS MO"); 27805b9c547cSRui Paulo return -1; 27815b9c547cSRui Paulo } 27825b9c547cSRui Paulo 27835b9c547cSRui Paulo if (!ctx->fqdn) { 27845b9c547cSRui Paulo char *tmp; 27855b9c547cSRui Paulo node = get_child_node(ctx->xml, pps, "HomeSP/FQDN"); 27865b9c547cSRui Paulo if (node == NULL) { 27875b9c547cSRui Paulo wpa_printf(MSG_INFO, "No HomeSP/FQDN found from PPS"); 27885b9c547cSRui Paulo return -1; 27895b9c547cSRui Paulo } 27905b9c547cSRui Paulo tmp = xml_node_get_text(ctx->xml, node); 27915b9c547cSRui Paulo if (tmp == NULL) { 27925b9c547cSRui Paulo wpa_printf(MSG_INFO, "No HomeSP/FQDN text found from PPS"); 27935b9c547cSRui Paulo return -1; 27945b9c547cSRui Paulo } 27955b9c547cSRui Paulo ctx->fqdn = os_strdup(tmp); 27965b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, tmp); 27975b9c547cSRui Paulo if (!ctx->fqdn) { 27985b9c547cSRui Paulo wpa_printf(MSG_INFO, "No FQDN known"); 27995b9c547cSRui Paulo return -1; 28005b9c547cSRui Paulo } 28015b9c547cSRui Paulo } 28025b9c547cSRui Paulo 28035b9c547cSRui Paulo node = get_child_node(ctx->xml, pps, 28045b9c547cSRui Paulo "Policy/PolicyUpdate/UpdateMethod"); 28055b9c547cSRui Paulo if (node) { 28065b9c547cSRui Paulo char *tmp; 28075b9c547cSRui Paulo tmp = xml_node_get_text(ctx->xml, node); 28085b9c547cSRui Paulo if (tmp && os_strcasecmp(tmp, "OMA-DM-ClientInitiated") == 0) 28095b9c547cSRui Paulo spp = 0; 28105b9c547cSRui Paulo else 28115b9c547cSRui Paulo spp = 1; 28125b9c547cSRui Paulo } else { 28135b9c547cSRui Paulo wpa_printf(MSG_INFO, "No UpdateMethod specified - assume SPP"); 28145b9c547cSRui Paulo spp = 1; 28155b9c547cSRui Paulo } 28165b9c547cSRui Paulo 28175b9c547cSRui Paulo get_user_pw(ctx, pps, "Policy/PolicyUpdate/UsernamePassword", 28185b9c547cSRui Paulo &cred_username, &cred_password); 28195b9c547cSRui Paulo if (cred_username) 28205b9c547cSRui Paulo wpa_printf(MSG_INFO, "Using username: %s", cred_username); 28215b9c547cSRui Paulo if (cred_password) 28225b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "Using password: %s", cred_password); 28235b9c547cSRui Paulo 28245b9c547cSRui Paulo if (cred_username == NULL && cred_password == NULL && 28255b9c547cSRui Paulo get_child_node(ctx->xml, pps, "Credential/DigitalCertificate")) { 28265b9c547cSRui Paulo wpa_printf(MSG_INFO, "Using client certificate"); 28275b9c547cSRui Paulo os_snprintf(client_cert_buf, sizeof(client_cert_buf), 28285b9c547cSRui Paulo "SP/%s/client-cert.pem", ctx->fqdn); 28295b9c547cSRui Paulo client_cert = client_cert_buf; 28305b9c547cSRui Paulo os_snprintf(client_key_buf, sizeof(client_key_buf), 28315b9c547cSRui Paulo "SP/%s/client-key.pem", ctx->fqdn); 28325b9c547cSRui Paulo client_key = client_key_buf; 28335b9c547cSRui Paulo } 28345b9c547cSRui Paulo 28355b9c547cSRui Paulo if (!address) { 28365b9c547cSRui Paulo node = get_child_node(ctx->xml, pps, "Policy/PolicyUpdate/URI"); 28375b9c547cSRui Paulo if (node) { 28385b9c547cSRui Paulo uri = xml_node_get_text(ctx->xml, node); 28395b9c547cSRui Paulo wpa_printf(MSG_INFO, "URI based on PPS: %s", uri); 28405b9c547cSRui Paulo address = uri; 28415b9c547cSRui Paulo } 28425b9c547cSRui Paulo } 28435b9c547cSRui Paulo if (!address) { 28445b9c547cSRui Paulo wpa_printf(MSG_INFO, "Server URL not known"); 28455b9c547cSRui Paulo return -1; 28465b9c547cSRui Paulo } 28475b9c547cSRui Paulo 28485b9c547cSRui Paulo if (spp) 28495b9c547cSRui Paulo spp_pol_upd(ctx, address, pps_fname, 28505b9c547cSRui Paulo client_cert, client_key, 28515b9c547cSRui Paulo cred_username, cred_password, pps); 28525b9c547cSRui Paulo else 28535b9c547cSRui Paulo oma_dm_pol_upd(ctx, address, pps_fname, 28545b9c547cSRui Paulo client_cert, client_key, 28555b9c547cSRui Paulo cred_username, cred_password, pps); 28565b9c547cSRui Paulo 28575b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, uri); 28585b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, cred_username); 28595b9c547cSRui Paulo str_clear_free(cred_password); 28605b9c547cSRui Paulo xml_node_free(ctx->xml, pps); 28615b9c547cSRui Paulo 28625b9c547cSRui Paulo return 0; 28635b9c547cSRui Paulo } 28645b9c547cSRui Paulo 28655b9c547cSRui Paulo 28665b9c547cSRui Paulo static char * get_hostname(const char *url) 28675b9c547cSRui Paulo { 28685b9c547cSRui Paulo const char *pos, *end, *end2; 28695b9c547cSRui Paulo char *ret; 28705b9c547cSRui Paulo 28715b9c547cSRui Paulo if (url == NULL) 28725b9c547cSRui Paulo return NULL; 28735b9c547cSRui Paulo 28745b9c547cSRui Paulo pos = os_strchr(url, '/'); 28755b9c547cSRui Paulo if (pos == NULL) 28765b9c547cSRui Paulo return NULL; 28775b9c547cSRui Paulo pos++; 28785b9c547cSRui Paulo if (*pos != '/') 28795b9c547cSRui Paulo return NULL; 28805b9c547cSRui Paulo pos++; 28815b9c547cSRui Paulo 28825b9c547cSRui Paulo end = os_strchr(pos, '/'); 28835b9c547cSRui Paulo end2 = os_strchr(pos, ':'); 2884325151a3SRui Paulo if ((end && end2 && end2 < end) || (!end && end2)) 28855b9c547cSRui Paulo end = end2; 28865b9c547cSRui Paulo if (end) 28875b9c547cSRui Paulo end--; 28885b9c547cSRui Paulo else { 28895b9c547cSRui Paulo end = pos; 28905b9c547cSRui Paulo while (*end) 28915b9c547cSRui Paulo end++; 28925b9c547cSRui Paulo if (end > pos) 28935b9c547cSRui Paulo end--; 28945b9c547cSRui Paulo } 28955b9c547cSRui Paulo 28965b9c547cSRui Paulo ret = os_malloc(end - pos + 2); 28975b9c547cSRui Paulo if (ret == NULL) 28985b9c547cSRui Paulo return NULL; 28995b9c547cSRui Paulo 29005b9c547cSRui Paulo os_memcpy(ret, pos, end - pos + 1); 29015b9c547cSRui Paulo ret[end - pos + 1] = '\0'; 29025b9c547cSRui Paulo 29035b9c547cSRui Paulo return ret; 29045b9c547cSRui Paulo } 29055b9c547cSRui Paulo 29065b9c547cSRui Paulo 29075b9c547cSRui Paulo static int osu_cert_cb(void *_ctx, struct http_cert *cert) 29085b9c547cSRui Paulo { 29095b9c547cSRui Paulo struct hs20_osu_client *ctx = _ctx; 2910*c1d255d3SCy Schubert size_t i, j; 29115b9c547cSRui Paulo int found; 29125b9c547cSRui Paulo char *host = NULL; 29135b9c547cSRui Paulo 2914325151a3SRui Paulo wpa_printf(MSG_INFO, "osu_cert_cb(osu_cert_validation=%d, url=%s)", 2915325151a3SRui Paulo !ctx->no_osu_cert_validation, ctx->server_url); 29165b9c547cSRui Paulo 29175b9c547cSRui Paulo host = get_hostname(ctx->server_url); 29185b9c547cSRui Paulo 29195b9c547cSRui Paulo for (i = 0; i < ctx->server_dnsname_count; i++) 29205b9c547cSRui Paulo os_free(ctx->server_dnsname[i]); 29215b9c547cSRui Paulo os_free(ctx->server_dnsname); 29225b9c547cSRui Paulo ctx->server_dnsname = os_calloc(cert->num_dnsname, sizeof(char *)); 29235b9c547cSRui Paulo ctx->server_dnsname_count = 0; 29245b9c547cSRui Paulo 29255b9c547cSRui Paulo found = 0; 29265b9c547cSRui Paulo for (i = 0; i < cert->num_dnsname; i++) { 29275b9c547cSRui Paulo if (ctx->server_dnsname) { 29285b9c547cSRui Paulo ctx->server_dnsname[ctx->server_dnsname_count] = 29295b9c547cSRui Paulo os_strdup(cert->dnsname[i]); 29305b9c547cSRui Paulo if (ctx->server_dnsname[ctx->server_dnsname_count]) 29315b9c547cSRui Paulo ctx->server_dnsname_count++; 29325b9c547cSRui Paulo } 29335b9c547cSRui Paulo if (host && os_strcasecmp(host, cert->dnsname[i]) == 0) 29345b9c547cSRui Paulo found = 1; 29355b9c547cSRui Paulo wpa_printf(MSG_INFO, "dNSName '%s'", cert->dnsname[i]); 29365b9c547cSRui Paulo } 29375b9c547cSRui Paulo 29385b9c547cSRui Paulo if (host && !found) { 29395b9c547cSRui Paulo wpa_printf(MSG_INFO, "Server name from URL (%s) did not match any dNSName - abort connection", 29405b9c547cSRui Paulo host); 29415b9c547cSRui Paulo write_result(ctx, "Server name from URL (%s) did not match any dNSName - abort connection", 29425b9c547cSRui Paulo host); 29435b9c547cSRui Paulo os_free(host); 29445b9c547cSRui Paulo return -1; 29455b9c547cSRui Paulo } 29465b9c547cSRui Paulo 29475b9c547cSRui Paulo os_free(host); 29485b9c547cSRui Paulo 29495b9c547cSRui Paulo for (i = 0; i < cert->num_othername; i++) { 29505b9c547cSRui Paulo if (os_strcmp(cert->othername[i].oid, 29515b9c547cSRui Paulo "1.3.6.1.4.1.40808.1.1.1") == 0) { 29525b9c547cSRui Paulo wpa_hexdump_ascii(MSG_INFO, 29535b9c547cSRui Paulo "id-wfa-hotspot-friendlyName", 29545b9c547cSRui Paulo cert->othername[i].data, 29555b9c547cSRui Paulo cert->othername[i].len); 29565b9c547cSRui Paulo } 29575b9c547cSRui Paulo } 29585b9c547cSRui Paulo 29595b9c547cSRui Paulo for (j = 0; !ctx->no_osu_cert_validation && 29605b9c547cSRui Paulo j < ctx->friendly_name_count; j++) { 29615b9c547cSRui Paulo int found = 0; 29625b9c547cSRui Paulo for (i = 0; i < cert->num_othername; i++) { 29635b9c547cSRui Paulo if (os_strcmp(cert->othername[i].oid, 29645b9c547cSRui Paulo "1.3.6.1.4.1.40808.1.1.1") != 0) 29655b9c547cSRui Paulo continue; 29665b9c547cSRui Paulo if (cert->othername[i].len < 3) 29675b9c547cSRui Paulo continue; 29685b9c547cSRui Paulo if (os_strncasecmp((char *) cert->othername[i].data, 29695b9c547cSRui Paulo ctx->friendly_name[j].lang, 3) != 0) 29705b9c547cSRui Paulo continue; 29715b9c547cSRui Paulo if (os_strncmp((char *) cert->othername[i].data + 3, 29725b9c547cSRui Paulo ctx->friendly_name[j].text, 29735b9c547cSRui Paulo cert->othername[i].len - 3) == 0) { 29745b9c547cSRui Paulo found = 1; 29755b9c547cSRui Paulo break; 29765b9c547cSRui Paulo } 29775b9c547cSRui Paulo } 29785b9c547cSRui Paulo 29795b9c547cSRui Paulo if (!found) { 29805b9c547cSRui Paulo wpa_printf(MSG_INFO, "No friendly name match found for '[%s]%s'", 29815b9c547cSRui Paulo ctx->friendly_name[j].lang, 29825b9c547cSRui Paulo ctx->friendly_name[j].text); 29835b9c547cSRui Paulo write_result(ctx, "No friendly name match found for '[%s]%s'", 29845b9c547cSRui Paulo ctx->friendly_name[j].lang, 29855b9c547cSRui Paulo ctx->friendly_name[j].text); 29865b9c547cSRui Paulo return -1; 29875b9c547cSRui Paulo } 29885b9c547cSRui Paulo } 29895b9c547cSRui Paulo 29905b9c547cSRui Paulo for (i = 0; i < cert->num_logo; i++) { 29915b9c547cSRui Paulo struct http_logo *logo = &cert->logo[i]; 29925b9c547cSRui Paulo 29935b9c547cSRui Paulo wpa_printf(MSG_INFO, "logo hash alg %s uri '%s'", 29945b9c547cSRui Paulo logo->alg_oid, logo->uri); 29955b9c547cSRui Paulo wpa_hexdump_ascii(MSG_INFO, "hashValue", 29965b9c547cSRui Paulo logo->hash, logo->hash_len); 29975b9c547cSRui Paulo } 29985b9c547cSRui Paulo 29995b9c547cSRui Paulo for (j = 0; !ctx->no_osu_cert_validation && j < ctx->icon_count; j++) { 30005b9c547cSRui Paulo int found = 0; 30015b9c547cSRui Paulo char *name = ctx->icon_filename[j]; 30025b9c547cSRui Paulo size_t name_len = os_strlen(name); 30035b9c547cSRui Paulo 3004325151a3SRui Paulo wpa_printf(MSG_INFO, 3005*c1d255d3SCy Schubert "[%zu] Looking for icon file name '%s' match", 3006325151a3SRui Paulo j, name); 30075b9c547cSRui Paulo for (i = 0; i < cert->num_logo; i++) { 30085b9c547cSRui Paulo struct http_logo *logo = &cert->logo[i]; 30095b9c547cSRui Paulo size_t uri_len = os_strlen(logo->uri); 30105b9c547cSRui Paulo char *pos; 30115b9c547cSRui Paulo 3012325151a3SRui Paulo wpa_printf(MSG_INFO, 3013*c1d255d3SCy Schubert "[%zu] Comparing to '%s' uri_len=%d name_len=%d", 3014325151a3SRui Paulo i, logo->uri, (int) uri_len, (int) name_len); 3015325151a3SRui Paulo if (uri_len < 1 + name_len) { 3016325151a3SRui Paulo wpa_printf(MSG_INFO, "URI Length is too short"); 30175b9c547cSRui Paulo continue; 3018325151a3SRui Paulo } 30195b9c547cSRui Paulo pos = &logo->uri[uri_len - name_len - 1]; 30205b9c547cSRui Paulo if (*pos != '/') 30215b9c547cSRui Paulo continue; 30225b9c547cSRui Paulo pos++; 30235b9c547cSRui Paulo if (os_strcmp(pos, name) == 0) { 30245b9c547cSRui Paulo found = 1; 30255b9c547cSRui Paulo break; 30265b9c547cSRui Paulo } 30275b9c547cSRui Paulo } 30285b9c547cSRui Paulo 30295b9c547cSRui Paulo if (!found) { 30305b9c547cSRui Paulo wpa_printf(MSG_INFO, "No icon filename match found for '%s'", 30315b9c547cSRui Paulo name); 30325b9c547cSRui Paulo write_result(ctx, 30335b9c547cSRui Paulo "No icon filename match found for '%s'", 30345b9c547cSRui Paulo name); 30355b9c547cSRui Paulo return -1; 30365b9c547cSRui Paulo } 30375b9c547cSRui Paulo } 30385b9c547cSRui Paulo 30395b9c547cSRui Paulo for (j = 0; !ctx->no_osu_cert_validation && j < ctx->icon_count; j++) { 30405b9c547cSRui Paulo int found = 0; 30415b9c547cSRui Paulo 30425b9c547cSRui Paulo for (i = 0; i < cert->num_logo; i++) { 30435b9c547cSRui Paulo struct http_logo *logo = &cert->logo[i]; 30445b9c547cSRui Paulo 3045325151a3SRui Paulo if (logo->hash_len != 32) { 3046325151a3SRui Paulo wpa_printf(MSG_INFO, 3047*c1d255d3SCy Schubert "[%zu][%zu] Icon hash length invalid (should be 32): %d", 3048325151a3SRui Paulo j, i, (int) logo->hash_len); 30495b9c547cSRui Paulo continue; 3050325151a3SRui Paulo } 30515b9c547cSRui Paulo if (os_memcmp(logo->hash, ctx->icon_hash[j], 32) == 0) { 30525b9c547cSRui Paulo found = 1; 30535b9c547cSRui Paulo break; 30545b9c547cSRui Paulo } 3055325151a3SRui Paulo 3056325151a3SRui Paulo wpa_printf(MSG_DEBUG, 3057*c1d255d3SCy Schubert "[%zu][%zu] Icon hash did not match", j, i); 3058325151a3SRui Paulo wpa_hexdump_ascii(MSG_DEBUG, "logo->hash", 3059325151a3SRui Paulo logo->hash, 32); 3060325151a3SRui Paulo wpa_hexdump_ascii(MSG_DEBUG, "ctx->icon_hash[j]", 3061325151a3SRui Paulo ctx->icon_hash[j], 32); 30625b9c547cSRui Paulo } 30635b9c547cSRui Paulo 30645b9c547cSRui Paulo if (!found) { 3065325151a3SRui Paulo wpa_printf(MSG_INFO, 3066325151a3SRui Paulo "No icon hash match (by hash) found"); 3067325151a3SRui Paulo write_result(ctx, 3068325151a3SRui Paulo "No icon hash match (by hash) found"); 30695b9c547cSRui Paulo return -1; 30705b9c547cSRui Paulo } 30715b9c547cSRui Paulo } 30725b9c547cSRui Paulo 30735b9c547cSRui Paulo return 0; 30745b9c547cSRui Paulo } 30755b9c547cSRui Paulo 30765b9c547cSRui Paulo 30775b9c547cSRui Paulo static int init_ctx(struct hs20_osu_client *ctx) 30785b9c547cSRui Paulo { 30795b9c547cSRui Paulo xml_node_t *devinfo, *devid; 30805b9c547cSRui Paulo 30815b9c547cSRui Paulo os_memset(ctx, 0, sizeof(*ctx)); 30825b9c547cSRui Paulo ctx->ifname = "wlan0"; 30835b9c547cSRui Paulo ctx->xml = xml_node_init_ctx(ctx, NULL); 30845b9c547cSRui Paulo if (ctx->xml == NULL) 30855b9c547cSRui Paulo return -1; 30865b9c547cSRui Paulo 30875b9c547cSRui Paulo devinfo = node_from_file(ctx->xml, "devinfo.xml"); 308885732ac8SCy Schubert if (devinfo) { 30895b9c547cSRui Paulo devid = get_node(ctx->xml, devinfo, "DevId"); 30905b9c547cSRui Paulo if (devid) { 30915b9c547cSRui Paulo char *tmp = xml_node_get_text(ctx->xml, devid); 309285732ac8SCy Schubert 30935b9c547cSRui Paulo if (tmp) { 30945b9c547cSRui Paulo ctx->devid = os_strdup(tmp); 30955b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, tmp); 30965b9c547cSRui Paulo } 30975b9c547cSRui Paulo } 30985b9c547cSRui Paulo xml_node_free(ctx->xml, devinfo); 30995b9c547cSRui Paulo } 31005b9c547cSRui Paulo 31015b9c547cSRui Paulo ctx->http = http_init_ctx(ctx, ctx->xml); 31025b9c547cSRui Paulo if (ctx->http == NULL) { 31035b9c547cSRui Paulo xml_node_deinit_ctx(ctx->xml); 31045b9c547cSRui Paulo return -1; 31055b9c547cSRui Paulo } 31065b9c547cSRui Paulo http_ocsp_set(ctx->http, 2); 31075b9c547cSRui Paulo http_set_cert_cb(ctx->http, osu_cert_cb, ctx); 31085b9c547cSRui Paulo 31095b9c547cSRui Paulo return 0; 31105b9c547cSRui Paulo } 31115b9c547cSRui Paulo 31125b9c547cSRui Paulo 31135b9c547cSRui Paulo static void deinit_ctx(struct hs20_osu_client *ctx) 31145b9c547cSRui Paulo { 31155b9c547cSRui Paulo size_t i; 31165b9c547cSRui Paulo 31175b9c547cSRui Paulo http_deinit_ctx(ctx->http); 31185b9c547cSRui Paulo xml_node_deinit_ctx(ctx->xml); 31195b9c547cSRui Paulo os_free(ctx->fqdn); 31205b9c547cSRui Paulo os_free(ctx->server_url); 31215b9c547cSRui Paulo os_free(ctx->devid); 31225b9c547cSRui Paulo 31235b9c547cSRui Paulo for (i = 0; i < ctx->server_dnsname_count; i++) 31245b9c547cSRui Paulo os_free(ctx->server_dnsname[i]); 31255b9c547cSRui Paulo os_free(ctx->server_dnsname); 31265b9c547cSRui Paulo } 31275b9c547cSRui Paulo 31285b9c547cSRui Paulo 31295b9c547cSRui Paulo static void check_workarounds(struct hs20_osu_client *ctx) 31305b9c547cSRui Paulo { 31315b9c547cSRui Paulo FILE *f; 31325b9c547cSRui Paulo char buf[100]; 31335b9c547cSRui Paulo unsigned long int val = 0; 31345b9c547cSRui Paulo 31355b9c547cSRui Paulo f = fopen("hs20-osu-client.workarounds", "r"); 31365b9c547cSRui Paulo if (f == NULL) 31375b9c547cSRui Paulo return; 31385b9c547cSRui Paulo 31395b9c547cSRui Paulo if (fgets(buf, sizeof(buf), f)) 31405b9c547cSRui Paulo val = strtoul(buf, NULL, 16); 31415b9c547cSRui Paulo 31425b9c547cSRui Paulo fclose(f); 31435b9c547cSRui Paulo 31445b9c547cSRui Paulo if (val) { 31455b9c547cSRui Paulo wpa_printf(MSG_INFO, "Workarounds enabled: 0x%lx", val); 31465b9c547cSRui Paulo ctx->workarounds = val; 31475b9c547cSRui Paulo if (ctx->workarounds & WORKAROUND_OCSP_OPTIONAL) 31485b9c547cSRui Paulo http_ocsp_set(ctx->http, 1); 31495b9c547cSRui Paulo } 31505b9c547cSRui Paulo } 31515b9c547cSRui Paulo 31525b9c547cSRui Paulo 31535b9c547cSRui Paulo static void usage(void) 31545b9c547cSRui Paulo { 3155*c1d255d3SCy Schubert printf("usage: hs20-osu-client [-dddqqKtT] [-S<station ifname>] \\\n" 31565b9c547cSRui Paulo " [-w<wpa_supplicant ctrl_iface dir>] " 31575b9c547cSRui Paulo "[-r<result file>] [-f<debug file>] \\\n" 31585b9c547cSRui Paulo " [-s<summary file>] \\\n" 3159325151a3SRui Paulo " [-x<spp.xsd file name>] \\\n" 31605b9c547cSRui Paulo " <command> [arguments..]\n" 31615b9c547cSRui Paulo "commands:\n" 31625b9c547cSRui Paulo "- to_tnds <XML MO> <XML MO in TNDS format> [URN]\n" 31635b9c547cSRui Paulo "- to_tnds2 <XML MO> <XML MO in TNDS format (Path) " 31645b9c547cSRui Paulo "[URN]>\n" 31655b9c547cSRui Paulo "- from_tnds <XML MO in TNDS format> <XML MO>\n" 31665b9c547cSRui Paulo "- set_pps <PerProviderSubscription XML file name>\n" 31675b9c547cSRui Paulo "- get_fqdn <PerProviderSubscription XML file name>\n" 31685b9c547cSRui Paulo "- pol_upd [Server URL] [PPS] [CA cert]\n" 31695b9c547cSRui Paulo "- sub_rem <Server URL> [PPS] [CA cert]\n" 31705b9c547cSRui Paulo "- prov <Server URL> [CA cert]\n" 31715b9c547cSRui Paulo "- oma_dm_prov <Server URL> [CA cert]\n" 31725b9c547cSRui Paulo "- sim_prov <Server URL> [CA cert]\n" 31735b9c547cSRui Paulo "- oma_dm_sim_prov <Server URL> [CA cert]\n" 31745b9c547cSRui Paulo "- signup [CA cert]\n" 31755b9c547cSRui Paulo "- dl_osu_ca <PPS> <CA file>\n" 31765b9c547cSRui Paulo "- dl_polupd_ca <PPS> <CA file>\n" 31775b9c547cSRui Paulo "- dl_aaa_ca <PPS> <CA file>\n" 31785b9c547cSRui Paulo "- browser <URL>\n" 31795b9c547cSRui Paulo "- parse_cert <X.509 certificate (DER)>\n" 31805b9c547cSRui Paulo "- osu_select <OSU info directory> [CA cert]\n"); 31815b9c547cSRui Paulo } 31825b9c547cSRui Paulo 31835b9c547cSRui Paulo 31845b9c547cSRui Paulo int main(int argc, char *argv[]) 31855b9c547cSRui Paulo { 31865b9c547cSRui Paulo struct hs20_osu_client ctx; 31875b9c547cSRui Paulo int c; 31885b9c547cSRui Paulo int ret = 0; 31895b9c547cSRui Paulo int no_prod_assoc = 0; 31905b9c547cSRui Paulo const char *friendly_name = NULL; 31915b9c547cSRui Paulo const char *wpa_debug_file_path = NULL; 31925b9c547cSRui Paulo extern char *wpas_ctrl_path; 31935b9c547cSRui Paulo extern int wpa_debug_level; 31945b9c547cSRui Paulo extern int wpa_debug_show_keys; 31955b9c547cSRui Paulo extern int wpa_debug_timestamp; 31965b9c547cSRui Paulo 31975b9c547cSRui Paulo if (init_ctx(&ctx) < 0) 31985b9c547cSRui Paulo return -1; 31995b9c547cSRui Paulo 32005b9c547cSRui Paulo for (;;) { 3201*c1d255d3SCy Schubert c = getopt(argc, argv, "df:hKNo:O:qr:s:S:tTw:x:"); 32025b9c547cSRui Paulo if (c < 0) 32035b9c547cSRui Paulo break; 32045b9c547cSRui Paulo switch (c) { 32055b9c547cSRui Paulo case 'd': 32065b9c547cSRui Paulo if (wpa_debug_level > 0) 32075b9c547cSRui Paulo wpa_debug_level--; 32085b9c547cSRui Paulo break; 32095b9c547cSRui Paulo case 'f': 32105b9c547cSRui Paulo wpa_debug_file_path = optarg; 32115b9c547cSRui Paulo break; 32125b9c547cSRui Paulo case 'K': 32135b9c547cSRui Paulo wpa_debug_show_keys++; 32145b9c547cSRui Paulo break; 32155b9c547cSRui Paulo case 'N': 32165b9c547cSRui Paulo no_prod_assoc = 1; 32175b9c547cSRui Paulo break; 321885732ac8SCy Schubert case 'o': 321985732ac8SCy Schubert ctx.osu_ssid = optarg; 322085732ac8SCy Schubert break; 32215b9c547cSRui Paulo case 'O': 32225b9c547cSRui Paulo friendly_name = optarg; 32235b9c547cSRui Paulo break; 32245b9c547cSRui Paulo case 'q': 32255b9c547cSRui Paulo wpa_debug_level++; 32265b9c547cSRui Paulo break; 32275b9c547cSRui Paulo case 'r': 32285b9c547cSRui Paulo ctx.result_file = optarg; 32295b9c547cSRui Paulo break; 32305b9c547cSRui Paulo case 's': 32315b9c547cSRui Paulo ctx.summary_file = optarg; 32325b9c547cSRui Paulo break; 32335b9c547cSRui Paulo case 'S': 32345b9c547cSRui Paulo ctx.ifname = optarg; 32355b9c547cSRui Paulo break; 32365b9c547cSRui Paulo case 't': 32375b9c547cSRui Paulo wpa_debug_timestamp++; 32385b9c547cSRui Paulo break; 3239*c1d255d3SCy Schubert case 'T': 3240*c1d255d3SCy Schubert ctx.ignore_tls = 1; 3241*c1d255d3SCy Schubert break; 32425b9c547cSRui Paulo case 'w': 32435b9c547cSRui Paulo wpas_ctrl_path = optarg; 32445b9c547cSRui Paulo break; 3245325151a3SRui Paulo case 'x': 3246325151a3SRui Paulo spp_xsd_fname = optarg; 3247325151a3SRui Paulo break; 32485b9c547cSRui Paulo case 'h': 32495b9c547cSRui Paulo default: 32505b9c547cSRui Paulo usage(); 32515b9c547cSRui Paulo exit(0); 32525b9c547cSRui Paulo break; 32535b9c547cSRui Paulo } 32545b9c547cSRui Paulo } 32555b9c547cSRui Paulo 32565b9c547cSRui Paulo if (argc - optind < 1) { 32575b9c547cSRui Paulo usage(); 32585b9c547cSRui Paulo exit(0); 32595b9c547cSRui Paulo } 32605b9c547cSRui Paulo 32615b9c547cSRui Paulo wpa_debug_open_file(wpa_debug_file_path); 32625b9c547cSRui Paulo 32635b9c547cSRui Paulo #ifdef __linux__ 32645b9c547cSRui Paulo setlinebuf(stdout); 32655b9c547cSRui Paulo #endif /* __linux__ */ 32665b9c547cSRui Paulo 32675b9c547cSRui Paulo if (ctx.result_file) 32685b9c547cSRui Paulo unlink(ctx.result_file); 32695b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "===[hs20-osu-client START - command: %s ]======" 32705b9c547cSRui Paulo "================", argv[optind]); 32715b9c547cSRui Paulo check_workarounds(&ctx); 32725b9c547cSRui Paulo 32735b9c547cSRui Paulo if (strcmp(argv[optind], "to_tnds") == 0) { 32745b9c547cSRui Paulo if (argc - optind < 2) { 32755b9c547cSRui Paulo usage(); 32765b9c547cSRui Paulo exit(0); 32775b9c547cSRui Paulo } 32785b9c547cSRui Paulo cmd_to_tnds(&ctx, argv[optind + 1], argv[optind + 2], 32795b9c547cSRui Paulo argc > optind + 3 ? argv[optind + 3] : NULL, 32805b9c547cSRui Paulo 0); 32815b9c547cSRui Paulo } else if (strcmp(argv[optind], "to_tnds2") == 0) { 32825b9c547cSRui Paulo if (argc - optind < 2) { 32835b9c547cSRui Paulo usage(); 32845b9c547cSRui Paulo exit(0); 32855b9c547cSRui Paulo } 32865b9c547cSRui Paulo cmd_to_tnds(&ctx, argv[optind + 1], argv[optind + 2], 32875b9c547cSRui Paulo argc > optind + 3 ? argv[optind + 3] : NULL, 32885b9c547cSRui Paulo 1); 32895b9c547cSRui Paulo } else if (strcmp(argv[optind], "from_tnds") == 0) { 32905b9c547cSRui Paulo if (argc - optind < 2) { 32915b9c547cSRui Paulo usage(); 32925b9c547cSRui Paulo exit(0); 32935b9c547cSRui Paulo } 32945b9c547cSRui Paulo cmd_from_tnds(&ctx, argv[optind + 1], argv[optind + 2]); 32955b9c547cSRui Paulo } else if (strcmp(argv[optind], "sub_rem") == 0) { 32965b9c547cSRui Paulo if (argc - optind < 2) { 32975b9c547cSRui Paulo usage(); 32985b9c547cSRui Paulo exit(0); 32995b9c547cSRui Paulo } 33005b9c547cSRui Paulo ret = cmd_sub_rem(&ctx, argv[optind + 1], 3301780fb4a2SCy Schubert argc > optind + 2 ? argv[optind + 2] : NULL, 3302780fb4a2SCy Schubert argc > optind + 3 ? argv[optind + 3] : NULL); 33035b9c547cSRui Paulo } else if (strcmp(argv[optind], "pol_upd") == 0) { 3304780fb4a2SCy Schubert ret = cmd_pol_upd(&ctx, 3305780fb4a2SCy Schubert argc > optind + 1 ? argv[optind + 1] : NULL, 33065b9c547cSRui Paulo argc > optind + 2 ? argv[optind + 2] : NULL, 33075b9c547cSRui Paulo argc > optind + 3 ? argv[optind + 3] : NULL); 33085b9c547cSRui Paulo } else if (strcmp(argv[optind], "prov") == 0) { 33095b9c547cSRui Paulo if (argc - optind < 2) { 33105b9c547cSRui Paulo usage(); 33115b9c547cSRui Paulo exit(0); 33125b9c547cSRui Paulo } 33135b9c547cSRui Paulo ctx.ca_fname = argv[optind + 2]; 3314325151a3SRui Paulo wpa_printf(MSG_DEBUG, "Calling cmd_prov from main"); 33155b9c547cSRui Paulo cmd_prov(&ctx, argv[optind + 1]); 33165b9c547cSRui Paulo } else if (strcmp(argv[optind], "sim_prov") == 0) { 33175b9c547cSRui Paulo if (argc - optind < 2) { 33185b9c547cSRui Paulo usage(); 33195b9c547cSRui Paulo exit(0); 33205b9c547cSRui Paulo } 33215b9c547cSRui Paulo ctx.ca_fname = argv[optind + 2]; 33225b9c547cSRui Paulo cmd_sim_prov(&ctx, argv[optind + 1]); 33235b9c547cSRui Paulo } else if (strcmp(argv[optind], "dl_osu_ca") == 0) { 33245b9c547cSRui Paulo if (argc - optind < 2) { 33255b9c547cSRui Paulo usage(); 33265b9c547cSRui Paulo exit(0); 33275b9c547cSRui Paulo } 33285b9c547cSRui Paulo cmd_dl_osu_ca(&ctx, argv[optind + 1], argv[optind + 2]); 33295b9c547cSRui Paulo } else if (strcmp(argv[optind], "dl_polupd_ca") == 0) { 33305b9c547cSRui Paulo if (argc - optind < 2) { 33315b9c547cSRui Paulo usage(); 33325b9c547cSRui Paulo exit(0); 33335b9c547cSRui Paulo } 33345b9c547cSRui Paulo cmd_dl_polupd_ca(&ctx, argv[optind + 1], argv[optind + 2]); 33355b9c547cSRui Paulo } else if (strcmp(argv[optind], "dl_aaa_ca") == 0) { 33365b9c547cSRui Paulo if (argc - optind < 2) { 33375b9c547cSRui Paulo usage(); 33385b9c547cSRui Paulo exit(0); 33395b9c547cSRui Paulo } 33405b9c547cSRui Paulo cmd_dl_aaa_ca(&ctx, argv[optind + 1], argv[optind + 2]); 33415b9c547cSRui Paulo } else if (strcmp(argv[optind], "osu_select") == 0) { 33425b9c547cSRui Paulo if (argc - optind < 2) { 33435b9c547cSRui Paulo usage(); 33445b9c547cSRui Paulo exit(0); 33455b9c547cSRui Paulo } 33465b9c547cSRui Paulo ctx.ca_fname = argc > optind + 2 ? argv[optind + 2] : NULL; 33475b9c547cSRui Paulo cmd_osu_select(&ctx, argv[optind + 1], 2, 1, NULL); 33485b9c547cSRui Paulo } else if (strcmp(argv[optind], "signup") == 0) { 33495b9c547cSRui Paulo ctx.ca_fname = argc > optind + 1 ? argv[optind + 1] : NULL; 33505b9c547cSRui Paulo ret = cmd_signup(&ctx, no_prod_assoc, friendly_name); 33515b9c547cSRui Paulo } else if (strcmp(argv[optind], "set_pps") == 0) { 33525b9c547cSRui Paulo if (argc - optind < 2) { 33535b9c547cSRui Paulo usage(); 33545b9c547cSRui Paulo exit(0); 33555b9c547cSRui Paulo } 33565b9c547cSRui Paulo cmd_set_pps(&ctx, argv[optind + 1]); 33575b9c547cSRui Paulo } else if (strcmp(argv[optind], "get_fqdn") == 0) { 33585b9c547cSRui Paulo if (argc - optind < 1) { 33595b9c547cSRui Paulo usage(); 33605b9c547cSRui Paulo exit(0); 33615b9c547cSRui Paulo } 33625b9c547cSRui Paulo ret = cmd_get_fqdn(&ctx, argv[optind + 1]); 33635b9c547cSRui Paulo } else if (strcmp(argv[optind], "oma_dm_prov") == 0) { 33645b9c547cSRui Paulo if (argc - optind < 2) { 33655b9c547cSRui Paulo usage(); 33665b9c547cSRui Paulo exit(0); 33675b9c547cSRui Paulo } 33685b9c547cSRui Paulo ctx.ca_fname = argv[optind + 2]; 33695b9c547cSRui Paulo cmd_oma_dm_prov(&ctx, argv[optind + 1]); 33705b9c547cSRui Paulo } else if (strcmp(argv[optind], "oma_dm_sim_prov") == 0) { 33715b9c547cSRui Paulo if (argc - optind < 2) { 33725b9c547cSRui Paulo usage(); 33735b9c547cSRui Paulo exit(0); 33745b9c547cSRui Paulo } 33755b9c547cSRui Paulo ctx.ca_fname = argv[optind + 2]; 33765b9c547cSRui Paulo if (cmd_oma_dm_sim_prov(&ctx, argv[optind + 1]) < 0) { 33775b9c547cSRui Paulo write_summary(&ctx, "Failed to complete OMA DM SIM provisioning"); 33785b9c547cSRui Paulo return -1; 33795b9c547cSRui Paulo } 33805b9c547cSRui Paulo } else if (strcmp(argv[optind], "oma_dm_add") == 0) { 33815b9c547cSRui Paulo if (argc - optind < 2) { 33825b9c547cSRui Paulo usage(); 33835b9c547cSRui Paulo exit(0); 33845b9c547cSRui Paulo } 33855b9c547cSRui Paulo cmd_oma_dm_add(&ctx, argv[optind + 1], argv[optind + 2]); 33865b9c547cSRui Paulo } else if (strcmp(argv[optind], "oma_dm_replace") == 0) { 33875b9c547cSRui Paulo if (argc - optind < 2) { 33885b9c547cSRui Paulo usage(); 33895b9c547cSRui Paulo exit(0); 33905b9c547cSRui Paulo } 33915b9c547cSRui Paulo cmd_oma_dm_replace(&ctx, argv[optind + 1], argv[optind + 2]); 33925b9c547cSRui Paulo } else if (strcmp(argv[optind], "est_csr") == 0) { 33935b9c547cSRui Paulo if (argc - optind < 2) { 33945b9c547cSRui Paulo usage(); 33955b9c547cSRui Paulo exit(0); 33965b9c547cSRui Paulo } 33975b9c547cSRui Paulo mkdir("Cert", S_IRWXU); 33985b9c547cSRui Paulo est_build_csr(&ctx, argv[optind + 1]); 33995b9c547cSRui Paulo } else if (strcmp(argv[optind], "browser") == 0) { 34005b9c547cSRui Paulo int ret; 34015b9c547cSRui Paulo 34025b9c547cSRui Paulo if (argc - optind < 2) { 34035b9c547cSRui Paulo usage(); 34045b9c547cSRui Paulo exit(0); 34055b9c547cSRui Paulo } 34065b9c547cSRui Paulo 34075b9c547cSRui Paulo wpa_printf(MSG_INFO, "Launch web browser to URL %s", 34085b9c547cSRui Paulo argv[optind + 1]); 3409*c1d255d3SCy Schubert ret = hs20_web_browser(argv[optind + 1], ctx.ignore_tls); 34105b9c547cSRui Paulo wpa_printf(MSG_INFO, "Web browser result: %d", ret); 34115b9c547cSRui Paulo } else if (strcmp(argv[optind], "parse_cert") == 0) { 34125b9c547cSRui Paulo if (argc - optind < 2) { 34135b9c547cSRui Paulo usage(); 34145b9c547cSRui Paulo exit(0); 34155b9c547cSRui Paulo } 34165b9c547cSRui Paulo 34175b9c547cSRui Paulo wpa_debug_level = MSG_MSGDUMP; 34185b9c547cSRui Paulo http_parse_x509_certificate(ctx.http, argv[optind + 1]); 34195b9c547cSRui Paulo wpa_debug_level = MSG_INFO; 34205b9c547cSRui Paulo } else { 34215b9c547cSRui Paulo wpa_printf(MSG_INFO, "Unknown command '%s'", argv[optind]); 34225b9c547cSRui Paulo } 34235b9c547cSRui Paulo 34245b9c547cSRui Paulo deinit_ctx(&ctx); 34255b9c547cSRui Paulo wpa_printf(MSG_DEBUG, 34265b9c547cSRui Paulo "===[hs20-osu-client END ]======================"); 34275b9c547cSRui Paulo 34285b9c547cSRui Paulo wpa_debug_close_file(); 34295b9c547cSRui Paulo 34305b9c547cSRui Paulo return ret; 34315b9c547cSRui Paulo } 3432