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 108*85732ac8SCy Schubert static int android_update_permission(const char *path, mode_t mode) 109*85732ac8SCy Schubert { 110*85732ac8SCy Schubert #ifdef ANDROID 111*85732ac8SCy Schubert /* we need to change file/folder permission for Android */ 112*85732ac8SCy Schubert 113*85732ac8SCy Schubert if (!path) { 114*85732ac8SCy Schubert wpa_printf(MSG_ERROR, "file path null"); 115*85732ac8SCy Schubert return -1; 116*85732ac8SCy Schubert } 117*85732ac8SCy Schubert 118*85732ac8SCy Schubert /* Allow processes running with Group ID as AID_WIFI, 119*85732ac8SCy Schubert * to read files from SP, SP/<fqdn>, Cert and osu-info directories */ 120*85732ac8SCy Schubert if (chown(path, -1, AID_WIFI)) { 121*85732ac8SCy Schubert wpa_printf(MSG_INFO, "CTRL: Could not chown directory: %s", 122*85732ac8SCy Schubert strerror(errno)); 123*85732ac8SCy Schubert return -1; 124*85732ac8SCy Schubert } 125*85732ac8SCy Schubert 126*85732ac8SCy Schubert if (chmod(path, mode) < 0) { 127*85732ac8SCy Schubert wpa_printf(MSG_INFO, "CTRL: Could not chmod directory: %s", 128*85732ac8SCy Schubert strerror(errno)); 129*85732ac8SCy Schubert return -1; 130*85732ac8SCy Schubert } 131*85732ac8SCy Schubert #endif /* ANDROID */ 132*85732ac8SCy Schubert 133*85732ac8SCy Schubert return 0; 134*85732ac8SCy Schubert } 135*85732ac8SCy Schubert 136*85732ac8SCy 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); 201*85732ac8SCy Schubert android_update_permission("Cert", S_IRWXU | S_IRWXG); 202*85732ac8SCy 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; 3135b9c547cSRui Paulo unsigned 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 3675b9c547cSRui Paulo b64 = base64_encode((unsigned char *) 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); 439*85732ac8SCy 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); 466*85732ac8SCy 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]; 488*85732ac8SCy 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); 503*85732ac8SCy Schubert ret1 = cmd_dl_polupd_ca(ctx, pps_fname, fname); 504*85732ac8SCy Schubert if (ret == 0 && ret1 == -1) 505*85732ac8SCy Schubert ret = -1; 5065b9c547cSRui Paulo snprintf(fname, sizeof(fname), "%s/aaa-ca.pem", dir); 507*85732ac8SCy Schubert ret1 = cmd_dl_aaa_ca(ctx, pps_fname, fname); 508*85732ac8SCy Schubert if (ret == 0 && ret1 == -1) 509*85732ac8SCy 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 615*85732ac8SCy Schubert android_update_permission("SP", S_IRWXU | S_IRGRP | S_IXGRP); 616*85732ac8SCy Schubert android_update_permission(fname, S_IRWXU | S_IRGRP | S_IXGRP); 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 { 1238*85732ac8SCy 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); 1313*85732ac8SCy Schubert if (set_cred_quoted(ctx->ifname, id, "roaming_consortiums", 1314*85732ac8SCy Schubert str) < 0) 1315*85732ac8SCy 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 1468*85732ac8SCy Schubert static void set_pps_cred_eap_method_eap_type(struct hs20_osu_client *ctx, 1469*85732ac8SCy Schubert int id, xml_node_t *node) 1470*85732ac8SCy Schubert { 1471*85732ac8SCy Schubert char *str = xml_node_get_text(ctx->xml, node); 1472*85732ac8SCy Schubert int type; 1473*85732ac8SCy Schubert const char *eap_method = NULL; 1474*85732ac8SCy Schubert 1475*85732ac8SCy Schubert if (!str) 1476*85732ac8SCy Schubert return; 1477*85732ac8SCy Schubert wpa_printf(MSG_INFO, 1478*85732ac8SCy Schubert "- Credential/UsernamePassword/EAPMethod/EAPType = %s", str); 1479*85732ac8SCy Schubert type = atoi(str); 1480*85732ac8SCy Schubert switch (type) { 1481*85732ac8SCy Schubert case EAP_TYPE_TLS: 1482*85732ac8SCy Schubert eap_method = "TLS"; 1483*85732ac8SCy Schubert break; 1484*85732ac8SCy Schubert case EAP_TYPE_TTLS: 1485*85732ac8SCy Schubert eap_method = "TTLS"; 1486*85732ac8SCy Schubert break; 1487*85732ac8SCy Schubert case EAP_TYPE_PEAP: 1488*85732ac8SCy Schubert eap_method = "PEAP"; 1489*85732ac8SCy Schubert break; 1490*85732ac8SCy Schubert case EAP_TYPE_PWD: 1491*85732ac8SCy Schubert eap_method = "PWD"; 1492*85732ac8SCy Schubert break; 1493*85732ac8SCy Schubert } 1494*85732ac8SCy Schubert xml_node_get_text_free(ctx->xml, str); 1495*85732ac8SCy Schubert if (!eap_method) { 1496*85732ac8SCy Schubert wpa_printf(MSG_INFO, "Unknown EAPType value"); 1497*85732ac8SCy Schubert return; 1498*85732ac8SCy Schubert } 1499*85732ac8SCy Schubert 1500*85732ac8SCy Schubert if (set_cred(ctx->ifname, id, "eap", eap_method) < 0) 1501*85732ac8SCy Schubert wpa_printf(MSG_INFO, "Failed to set cred eap"); 1502*85732ac8SCy Schubert } 1503*85732ac8SCy Schubert 1504*85732ac8SCy Schubert 1505*85732ac8SCy Schubert static void set_pps_cred_eap_method_inner_method(struct hs20_osu_client *ctx, 1506*85732ac8SCy Schubert int id, xml_node_t *node) 1507*85732ac8SCy Schubert { 1508*85732ac8SCy Schubert char *str = xml_node_get_text(ctx->xml, node); 1509*85732ac8SCy Schubert const char *phase2 = NULL; 1510*85732ac8SCy Schubert 1511*85732ac8SCy Schubert if (!str) 1512*85732ac8SCy Schubert return; 1513*85732ac8SCy Schubert wpa_printf(MSG_INFO, 1514*85732ac8SCy Schubert "- Credential/UsernamePassword/EAPMethod/InnerMethod = %s", 1515*85732ac8SCy Schubert str); 1516*85732ac8SCy Schubert if (os_strcmp(str, "PAP") == 0) 1517*85732ac8SCy Schubert phase2 = "auth=PAP"; 1518*85732ac8SCy Schubert else if (os_strcmp(str, "CHAP") == 0) 1519*85732ac8SCy Schubert phase2 = "auth=CHAP"; 1520*85732ac8SCy Schubert else if (os_strcmp(str, "MS-CHAP") == 0) 1521*85732ac8SCy Schubert phase2 = "auth=MSCHAP"; 1522*85732ac8SCy Schubert else if (os_strcmp(str, "MS-CHAP-V2") == 0) 1523*85732ac8SCy Schubert phase2 = "auth=MSCHAPV2"; 1524*85732ac8SCy Schubert xml_node_get_text_free(ctx->xml, str); 1525*85732ac8SCy Schubert if (!phase2) { 1526*85732ac8SCy Schubert wpa_printf(MSG_INFO, "Unknown InnerMethod value"); 1527*85732ac8SCy Schubert return; 1528*85732ac8SCy Schubert } 1529*85732ac8SCy Schubert 1530*85732ac8SCy Schubert if (set_cred_quoted(ctx->ifname, id, "phase2", phase2) < 0) 1531*85732ac8SCy Schubert wpa_printf(MSG_INFO, "Failed to set cred phase2"); 1532*85732ac8SCy Schubert } 1533*85732ac8SCy Schubert 1534*85732ac8SCy 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 { 1538*85732ac8SCy Schubert xml_node_t *child; 1539*85732ac8SCy Schubert const char *name; 1540*85732ac8SCy Schubert 1541*85732ac8SCy Schubert wpa_printf(MSG_INFO, "- Credential/UsernamePassword/EAPMethod"); 1542*85732ac8SCy Schubert 1543*85732ac8SCy Schubert xml_node_for_each_child(ctx->xml, child, node) { 1544*85732ac8SCy Schubert xml_node_for_each_check(ctx->xml, child); 1545*85732ac8SCy Schubert name = xml_node_get_localname(ctx->xml, child); 1546*85732ac8SCy Schubert if (os_strcasecmp(name, "EAPType") == 0) 1547*85732ac8SCy Schubert set_pps_cred_eap_method_eap_type(ctx, id, child); 1548*85732ac8SCy Schubert else if (os_strcasecmp(name, "InnerMethod") == 0) 1549*85732ac8SCy Schubert set_pps_cred_eap_method_inner_method(ctx, id, child); 1550*85732ac8SCy Schubert else 1551*85732ac8SCy Schubert wpa_printf(MSG_INFO, "Unknown Credential/UsernamePassword/EAPMethod node '%s'", 1552*85732ac8SCy Schubert name); 1553*85732ac8SCy 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]; 15915b9c547cSRui Paulo 15925b9c547cSRui Paulo wpa_printf(MSG_INFO, "- Credential/DigitalCertificate"); 15935b9c547cSRui Paulo 15945b9c547cSRui Paulo if (getcwd(dir, sizeof(dir)) == NULL) 15955b9c547cSRui Paulo return; 15965b9c547cSRui Paulo 15975b9c547cSRui Paulo /* TODO: could build username from Subject of Subject AltName */ 15985b9c547cSRui Paulo if (set_cred_quoted(ctx->ifname, id, "username", "cert") < 0) { 15995b9c547cSRui Paulo wpa_printf(MSG_INFO, "Failed to set username"); 16005b9c547cSRui Paulo } 16015b9c547cSRui Paulo 16025b9c547cSRui Paulo snprintf(buf, sizeof(buf), "%s/SP/%s/client-cert.pem", dir, fqdn); 16035b9c547cSRui Paulo if (os_file_exists(buf)) { 16045b9c547cSRui Paulo if (set_cred_quoted(ctx->ifname, id, "client_cert", buf) < 0) { 16055b9c547cSRui Paulo wpa_printf(MSG_INFO, "Failed to set client_cert"); 16065b9c547cSRui Paulo } 16075b9c547cSRui Paulo } 16085b9c547cSRui Paulo 16095b9c547cSRui Paulo snprintf(buf, sizeof(buf), "%s/SP/%s/client-key.pem", dir, fqdn); 16105b9c547cSRui Paulo if (os_file_exists(buf)) { 16115b9c547cSRui Paulo if (set_cred_quoted(ctx->ifname, id, "private_key", buf) < 0) { 16125b9c547cSRui Paulo wpa_printf(MSG_INFO, "Failed to set private_key"); 16135b9c547cSRui Paulo } 16145b9c547cSRui Paulo } 16155b9c547cSRui Paulo } 16165b9c547cSRui Paulo 16175b9c547cSRui Paulo 16185b9c547cSRui Paulo static void set_pps_cred_realm(struct hs20_osu_client *ctx, int id, 16195b9c547cSRui Paulo xml_node_t *node, const char *fqdn, int sim) 16205b9c547cSRui Paulo { 16215b9c547cSRui Paulo char *str = xml_node_get_text(ctx->xml, node); 16225b9c547cSRui Paulo char buf[200], dir[200]; 16235b9c547cSRui Paulo 16245b9c547cSRui Paulo if (str == NULL) 16255b9c547cSRui Paulo return; 16265b9c547cSRui Paulo 16275b9c547cSRui Paulo wpa_printf(MSG_INFO, "- Credential/Realm = %s", str); 16285b9c547cSRui Paulo if (set_cred_quoted(ctx->ifname, id, "realm", str) < 0) 16295b9c547cSRui Paulo wpa_printf(MSG_INFO, "Failed to set cred realm"); 16305b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, str); 16315b9c547cSRui Paulo 16325b9c547cSRui Paulo if (sim) 16335b9c547cSRui Paulo return; 16345b9c547cSRui Paulo 16355b9c547cSRui Paulo if (getcwd(dir, sizeof(dir)) == NULL) 16365b9c547cSRui Paulo return; 16375b9c547cSRui Paulo snprintf(buf, sizeof(buf), "%s/SP/%s/aaa-ca.pem", dir, fqdn); 16385b9c547cSRui Paulo if (os_file_exists(buf)) { 16395b9c547cSRui Paulo if (set_cred_quoted(ctx->ifname, id, "ca_cert", buf) < 0) { 16405b9c547cSRui Paulo wpa_printf(MSG_INFO, "Failed to set CA cert"); 16415b9c547cSRui Paulo } 16425b9c547cSRui Paulo } 16435b9c547cSRui Paulo } 16445b9c547cSRui Paulo 16455b9c547cSRui Paulo 16465b9c547cSRui Paulo static void set_pps_cred_check_aaa_cert_status(struct hs20_osu_client *ctx, 16475b9c547cSRui Paulo int id, xml_node_t *node) 16485b9c547cSRui Paulo { 16495b9c547cSRui Paulo char *str = xml_node_get_text(ctx->xml, node); 16505b9c547cSRui Paulo 16515b9c547cSRui Paulo if (str == NULL) 16525b9c547cSRui Paulo return; 16535b9c547cSRui Paulo 16545b9c547cSRui Paulo wpa_printf(MSG_INFO, "- Credential/CheckAAAServerCertStatus = %s", str); 16555b9c547cSRui Paulo if (os_strcasecmp(str, "true") == 0 && 16565b9c547cSRui Paulo set_cred(ctx->ifname, id, "ocsp", "2") < 0) 16575b9c547cSRui Paulo wpa_printf(MSG_INFO, "Failed to set cred ocsp"); 16585b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, str); 16595b9c547cSRui Paulo } 16605b9c547cSRui Paulo 16615b9c547cSRui Paulo 16625b9c547cSRui Paulo static void set_pps_cred_sim(struct hs20_osu_client *ctx, int id, 16635b9c547cSRui Paulo xml_node_t *sim, xml_node_t *realm) 16645b9c547cSRui Paulo { 16655b9c547cSRui Paulo xml_node_t *node; 16665b9c547cSRui Paulo char *imsi, *eaptype, *str, buf[20]; 16675b9c547cSRui Paulo int type; 16685b9c547cSRui Paulo int mnc_len = 3; 16695b9c547cSRui Paulo size_t imsi_len; 16705b9c547cSRui Paulo 16715b9c547cSRui Paulo node = get_node(ctx->xml, sim, "EAPType"); 16725b9c547cSRui Paulo if (node == NULL) { 16735b9c547cSRui Paulo wpa_printf(MSG_INFO, "No SIM/EAPType node in credential"); 16745b9c547cSRui Paulo return; 16755b9c547cSRui Paulo } 16765b9c547cSRui Paulo eaptype = xml_node_get_text(ctx->xml, node); 16775b9c547cSRui Paulo if (eaptype == NULL) { 16785b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not extract SIM/EAPType"); 16795b9c547cSRui Paulo return; 16805b9c547cSRui Paulo } 16815b9c547cSRui Paulo wpa_printf(MSG_INFO, " - Credential/SIM/EAPType = %s", eaptype); 16825b9c547cSRui Paulo type = atoi(eaptype); 16835b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, eaptype); 16845b9c547cSRui Paulo 16855b9c547cSRui Paulo switch (type) { 16865b9c547cSRui Paulo case EAP_TYPE_SIM: 16875b9c547cSRui Paulo if (set_cred(ctx->ifname, id, "eap", "SIM") < 0) 16885b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not set eap=SIM"); 16895b9c547cSRui Paulo break; 16905b9c547cSRui Paulo case EAP_TYPE_AKA: 16915b9c547cSRui Paulo if (set_cred(ctx->ifname, id, "eap", "AKA") < 0) 16925b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not set eap=SIM"); 16935b9c547cSRui Paulo break; 16945b9c547cSRui Paulo case EAP_TYPE_AKA_PRIME: 16955b9c547cSRui Paulo if (set_cred(ctx->ifname, id, "eap", "AKA'") < 0) 16965b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not set eap=SIM"); 16975b9c547cSRui Paulo break; 16985b9c547cSRui Paulo default: 16995b9c547cSRui Paulo wpa_printf(MSG_INFO, "Unsupported SIM/EAPType %d", type); 17005b9c547cSRui Paulo return; 17015b9c547cSRui Paulo } 17025b9c547cSRui Paulo 17035b9c547cSRui Paulo node = get_node(ctx->xml, sim, "IMSI"); 17045b9c547cSRui Paulo if (node == NULL) { 17055b9c547cSRui Paulo wpa_printf(MSG_INFO, "No SIM/IMSI node in credential"); 17065b9c547cSRui Paulo return; 17075b9c547cSRui Paulo } 17085b9c547cSRui Paulo imsi = xml_node_get_text(ctx->xml, node); 17095b9c547cSRui Paulo if (imsi == NULL) { 17105b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not extract SIM/IMSI"); 17115b9c547cSRui Paulo return; 17125b9c547cSRui Paulo } 17135b9c547cSRui Paulo wpa_printf(MSG_INFO, " - Credential/SIM/IMSI = %s", imsi); 17145b9c547cSRui Paulo imsi_len = os_strlen(imsi); 17155b9c547cSRui Paulo if (imsi_len < 7 || imsi_len + 2 > sizeof(buf)) { 17165b9c547cSRui Paulo wpa_printf(MSG_INFO, "Invalid IMSI length"); 17175b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, imsi); 17185b9c547cSRui Paulo return; 17195b9c547cSRui Paulo } 17205b9c547cSRui Paulo 17215b9c547cSRui Paulo str = xml_node_get_text(ctx->xml, node); 17225b9c547cSRui Paulo if (str) { 17235b9c547cSRui Paulo char *pos; 17245b9c547cSRui Paulo pos = os_strstr(str, "mnc"); 17255b9c547cSRui Paulo if (pos && os_strlen(pos) >= 6) { 17265b9c547cSRui Paulo if (os_strncmp(imsi + 3, pos + 3, 3) == 0) 17275b9c547cSRui Paulo mnc_len = 3; 17285b9c547cSRui Paulo else if (os_strncmp(imsi + 3, pos + 4, 2) == 0) 17295b9c547cSRui Paulo mnc_len = 2; 17305b9c547cSRui Paulo } 17315b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, str); 17325b9c547cSRui Paulo } 17335b9c547cSRui Paulo 17345b9c547cSRui Paulo os_memcpy(buf, imsi, 3 + mnc_len); 17355b9c547cSRui Paulo buf[3 + mnc_len] = '-'; 17365b9c547cSRui Paulo os_strlcpy(buf + 3 + mnc_len + 1, imsi + 3 + mnc_len, 17375b9c547cSRui Paulo sizeof(buf) - 3 - mnc_len - 1); 17385b9c547cSRui Paulo 17395b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, imsi); 17405b9c547cSRui Paulo 17415b9c547cSRui Paulo if (set_cred_quoted(ctx->ifname, id, "imsi", buf) < 0) 17425b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not set IMSI"); 17435b9c547cSRui Paulo 17445b9c547cSRui Paulo if (set_cred_quoted(ctx->ifname, id, "milenage", 17455b9c547cSRui Paulo "90dca4eda45b53cf0f12d7c9c3bc6a89:" 17465b9c547cSRui Paulo "cb9cccc4b9258e6dca4760379fb82581:000000000123") < 17475b9c547cSRui Paulo 0) 17485b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not set Milenage parameters"); 17495b9c547cSRui Paulo } 17505b9c547cSRui Paulo 17515b9c547cSRui Paulo 17525b9c547cSRui Paulo static void set_pps_cred_credential(struct hs20_osu_client *ctx, int id, 17535b9c547cSRui Paulo xml_node_t *node, const char *fqdn) 17545b9c547cSRui Paulo { 17555b9c547cSRui Paulo xml_node_t *child, *sim, *realm; 17565b9c547cSRui Paulo const char *name; 17575b9c547cSRui Paulo 17585b9c547cSRui Paulo wpa_printf(MSG_INFO, "- Credential"); 17595b9c547cSRui Paulo 17605b9c547cSRui Paulo sim = get_node(ctx->xml, node, "SIM"); 17615b9c547cSRui Paulo realm = get_node(ctx->xml, node, "Realm"); 17625b9c547cSRui Paulo 17635b9c547cSRui Paulo xml_node_for_each_child(ctx->xml, child, node) { 17645b9c547cSRui Paulo xml_node_for_each_check(ctx->xml, child); 17655b9c547cSRui Paulo name = xml_node_get_localname(ctx->xml, child); 17665b9c547cSRui Paulo if (os_strcasecmp(name, "CreationDate") == 0) 17675b9c547cSRui Paulo set_pps_cred_creation_date(ctx, id, child); 17685b9c547cSRui Paulo else if (os_strcasecmp(name, "ExpirationDate") == 0) 17695b9c547cSRui Paulo set_pps_cred_expiration_date(ctx, id, child); 17705b9c547cSRui Paulo else if (os_strcasecmp(name, "UsernamePassword") == 0) 17715b9c547cSRui Paulo set_pps_cred_username_password(ctx, id, child); 17725b9c547cSRui Paulo else if (os_strcasecmp(name, "DigitalCertificate") == 0) 17735b9c547cSRui Paulo set_pps_cred_digital_cert(ctx, id, child, fqdn); 17745b9c547cSRui Paulo else if (os_strcasecmp(name, "Realm") == 0) 17755b9c547cSRui Paulo set_pps_cred_realm(ctx, id, child, fqdn, sim != NULL); 17765b9c547cSRui Paulo else if (os_strcasecmp(name, "CheckAAAServerCertStatus") == 0) 17775b9c547cSRui Paulo set_pps_cred_check_aaa_cert_status(ctx, id, child); 17785b9c547cSRui Paulo else if (os_strcasecmp(name, "SIM") == 0) 17795b9c547cSRui Paulo set_pps_cred_sim(ctx, id, child, realm); 17805b9c547cSRui Paulo else 17815b9c547cSRui Paulo wpa_printf(MSG_INFO, "Unknown Credential node '%s'", 17825b9c547cSRui Paulo name); 17835b9c547cSRui Paulo } 17845b9c547cSRui Paulo } 17855b9c547cSRui Paulo 17865b9c547cSRui Paulo 17875b9c547cSRui Paulo static void set_pps_credential(struct hs20_osu_client *ctx, int id, 17885b9c547cSRui Paulo xml_node_t *cred, const char *fqdn) 17895b9c547cSRui Paulo { 17905b9c547cSRui Paulo xml_node_t *child; 17915b9c547cSRui Paulo const char *name; 17925b9c547cSRui Paulo 17935b9c547cSRui Paulo xml_node_for_each_child(ctx->xml, child, cred) { 17945b9c547cSRui Paulo xml_node_for_each_check(ctx->xml, child); 17955b9c547cSRui Paulo name = xml_node_get_localname(ctx->xml, child); 17965b9c547cSRui Paulo if (os_strcasecmp(name, "Policy") == 0) 17975b9c547cSRui Paulo set_pps_cred_policy(ctx, id, child); 17985b9c547cSRui Paulo else if (os_strcasecmp(name, "CredentialPriority") == 0) 17995b9c547cSRui Paulo set_pps_cred_priority(ctx, id, child); 18005b9c547cSRui Paulo else if (os_strcasecmp(name, "AAAServerTrustRoot") == 0) 18015b9c547cSRui Paulo set_pps_cred_aaa_server_trust_root(ctx, id, child); 18025b9c547cSRui Paulo else if (os_strcasecmp(name, "SubscriptionUpdate") == 0) 18035b9c547cSRui Paulo set_pps_cred_sub_update(ctx, id, child); 18045b9c547cSRui Paulo else if (os_strcasecmp(name, "HomeSP") == 0) 18055b9c547cSRui Paulo set_pps_cred_home_sp(ctx, id, child); 18065b9c547cSRui Paulo else if (os_strcasecmp(name, "SubscriptionParameters") == 0) 18075b9c547cSRui Paulo set_pps_cred_sub_params(ctx, id, child); 18085b9c547cSRui Paulo else if (os_strcasecmp(name, "Credential") == 0) 18095b9c547cSRui Paulo set_pps_cred_credential(ctx, id, child, fqdn); 18105b9c547cSRui Paulo else 18115b9c547cSRui Paulo wpa_printf(MSG_INFO, "Unknown credential node '%s'", 18125b9c547cSRui Paulo name); 18135b9c547cSRui Paulo } 18145b9c547cSRui Paulo } 18155b9c547cSRui Paulo 18165b9c547cSRui Paulo 18175b9c547cSRui Paulo static void set_pps(struct hs20_osu_client *ctx, xml_node_t *pps, 18185b9c547cSRui Paulo const char *fqdn) 18195b9c547cSRui Paulo { 18205b9c547cSRui Paulo xml_node_t *child; 18215b9c547cSRui Paulo const char *name; 18225b9c547cSRui Paulo int id; 18235b9c547cSRui Paulo char *update_identifier = NULL; 18245b9c547cSRui Paulo 18255b9c547cSRui Paulo /* 18265b9c547cSRui Paulo * TODO: Could consider more complex mechanism that would remove 18275b9c547cSRui Paulo * credentials only if there are changes in the information sent to 18285b9c547cSRui Paulo * wpa_supplicant. 18295b9c547cSRui Paulo */ 18305b9c547cSRui Paulo remove_sp_creds(ctx, fqdn); 18315b9c547cSRui Paulo 18325b9c547cSRui Paulo xml_node_for_each_child(ctx->xml, child, pps) { 18335b9c547cSRui Paulo xml_node_for_each_check(ctx->xml, child); 18345b9c547cSRui Paulo name = xml_node_get_localname(ctx->xml, child); 18355b9c547cSRui Paulo if (os_strcasecmp(name, "UpdateIdentifier") == 0) { 18365b9c547cSRui Paulo update_identifier = xml_node_get_text(ctx->xml, child); 18375b9c547cSRui Paulo if (update_identifier) { 18385b9c547cSRui Paulo wpa_printf(MSG_INFO, "- UpdateIdentifier = %s", 18395b9c547cSRui Paulo update_identifier); 18405b9c547cSRui Paulo break; 18415b9c547cSRui Paulo } 18425b9c547cSRui Paulo } 18435b9c547cSRui Paulo } 18445b9c547cSRui Paulo 18455b9c547cSRui Paulo xml_node_for_each_child(ctx->xml, child, pps) { 18465b9c547cSRui Paulo xml_node_for_each_check(ctx->xml, child); 18475b9c547cSRui Paulo name = xml_node_get_localname(ctx->xml, child); 18485b9c547cSRui Paulo if (os_strcasecmp(name, "UpdateIdentifier") == 0) 18495b9c547cSRui Paulo continue; 18505b9c547cSRui Paulo id = add_cred(ctx->ifname); 18515b9c547cSRui Paulo if (id < 0) { 18525b9c547cSRui Paulo wpa_printf(MSG_INFO, "Failed to add credential to wpa_supplicant"); 18535b9c547cSRui Paulo write_summary(ctx, "Failed to add credential to wpa_supplicant"); 18545b9c547cSRui Paulo break; 18555b9c547cSRui Paulo } 18565b9c547cSRui Paulo write_summary(ctx, "Add a credential to wpa_supplicant"); 18575b9c547cSRui Paulo if (update_identifier && 18585b9c547cSRui Paulo set_cred(ctx->ifname, id, "update_identifier", 18595b9c547cSRui Paulo update_identifier) < 0) 18605b9c547cSRui Paulo wpa_printf(MSG_INFO, "Failed to set update_identifier"); 18615b9c547cSRui Paulo if (set_cred_quoted(ctx->ifname, id, "provisioning_sp", fqdn) < 18625b9c547cSRui Paulo 0) 18635b9c547cSRui Paulo wpa_printf(MSG_INFO, "Failed to set provisioning_sp"); 18645b9c547cSRui Paulo wpa_printf(MSG_INFO, "credential localname: '%s'", name); 18655b9c547cSRui Paulo set_pps_credential(ctx, id, child, fqdn); 18665b9c547cSRui Paulo ctx->pps_cred_set = 1; 18675b9c547cSRui Paulo } 18685b9c547cSRui Paulo 18695b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, update_identifier); 18705b9c547cSRui Paulo } 18715b9c547cSRui Paulo 18725b9c547cSRui Paulo 18735b9c547cSRui Paulo void cmd_set_pps(struct hs20_osu_client *ctx, const char *pps_fname) 18745b9c547cSRui Paulo { 18755b9c547cSRui Paulo xml_node_t *pps; 18765b9c547cSRui Paulo const char *fqdn; 18775b9c547cSRui Paulo char *fqdn_buf = NULL, *pos; 18785b9c547cSRui Paulo 18795b9c547cSRui Paulo pps = node_from_file(ctx->xml, pps_fname); 18805b9c547cSRui Paulo if (pps == NULL) { 18815b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not read or parse '%s'", pps_fname); 18825b9c547cSRui Paulo return; 18835b9c547cSRui Paulo } 18845b9c547cSRui Paulo 18855b9c547cSRui Paulo fqdn = os_strstr(pps_fname, "SP/"); 18865b9c547cSRui Paulo if (fqdn) { 18875b9c547cSRui Paulo fqdn_buf = os_strdup(fqdn + 3); 18885b9c547cSRui Paulo if (fqdn_buf == NULL) 18895b9c547cSRui Paulo return; 18905b9c547cSRui Paulo pos = os_strchr(fqdn_buf, '/'); 18915b9c547cSRui Paulo if (pos) 18925b9c547cSRui Paulo *pos = '\0'; 18935b9c547cSRui Paulo fqdn = fqdn_buf; 18945b9c547cSRui Paulo } else 18955b9c547cSRui Paulo fqdn = "wi-fi.org"; 18965b9c547cSRui Paulo 18975b9c547cSRui Paulo wpa_printf(MSG_INFO, "Set PPS MO info to wpa_supplicant - SP FQDN %s", 18985b9c547cSRui Paulo fqdn); 18995b9c547cSRui Paulo set_pps(ctx, pps, fqdn); 19005b9c547cSRui Paulo 19015b9c547cSRui Paulo os_free(fqdn_buf); 19025b9c547cSRui Paulo xml_node_free(ctx->xml, pps); 19035b9c547cSRui Paulo } 19045b9c547cSRui Paulo 19055b9c547cSRui Paulo 19065b9c547cSRui Paulo static int cmd_get_fqdn(struct hs20_osu_client *ctx, const char *pps_fname) 19075b9c547cSRui Paulo { 19085b9c547cSRui Paulo xml_node_t *pps, *node; 19095b9c547cSRui Paulo char *fqdn = NULL; 19105b9c547cSRui Paulo 19115b9c547cSRui Paulo pps = node_from_file(ctx->xml, pps_fname); 19125b9c547cSRui Paulo if (pps == NULL) { 19135b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not read or parse '%s'", pps_fname); 19145b9c547cSRui Paulo return -1; 19155b9c547cSRui Paulo } 19165b9c547cSRui Paulo 19175b9c547cSRui Paulo node = get_child_node(ctx->xml, pps, "HomeSP/FQDN"); 19185b9c547cSRui Paulo if (node) 19195b9c547cSRui Paulo fqdn = xml_node_get_text(ctx->xml, node); 19205b9c547cSRui Paulo 19215b9c547cSRui Paulo xml_node_free(ctx->xml, pps); 19225b9c547cSRui Paulo 19235b9c547cSRui Paulo if (fqdn) { 19245b9c547cSRui Paulo FILE *f = fopen("pps-fqdn", "w"); 19255b9c547cSRui Paulo if (f) { 19265b9c547cSRui Paulo fprintf(f, "%s", fqdn); 19275b9c547cSRui Paulo fclose(f); 19285b9c547cSRui Paulo } 19295b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, fqdn); 19305b9c547cSRui Paulo return 0; 19315b9c547cSRui Paulo } 19325b9c547cSRui Paulo 19335b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, fqdn); 19345b9c547cSRui Paulo return -1; 19355b9c547cSRui Paulo } 19365b9c547cSRui Paulo 19375b9c547cSRui Paulo 19385b9c547cSRui Paulo static void cmd_to_tnds(struct hs20_osu_client *ctx, const char *in_fname, 19395b9c547cSRui Paulo const char *out_fname, const char *urn, int use_path) 19405b9c547cSRui Paulo { 19415b9c547cSRui Paulo xml_node_t *mo, *node; 19425b9c547cSRui Paulo 19435b9c547cSRui Paulo mo = node_from_file(ctx->xml, in_fname); 19445b9c547cSRui Paulo if (mo == NULL) { 19455b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not read or parse '%s'", in_fname); 19465b9c547cSRui Paulo return; 19475b9c547cSRui Paulo } 19485b9c547cSRui Paulo 19495b9c547cSRui Paulo node = mo_to_tnds(ctx->xml, mo, use_path, urn, NULL); 19505b9c547cSRui Paulo if (node) { 19515b9c547cSRui Paulo node_to_file(ctx->xml, out_fname, node); 19525b9c547cSRui Paulo xml_node_free(ctx->xml, node); 19535b9c547cSRui Paulo } 19545b9c547cSRui Paulo 19555b9c547cSRui Paulo xml_node_free(ctx->xml, mo); 19565b9c547cSRui Paulo } 19575b9c547cSRui Paulo 19585b9c547cSRui Paulo 19595b9c547cSRui Paulo static void cmd_from_tnds(struct hs20_osu_client *ctx, const char *in_fname, 19605b9c547cSRui Paulo const char *out_fname) 19615b9c547cSRui Paulo { 19625b9c547cSRui Paulo xml_node_t *tnds, *mo; 19635b9c547cSRui Paulo 19645b9c547cSRui Paulo tnds = node_from_file(ctx->xml, in_fname); 19655b9c547cSRui Paulo if (tnds == NULL) { 19665b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not read or parse '%s'", in_fname); 19675b9c547cSRui Paulo return; 19685b9c547cSRui Paulo } 19695b9c547cSRui Paulo 19705b9c547cSRui Paulo mo = tnds_to_mo(ctx->xml, tnds); 19715b9c547cSRui Paulo if (mo) { 19725b9c547cSRui Paulo node_to_file(ctx->xml, out_fname, mo); 19735b9c547cSRui Paulo xml_node_free(ctx->xml, mo); 19745b9c547cSRui Paulo } 19755b9c547cSRui Paulo 19765b9c547cSRui Paulo xml_node_free(ctx->xml, tnds); 19775b9c547cSRui Paulo } 19785b9c547cSRui Paulo 19795b9c547cSRui Paulo 19805b9c547cSRui Paulo struct osu_icon { 19815b9c547cSRui Paulo int id; 19825b9c547cSRui Paulo char lang[4]; 19835b9c547cSRui Paulo char mime_type[256]; 19845b9c547cSRui Paulo char filename[256]; 19855b9c547cSRui Paulo }; 19865b9c547cSRui Paulo 19875b9c547cSRui Paulo struct osu_data { 19885b9c547cSRui Paulo char bssid[20]; 19895b9c547cSRui Paulo char url[256]; 19905b9c547cSRui Paulo unsigned int methods; 19915b9c547cSRui Paulo char osu_ssid[33]; 1992*85732ac8SCy Schubert char osu_ssid2[33]; 19935b9c547cSRui Paulo char osu_nai[256]; 1994*85732ac8SCy Schubert char osu_nai2[256]; 19955b9c547cSRui Paulo struct osu_lang_text friendly_name[MAX_OSU_VALS]; 19965b9c547cSRui Paulo size_t friendly_name_count; 19975b9c547cSRui Paulo struct osu_lang_text serv_desc[MAX_OSU_VALS]; 19985b9c547cSRui Paulo size_t serv_desc_count; 19995b9c547cSRui Paulo struct osu_icon icon[MAX_OSU_VALS]; 20005b9c547cSRui Paulo size_t icon_count; 20015b9c547cSRui Paulo }; 20025b9c547cSRui Paulo 20035b9c547cSRui Paulo 20045b9c547cSRui Paulo static struct osu_data * parse_osu_providers(const char *fname, size_t *count) 20055b9c547cSRui Paulo { 20065b9c547cSRui Paulo FILE *f; 20075b9c547cSRui Paulo char buf[1000]; 20085b9c547cSRui Paulo struct osu_data *osu = NULL, *last = NULL; 20095b9c547cSRui Paulo size_t osu_count = 0; 20105b9c547cSRui Paulo char *pos, *end; 20115b9c547cSRui Paulo 20125b9c547cSRui Paulo f = fopen(fname, "r"); 20135b9c547cSRui Paulo if (f == NULL) { 20145b9c547cSRui Paulo wpa_printf(MSG_ERROR, "Could not open %s", fname); 20155b9c547cSRui Paulo return NULL; 20165b9c547cSRui Paulo } 20175b9c547cSRui Paulo 20185b9c547cSRui Paulo while (fgets(buf, sizeof(buf), f)) { 20195b9c547cSRui Paulo pos = strchr(buf, '\n'); 20205b9c547cSRui Paulo if (pos) 20215b9c547cSRui Paulo *pos = '\0'; 20225b9c547cSRui Paulo 20235b9c547cSRui Paulo if (strncmp(buf, "OSU-PROVIDER ", 13) == 0) { 20245b9c547cSRui Paulo last = realloc(osu, (osu_count + 1) * sizeof(*osu)); 20255b9c547cSRui Paulo if (last == NULL) 20265b9c547cSRui Paulo break; 20275b9c547cSRui Paulo osu = last; 20285b9c547cSRui Paulo last = &osu[osu_count++]; 20295b9c547cSRui Paulo memset(last, 0, sizeof(*last)); 20305b9c547cSRui Paulo snprintf(last->bssid, sizeof(last->bssid), "%s", 20315b9c547cSRui Paulo buf + 13); 20325b9c547cSRui Paulo continue; 20335b9c547cSRui Paulo } 20345b9c547cSRui Paulo if (!last) 20355b9c547cSRui Paulo continue; 20365b9c547cSRui Paulo 20375b9c547cSRui Paulo if (strncmp(buf, "uri=", 4) == 0) { 20385b9c547cSRui Paulo snprintf(last->url, sizeof(last->url), "%s", buf + 4); 20395b9c547cSRui Paulo continue; 20405b9c547cSRui Paulo } 20415b9c547cSRui Paulo 20425b9c547cSRui Paulo if (strncmp(buf, "methods=", 8) == 0) { 20435b9c547cSRui Paulo last->methods = strtol(buf + 8, NULL, 16); 20445b9c547cSRui Paulo continue; 20455b9c547cSRui Paulo } 20465b9c547cSRui Paulo 20475b9c547cSRui Paulo if (strncmp(buf, "osu_ssid=", 9) == 0) { 20485b9c547cSRui Paulo snprintf(last->osu_ssid, sizeof(last->osu_ssid), 20495b9c547cSRui Paulo "%s", buf + 9); 20505b9c547cSRui Paulo continue; 20515b9c547cSRui Paulo } 20525b9c547cSRui Paulo 2053*85732ac8SCy Schubert if (strncmp(buf, "osu_ssid2=", 10) == 0) { 2054*85732ac8SCy Schubert snprintf(last->osu_ssid2, sizeof(last->osu_ssid2), 2055*85732ac8SCy Schubert "%s", buf + 10); 2056*85732ac8SCy Schubert continue; 2057*85732ac8SCy Schubert } 2058*85732ac8SCy Schubert 20595b9c547cSRui Paulo if (os_strncmp(buf, "osu_nai=", 8) == 0) { 20605b9c547cSRui Paulo os_snprintf(last->osu_nai, sizeof(last->osu_nai), 20615b9c547cSRui Paulo "%s", buf + 8); 20625b9c547cSRui Paulo continue; 20635b9c547cSRui Paulo } 20645b9c547cSRui Paulo 2065*85732ac8SCy Schubert if (os_strncmp(buf, "osu_nai2=", 9) == 0) { 2066*85732ac8SCy Schubert os_snprintf(last->osu_nai2, sizeof(last->osu_nai2), 2067*85732ac8SCy Schubert "%s", buf + 9); 2068*85732ac8SCy Schubert continue; 2069*85732ac8SCy Schubert } 2070*85732ac8SCy Schubert 20715b9c547cSRui Paulo if (strncmp(buf, "friendly_name=", 14) == 0) { 20725b9c547cSRui Paulo struct osu_lang_text *txt; 20735b9c547cSRui Paulo if (last->friendly_name_count == MAX_OSU_VALS) 20745b9c547cSRui Paulo continue; 20755b9c547cSRui Paulo pos = strchr(buf + 14, ':'); 20765b9c547cSRui Paulo if (pos == NULL) 20775b9c547cSRui Paulo continue; 20785b9c547cSRui Paulo *pos++ = '\0'; 20795b9c547cSRui Paulo txt = &last->friendly_name[last->friendly_name_count++]; 20805b9c547cSRui Paulo snprintf(txt->lang, sizeof(txt->lang), "%s", buf + 14); 20815b9c547cSRui Paulo snprintf(txt->text, sizeof(txt->text), "%s", pos); 20825b9c547cSRui Paulo } 20835b9c547cSRui Paulo 20845b9c547cSRui Paulo if (strncmp(buf, "desc=", 5) == 0) { 20855b9c547cSRui Paulo struct osu_lang_text *txt; 20865b9c547cSRui Paulo if (last->serv_desc_count == MAX_OSU_VALS) 20875b9c547cSRui Paulo continue; 20885b9c547cSRui Paulo pos = strchr(buf + 5, ':'); 20895b9c547cSRui Paulo if (pos == NULL) 20905b9c547cSRui Paulo continue; 20915b9c547cSRui Paulo *pos++ = '\0'; 20925b9c547cSRui Paulo txt = &last->serv_desc[last->serv_desc_count++]; 20935b9c547cSRui Paulo snprintf(txt->lang, sizeof(txt->lang), "%s", buf + 5); 20945b9c547cSRui Paulo snprintf(txt->text, sizeof(txt->text), "%s", pos); 20955b9c547cSRui Paulo } 20965b9c547cSRui Paulo 20975b9c547cSRui Paulo if (strncmp(buf, "icon=", 5) == 0) { 20985b9c547cSRui Paulo struct osu_icon *icon; 20995b9c547cSRui Paulo if (last->icon_count == MAX_OSU_VALS) 21005b9c547cSRui Paulo continue; 21015b9c547cSRui Paulo icon = &last->icon[last->icon_count++]; 21025b9c547cSRui Paulo icon->id = atoi(buf + 5); 21035b9c547cSRui Paulo pos = strchr(buf, ':'); 21045b9c547cSRui Paulo if (pos == NULL) 21055b9c547cSRui Paulo continue; 21065b9c547cSRui Paulo pos = strchr(pos + 1, ':'); 21075b9c547cSRui Paulo if (pos == NULL) 21085b9c547cSRui Paulo continue; 21095b9c547cSRui Paulo pos = strchr(pos + 1, ':'); 21105b9c547cSRui Paulo if (pos == NULL) 21115b9c547cSRui Paulo continue; 21125b9c547cSRui Paulo pos++; 21135b9c547cSRui Paulo end = strchr(pos, ':'); 21145b9c547cSRui Paulo if (!end) 21155b9c547cSRui Paulo continue; 21165b9c547cSRui Paulo *end = '\0'; 21175b9c547cSRui Paulo snprintf(icon->lang, sizeof(icon->lang), "%s", pos); 21185b9c547cSRui Paulo pos = end + 1; 21195b9c547cSRui Paulo 21205b9c547cSRui Paulo end = strchr(pos, ':'); 21215b9c547cSRui Paulo if (end) 21225b9c547cSRui Paulo *end = '\0'; 21235b9c547cSRui Paulo snprintf(icon->mime_type, sizeof(icon->mime_type), 21245b9c547cSRui Paulo "%s", pos); 21255b9c547cSRui Paulo if (!pos) 21265b9c547cSRui Paulo continue; 21275b9c547cSRui Paulo pos = end + 1; 21285b9c547cSRui Paulo 21295b9c547cSRui Paulo end = strchr(pos, ':'); 21305b9c547cSRui Paulo if (end) 21315b9c547cSRui Paulo *end = '\0'; 21325b9c547cSRui Paulo snprintf(icon->filename, sizeof(icon->filename), 21335b9c547cSRui Paulo "%s", pos); 21345b9c547cSRui Paulo continue; 21355b9c547cSRui Paulo } 21365b9c547cSRui Paulo } 21375b9c547cSRui Paulo 21385b9c547cSRui Paulo fclose(f); 21395b9c547cSRui Paulo 21405b9c547cSRui Paulo *count = osu_count; 21415b9c547cSRui Paulo return osu; 21425b9c547cSRui Paulo } 21435b9c547cSRui Paulo 21445b9c547cSRui Paulo 21455b9c547cSRui Paulo static int osu_connect(struct hs20_osu_client *ctx, const char *bssid, 2146*85732ac8SCy Schubert const char *ssid, const char *ssid2, const char *url, 21475b9c547cSRui Paulo unsigned int methods, int no_prod_assoc, 2148*85732ac8SCy Schubert const char *osu_nai, const char *osu_nai2) 21495b9c547cSRui Paulo { 21505b9c547cSRui Paulo int id; 21515b9c547cSRui Paulo const char *ifname = ctx->ifname; 21525b9c547cSRui Paulo char buf[200]; 21535b9c547cSRui Paulo struct wpa_ctrl *mon; 21545b9c547cSRui Paulo int res; 21555b9c547cSRui Paulo 2156*85732ac8SCy Schubert if (ssid2 && ssid2[0] == '\0') 2157*85732ac8SCy Schubert ssid2 = NULL; 2158*85732ac8SCy Schubert 2159*85732ac8SCy Schubert if (ctx->osu_ssid) { 2160*85732ac8SCy Schubert if (os_strcmp(ssid, ctx->osu_ssid) == 0) { 2161*85732ac8SCy Schubert wpa_printf(MSG_DEBUG, 2162*85732ac8SCy Schubert "Enforced OSU SSID matches ANQP info"); 2163*85732ac8SCy Schubert ssid2 = NULL; 2164*85732ac8SCy Schubert } else if (ssid2 && os_strcmp(ssid2, ctx->osu_ssid) == 0) { 2165*85732ac8SCy Schubert wpa_printf(MSG_DEBUG, 2166*85732ac8SCy Schubert "Enforced OSU SSID matches RSN[OSEN] info"); 2167*85732ac8SCy Schubert ssid = ssid2; 2168*85732ac8SCy Schubert } else { 2169*85732ac8SCy Schubert wpa_printf(MSG_INFO, "Enforced OSU SSID did not match"); 2170*85732ac8SCy Schubert write_summary(ctx, "Enforced OSU SSID did not match"); 2171*85732ac8SCy Schubert return -1; 2172*85732ac8SCy Schubert } 2173*85732ac8SCy Schubert } 2174*85732ac8SCy Schubert 21755b9c547cSRui Paulo id = add_network(ifname); 21765b9c547cSRui Paulo if (id < 0) 21775b9c547cSRui Paulo return -1; 21785b9c547cSRui Paulo if (set_network_quoted(ifname, id, "ssid", ssid) < 0) 21795b9c547cSRui Paulo return -1; 2180*85732ac8SCy Schubert if (ssid2) 2181*85732ac8SCy Schubert osu_nai = osu_nai2; 21825b9c547cSRui Paulo if (osu_nai && os_strlen(osu_nai) > 0) { 21835b9c547cSRui Paulo char dir[255], fname[300]; 21845b9c547cSRui Paulo if (getcwd(dir, sizeof(dir)) == NULL) 21855b9c547cSRui Paulo return -1; 21865b9c547cSRui Paulo os_snprintf(fname, sizeof(fname), "%s/osu-ca.pem", dir); 21875b9c547cSRui Paulo 2188*85732ac8SCy Schubert if (ssid2 && set_network_quoted(ifname, id, "ssid", ssid2) < 0) 2189*85732ac8SCy Schubert return -1; 2190*85732ac8SCy Schubert 21915b9c547cSRui Paulo if (set_network(ifname, id, "proto", "OSEN") < 0 || 21925b9c547cSRui Paulo set_network(ifname, id, "key_mgmt", "OSEN") < 0 || 21935b9c547cSRui Paulo set_network(ifname, id, "pairwise", "CCMP") < 0 || 2194*85732ac8SCy Schubert set_network(ifname, id, "group", "GTK_NOT_USED CCMP") < 0 || 21955b9c547cSRui Paulo set_network(ifname, id, "eap", "WFA-UNAUTH-TLS") < 0 || 21965b9c547cSRui Paulo set_network(ifname, id, "ocsp", "2") < 0 || 21975b9c547cSRui Paulo set_network_quoted(ifname, id, "identity", osu_nai) < 0 || 21985b9c547cSRui Paulo set_network_quoted(ifname, id, "ca_cert", fname) < 0) 21995b9c547cSRui Paulo return -1; 2200*85732ac8SCy Schubert } else if (ssid2) { 2201*85732ac8SCy Schubert wpa_printf(MSG_INFO, "No OSU_NAI set for RSN[OSEN]"); 2202*85732ac8SCy Schubert write_summary(ctx, "No OSU_NAI set for RSN[OSEN]"); 2203*85732ac8SCy Schubert return -1; 22045b9c547cSRui Paulo } else { 22055b9c547cSRui Paulo if (set_network(ifname, id, "key_mgmt", "NONE") < 0) 22065b9c547cSRui Paulo return -1; 22075b9c547cSRui Paulo } 22085b9c547cSRui Paulo 22095b9c547cSRui Paulo mon = open_wpa_mon(ifname); 22105b9c547cSRui Paulo if (mon == NULL) 22115b9c547cSRui Paulo return -1; 22125b9c547cSRui Paulo 22135b9c547cSRui Paulo wpa_printf(MSG_INFO, "Associate with OSU SSID"); 22145b9c547cSRui Paulo write_summary(ctx, "Associate with OSU SSID"); 22155b9c547cSRui Paulo snprintf(buf, sizeof(buf), "SELECT_NETWORK %d", id); 22165b9c547cSRui Paulo if (wpa_command(ifname, buf) < 0) 22175b9c547cSRui Paulo return -1; 22185b9c547cSRui Paulo 22195b9c547cSRui Paulo res = get_wpa_cli_event(mon, "CTRL-EVENT-CONNECTED", 22205b9c547cSRui Paulo buf, sizeof(buf)); 22215b9c547cSRui Paulo 22225b9c547cSRui Paulo wpa_ctrl_detach(mon); 22235b9c547cSRui Paulo wpa_ctrl_close(mon); 22245b9c547cSRui Paulo 22255b9c547cSRui Paulo if (res < 0) { 22265b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not connect"); 22275b9c547cSRui Paulo write_summary(ctx, "Could not connect to OSU network"); 22285b9c547cSRui Paulo wpa_printf(MSG_INFO, "Remove OSU network connection"); 22295b9c547cSRui Paulo snprintf(buf, sizeof(buf), "REMOVE_NETWORK %d", id); 22305b9c547cSRui Paulo wpa_command(ifname, buf); 22315b9c547cSRui Paulo return -1; 22325b9c547cSRui Paulo } 22335b9c547cSRui Paulo 22345b9c547cSRui Paulo write_summary(ctx, "Waiting for IP address for subscription registration"); 22355b9c547cSRui Paulo if (wait_ip_addr(ifname, 15) < 0) { 22365b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not get IP address for WLAN - try connection anyway"); 22375b9c547cSRui Paulo } 22385b9c547cSRui Paulo 22395b9c547cSRui Paulo if (no_prod_assoc) { 22405b9c547cSRui Paulo if (res < 0) 22415b9c547cSRui Paulo return -1; 22425b9c547cSRui Paulo wpa_printf(MSG_INFO, "No production connection used for testing purposes"); 22435b9c547cSRui Paulo write_summary(ctx, "No production connection used for testing purposes"); 22445b9c547cSRui Paulo return 0; 22455b9c547cSRui Paulo } 22465b9c547cSRui Paulo 22475b9c547cSRui Paulo ctx->no_reconnect = 1; 2248325151a3SRui Paulo if (methods & 0x02) { 2249325151a3SRui Paulo wpa_printf(MSG_DEBUG, "Calling cmd_prov from osu_connect"); 22505b9c547cSRui Paulo res = cmd_prov(ctx, url); 2251325151a3SRui Paulo } else if (methods & 0x01) { 2252325151a3SRui Paulo wpa_printf(MSG_DEBUG, 2253325151a3SRui Paulo "Calling cmd_oma_dm_prov from osu_connect"); 22545b9c547cSRui Paulo res = cmd_oma_dm_prov(ctx, url); 2255325151a3SRui Paulo } 22565b9c547cSRui Paulo 22575b9c547cSRui Paulo wpa_printf(MSG_INFO, "Remove OSU network connection"); 22585b9c547cSRui Paulo write_summary(ctx, "Remove OSU network connection"); 22595b9c547cSRui Paulo snprintf(buf, sizeof(buf), "REMOVE_NETWORK %d", id); 22605b9c547cSRui Paulo wpa_command(ifname, buf); 22615b9c547cSRui Paulo 22625b9c547cSRui Paulo if (res < 0) 22635b9c547cSRui Paulo return -1; 22645b9c547cSRui Paulo 22655b9c547cSRui Paulo wpa_printf(MSG_INFO, "Requesting reconnection with updated configuration"); 22665b9c547cSRui Paulo write_summary(ctx, "Requesting reconnection with updated configuration"); 22675b9c547cSRui Paulo if (wpa_command(ctx->ifname, "INTERWORKING_SELECT auto") < 0) { 22685b9c547cSRui Paulo wpa_printf(MSG_INFO, "Failed to request wpa_supplicant to reconnect"); 22695b9c547cSRui Paulo write_summary(ctx, "Failed to request wpa_supplicant to reconnect"); 22705b9c547cSRui Paulo return -1; 22715b9c547cSRui Paulo } 22725b9c547cSRui Paulo 22735b9c547cSRui Paulo return 0; 22745b9c547cSRui Paulo } 22755b9c547cSRui Paulo 22765b9c547cSRui Paulo 22775b9c547cSRui Paulo static int cmd_osu_select(struct hs20_osu_client *ctx, const char *dir, 22785b9c547cSRui Paulo int connect, int no_prod_assoc, 22795b9c547cSRui Paulo const char *friendly_name) 22805b9c547cSRui Paulo { 22815b9c547cSRui Paulo char fname[255]; 22825b9c547cSRui Paulo FILE *f; 22835b9c547cSRui Paulo struct osu_data *osu = NULL, *last = NULL; 2284*85732ac8SCy Schubert size_t osu_count = 0, i, j; 22855b9c547cSRui Paulo int ret; 22865b9c547cSRui Paulo 22875b9c547cSRui Paulo write_summary(ctx, "OSU provider selection"); 22885b9c547cSRui Paulo 22895b9c547cSRui Paulo if (dir == NULL) { 22905b9c547cSRui Paulo wpa_printf(MSG_INFO, "Missing dir parameter to osu_select"); 22915b9c547cSRui Paulo return -1; 22925b9c547cSRui Paulo } 22935b9c547cSRui Paulo 22945b9c547cSRui Paulo snprintf(fname, sizeof(fname), "%s/osu-providers.txt", dir); 22955b9c547cSRui Paulo osu = parse_osu_providers(fname, &osu_count); 22965b9c547cSRui Paulo if (osu == NULL) { 2297325151a3SRui Paulo wpa_printf(MSG_INFO, "Could not find any OSU providers from %s", 22985b9c547cSRui Paulo fname); 22995b9c547cSRui Paulo write_result(ctx, "No OSU providers available"); 23005b9c547cSRui Paulo return -1; 23015b9c547cSRui Paulo } 23025b9c547cSRui Paulo 23035b9c547cSRui Paulo if (friendly_name) { 23045b9c547cSRui Paulo for (i = 0; i < osu_count; i++) { 23055b9c547cSRui Paulo last = &osu[i]; 23065b9c547cSRui Paulo for (j = 0; j < last->friendly_name_count; j++) { 23075b9c547cSRui Paulo if (os_strcmp(last->friendly_name[j].text, 23085b9c547cSRui Paulo friendly_name) == 0) 23095b9c547cSRui Paulo break; 23105b9c547cSRui Paulo } 23115b9c547cSRui Paulo if (j < last->friendly_name_count) 23125b9c547cSRui Paulo break; 23135b9c547cSRui Paulo } 23145b9c547cSRui Paulo if (i == osu_count) { 23155b9c547cSRui Paulo wpa_printf(MSG_INFO, "Requested operator friendly name '%s' not found in the list of available providers", 23165b9c547cSRui Paulo friendly_name); 23175b9c547cSRui Paulo write_summary(ctx, "Requested operator friendly name '%s' not found in the list of available providers", 23185b9c547cSRui Paulo friendly_name); 23195b9c547cSRui Paulo free(osu); 23205b9c547cSRui Paulo return -1; 23215b9c547cSRui Paulo } 23225b9c547cSRui Paulo 23235b9c547cSRui Paulo wpa_printf(MSG_INFO, "OSU Provider selected based on requested operator friendly name '%s'", 23245b9c547cSRui Paulo friendly_name); 23255b9c547cSRui Paulo write_summary(ctx, "OSU Provider selected based on requested operator friendly name '%s'", 23265b9c547cSRui Paulo friendly_name); 23275b9c547cSRui Paulo ret = i + 1; 23285b9c547cSRui Paulo goto selected; 23295b9c547cSRui Paulo } 23305b9c547cSRui Paulo 23315b9c547cSRui Paulo snprintf(fname, sizeof(fname), "%s/osu-providers.html", dir); 23325b9c547cSRui Paulo f = fopen(fname, "w"); 23335b9c547cSRui Paulo if (f == NULL) { 23345b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not open %s", fname); 23355b9c547cSRui Paulo free(osu); 23365b9c547cSRui Paulo return -1; 23375b9c547cSRui Paulo } 23385b9c547cSRui Paulo 23395b9c547cSRui Paulo fprintf(f, "<html><head>" 23405b9c547cSRui Paulo "<meta http-equiv=\"Content-type\" content=\"text/html; " 23415b9c547cSRui Paulo "charset=utf-8\"<title>Select service operator</title>" 23425b9c547cSRui Paulo "</head><body><h1>Select service operator</h1>\n"); 23435b9c547cSRui Paulo 23445b9c547cSRui Paulo if (osu_count == 0) 23455b9c547cSRui Paulo fprintf(f, "No online signup available\n"); 23465b9c547cSRui Paulo 23475b9c547cSRui Paulo for (i = 0; i < osu_count; i++) { 23485b9c547cSRui Paulo last = &osu[i]; 23495b9c547cSRui Paulo #ifdef ANDROID 23505b9c547cSRui Paulo fprintf(f, "<p>\n" 23515b9c547cSRui Paulo "<a href=\"http://localhost:12345/osu/%d\">" 23525b9c547cSRui Paulo "<table><tr><td>", (int) i + 1); 23535b9c547cSRui Paulo #else /* ANDROID */ 23545b9c547cSRui Paulo fprintf(f, "<p>\n" 23555b9c547cSRui Paulo "<a href=\"osu://%d\">" 23565b9c547cSRui Paulo "<table><tr><td>", (int) i + 1); 23575b9c547cSRui Paulo #endif /* ANDROID */ 23585b9c547cSRui Paulo for (j = 0; j < last->icon_count; j++) { 23595b9c547cSRui Paulo fprintf(f, "<img src=\"osu-icon-%d.%s\">\n", 23605b9c547cSRui Paulo last->icon[j].id, 23615b9c547cSRui Paulo strcasecmp(last->icon[j].mime_type, 23625b9c547cSRui Paulo "image/png") == 0 ? "png" : "icon"); 23635b9c547cSRui Paulo } 23645b9c547cSRui Paulo fprintf(f, "<td>"); 23655b9c547cSRui Paulo for (j = 0; j < last->friendly_name_count; j++) { 23665b9c547cSRui Paulo fprintf(f, "<small>[%s]</small> %s<br>\n", 23675b9c547cSRui Paulo last->friendly_name[j].lang, 23685b9c547cSRui Paulo last->friendly_name[j].text); 23695b9c547cSRui Paulo } 23705b9c547cSRui Paulo fprintf(f, "<tr><td colspan=2>"); 23715b9c547cSRui Paulo for (j = 0; j < last->serv_desc_count; j++) { 23725b9c547cSRui Paulo fprintf(f, "<small>[%s]</small> %s<br>\n", 23735b9c547cSRui Paulo last->serv_desc[j].lang, 23745b9c547cSRui Paulo last->serv_desc[j].text); 23755b9c547cSRui Paulo } 23765b9c547cSRui Paulo fprintf(f, "</table></a><br><small>BSSID: %s<br>\n" 23775b9c547cSRui Paulo "SSID: %s<br>\n", 23785b9c547cSRui Paulo last->bssid, last->osu_ssid); 2379*85732ac8SCy Schubert if (last->osu_ssid2[0]) 2380*85732ac8SCy Schubert fprintf(f, "SSID2: %s<br>\n", last->osu_ssid2); 2381780fb4a2SCy Schubert if (last->osu_nai[0]) 23825b9c547cSRui Paulo fprintf(f, "NAI: %s<br>\n", last->osu_nai); 2383*85732ac8SCy Schubert if (last->osu_nai2[0]) 2384*85732ac8SCy Schubert fprintf(f, "NAI2: %s<br>\n", last->osu_nai2); 23855b9c547cSRui Paulo fprintf(f, "URL: %s<br>\n" 23865b9c547cSRui Paulo "methods:%s%s<br>\n" 23875b9c547cSRui Paulo "</small></p>\n", 23885b9c547cSRui Paulo last->url, 23895b9c547cSRui Paulo last->methods & 0x01 ? " OMA-DM" : "", 23905b9c547cSRui Paulo last->methods & 0x02 ? " SOAP-XML-SPP" : ""); 23915b9c547cSRui Paulo } 23925b9c547cSRui Paulo 23935b9c547cSRui Paulo fprintf(f, "</body></html>\n"); 23945b9c547cSRui Paulo 23955b9c547cSRui Paulo fclose(f); 23965b9c547cSRui Paulo 23975b9c547cSRui Paulo snprintf(fname, sizeof(fname), "file://%s/osu-providers.html", dir); 23985b9c547cSRui Paulo write_summary(ctx, "Start web browser with OSU provider selection page"); 23995b9c547cSRui Paulo ret = hs20_web_browser(fname); 24005b9c547cSRui Paulo 24015b9c547cSRui Paulo selected: 24025b9c547cSRui Paulo if (ret > 0 && (size_t) ret <= osu_count) { 24035b9c547cSRui Paulo char *data; 24045b9c547cSRui Paulo size_t data_len; 24055b9c547cSRui Paulo 24065b9c547cSRui Paulo wpa_printf(MSG_INFO, "Selected OSU id=%d", ret); 24075b9c547cSRui Paulo last = &osu[ret - 1]; 24085b9c547cSRui Paulo ret = 0; 24095b9c547cSRui Paulo wpa_printf(MSG_INFO, "BSSID: %s", last->bssid); 24105b9c547cSRui Paulo wpa_printf(MSG_INFO, "SSID: %s", last->osu_ssid); 2411*85732ac8SCy Schubert if (last->osu_ssid2[0]) 2412*85732ac8SCy Schubert wpa_printf(MSG_INFO, "SSID2: %s", last->osu_ssid2); 24135b9c547cSRui Paulo wpa_printf(MSG_INFO, "URL: %s", last->url); 24145b9c547cSRui Paulo write_summary(ctx, "Selected OSU provider id=%d BSSID=%s SSID=%s URL=%s", 24155b9c547cSRui Paulo ret, last->bssid, last->osu_ssid, last->url); 24165b9c547cSRui Paulo 24175b9c547cSRui Paulo ctx->friendly_name_count = last->friendly_name_count; 24185b9c547cSRui Paulo for (j = 0; j < last->friendly_name_count; j++) { 24195b9c547cSRui Paulo wpa_printf(MSG_INFO, "FRIENDLY_NAME: [%s]%s", 24205b9c547cSRui Paulo last->friendly_name[j].lang, 24215b9c547cSRui Paulo last->friendly_name[j].text); 24225b9c547cSRui Paulo os_strlcpy(ctx->friendly_name[j].lang, 24235b9c547cSRui Paulo last->friendly_name[j].lang, 24245b9c547cSRui Paulo sizeof(ctx->friendly_name[j].lang)); 24255b9c547cSRui Paulo os_strlcpy(ctx->friendly_name[j].text, 24265b9c547cSRui Paulo last->friendly_name[j].text, 24275b9c547cSRui Paulo sizeof(ctx->friendly_name[j].text)); 24285b9c547cSRui Paulo } 24295b9c547cSRui Paulo 24305b9c547cSRui Paulo ctx->icon_count = last->icon_count; 24315b9c547cSRui Paulo for (j = 0; j < last->icon_count; j++) { 24325b9c547cSRui Paulo char fname[256]; 24335b9c547cSRui Paulo 24345b9c547cSRui Paulo os_snprintf(fname, sizeof(fname), "%s/osu-icon-%d.%s", 24355b9c547cSRui Paulo dir, last->icon[j].id, 24365b9c547cSRui Paulo strcasecmp(last->icon[j].mime_type, 24375b9c547cSRui Paulo "image/png") == 0 ? 24385b9c547cSRui Paulo "png" : "icon"); 24395b9c547cSRui Paulo wpa_printf(MSG_INFO, "ICON: %s (%s)", 24405b9c547cSRui Paulo fname, last->icon[j].filename); 24415b9c547cSRui Paulo os_strlcpy(ctx->icon_filename[j], 24425b9c547cSRui Paulo last->icon[j].filename, 24435b9c547cSRui Paulo sizeof(ctx->icon_filename[j])); 24445b9c547cSRui Paulo 24455b9c547cSRui Paulo data = os_readfile(fname, &data_len); 24465b9c547cSRui Paulo if (data) { 24475b9c547cSRui Paulo sha256_vector(1, (const u8 **) &data, &data_len, 24485b9c547cSRui Paulo ctx->icon_hash[j]); 24495b9c547cSRui Paulo os_free(data); 24505b9c547cSRui Paulo } 24515b9c547cSRui Paulo } 24525b9c547cSRui Paulo 24535b9c547cSRui Paulo if (connect == 2) { 2454325151a3SRui Paulo if (last->methods & 0x02) { 2455325151a3SRui Paulo wpa_printf(MSG_DEBUG, 2456325151a3SRui Paulo "Calling cmd_prov from cmd_osu_select"); 24575b9c547cSRui Paulo ret = cmd_prov(ctx, last->url); 2458325151a3SRui Paulo } else if (last->methods & 0x01) { 2459325151a3SRui Paulo wpa_printf(MSG_DEBUG, 2460325151a3SRui Paulo "Calling cmd_oma_dm_prov from cmd_osu_select"); 24615b9c547cSRui Paulo ret = cmd_oma_dm_prov(ctx, last->url); 2462325151a3SRui Paulo } else { 2463325151a3SRui Paulo wpa_printf(MSG_DEBUG, 2464325151a3SRui Paulo "No supported OSU provisioning method"); 24655b9c547cSRui Paulo ret = -1; 2466325151a3SRui Paulo } 2467*85732ac8SCy Schubert } else if (connect) { 24685b9c547cSRui Paulo ret = osu_connect(ctx, last->bssid, last->osu_ssid, 2469*85732ac8SCy Schubert last->osu_ssid2, 24705b9c547cSRui Paulo last->url, last->methods, 2471*85732ac8SCy Schubert no_prod_assoc, last->osu_nai, 2472*85732ac8SCy Schubert last->osu_nai2); 2473*85732ac8SCy Schubert } 24745b9c547cSRui Paulo } else 24755b9c547cSRui Paulo ret = -1; 24765b9c547cSRui Paulo 24775b9c547cSRui Paulo free(osu); 24785b9c547cSRui Paulo 24795b9c547cSRui Paulo return ret; 24805b9c547cSRui Paulo } 24815b9c547cSRui Paulo 24825b9c547cSRui Paulo 24835b9c547cSRui Paulo static int cmd_signup(struct hs20_osu_client *ctx, int no_prod_assoc, 24845b9c547cSRui Paulo const char *friendly_name) 24855b9c547cSRui Paulo { 24865b9c547cSRui Paulo char dir[255]; 24875b9c547cSRui Paulo char fname[300], buf[400]; 24885b9c547cSRui Paulo struct wpa_ctrl *mon; 24895b9c547cSRui Paulo const char *ifname; 24905b9c547cSRui Paulo int res; 24915b9c547cSRui Paulo 24925b9c547cSRui Paulo ifname = ctx->ifname; 24935b9c547cSRui Paulo 24945b9c547cSRui Paulo if (getcwd(dir, sizeof(dir)) == NULL) 24955b9c547cSRui Paulo return -1; 24965b9c547cSRui Paulo 24975b9c547cSRui Paulo snprintf(fname, sizeof(fname), "%s/osu-info", dir); 2498780fb4a2SCy Schubert if (mkdir(fname, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) < 0 && 2499780fb4a2SCy Schubert errno != EEXIST) { 25005b9c547cSRui Paulo wpa_printf(MSG_INFO, "mkdir(%s) failed: %s", 25015b9c547cSRui Paulo fname, strerror(errno)); 25025b9c547cSRui Paulo return -1; 25035b9c547cSRui Paulo } 25045b9c547cSRui Paulo 2505*85732ac8SCy Schubert android_update_permission(fname, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); 2506780fb4a2SCy Schubert 25075b9c547cSRui Paulo snprintf(buf, sizeof(buf), "SET osu_dir %s", fname); 25085b9c547cSRui Paulo if (wpa_command(ifname, buf) < 0) { 25095b9c547cSRui Paulo wpa_printf(MSG_INFO, "Failed to configure osu_dir to wpa_supplicant"); 25105b9c547cSRui Paulo return -1; 25115b9c547cSRui Paulo } 25125b9c547cSRui Paulo 25135b9c547cSRui Paulo mon = open_wpa_mon(ifname); 25145b9c547cSRui Paulo if (mon == NULL) 25155b9c547cSRui Paulo return -1; 25165b9c547cSRui Paulo 25175b9c547cSRui Paulo wpa_printf(MSG_INFO, "Starting OSU fetch"); 25185b9c547cSRui Paulo write_summary(ctx, "Starting OSU provider information fetch"); 25195b9c547cSRui Paulo if (wpa_command(ifname, "FETCH_OSU") < 0) { 25205b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not start OSU fetch"); 25215b9c547cSRui Paulo wpa_ctrl_detach(mon); 25225b9c547cSRui Paulo wpa_ctrl_close(mon); 25235b9c547cSRui Paulo return -1; 25245b9c547cSRui Paulo } 25255b9c547cSRui Paulo res = get_wpa_cli_event(mon, "OSU provider fetch completed", 25265b9c547cSRui Paulo buf, sizeof(buf)); 25275b9c547cSRui Paulo 25285b9c547cSRui Paulo wpa_ctrl_detach(mon); 25295b9c547cSRui Paulo wpa_ctrl_close(mon); 25305b9c547cSRui Paulo 25315b9c547cSRui Paulo if (res < 0) { 25325b9c547cSRui Paulo wpa_printf(MSG_INFO, "OSU fetch did not complete"); 25335b9c547cSRui Paulo write_summary(ctx, "OSU fetch did not complete"); 25345b9c547cSRui Paulo return -1; 25355b9c547cSRui Paulo } 25365b9c547cSRui Paulo wpa_printf(MSG_INFO, "OSU provider fetch completed"); 25375b9c547cSRui Paulo 25385b9c547cSRui Paulo return cmd_osu_select(ctx, fname, 1, no_prod_assoc, friendly_name); 25395b9c547cSRui Paulo } 25405b9c547cSRui Paulo 25415b9c547cSRui Paulo 25425b9c547cSRui Paulo static int cmd_sub_rem(struct hs20_osu_client *ctx, const char *address, 25435b9c547cSRui Paulo const char *pps_fname, const char *ca_fname) 25445b9c547cSRui Paulo { 25455b9c547cSRui Paulo xml_node_t *pps, *node; 25465b9c547cSRui Paulo char pps_fname_buf[300]; 25475b9c547cSRui Paulo char ca_fname_buf[200]; 25485b9c547cSRui Paulo char *cred_username = NULL; 25495b9c547cSRui Paulo char *cred_password = NULL; 25505b9c547cSRui Paulo char *sub_rem_uri = NULL; 25515b9c547cSRui Paulo char client_cert_buf[200]; 25525b9c547cSRui Paulo char *client_cert = NULL; 25535b9c547cSRui Paulo char client_key_buf[200]; 25545b9c547cSRui Paulo char *client_key = NULL; 25555b9c547cSRui Paulo int spp; 25565b9c547cSRui Paulo 25575b9c547cSRui Paulo wpa_printf(MSG_INFO, "Subscription remediation requested with Server URL: %s", 25585b9c547cSRui Paulo address); 25595b9c547cSRui Paulo 25605b9c547cSRui Paulo if (!pps_fname) { 25615b9c547cSRui Paulo char buf[256]; 25625b9c547cSRui Paulo wpa_printf(MSG_INFO, "Determining PPS file based on Home SP information"); 25635b9c547cSRui Paulo if (os_strncmp(address, "fqdn=", 5) == 0) { 25645b9c547cSRui Paulo wpa_printf(MSG_INFO, "Use requested FQDN from command line"); 25655b9c547cSRui Paulo os_snprintf(buf, sizeof(buf), "%s", address + 5); 25665b9c547cSRui Paulo address = NULL; 25675b9c547cSRui Paulo } else if (get_wpa_status(ctx->ifname, "provisioning_sp", buf, 25685b9c547cSRui Paulo sizeof(buf)) < 0) { 25695b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not get provisioning Home SP FQDN from wpa_supplicant"); 25705b9c547cSRui Paulo return -1; 25715b9c547cSRui Paulo } 25725b9c547cSRui Paulo os_free(ctx->fqdn); 25735b9c547cSRui Paulo ctx->fqdn = os_strdup(buf); 25745b9c547cSRui Paulo if (ctx->fqdn == NULL) 25755b9c547cSRui Paulo return -1; 25765b9c547cSRui Paulo wpa_printf(MSG_INFO, "Home SP FQDN for current credential: %s", 25775b9c547cSRui Paulo buf); 25785b9c547cSRui Paulo os_snprintf(pps_fname_buf, sizeof(pps_fname_buf), 25795b9c547cSRui Paulo "SP/%s/pps.xml", ctx->fqdn); 25805b9c547cSRui Paulo pps_fname = pps_fname_buf; 25815b9c547cSRui Paulo 25825b9c547cSRui Paulo os_snprintf(ca_fname_buf, sizeof(ca_fname_buf), "SP/%s/ca.pem", 25835b9c547cSRui Paulo ctx->fqdn); 25845b9c547cSRui Paulo ca_fname = ca_fname_buf; 25855b9c547cSRui Paulo } 25865b9c547cSRui Paulo 25875b9c547cSRui Paulo if (!os_file_exists(pps_fname)) { 25885b9c547cSRui Paulo wpa_printf(MSG_INFO, "PPS file '%s' does not exist or is not accessible", 25895b9c547cSRui Paulo pps_fname); 25905b9c547cSRui Paulo return -1; 25915b9c547cSRui Paulo } 25925b9c547cSRui Paulo wpa_printf(MSG_INFO, "Using PPS file: %s", pps_fname); 25935b9c547cSRui Paulo 25945b9c547cSRui Paulo if (ca_fname && !os_file_exists(ca_fname)) { 25955b9c547cSRui Paulo wpa_printf(MSG_INFO, "CA file '%s' does not exist or is not accessible", 25965b9c547cSRui Paulo ca_fname); 25975b9c547cSRui Paulo return -1; 25985b9c547cSRui Paulo } 25995b9c547cSRui Paulo wpa_printf(MSG_INFO, "Using server trust root: %s", ca_fname); 26005b9c547cSRui Paulo ctx->ca_fname = ca_fname; 26015b9c547cSRui Paulo 26025b9c547cSRui Paulo pps = node_from_file(ctx->xml, pps_fname); 26035b9c547cSRui Paulo if (pps == NULL) { 26045b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not read PPS MO"); 26055b9c547cSRui Paulo return -1; 26065b9c547cSRui Paulo } 26075b9c547cSRui Paulo 26085b9c547cSRui Paulo if (!ctx->fqdn) { 26095b9c547cSRui Paulo char *tmp; 26105b9c547cSRui Paulo node = get_child_node(ctx->xml, pps, "HomeSP/FQDN"); 26115b9c547cSRui Paulo if (node == NULL) { 26125b9c547cSRui Paulo wpa_printf(MSG_INFO, "No HomeSP/FQDN found from PPS"); 26135b9c547cSRui Paulo return -1; 26145b9c547cSRui Paulo } 26155b9c547cSRui Paulo tmp = xml_node_get_text(ctx->xml, node); 26165b9c547cSRui Paulo if (tmp == NULL) { 26175b9c547cSRui Paulo wpa_printf(MSG_INFO, "No HomeSP/FQDN text found from PPS"); 26185b9c547cSRui Paulo return -1; 26195b9c547cSRui Paulo } 26205b9c547cSRui Paulo ctx->fqdn = os_strdup(tmp); 26215b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, tmp); 26225b9c547cSRui Paulo if (!ctx->fqdn) { 26235b9c547cSRui Paulo wpa_printf(MSG_INFO, "No FQDN known"); 26245b9c547cSRui Paulo return -1; 26255b9c547cSRui Paulo } 26265b9c547cSRui Paulo } 26275b9c547cSRui Paulo 26285b9c547cSRui Paulo node = get_child_node(ctx->xml, pps, 26295b9c547cSRui Paulo "SubscriptionUpdate/UpdateMethod"); 26305b9c547cSRui Paulo if (node) { 26315b9c547cSRui Paulo char *tmp; 26325b9c547cSRui Paulo tmp = xml_node_get_text(ctx->xml, node); 26335b9c547cSRui Paulo if (tmp && os_strcasecmp(tmp, "OMA-DM-ClientInitiated") == 0) 26345b9c547cSRui Paulo spp = 0; 26355b9c547cSRui Paulo else 26365b9c547cSRui Paulo spp = 1; 26375b9c547cSRui Paulo } else { 26385b9c547cSRui Paulo wpa_printf(MSG_INFO, "No UpdateMethod specified - assume SPP"); 26395b9c547cSRui Paulo spp = 1; 26405b9c547cSRui Paulo } 26415b9c547cSRui Paulo 26425b9c547cSRui Paulo get_user_pw(ctx, pps, "SubscriptionUpdate/UsernamePassword", 26435b9c547cSRui Paulo &cred_username, &cred_password); 26445b9c547cSRui Paulo if (cred_username) 26455b9c547cSRui Paulo wpa_printf(MSG_INFO, "Using username: %s", cred_username); 26465b9c547cSRui Paulo if (cred_password) 26475b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "Using password: %s", cred_password); 26485b9c547cSRui Paulo 26495b9c547cSRui Paulo if (cred_username == NULL && cred_password == NULL && 26505b9c547cSRui Paulo get_child_node(ctx->xml, pps, "Credential/DigitalCertificate")) { 26515b9c547cSRui Paulo wpa_printf(MSG_INFO, "Using client certificate"); 26525b9c547cSRui Paulo os_snprintf(client_cert_buf, sizeof(client_cert_buf), 26535b9c547cSRui Paulo "SP/%s/client-cert.pem", ctx->fqdn); 26545b9c547cSRui Paulo client_cert = client_cert_buf; 26555b9c547cSRui Paulo os_snprintf(client_key_buf, sizeof(client_key_buf), 26565b9c547cSRui Paulo "SP/%s/client-key.pem", ctx->fqdn); 26575b9c547cSRui Paulo client_key = client_key_buf; 26585b9c547cSRui Paulo ctx->client_cert_present = 1; 26595b9c547cSRui Paulo } 26605b9c547cSRui Paulo 26615b9c547cSRui Paulo node = get_child_node(ctx->xml, pps, "SubscriptionUpdate/URI"); 26625b9c547cSRui Paulo if (node) { 26635b9c547cSRui Paulo sub_rem_uri = xml_node_get_text(ctx->xml, node); 26645b9c547cSRui Paulo if (sub_rem_uri && 26655b9c547cSRui Paulo (!address || os_strcmp(address, sub_rem_uri) != 0)) { 26665b9c547cSRui Paulo wpa_printf(MSG_INFO, "Override sub rem URI based on PPS: %s", 26675b9c547cSRui Paulo sub_rem_uri); 26685b9c547cSRui Paulo address = sub_rem_uri; 26695b9c547cSRui Paulo } 26705b9c547cSRui Paulo } 26715b9c547cSRui Paulo if (!address) { 26725b9c547cSRui Paulo wpa_printf(MSG_INFO, "Server URL not known"); 26735b9c547cSRui Paulo return -1; 26745b9c547cSRui Paulo } 26755b9c547cSRui Paulo 26765b9c547cSRui Paulo write_summary(ctx, "Wait for IP address for subscriptiom remediation"); 26775b9c547cSRui Paulo wpa_printf(MSG_INFO, "Wait for IP address before starting subscription remediation"); 26785b9c547cSRui Paulo 26795b9c547cSRui Paulo if (wait_ip_addr(ctx->ifname, 15) < 0) { 26805b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not get IP address for WLAN - try connection anyway"); 26815b9c547cSRui Paulo } 26825b9c547cSRui Paulo 26835b9c547cSRui Paulo if (spp) 26845b9c547cSRui Paulo spp_sub_rem(ctx, address, pps_fname, 26855b9c547cSRui Paulo client_cert, client_key, 26865b9c547cSRui Paulo cred_username, cred_password, pps); 26875b9c547cSRui Paulo else 26885b9c547cSRui Paulo oma_dm_sub_rem(ctx, address, pps_fname, 26895b9c547cSRui Paulo client_cert, client_key, 26905b9c547cSRui Paulo cred_username, cred_password, pps); 26915b9c547cSRui Paulo 26925b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, sub_rem_uri); 26935b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, cred_username); 26945b9c547cSRui Paulo str_clear_free(cred_password); 26955b9c547cSRui Paulo xml_node_free(ctx->xml, pps); 26965b9c547cSRui Paulo return 0; 26975b9c547cSRui Paulo } 26985b9c547cSRui Paulo 26995b9c547cSRui Paulo 27005b9c547cSRui Paulo static int cmd_pol_upd(struct hs20_osu_client *ctx, const char *address, 27015b9c547cSRui Paulo const char *pps_fname, const char *ca_fname) 27025b9c547cSRui Paulo { 27035b9c547cSRui Paulo xml_node_t *pps; 27045b9c547cSRui Paulo xml_node_t *node; 27055b9c547cSRui Paulo char pps_fname_buf[300]; 27065b9c547cSRui Paulo char ca_fname_buf[200]; 27075b9c547cSRui Paulo char *uri = NULL; 27085b9c547cSRui Paulo char *cred_username = NULL; 27095b9c547cSRui Paulo char *cred_password = NULL; 27105b9c547cSRui Paulo char client_cert_buf[200]; 27115b9c547cSRui Paulo char *client_cert = NULL; 27125b9c547cSRui Paulo char client_key_buf[200]; 27135b9c547cSRui Paulo char *client_key = NULL; 27145b9c547cSRui Paulo int spp; 27155b9c547cSRui Paulo 27165b9c547cSRui Paulo wpa_printf(MSG_INFO, "Policy update requested"); 27175b9c547cSRui Paulo 27185b9c547cSRui Paulo if (!pps_fname) { 27195b9c547cSRui Paulo char buf[256]; 27205b9c547cSRui Paulo wpa_printf(MSG_INFO, "Determining PPS file based on Home SP information"); 2721780fb4a2SCy Schubert if (address && os_strncmp(address, "fqdn=", 5) == 0) { 27225b9c547cSRui Paulo wpa_printf(MSG_INFO, "Use requested FQDN from command line"); 27235b9c547cSRui Paulo os_snprintf(buf, sizeof(buf), "%s", address + 5); 27245b9c547cSRui Paulo address = NULL; 27255b9c547cSRui Paulo } else if (get_wpa_status(ctx->ifname, "provisioning_sp", buf, 27265b9c547cSRui Paulo sizeof(buf)) < 0) { 27275b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not get provisioning Home SP FQDN from wpa_supplicant"); 27285b9c547cSRui Paulo return -1; 27295b9c547cSRui Paulo } 27305b9c547cSRui Paulo os_free(ctx->fqdn); 27315b9c547cSRui Paulo ctx->fqdn = os_strdup(buf); 27325b9c547cSRui Paulo if (ctx->fqdn == NULL) 27335b9c547cSRui Paulo return -1; 27345b9c547cSRui Paulo wpa_printf(MSG_INFO, "Home SP FQDN for current credential: %s", 27355b9c547cSRui Paulo buf); 27365b9c547cSRui Paulo os_snprintf(pps_fname_buf, sizeof(pps_fname_buf), 27375b9c547cSRui Paulo "SP/%s/pps.xml", ctx->fqdn); 27385b9c547cSRui Paulo pps_fname = pps_fname_buf; 27395b9c547cSRui Paulo 27405b9c547cSRui Paulo os_snprintf(ca_fname_buf, sizeof(ca_fname_buf), "SP/%s/ca.pem", 27415b9c547cSRui Paulo buf); 27425b9c547cSRui Paulo ca_fname = ca_fname_buf; 27435b9c547cSRui Paulo } 27445b9c547cSRui Paulo 27455b9c547cSRui Paulo if (!os_file_exists(pps_fname)) { 27465b9c547cSRui Paulo wpa_printf(MSG_INFO, "PPS file '%s' does not exist or is not accessible", 27475b9c547cSRui Paulo pps_fname); 27485b9c547cSRui Paulo return -1; 27495b9c547cSRui Paulo } 27505b9c547cSRui Paulo wpa_printf(MSG_INFO, "Using PPS file: %s", pps_fname); 27515b9c547cSRui Paulo 27525b9c547cSRui Paulo if (ca_fname && !os_file_exists(ca_fname)) { 27535b9c547cSRui Paulo wpa_printf(MSG_INFO, "CA file '%s' does not exist or is not accessible", 27545b9c547cSRui Paulo ca_fname); 27555b9c547cSRui Paulo return -1; 27565b9c547cSRui Paulo } 27575b9c547cSRui Paulo wpa_printf(MSG_INFO, "Using server trust root: %s", ca_fname); 27585b9c547cSRui Paulo ctx->ca_fname = ca_fname; 27595b9c547cSRui Paulo 27605b9c547cSRui Paulo pps = node_from_file(ctx->xml, pps_fname); 27615b9c547cSRui Paulo if (pps == NULL) { 27625b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not read PPS MO"); 27635b9c547cSRui Paulo return -1; 27645b9c547cSRui Paulo } 27655b9c547cSRui Paulo 27665b9c547cSRui Paulo if (!ctx->fqdn) { 27675b9c547cSRui Paulo char *tmp; 27685b9c547cSRui Paulo node = get_child_node(ctx->xml, pps, "HomeSP/FQDN"); 27695b9c547cSRui Paulo if (node == NULL) { 27705b9c547cSRui Paulo wpa_printf(MSG_INFO, "No HomeSP/FQDN found from PPS"); 27715b9c547cSRui Paulo return -1; 27725b9c547cSRui Paulo } 27735b9c547cSRui Paulo tmp = xml_node_get_text(ctx->xml, node); 27745b9c547cSRui Paulo if (tmp == NULL) { 27755b9c547cSRui Paulo wpa_printf(MSG_INFO, "No HomeSP/FQDN text found from PPS"); 27765b9c547cSRui Paulo return -1; 27775b9c547cSRui Paulo } 27785b9c547cSRui Paulo ctx->fqdn = os_strdup(tmp); 27795b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, tmp); 27805b9c547cSRui Paulo if (!ctx->fqdn) { 27815b9c547cSRui Paulo wpa_printf(MSG_INFO, "No FQDN known"); 27825b9c547cSRui Paulo return -1; 27835b9c547cSRui Paulo } 27845b9c547cSRui Paulo } 27855b9c547cSRui Paulo 27865b9c547cSRui Paulo node = get_child_node(ctx->xml, pps, 27875b9c547cSRui Paulo "Policy/PolicyUpdate/UpdateMethod"); 27885b9c547cSRui Paulo if (node) { 27895b9c547cSRui Paulo char *tmp; 27905b9c547cSRui Paulo tmp = xml_node_get_text(ctx->xml, node); 27915b9c547cSRui Paulo if (tmp && os_strcasecmp(tmp, "OMA-DM-ClientInitiated") == 0) 27925b9c547cSRui Paulo spp = 0; 27935b9c547cSRui Paulo else 27945b9c547cSRui Paulo spp = 1; 27955b9c547cSRui Paulo } else { 27965b9c547cSRui Paulo wpa_printf(MSG_INFO, "No UpdateMethod specified - assume SPP"); 27975b9c547cSRui Paulo spp = 1; 27985b9c547cSRui Paulo } 27995b9c547cSRui Paulo 28005b9c547cSRui Paulo get_user_pw(ctx, pps, "Policy/PolicyUpdate/UsernamePassword", 28015b9c547cSRui Paulo &cred_username, &cred_password); 28025b9c547cSRui Paulo if (cred_username) 28035b9c547cSRui Paulo wpa_printf(MSG_INFO, "Using username: %s", cred_username); 28045b9c547cSRui Paulo if (cred_password) 28055b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "Using password: %s", cred_password); 28065b9c547cSRui Paulo 28075b9c547cSRui Paulo if (cred_username == NULL && cred_password == NULL && 28085b9c547cSRui Paulo get_child_node(ctx->xml, pps, "Credential/DigitalCertificate")) { 28095b9c547cSRui Paulo wpa_printf(MSG_INFO, "Using client certificate"); 28105b9c547cSRui Paulo os_snprintf(client_cert_buf, sizeof(client_cert_buf), 28115b9c547cSRui Paulo "SP/%s/client-cert.pem", ctx->fqdn); 28125b9c547cSRui Paulo client_cert = client_cert_buf; 28135b9c547cSRui Paulo os_snprintf(client_key_buf, sizeof(client_key_buf), 28145b9c547cSRui Paulo "SP/%s/client-key.pem", ctx->fqdn); 28155b9c547cSRui Paulo client_key = client_key_buf; 28165b9c547cSRui Paulo } 28175b9c547cSRui Paulo 28185b9c547cSRui Paulo if (!address) { 28195b9c547cSRui Paulo node = get_child_node(ctx->xml, pps, "Policy/PolicyUpdate/URI"); 28205b9c547cSRui Paulo if (node) { 28215b9c547cSRui Paulo uri = xml_node_get_text(ctx->xml, node); 28225b9c547cSRui Paulo wpa_printf(MSG_INFO, "URI based on PPS: %s", uri); 28235b9c547cSRui Paulo address = uri; 28245b9c547cSRui Paulo } 28255b9c547cSRui Paulo } 28265b9c547cSRui Paulo if (!address) { 28275b9c547cSRui Paulo wpa_printf(MSG_INFO, "Server URL not known"); 28285b9c547cSRui Paulo return -1; 28295b9c547cSRui Paulo } 28305b9c547cSRui Paulo 28315b9c547cSRui Paulo if (spp) 28325b9c547cSRui Paulo spp_pol_upd(ctx, address, pps_fname, 28335b9c547cSRui Paulo client_cert, client_key, 28345b9c547cSRui Paulo cred_username, cred_password, pps); 28355b9c547cSRui Paulo else 28365b9c547cSRui Paulo oma_dm_pol_upd(ctx, address, pps_fname, 28375b9c547cSRui Paulo client_cert, client_key, 28385b9c547cSRui Paulo cred_username, cred_password, pps); 28395b9c547cSRui Paulo 28405b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, uri); 28415b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, cred_username); 28425b9c547cSRui Paulo str_clear_free(cred_password); 28435b9c547cSRui Paulo xml_node_free(ctx->xml, pps); 28445b9c547cSRui Paulo 28455b9c547cSRui Paulo return 0; 28465b9c547cSRui Paulo } 28475b9c547cSRui Paulo 28485b9c547cSRui Paulo 28495b9c547cSRui Paulo static char * get_hostname(const char *url) 28505b9c547cSRui Paulo { 28515b9c547cSRui Paulo const char *pos, *end, *end2; 28525b9c547cSRui Paulo char *ret; 28535b9c547cSRui Paulo 28545b9c547cSRui Paulo if (url == NULL) 28555b9c547cSRui Paulo return NULL; 28565b9c547cSRui Paulo 28575b9c547cSRui Paulo pos = os_strchr(url, '/'); 28585b9c547cSRui Paulo if (pos == NULL) 28595b9c547cSRui Paulo return NULL; 28605b9c547cSRui Paulo pos++; 28615b9c547cSRui Paulo if (*pos != '/') 28625b9c547cSRui Paulo return NULL; 28635b9c547cSRui Paulo pos++; 28645b9c547cSRui Paulo 28655b9c547cSRui Paulo end = os_strchr(pos, '/'); 28665b9c547cSRui Paulo end2 = os_strchr(pos, ':'); 2867325151a3SRui Paulo if ((end && end2 && end2 < end) || (!end && end2)) 28685b9c547cSRui Paulo end = end2; 28695b9c547cSRui Paulo if (end) 28705b9c547cSRui Paulo end--; 28715b9c547cSRui Paulo else { 28725b9c547cSRui Paulo end = pos; 28735b9c547cSRui Paulo while (*end) 28745b9c547cSRui Paulo end++; 28755b9c547cSRui Paulo if (end > pos) 28765b9c547cSRui Paulo end--; 28775b9c547cSRui Paulo } 28785b9c547cSRui Paulo 28795b9c547cSRui Paulo ret = os_malloc(end - pos + 2); 28805b9c547cSRui Paulo if (ret == NULL) 28815b9c547cSRui Paulo return NULL; 28825b9c547cSRui Paulo 28835b9c547cSRui Paulo os_memcpy(ret, pos, end - pos + 1); 28845b9c547cSRui Paulo ret[end - pos + 1] = '\0'; 28855b9c547cSRui Paulo 28865b9c547cSRui Paulo return ret; 28875b9c547cSRui Paulo } 28885b9c547cSRui Paulo 28895b9c547cSRui Paulo 28905b9c547cSRui Paulo static int osu_cert_cb(void *_ctx, struct http_cert *cert) 28915b9c547cSRui Paulo { 28925b9c547cSRui Paulo struct hs20_osu_client *ctx = _ctx; 28935b9c547cSRui Paulo unsigned int i, j; 28945b9c547cSRui Paulo int found; 28955b9c547cSRui Paulo char *host = NULL; 28965b9c547cSRui Paulo 2897325151a3SRui Paulo wpa_printf(MSG_INFO, "osu_cert_cb(osu_cert_validation=%d, url=%s)", 2898325151a3SRui Paulo !ctx->no_osu_cert_validation, ctx->server_url); 28995b9c547cSRui Paulo 29005b9c547cSRui Paulo host = get_hostname(ctx->server_url); 29015b9c547cSRui Paulo 29025b9c547cSRui Paulo for (i = 0; i < ctx->server_dnsname_count; i++) 29035b9c547cSRui Paulo os_free(ctx->server_dnsname[i]); 29045b9c547cSRui Paulo os_free(ctx->server_dnsname); 29055b9c547cSRui Paulo ctx->server_dnsname = os_calloc(cert->num_dnsname, sizeof(char *)); 29065b9c547cSRui Paulo ctx->server_dnsname_count = 0; 29075b9c547cSRui Paulo 29085b9c547cSRui Paulo found = 0; 29095b9c547cSRui Paulo for (i = 0; i < cert->num_dnsname; i++) { 29105b9c547cSRui Paulo if (ctx->server_dnsname) { 29115b9c547cSRui Paulo ctx->server_dnsname[ctx->server_dnsname_count] = 29125b9c547cSRui Paulo os_strdup(cert->dnsname[i]); 29135b9c547cSRui Paulo if (ctx->server_dnsname[ctx->server_dnsname_count]) 29145b9c547cSRui Paulo ctx->server_dnsname_count++; 29155b9c547cSRui Paulo } 29165b9c547cSRui Paulo if (host && os_strcasecmp(host, cert->dnsname[i]) == 0) 29175b9c547cSRui Paulo found = 1; 29185b9c547cSRui Paulo wpa_printf(MSG_INFO, "dNSName '%s'", cert->dnsname[i]); 29195b9c547cSRui Paulo } 29205b9c547cSRui Paulo 29215b9c547cSRui Paulo if (host && !found) { 29225b9c547cSRui Paulo wpa_printf(MSG_INFO, "Server name from URL (%s) did not match any dNSName - abort connection", 29235b9c547cSRui Paulo host); 29245b9c547cSRui Paulo write_result(ctx, "Server name from URL (%s) did not match any dNSName - abort connection", 29255b9c547cSRui Paulo host); 29265b9c547cSRui Paulo os_free(host); 29275b9c547cSRui Paulo return -1; 29285b9c547cSRui Paulo } 29295b9c547cSRui Paulo 29305b9c547cSRui Paulo os_free(host); 29315b9c547cSRui Paulo 29325b9c547cSRui Paulo for (i = 0; i < cert->num_othername; i++) { 29335b9c547cSRui Paulo if (os_strcmp(cert->othername[i].oid, 29345b9c547cSRui Paulo "1.3.6.1.4.1.40808.1.1.1") == 0) { 29355b9c547cSRui Paulo wpa_hexdump_ascii(MSG_INFO, 29365b9c547cSRui Paulo "id-wfa-hotspot-friendlyName", 29375b9c547cSRui Paulo cert->othername[i].data, 29385b9c547cSRui Paulo cert->othername[i].len); 29395b9c547cSRui Paulo } 29405b9c547cSRui Paulo } 29415b9c547cSRui Paulo 29425b9c547cSRui Paulo for (j = 0; !ctx->no_osu_cert_validation && 29435b9c547cSRui Paulo j < ctx->friendly_name_count; j++) { 29445b9c547cSRui Paulo int found = 0; 29455b9c547cSRui Paulo for (i = 0; i < cert->num_othername; i++) { 29465b9c547cSRui Paulo if (os_strcmp(cert->othername[i].oid, 29475b9c547cSRui Paulo "1.3.6.1.4.1.40808.1.1.1") != 0) 29485b9c547cSRui Paulo continue; 29495b9c547cSRui Paulo if (cert->othername[i].len < 3) 29505b9c547cSRui Paulo continue; 29515b9c547cSRui Paulo if (os_strncasecmp((char *) cert->othername[i].data, 29525b9c547cSRui Paulo ctx->friendly_name[j].lang, 3) != 0) 29535b9c547cSRui Paulo continue; 29545b9c547cSRui Paulo if (os_strncmp((char *) cert->othername[i].data + 3, 29555b9c547cSRui Paulo ctx->friendly_name[j].text, 29565b9c547cSRui Paulo cert->othername[i].len - 3) == 0) { 29575b9c547cSRui Paulo found = 1; 29585b9c547cSRui Paulo break; 29595b9c547cSRui Paulo } 29605b9c547cSRui Paulo } 29615b9c547cSRui Paulo 29625b9c547cSRui Paulo if (!found) { 29635b9c547cSRui Paulo wpa_printf(MSG_INFO, "No friendly name match found for '[%s]%s'", 29645b9c547cSRui Paulo ctx->friendly_name[j].lang, 29655b9c547cSRui Paulo ctx->friendly_name[j].text); 29665b9c547cSRui Paulo write_result(ctx, "No friendly name match found for '[%s]%s'", 29675b9c547cSRui Paulo ctx->friendly_name[j].lang, 29685b9c547cSRui Paulo ctx->friendly_name[j].text); 29695b9c547cSRui Paulo return -1; 29705b9c547cSRui Paulo } 29715b9c547cSRui Paulo } 29725b9c547cSRui Paulo 29735b9c547cSRui Paulo for (i = 0; i < cert->num_logo; i++) { 29745b9c547cSRui Paulo struct http_logo *logo = &cert->logo[i]; 29755b9c547cSRui Paulo 29765b9c547cSRui Paulo wpa_printf(MSG_INFO, "logo hash alg %s uri '%s'", 29775b9c547cSRui Paulo logo->alg_oid, logo->uri); 29785b9c547cSRui Paulo wpa_hexdump_ascii(MSG_INFO, "hashValue", 29795b9c547cSRui Paulo logo->hash, logo->hash_len); 29805b9c547cSRui Paulo } 29815b9c547cSRui Paulo 29825b9c547cSRui Paulo for (j = 0; !ctx->no_osu_cert_validation && j < ctx->icon_count; j++) { 29835b9c547cSRui Paulo int found = 0; 29845b9c547cSRui Paulo char *name = ctx->icon_filename[j]; 29855b9c547cSRui Paulo size_t name_len = os_strlen(name); 29865b9c547cSRui Paulo 2987325151a3SRui Paulo wpa_printf(MSG_INFO, 2988325151a3SRui Paulo "[%i] Looking for icon file name '%s' match", 2989325151a3SRui Paulo j, name); 29905b9c547cSRui Paulo for (i = 0; i < cert->num_logo; i++) { 29915b9c547cSRui Paulo struct http_logo *logo = &cert->logo[i]; 29925b9c547cSRui Paulo size_t uri_len = os_strlen(logo->uri); 29935b9c547cSRui Paulo char *pos; 29945b9c547cSRui Paulo 2995325151a3SRui Paulo wpa_printf(MSG_INFO, 2996325151a3SRui Paulo "[%i] Comparing to '%s' uri_len=%d name_len=%d", 2997325151a3SRui Paulo i, logo->uri, (int) uri_len, (int) name_len); 2998325151a3SRui Paulo if (uri_len < 1 + name_len) { 2999325151a3SRui Paulo wpa_printf(MSG_INFO, "URI Length is too short"); 30005b9c547cSRui Paulo continue; 3001325151a3SRui Paulo } 30025b9c547cSRui Paulo pos = &logo->uri[uri_len - name_len - 1]; 30035b9c547cSRui Paulo if (*pos != '/') 30045b9c547cSRui Paulo continue; 30055b9c547cSRui Paulo pos++; 30065b9c547cSRui Paulo if (os_strcmp(pos, name) == 0) { 30075b9c547cSRui Paulo found = 1; 30085b9c547cSRui Paulo break; 30095b9c547cSRui Paulo } 30105b9c547cSRui Paulo } 30115b9c547cSRui Paulo 30125b9c547cSRui Paulo if (!found) { 30135b9c547cSRui Paulo wpa_printf(MSG_INFO, "No icon filename match found for '%s'", 30145b9c547cSRui Paulo name); 30155b9c547cSRui Paulo write_result(ctx, 30165b9c547cSRui Paulo "No icon filename match found for '%s'", 30175b9c547cSRui Paulo name); 30185b9c547cSRui Paulo return -1; 30195b9c547cSRui Paulo } 30205b9c547cSRui Paulo } 30215b9c547cSRui Paulo 30225b9c547cSRui Paulo for (j = 0; !ctx->no_osu_cert_validation && j < ctx->icon_count; j++) { 30235b9c547cSRui Paulo int found = 0; 30245b9c547cSRui Paulo 30255b9c547cSRui Paulo for (i = 0; i < cert->num_logo; i++) { 30265b9c547cSRui Paulo struct http_logo *logo = &cert->logo[i]; 30275b9c547cSRui Paulo 3028325151a3SRui Paulo if (logo->hash_len != 32) { 3029325151a3SRui Paulo wpa_printf(MSG_INFO, 3030325151a3SRui Paulo "[%i][%i] Icon hash length invalid (should be 32): %d", 3031325151a3SRui Paulo j, i, (int) logo->hash_len); 30325b9c547cSRui Paulo continue; 3033325151a3SRui Paulo } 30345b9c547cSRui Paulo if (os_memcmp(logo->hash, ctx->icon_hash[j], 32) == 0) { 30355b9c547cSRui Paulo found = 1; 30365b9c547cSRui Paulo break; 30375b9c547cSRui Paulo } 3038325151a3SRui Paulo 3039325151a3SRui Paulo wpa_printf(MSG_DEBUG, 3040325151a3SRui Paulo "[%u][%u] Icon hash did not match", j, i); 3041325151a3SRui Paulo wpa_hexdump_ascii(MSG_DEBUG, "logo->hash", 3042325151a3SRui Paulo logo->hash, 32); 3043325151a3SRui Paulo wpa_hexdump_ascii(MSG_DEBUG, "ctx->icon_hash[j]", 3044325151a3SRui Paulo ctx->icon_hash[j], 32); 30455b9c547cSRui Paulo } 30465b9c547cSRui Paulo 30475b9c547cSRui Paulo if (!found) { 3048325151a3SRui Paulo wpa_printf(MSG_INFO, 3049325151a3SRui Paulo "No icon hash match (by hash) found"); 3050325151a3SRui Paulo write_result(ctx, 3051325151a3SRui Paulo "No icon hash match (by hash) found"); 30525b9c547cSRui Paulo return -1; 30535b9c547cSRui Paulo } 30545b9c547cSRui Paulo } 30555b9c547cSRui Paulo 30565b9c547cSRui Paulo return 0; 30575b9c547cSRui Paulo } 30585b9c547cSRui Paulo 30595b9c547cSRui Paulo 30605b9c547cSRui Paulo static int init_ctx(struct hs20_osu_client *ctx) 30615b9c547cSRui Paulo { 30625b9c547cSRui Paulo xml_node_t *devinfo, *devid; 30635b9c547cSRui Paulo 30645b9c547cSRui Paulo os_memset(ctx, 0, sizeof(*ctx)); 30655b9c547cSRui Paulo ctx->ifname = "wlan0"; 30665b9c547cSRui Paulo ctx->xml = xml_node_init_ctx(ctx, NULL); 30675b9c547cSRui Paulo if (ctx->xml == NULL) 30685b9c547cSRui Paulo return -1; 30695b9c547cSRui Paulo 30705b9c547cSRui Paulo devinfo = node_from_file(ctx->xml, "devinfo.xml"); 3071*85732ac8SCy Schubert if (devinfo) { 30725b9c547cSRui Paulo devid = get_node(ctx->xml, devinfo, "DevId"); 30735b9c547cSRui Paulo if (devid) { 30745b9c547cSRui Paulo char *tmp = xml_node_get_text(ctx->xml, devid); 3075*85732ac8SCy Schubert 30765b9c547cSRui Paulo if (tmp) { 30775b9c547cSRui Paulo ctx->devid = os_strdup(tmp); 30785b9c547cSRui Paulo xml_node_get_text_free(ctx->xml, tmp); 30795b9c547cSRui Paulo } 30805b9c547cSRui Paulo } 30815b9c547cSRui Paulo xml_node_free(ctx->xml, devinfo); 30825b9c547cSRui Paulo } 30835b9c547cSRui Paulo 30845b9c547cSRui Paulo ctx->http = http_init_ctx(ctx, ctx->xml); 30855b9c547cSRui Paulo if (ctx->http == NULL) { 30865b9c547cSRui Paulo xml_node_deinit_ctx(ctx->xml); 30875b9c547cSRui Paulo return -1; 30885b9c547cSRui Paulo } 30895b9c547cSRui Paulo http_ocsp_set(ctx->http, 2); 30905b9c547cSRui Paulo http_set_cert_cb(ctx->http, osu_cert_cb, ctx); 30915b9c547cSRui Paulo 30925b9c547cSRui Paulo return 0; 30935b9c547cSRui Paulo } 30945b9c547cSRui Paulo 30955b9c547cSRui Paulo 30965b9c547cSRui Paulo static void deinit_ctx(struct hs20_osu_client *ctx) 30975b9c547cSRui Paulo { 30985b9c547cSRui Paulo size_t i; 30995b9c547cSRui Paulo 31005b9c547cSRui Paulo http_deinit_ctx(ctx->http); 31015b9c547cSRui Paulo xml_node_deinit_ctx(ctx->xml); 31025b9c547cSRui Paulo os_free(ctx->fqdn); 31035b9c547cSRui Paulo os_free(ctx->server_url); 31045b9c547cSRui Paulo os_free(ctx->devid); 31055b9c547cSRui Paulo 31065b9c547cSRui Paulo for (i = 0; i < ctx->server_dnsname_count; i++) 31075b9c547cSRui Paulo os_free(ctx->server_dnsname[i]); 31085b9c547cSRui Paulo os_free(ctx->server_dnsname); 31095b9c547cSRui Paulo } 31105b9c547cSRui Paulo 31115b9c547cSRui Paulo 31125b9c547cSRui Paulo static void check_workarounds(struct hs20_osu_client *ctx) 31135b9c547cSRui Paulo { 31145b9c547cSRui Paulo FILE *f; 31155b9c547cSRui Paulo char buf[100]; 31165b9c547cSRui Paulo unsigned long int val = 0; 31175b9c547cSRui Paulo 31185b9c547cSRui Paulo f = fopen("hs20-osu-client.workarounds", "r"); 31195b9c547cSRui Paulo if (f == NULL) 31205b9c547cSRui Paulo return; 31215b9c547cSRui Paulo 31225b9c547cSRui Paulo if (fgets(buf, sizeof(buf), f)) 31235b9c547cSRui Paulo val = strtoul(buf, NULL, 16); 31245b9c547cSRui Paulo 31255b9c547cSRui Paulo fclose(f); 31265b9c547cSRui Paulo 31275b9c547cSRui Paulo if (val) { 31285b9c547cSRui Paulo wpa_printf(MSG_INFO, "Workarounds enabled: 0x%lx", val); 31295b9c547cSRui Paulo ctx->workarounds = val; 31305b9c547cSRui Paulo if (ctx->workarounds & WORKAROUND_OCSP_OPTIONAL) 31315b9c547cSRui Paulo http_ocsp_set(ctx->http, 1); 31325b9c547cSRui Paulo } 31335b9c547cSRui Paulo } 31345b9c547cSRui Paulo 31355b9c547cSRui Paulo 31365b9c547cSRui Paulo static void usage(void) 31375b9c547cSRui Paulo { 31385b9c547cSRui Paulo printf("usage: hs20-osu-client [-dddqqKt] [-S<station ifname>] \\\n" 31395b9c547cSRui Paulo " [-w<wpa_supplicant ctrl_iface dir>] " 31405b9c547cSRui Paulo "[-r<result file>] [-f<debug file>] \\\n" 31415b9c547cSRui Paulo " [-s<summary file>] \\\n" 3142325151a3SRui Paulo " [-x<spp.xsd file name>] \\\n" 31435b9c547cSRui Paulo " <command> [arguments..]\n" 31445b9c547cSRui Paulo "commands:\n" 31455b9c547cSRui Paulo "- to_tnds <XML MO> <XML MO in TNDS format> [URN]\n" 31465b9c547cSRui Paulo "- to_tnds2 <XML MO> <XML MO in TNDS format (Path) " 31475b9c547cSRui Paulo "[URN]>\n" 31485b9c547cSRui Paulo "- from_tnds <XML MO in TNDS format> <XML MO>\n" 31495b9c547cSRui Paulo "- set_pps <PerProviderSubscription XML file name>\n" 31505b9c547cSRui Paulo "- get_fqdn <PerProviderSubscription XML file name>\n" 31515b9c547cSRui Paulo "- pol_upd [Server URL] [PPS] [CA cert]\n" 31525b9c547cSRui Paulo "- sub_rem <Server URL> [PPS] [CA cert]\n" 31535b9c547cSRui Paulo "- prov <Server URL> [CA cert]\n" 31545b9c547cSRui Paulo "- oma_dm_prov <Server URL> [CA cert]\n" 31555b9c547cSRui Paulo "- sim_prov <Server URL> [CA cert]\n" 31565b9c547cSRui Paulo "- oma_dm_sim_prov <Server URL> [CA cert]\n" 31575b9c547cSRui Paulo "- signup [CA cert]\n" 31585b9c547cSRui Paulo "- dl_osu_ca <PPS> <CA file>\n" 31595b9c547cSRui Paulo "- dl_polupd_ca <PPS> <CA file>\n" 31605b9c547cSRui Paulo "- dl_aaa_ca <PPS> <CA file>\n" 31615b9c547cSRui Paulo "- browser <URL>\n" 31625b9c547cSRui Paulo "- parse_cert <X.509 certificate (DER)>\n" 31635b9c547cSRui Paulo "- osu_select <OSU info directory> [CA cert]\n"); 31645b9c547cSRui Paulo } 31655b9c547cSRui Paulo 31665b9c547cSRui Paulo 31675b9c547cSRui Paulo int main(int argc, char *argv[]) 31685b9c547cSRui Paulo { 31695b9c547cSRui Paulo struct hs20_osu_client ctx; 31705b9c547cSRui Paulo int c; 31715b9c547cSRui Paulo int ret = 0; 31725b9c547cSRui Paulo int no_prod_assoc = 0; 31735b9c547cSRui Paulo const char *friendly_name = NULL; 31745b9c547cSRui Paulo const char *wpa_debug_file_path = NULL; 31755b9c547cSRui Paulo extern char *wpas_ctrl_path; 31765b9c547cSRui Paulo extern int wpa_debug_level; 31775b9c547cSRui Paulo extern int wpa_debug_show_keys; 31785b9c547cSRui Paulo extern int wpa_debug_timestamp; 31795b9c547cSRui Paulo 31805b9c547cSRui Paulo if (init_ctx(&ctx) < 0) 31815b9c547cSRui Paulo return -1; 31825b9c547cSRui Paulo 31835b9c547cSRui Paulo for (;;) { 3184*85732ac8SCy Schubert c = getopt(argc, argv, "df:hKNo:O:qr:s:S:tw:x:"); 31855b9c547cSRui Paulo if (c < 0) 31865b9c547cSRui Paulo break; 31875b9c547cSRui Paulo switch (c) { 31885b9c547cSRui Paulo case 'd': 31895b9c547cSRui Paulo if (wpa_debug_level > 0) 31905b9c547cSRui Paulo wpa_debug_level--; 31915b9c547cSRui Paulo break; 31925b9c547cSRui Paulo case 'f': 31935b9c547cSRui Paulo wpa_debug_file_path = optarg; 31945b9c547cSRui Paulo break; 31955b9c547cSRui Paulo case 'K': 31965b9c547cSRui Paulo wpa_debug_show_keys++; 31975b9c547cSRui Paulo break; 31985b9c547cSRui Paulo case 'N': 31995b9c547cSRui Paulo no_prod_assoc = 1; 32005b9c547cSRui Paulo break; 3201*85732ac8SCy Schubert case 'o': 3202*85732ac8SCy Schubert ctx.osu_ssid = optarg; 3203*85732ac8SCy Schubert break; 32045b9c547cSRui Paulo case 'O': 32055b9c547cSRui Paulo friendly_name = optarg; 32065b9c547cSRui Paulo break; 32075b9c547cSRui Paulo case 'q': 32085b9c547cSRui Paulo wpa_debug_level++; 32095b9c547cSRui Paulo break; 32105b9c547cSRui Paulo case 'r': 32115b9c547cSRui Paulo ctx.result_file = optarg; 32125b9c547cSRui Paulo break; 32135b9c547cSRui Paulo case 's': 32145b9c547cSRui Paulo ctx.summary_file = optarg; 32155b9c547cSRui Paulo break; 32165b9c547cSRui Paulo case 'S': 32175b9c547cSRui Paulo ctx.ifname = optarg; 32185b9c547cSRui Paulo break; 32195b9c547cSRui Paulo case 't': 32205b9c547cSRui Paulo wpa_debug_timestamp++; 32215b9c547cSRui Paulo break; 32225b9c547cSRui Paulo case 'w': 32235b9c547cSRui Paulo wpas_ctrl_path = optarg; 32245b9c547cSRui Paulo break; 3225325151a3SRui Paulo case 'x': 3226325151a3SRui Paulo spp_xsd_fname = optarg; 3227325151a3SRui Paulo break; 32285b9c547cSRui Paulo case 'h': 32295b9c547cSRui Paulo default: 32305b9c547cSRui Paulo usage(); 32315b9c547cSRui Paulo exit(0); 32325b9c547cSRui Paulo break; 32335b9c547cSRui Paulo } 32345b9c547cSRui Paulo } 32355b9c547cSRui Paulo 32365b9c547cSRui Paulo if (argc - optind < 1) { 32375b9c547cSRui Paulo usage(); 32385b9c547cSRui Paulo exit(0); 32395b9c547cSRui Paulo } 32405b9c547cSRui Paulo 32415b9c547cSRui Paulo wpa_debug_open_file(wpa_debug_file_path); 32425b9c547cSRui Paulo 32435b9c547cSRui Paulo #ifdef __linux__ 32445b9c547cSRui Paulo setlinebuf(stdout); 32455b9c547cSRui Paulo #endif /* __linux__ */ 32465b9c547cSRui Paulo 32475b9c547cSRui Paulo if (ctx.result_file) 32485b9c547cSRui Paulo unlink(ctx.result_file); 32495b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "===[hs20-osu-client START - command: %s ]======" 32505b9c547cSRui Paulo "================", argv[optind]); 32515b9c547cSRui Paulo check_workarounds(&ctx); 32525b9c547cSRui Paulo 32535b9c547cSRui Paulo if (strcmp(argv[optind], "to_tnds") == 0) { 32545b9c547cSRui Paulo if (argc - optind < 2) { 32555b9c547cSRui Paulo usage(); 32565b9c547cSRui Paulo exit(0); 32575b9c547cSRui Paulo } 32585b9c547cSRui Paulo cmd_to_tnds(&ctx, argv[optind + 1], argv[optind + 2], 32595b9c547cSRui Paulo argc > optind + 3 ? argv[optind + 3] : NULL, 32605b9c547cSRui Paulo 0); 32615b9c547cSRui Paulo } else if (strcmp(argv[optind], "to_tnds2") == 0) { 32625b9c547cSRui Paulo if (argc - optind < 2) { 32635b9c547cSRui Paulo usage(); 32645b9c547cSRui Paulo exit(0); 32655b9c547cSRui Paulo } 32665b9c547cSRui Paulo cmd_to_tnds(&ctx, argv[optind + 1], argv[optind + 2], 32675b9c547cSRui Paulo argc > optind + 3 ? argv[optind + 3] : NULL, 32685b9c547cSRui Paulo 1); 32695b9c547cSRui Paulo } else if (strcmp(argv[optind], "from_tnds") == 0) { 32705b9c547cSRui Paulo if (argc - optind < 2) { 32715b9c547cSRui Paulo usage(); 32725b9c547cSRui Paulo exit(0); 32735b9c547cSRui Paulo } 32745b9c547cSRui Paulo cmd_from_tnds(&ctx, argv[optind + 1], argv[optind + 2]); 32755b9c547cSRui Paulo } else if (strcmp(argv[optind], "sub_rem") == 0) { 32765b9c547cSRui Paulo if (argc - optind < 2) { 32775b9c547cSRui Paulo usage(); 32785b9c547cSRui Paulo exit(0); 32795b9c547cSRui Paulo } 32805b9c547cSRui Paulo ret = cmd_sub_rem(&ctx, argv[optind + 1], 3281780fb4a2SCy Schubert argc > optind + 2 ? argv[optind + 2] : NULL, 3282780fb4a2SCy Schubert argc > optind + 3 ? argv[optind + 3] : NULL); 32835b9c547cSRui Paulo } else if (strcmp(argv[optind], "pol_upd") == 0) { 3284780fb4a2SCy Schubert ret = cmd_pol_upd(&ctx, 3285780fb4a2SCy Schubert argc > optind + 1 ? argv[optind + 1] : NULL, 32865b9c547cSRui Paulo argc > optind + 2 ? argv[optind + 2] : NULL, 32875b9c547cSRui Paulo argc > optind + 3 ? argv[optind + 3] : NULL); 32885b9c547cSRui Paulo } else if (strcmp(argv[optind], "prov") == 0) { 32895b9c547cSRui Paulo if (argc - optind < 2) { 32905b9c547cSRui Paulo usage(); 32915b9c547cSRui Paulo exit(0); 32925b9c547cSRui Paulo } 32935b9c547cSRui Paulo ctx.ca_fname = argv[optind + 2]; 3294325151a3SRui Paulo wpa_printf(MSG_DEBUG, "Calling cmd_prov from main"); 32955b9c547cSRui Paulo cmd_prov(&ctx, argv[optind + 1]); 32965b9c547cSRui Paulo } else if (strcmp(argv[optind], "sim_prov") == 0) { 32975b9c547cSRui Paulo if (argc - optind < 2) { 32985b9c547cSRui Paulo usage(); 32995b9c547cSRui Paulo exit(0); 33005b9c547cSRui Paulo } 33015b9c547cSRui Paulo ctx.ca_fname = argv[optind + 2]; 33025b9c547cSRui Paulo cmd_sim_prov(&ctx, argv[optind + 1]); 33035b9c547cSRui Paulo } else if (strcmp(argv[optind], "dl_osu_ca") == 0) { 33045b9c547cSRui Paulo if (argc - optind < 2) { 33055b9c547cSRui Paulo usage(); 33065b9c547cSRui Paulo exit(0); 33075b9c547cSRui Paulo } 33085b9c547cSRui Paulo cmd_dl_osu_ca(&ctx, argv[optind + 1], argv[optind + 2]); 33095b9c547cSRui Paulo } else if (strcmp(argv[optind], "dl_polupd_ca") == 0) { 33105b9c547cSRui Paulo if (argc - optind < 2) { 33115b9c547cSRui Paulo usage(); 33125b9c547cSRui Paulo exit(0); 33135b9c547cSRui Paulo } 33145b9c547cSRui Paulo cmd_dl_polupd_ca(&ctx, argv[optind + 1], argv[optind + 2]); 33155b9c547cSRui Paulo } else if (strcmp(argv[optind], "dl_aaa_ca") == 0) { 33165b9c547cSRui Paulo if (argc - optind < 2) { 33175b9c547cSRui Paulo usage(); 33185b9c547cSRui Paulo exit(0); 33195b9c547cSRui Paulo } 33205b9c547cSRui Paulo cmd_dl_aaa_ca(&ctx, argv[optind + 1], argv[optind + 2]); 33215b9c547cSRui Paulo } else if (strcmp(argv[optind], "osu_select") == 0) { 33225b9c547cSRui Paulo if (argc - optind < 2) { 33235b9c547cSRui Paulo usage(); 33245b9c547cSRui Paulo exit(0); 33255b9c547cSRui Paulo } 33265b9c547cSRui Paulo ctx.ca_fname = argc > optind + 2 ? argv[optind + 2] : NULL; 33275b9c547cSRui Paulo cmd_osu_select(&ctx, argv[optind + 1], 2, 1, NULL); 33285b9c547cSRui Paulo } else if (strcmp(argv[optind], "signup") == 0) { 33295b9c547cSRui Paulo ctx.ca_fname = argc > optind + 1 ? argv[optind + 1] : NULL; 33305b9c547cSRui Paulo ret = cmd_signup(&ctx, no_prod_assoc, friendly_name); 33315b9c547cSRui Paulo } else if (strcmp(argv[optind], "set_pps") == 0) { 33325b9c547cSRui Paulo if (argc - optind < 2) { 33335b9c547cSRui Paulo usage(); 33345b9c547cSRui Paulo exit(0); 33355b9c547cSRui Paulo } 33365b9c547cSRui Paulo cmd_set_pps(&ctx, argv[optind + 1]); 33375b9c547cSRui Paulo } else if (strcmp(argv[optind], "get_fqdn") == 0) { 33385b9c547cSRui Paulo if (argc - optind < 1) { 33395b9c547cSRui Paulo usage(); 33405b9c547cSRui Paulo exit(0); 33415b9c547cSRui Paulo } 33425b9c547cSRui Paulo ret = cmd_get_fqdn(&ctx, argv[optind + 1]); 33435b9c547cSRui Paulo } else if (strcmp(argv[optind], "oma_dm_prov") == 0) { 33445b9c547cSRui Paulo if (argc - optind < 2) { 33455b9c547cSRui Paulo usage(); 33465b9c547cSRui Paulo exit(0); 33475b9c547cSRui Paulo } 33485b9c547cSRui Paulo ctx.ca_fname = argv[optind + 2]; 33495b9c547cSRui Paulo cmd_oma_dm_prov(&ctx, argv[optind + 1]); 33505b9c547cSRui Paulo } else if (strcmp(argv[optind], "oma_dm_sim_prov") == 0) { 33515b9c547cSRui Paulo if (argc - optind < 2) { 33525b9c547cSRui Paulo usage(); 33535b9c547cSRui Paulo exit(0); 33545b9c547cSRui Paulo } 33555b9c547cSRui Paulo ctx.ca_fname = argv[optind + 2]; 33565b9c547cSRui Paulo if (cmd_oma_dm_sim_prov(&ctx, argv[optind + 1]) < 0) { 33575b9c547cSRui Paulo write_summary(&ctx, "Failed to complete OMA DM SIM provisioning"); 33585b9c547cSRui Paulo return -1; 33595b9c547cSRui Paulo } 33605b9c547cSRui Paulo } else if (strcmp(argv[optind], "oma_dm_add") == 0) { 33615b9c547cSRui Paulo if (argc - optind < 2) { 33625b9c547cSRui Paulo usage(); 33635b9c547cSRui Paulo exit(0); 33645b9c547cSRui Paulo } 33655b9c547cSRui Paulo cmd_oma_dm_add(&ctx, argv[optind + 1], argv[optind + 2]); 33665b9c547cSRui Paulo } else if (strcmp(argv[optind], "oma_dm_replace") == 0) { 33675b9c547cSRui Paulo if (argc - optind < 2) { 33685b9c547cSRui Paulo usage(); 33695b9c547cSRui Paulo exit(0); 33705b9c547cSRui Paulo } 33715b9c547cSRui Paulo cmd_oma_dm_replace(&ctx, argv[optind + 1], argv[optind + 2]); 33725b9c547cSRui Paulo } else if (strcmp(argv[optind], "est_csr") == 0) { 33735b9c547cSRui Paulo if (argc - optind < 2) { 33745b9c547cSRui Paulo usage(); 33755b9c547cSRui Paulo exit(0); 33765b9c547cSRui Paulo } 33775b9c547cSRui Paulo mkdir("Cert", S_IRWXU); 33785b9c547cSRui Paulo est_build_csr(&ctx, argv[optind + 1]); 33795b9c547cSRui Paulo } else if (strcmp(argv[optind], "browser") == 0) { 33805b9c547cSRui Paulo int ret; 33815b9c547cSRui Paulo 33825b9c547cSRui Paulo if (argc - optind < 2) { 33835b9c547cSRui Paulo usage(); 33845b9c547cSRui Paulo exit(0); 33855b9c547cSRui Paulo } 33865b9c547cSRui Paulo 33875b9c547cSRui Paulo wpa_printf(MSG_INFO, "Launch web browser to URL %s", 33885b9c547cSRui Paulo argv[optind + 1]); 33895b9c547cSRui Paulo ret = hs20_web_browser(argv[optind + 1]); 33905b9c547cSRui Paulo wpa_printf(MSG_INFO, "Web browser result: %d", ret); 33915b9c547cSRui Paulo } else if (strcmp(argv[optind], "parse_cert") == 0) { 33925b9c547cSRui Paulo if (argc - optind < 2) { 33935b9c547cSRui Paulo usage(); 33945b9c547cSRui Paulo exit(0); 33955b9c547cSRui Paulo } 33965b9c547cSRui Paulo 33975b9c547cSRui Paulo wpa_debug_level = MSG_MSGDUMP; 33985b9c547cSRui Paulo http_parse_x509_certificate(ctx.http, argv[optind + 1]); 33995b9c547cSRui Paulo wpa_debug_level = MSG_INFO; 34005b9c547cSRui Paulo } else { 34015b9c547cSRui Paulo wpa_printf(MSG_INFO, "Unknown command '%s'", argv[optind]); 34025b9c547cSRui Paulo } 34035b9c547cSRui Paulo 34045b9c547cSRui Paulo deinit_ctx(&ctx); 34055b9c547cSRui Paulo wpa_printf(MSG_DEBUG, 34065b9c547cSRui Paulo "===[hs20-osu-client END ]======================"); 34075b9c547cSRui Paulo 34085b9c547cSRui Paulo wpa_debug_close_file(); 34095b9c547cSRui Paulo 34105b9c547cSRui Paulo return ret; 34115b9c547cSRui Paulo } 3412