]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
HS 2.0 client: Remove OSU/SPP/OMA-DM/EST functionality
authorJouni Malinen <quic_jouni@quicinc.com>
Sat, 22 Feb 2025 18:23:42 +0000 (20:23 +0200)
committerJouni Malinen <j@w1.fi>
Sat, 22 Feb 2025 20:10:46 +0000 (22:10 +0200)
Passpoint spec v3.4 removed all OSU functionality. In practice, this
means that there is not going to any deployment or use of the OSU
technology in the future and as such, there is no need to maintain this
OSU client implementation.

Signed-off-by: Jouni Malinen <quic_jouni@quicinc.com>
hs20/client/Android.mk
hs20/client/Makefile
hs20/client/devdetail.xml [deleted file]
hs20/client/devinfo.xml [deleted file]
hs20/client/est.c [deleted file]
hs20/client/oma_dm_client.c [deleted file]
hs20/client/osu_client.c
hs20/client/osu_client.h
hs20/client/spp_client.c [deleted file]

index 8d208b25901b0d8ffdcc35a160218212687094e1..1e1082be2e984380f23ecbae8f8341dcd1db3b68 100644 (file)
@@ -30,10 +30,7 @@ L_CFLAGS += -DCONFIG_CTRL_IFACE
 L_CFLAGS += -DCONFIG_CTRL_IFACE_UNIX
 L_CFLAGS += -DCONFIG_CTRL_IFACE_CLIENT_DIR=\"/data/misc/wifi/sockets\"
 
-OBJS = spp_client.c
-OBJS += oma_dm_client.c
-OBJS += osu_client.c
-OBJS += est.c
+OBJS = osu_client.c
 OBJS += ../../src/common/wpa_ctrl.c
 OBJS += ../../src/common/wpa_helpers.c
 OBJS += ../../src/utils/xml-utils.c
index 4dcfe2d3bf2c406360dd705a18d200f60f8fb639..9e65dc63e8d5c4bbe5c705021dfd328675e6fa53 100644 (file)
@@ -24,10 +24,7 @@ LIBS += $(GTKLIBS)
 endif
 endif
 
-OBJS=spp_client.o
-OBJS += oma_dm_client.o
-OBJS += osu_client.o
-OBJS += est.o
+OBJS = osu_client.o
 OBJS += ../../src/utils/xml-utils.o
 CFLAGS += -DCONFIG_CTRL_IFACE
 CFLAGS += -DCONFIG_CTRL_IFACE_UNIX
diff --git a/hs20/client/devdetail.xml b/hs20/client/devdetail.xml
deleted file mode 100644 (file)
index 6d0389e..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-<DevDetail xmlns="urn:oma:mo:oma-dm-devdetail:1.0">
-       <Ext>
-               <org.wi-fi>
-                       <Wi-Fi>
-                               <EAPMethodList>
-                                       <EAPMethod1>
-                                               <EAPType>13</EAPType>
-                                       </EAPMethod1>
-                                       <EAPMethod2>
-                                               <EAPType>21</EAPType>
-                                               <InnerMethod>MS-CHAP-V2</InnerMethod>
-                                       </EAPMethod2>
-                                       <EAPMethod3>
-                                               <EAPType>18</EAPType>
-                                       </EAPMethod3>
-                                       <EAPMethod4>
-                                               <EAPType>23</EAPType>
-                                       </EAPMethod4>
-                                       <EAPMethod5>
-                                               <EAPType>50</EAPType>
-                                       </EAPMethod5>
-                               </EAPMethodList>
-                               <ManufacturingCertificate>false</ManufacturingCertificate>
-                               <Wi-FiMACAddress>020102030405</Wi-FiMACAddress>
-                               <IMSI>310026000000000</IMSI>
-                               <IMEI_MEID>imei:490123456789012</IMEI_MEID>
-                               <ClientTriggerRedirectURI>http://localhost:12345/</ClientTriggerRedirectURI>
-                               <Ops>
-                                       <launchBrowserToURI></launchBrowserToURI>
-                                       <negotiateClientCertTLS></negotiateClientCertTLS>
-                                       <getCertificate></getCertificate>
-                               </Ops>
-                       </Wi-Fi>
-               </org.wi-fi>
-       </Ext>
-       <URI>
-               <MaxDepth>0</MaxDepth>
-               <MaxTotLen>0</MaxTotLen>
-               <MaxSegLen>0</MaxSegLen>
-       </URI>
-       <DevType>MobilePhone</DevType>
-       <OEM>Manufacturer</OEM>
-       <FwV>1.0</FwV>
-       <SwV>1.0</SwV>
-       <HwV>1.0</HwV>
-       <LrgObj>false</LrgObj>
-</DevDetail>
diff --git a/hs20/client/devinfo.xml b/hs20/client/devinfo.xml
deleted file mode 100644 (file)
index d48a520..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-<DevInfo xmlns="urn:oma:mo:oma-dm-devinfo:1.0">
-       <DevId>urn:Example:HS20-station:123456</DevId>
-       <Man>Manufacturer</Man>
-       <Mod>HS20-station</Mod>
-       <DmV>1.2</DmV>
-       <Lang>en</Lang>
-</DevInfo>
diff --git a/hs20/client/est.c b/hs20/client/est.c
deleted file mode 100644 (file)
index 425b72d..0000000
+++ /dev/null
@@ -1,742 +0,0 @@
-/*
- * Hotspot 2.0 OSU client - EST client
- * Copyright (c) 2012-2014, Qualcomm Atheros, Inc.
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#include "includes.h"
-#include <openssl/err.h>
-#include <openssl/evp.h>
-#include <openssl/pem.h>
-#include <openssl/pkcs7.h>
-#include <openssl/asn1.h>
-#include <openssl/asn1t.h>
-#include <openssl/x509.h>
-#include <openssl/x509v3.h>
-#include <openssl/opensslv.h>
-#include <openssl/buffer.h>
-
-#include "common.h"
-#include "utils/base64.h"
-#include "utils/xml-utils.h"
-#include "utils/http-utils.h"
-#include "osu_client.h"
-
-
-static int pkcs7_to_cert(struct hs20_osu_client *ctx, const u8 *pkcs7,
-                        size_t len, char *pem_file, char *der_file)
-{
-#ifdef OPENSSL_IS_BORINGSSL
-       CBS pkcs7_cbs;
-#else /* OPENSSL_IS_BORINGSSL */
-       PKCS7 *p7 = NULL;
-       const unsigned char *p = pkcs7;
-#endif /* OPENSSL_IS_BORINGSSL */
-       STACK_OF(X509) *certs;
-       int i, num, ret = -1;
-       BIO *out = NULL;
-
-#ifdef OPENSSL_IS_BORINGSSL
-       certs = sk_X509_new_null();
-       if (!certs)
-               goto fail;
-       CBS_init(&pkcs7_cbs, pkcs7, len);
-       if (!PKCS7_get_certificates(certs, &pkcs7_cbs)) {
-               wpa_printf(MSG_INFO, "Could not parse PKCS#7 object: %s",
-                          ERR_error_string(ERR_get_error(), NULL));
-               write_result(ctx, "Could not parse PKCS#7 object from EST");
-               goto fail;
-       }
-#else /* OPENSSL_IS_BORINGSSL */
-       p7 = d2i_PKCS7(NULL, &p, len);
-       if (p7 == NULL) {
-               wpa_printf(MSG_INFO, "Could not parse PKCS#7 object: %s",
-                          ERR_error_string(ERR_get_error(), NULL));
-               write_result(ctx, "Could not parse PKCS#7 object from EST");
-               goto fail;
-       }
-
-       switch (OBJ_obj2nid(p7->type)) {
-       case NID_pkcs7_signed:
-               certs = p7->d.sign->cert;
-               break;
-       case NID_pkcs7_signedAndEnveloped:
-               certs = p7->d.signed_and_enveloped->cert;
-               break;
-       default:
-               certs = NULL;
-               break;
-       }
-#endif /* OPENSSL_IS_BORINGSSL */
-
-       if (!certs || ((num = sk_X509_num(certs)) == 0)) {
-               wpa_printf(MSG_INFO, "No certificates found in PKCS#7 object");
-               write_result(ctx, "No certificates found in PKCS#7 object");
-               goto fail;
-       }
-
-       if (der_file) {
-               FILE *f = fopen(der_file, "wb");
-               if (f == NULL)
-                       goto fail;
-               i2d_X509_fp(f, sk_X509_value(certs, 0));
-               fclose(f);
-       }
-
-       if (pem_file) {
-               out = BIO_new(BIO_s_file());
-               if (out == NULL ||
-                   BIO_write_filename(out, pem_file) <= 0)
-                       goto fail;
-
-               for (i = 0; i < num; i++) {
-                       X509 *cert = sk_X509_value(certs, i);
-                       X509_print(out, cert);
-                       PEM_write_bio_X509(out, cert);
-                       BIO_puts(out, "\n");
-               }
-       }
-
-       ret = 0;
-
-fail:
-#ifdef OPENSSL_IS_BORINGSSL
-       if (certs)
-               sk_X509_pop_free(certs, X509_free);
-#else /* OPENSSL_IS_BORINGSSL */
-       PKCS7_free(p7);
-#endif /* OPENSSL_IS_BORINGSSL */
-       if (out)
-               BIO_free_all(out);
-
-       return ret;
-}
-
-
-int est_load_cacerts(struct hs20_osu_client *ctx, const char *url)
-{
-       char *buf, *resp;
-       size_t buflen;
-       unsigned char *pkcs7;
-       size_t pkcs7_len, resp_len;
-       int res;
-
-       buflen = os_strlen(url) + 100;
-       buf = os_malloc(buflen);
-       if (buf == NULL)
-               return -1;
-
-       os_snprintf(buf, buflen, "%s/cacerts", url);
-       wpa_printf(MSG_INFO, "Download EST cacerts from %s", buf);
-       write_summary(ctx, "Download EST cacerts from %s", buf);
-       ctx->no_osu_cert_validation = 1;
-       http_ocsp_set(ctx->http, 1);
-       res = http_download_file(ctx->http, buf, "Cert/est-cacerts.txt",
-                                ctx->ca_fname);
-       http_ocsp_set(ctx->http,
-                     (ctx->workarounds & WORKAROUND_OCSP_OPTIONAL) ? 1 : 2);
-       ctx->no_osu_cert_validation = 0;
-       if (res < 0) {
-               wpa_printf(MSG_INFO, "Failed to download EST cacerts from %s",
-                          buf);
-               write_result(ctx, "Failed to download EST cacerts from %s",
-                            buf);
-               os_free(buf);
-               return -1;
-       }
-       os_free(buf);
-
-       resp = os_readfile("Cert/est-cacerts.txt", &resp_len);
-       if (resp == NULL) {
-               wpa_printf(MSG_INFO, "Could not read Cert/est-cacerts.txt");
-               write_result(ctx, "Could not read EST cacerts");
-               return -1;
-       }
-
-       pkcs7 = base64_decode(resp, resp_len, &pkcs7_len);
-       if (pkcs7 && pkcs7_len < resp_len / 2) {
-               wpa_printf(MSG_INFO, "Too short base64 decode (%u bytes; downloaded %u bytes) - assume this was binary",
-                          (unsigned int) pkcs7_len, (unsigned int) resp_len);
-               os_free(pkcs7);
-               pkcs7 = NULL;
-       }
-       if (pkcs7 == NULL) {
-               wpa_printf(MSG_INFO, "EST workaround - Could not decode base64, assume this is DER encoded PKCS7");
-               pkcs7 = os_malloc(resp_len);
-               if (pkcs7) {
-                       os_memcpy(pkcs7, resp, resp_len);
-                       pkcs7_len = resp_len;
-               }
-       }
-       os_free(resp);
-
-       if (pkcs7 == NULL) {
-               wpa_printf(MSG_INFO, "Could not fetch PKCS7 cacerts");
-               write_result(ctx, "Could not fetch EST PKCS#7 cacerts");
-               return -1;
-       }
-
-       res = pkcs7_to_cert(ctx, pkcs7, pkcs7_len, "Cert/est-cacerts.pem",
-                           NULL);
-       os_free(pkcs7);
-       if (res < 0) {
-               wpa_printf(MSG_INFO, "Could not parse CA certs from PKCS#7 cacerts response");
-               write_result(ctx, "Could not parse CA certs from EST PKCS#7 cacerts response");
-               return -1;
-       }
-       unlink("Cert/est-cacerts.txt");
-
-       return 0;
-}
-
-
-/*
- * CsrAttrs ::= SEQUENCE SIZE (0..MAX) OF AttrOrOID
- *
- * AttrOrOID ::= CHOICE {
- *   oid OBJECT IDENTIFIER,
- *   attribute Attribute }
- *
- * Attribute ::= SEQUENCE {
- *   type OBJECT IDENTIFIER,
- *   values SET SIZE(1..MAX) OF OBJECT IDENTIFIER }
- */
-
-typedef struct {
-       ASN1_OBJECT *type;
-       STACK_OF(ASN1_OBJECT) *values;
-} Attribute;
-
-typedef struct {
-       int type;
-       union {
-               ASN1_OBJECT *oid;
-               Attribute *attribute;
-       } d;
-} AttrOrOID;
-
-#if OPENSSL_VERSION_NUMBER >= 0x10100000L
-DEFINE_STACK_OF(AttrOrOID)
-#endif
-
-typedef struct {
-       int type;
-       STACK_OF(AttrOrOID) *attrs;
-} CsrAttrs;
-
-ASN1_SEQUENCE(Attribute) = {
-       ASN1_SIMPLE(Attribute, type, ASN1_OBJECT),
-       ASN1_SET_OF(Attribute, values, ASN1_OBJECT)
-} ASN1_SEQUENCE_END(Attribute);
-
-ASN1_CHOICE(AttrOrOID) = {
-       ASN1_SIMPLE(AttrOrOID, d.oid, ASN1_OBJECT),
-       ASN1_SIMPLE(AttrOrOID, d.attribute, Attribute)
-} ASN1_CHOICE_END(AttrOrOID);
-
-ASN1_CHOICE(CsrAttrs) = {
-       ASN1_SEQUENCE_OF(CsrAttrs, attrs, AttrOrOID)
-} ASN1_CHOICE_END(CsrAttrs);
-
-IMPLEMENT_ASN1_FUNCTIONS(CsrAttrs);
-
-
-static void add_csrattrs_oid(struct hs20_osu_client *ctx, ASN1_OBJECT *oid,
-                            STACK_OF(X509_EXTENSION) *exts)
-{
-       char txt[100];
-       int res;
-
-       if (!oid)
-               return;
-
-       res = OBJ_obj2txt(txt, sizeof(txt), oid, 1);
-       if (res < 0 || res >= (int) sizeof(txt))
-               return;
-
-       if (os_strcmp(txt, "1.2.840.113549.1.9.7") == 0) {
-               wpa_printf(MSG_INFO, "TODO: csrattr challengePassword");
-       } else if (os_strcmp(txt, "1.2.840.113549.1.1.11") == 0) {
-               wpa_printf(MSG_INFO, "csrattr sha256WithRSAEncryption");
-       } else {
-               wpa_printf(MSG_INFO, "Ignore unsupported csrattr oid %s", txt);
-       }
-}
-
-
-static void add_csrattrs_ext_req(struct hs20_osu_client *ctx,
-                                STACK_OF(ASN1_OBJECT) *values,
-                                STACK_OF(X509_EXTENSION) *exts)
-{
-       char txt[100];
-       int i, num, res;
-
-       num = sk_ASN1_OBJECT_num(values);
-       for (i = 0; i < num; i++) {
-               ASN1_OBJECT *oid = sk_ASN1_OBJECT_value(values, i);
-
-               res = OBJ_obj2txt(txt, sizeof(txt), oid, 1);
-               if (res < 0 || res >= (int) sizeof(txt))
-                       continue;
-
-               if (os_strcmp(txt, "1.3.6.1.1.1.1.22") == 0) {
-                       wpa_printf(MSG_INFO, "TODO: extReq macAddress");
-               } else if (os_strcmp(txt, "1.3.6.1.4.1.40808.1.1.3") == 0) {
-                       wpa_printf(MSG_INFO, "TODO: extReq imei");
-               } else if (os_strcmp(txt, "1.3.6.1.4.1.40808.1.1.4") == 0) {
-                       wpa_printf(MSG_INFO, "TODO: extReq meid");
-               } else if (os_strcmp(txt, "1.3.6.1.4.1.40808.1.1.5") == 0) {
-                       wpa_printf(MSG_INFO, "TODO: extReq DevId");
-               } else {
-                       wpa_printf(MSG_INFO, "Ignore unsupported cstattr extensionsRequest %s",
-                                  txt);
-               }
-       }
-}
-
-
-static void add_csrattrs_attr(struct hs20_osu_client *ctx, Attribute *attr,
-                             STACK_OF(X509_EXTENSION) *exts)
-{
-       char txt[100], txt2[100];
-       int i, num, res;
-
-       if (!attr || !attr->type || !attr->values)
-               return;
-
-       res = OBJ_obj2txt(txt, sizeof(txt), attr->type, 1);
-       if (res < 0 || res >= (int) sizeof(txt))
-               return;
-
-       if (os_strcmp(txt, "1.2.840.113549.1.9.14") == 0) {
-               add_csrattrs_ext_req(ctx, attr->values, exts);
-               return;
-       }
-
-       num = sk_ASN1_OBJECT_num(attr->values);
-       for (i = 0; i < num; i++) {
-               ASN1_OBJECT *oid = sk_ASN1_OBJECT_value(attr->values, i);
-
-               res = OBJ_obj2txt(txt2, sizeof(txt2), oid, 1);
-               if (res < 0 || res >= (int) sizeof(txt2))
-                       continue;
-
-               wpa_printf(MSG_INFO, "Ignore unsupported cstattr::attr %s oid %s",
-                          txt, txt2);
-       }
-}
-
-
-static void add_csrattrs(struct hs20_osu_client *ctx, CsrAttrs *csrattrs,
-                        STACK_OF(X509_EXTENSION) *exts)
-{
-       int i, num;
-
-       if (!csrattrs || ! csrattrs->attrs)
-               return;
-
-#if OPENSSL_VERSION_NUMBER >= 0x10100000L
-       num = sk_AttrOrOID_num(csrattrs->attrs);
-#else
-       num = SKM_sk_num(AttrOrOID, csrattrs->attrs);
-#endif
-       for (i = 0; i < num; i++) {
-#if OPENSSL_VERSION_NUMBER >= 0x10100000L
-               AttrOrOID *ao = sk_AttrOrOID_value(csrattrs->attrs, i);
-#else
-               AttrOrOID *ao = SKM_sk_value(AttrOrOID, csrattrs->attrs, i);
-#endif
-               switch (ao->type) {
-               case 0:
-                       add_csrattrs_oid(ctx, ao->d.oid, exts);
-                       break;
-               case 1:
-                       add_csrattrs_attr(ctx, ao->d.attribute, exts);
-                       break;
-               }
-       }
-}
-
-
-static int generate_csr(struct hs20_osu_client *ctx, char *key_pem,
-                       char *csr_pem, char *est_req, char *old_cert,
-                       CsrAttrs *csrattrs)
-{
-       EVP_PKEY_CTX *pctx = NULL;
-       EVP_PKEY *pkey = NULL;
-       X509_REQ *req = NULL;
-       int ret = -1;
-       unsigned int val;
-       X509_NAME *subj = NULL;
-       char name[100];
-       STACK_OF(X509_EXTENSION) *exts = NULL;
-       X509_EXTENSION *ex;
-       BIO *out;
-       CONF *ctmp = NULL;
-
-       wpa_printf(MSG_INFO, "Generate RSA private key");
-       write_summary(ctx, "Generate RSA private key");
-       pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL);
-       if (!pctx)
-               return -1;
-
-       if (EVP_PKEY_keygen_init(pctx) <= 0)
-               goto fail;
-
-       if (EVP_PKEY_CTX_set_rsa_keygen_bits(pctx, 2048) <= 0)
-               goto fail;
-
-       if (EVP_PKEY_keygen(pctx, &pkey) <= 0)
-               goto fail;
-       EVP_PKEY_CTX_free(pctx);
-       pctx = NULL;
-
-       if (key_pem) {
-               FILE *f = fopen(key_pem, "wb");
-               if (f == NULL)
-                       goto fail;
-               if (!PEM_write_PrivateKey(f, pkey, NULL, NULL, 0, NULL, NULL)) {
-                       wpa_printf(MSG_INFO, "Could not write private key: %s",
-                                  ERR_error_string(ERR_get_error(), NULL));
-                       fclose(f);
-                       goto fail;
-               }
-               fclose(f);
-       }
-
-       wpa_printf(MSG_INFO, "Generate CSR");
-       write_summary(ctx, "Generate CSR");
-       req = X509_REQ_new();
-       if (req == NULL)
-               goto fail;
-
-       if (old_cert) {
-               FILE *f;
-               X509 *cert;
-               int res;
-
-               f = fopen(old_cert, "r");
-               if (f == NULL)
-                       goto fail;
-               cert = PEM_read_X509(f, NULL, NULL, NULL);
-               fclose(f);
-
-               if (cert == NULL)
-                       goto fail;
-               res = X509_REQ_set_subject_name(req,
-                                               X509_get_subject_name(cert));
-               X509_free(cert);
-               if (!res)
-                       goto fail;
-       } else {
-               os_get_random((u8 *) &val, sizeof(val));
-               os_snprintf(name, sizeof(name), "cert-user-%u", val);
-               subj = X509_NAME_new();
-               if (subj == NULL ||
-                   !X509_NAME_add_entry_by_txt(subj, "CN", MBSTRING_ASC,
-                                               (unsigned char *) name,
-                                               -1, -1, 0) ||
-                   !X509_REQ_set_subject_name(req, subj))
-                       goto fail;
-               X509_NAME_free(subj);
-               subj = NULL;
-       }
-
-       if (!X509_REQ_set_pubkey(req, pkey))
-               goto fail;
-
-       exts = sk_X509_EXTENSION_new_null();
-       if (!exts)
-               goto fail;
-
-       ex = X509V3_EXT_nconf_nid(ctmp, NULL, NID_basic_constraints,
-                                 "CA:FALSE");
-       if (ex == NULL ||
-           !sk_X509_EXTENSION_push(exts, ex))
-               goto fail;
-
-       ex = X509V3_EXT_nconf_nid(ctmp, NULL, NID_key_usage,
-                                 "nonRepudiation,digitalSignature,keyEncipherment");
-       if (ex == NULL ||
-           !sk_X509_EXTENSION_push(exts, ex))
-               goto fail;
-
-       ex = X509V3_EXT_nconf_nid(ctmp, NULL, NID_ext_key_usage,
-                                 "1.3.6.1.4.1.40808.1.1.2");
-       if (ex == NULL ||
-           !sk_X509_EXTENSION_push(exts, ex))
-               goto fail;
-
-       add_csrattrs(ctx, csrattrs, exts);
-
-       if (!X509_REQ_add_extensions(req, exts))
-               goto fail;
-       sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free);
-       exts = NULL;
-
-       if (!X509_REQ_sign(req, pkey, EVP_sha256()))
-               goto fail;
-
-       out = BIO_new(BIO_s_mem());
-       if (out) {
-               char *txt;
-               size_t rlen;
-
-#if !defined(ANDROID) || !defined(OPENSSL_IS_BORINGSSL)
-               X509_REQ_print(out, req);
-#endif
-               rlen = BIO_ctrl_pending(out);
-               txt = os_malloc(rlen + 1);
-               if (txt) {
-                       int res = BIO_read(out, txt, rlen);
-                       if (res > 0) {
-                               txt[res] = '\0';
-                               wpa_printf(MSG_MSGDUMP, "OpenSSL: Certificate request:\n%s",
-                                          txt);
-                       }
-                       os_free(txt);
-               }
-               BIO_free(out);
-       }
-
-       if (csr_pem) {
-               FILE *f = fopen(csr_pem, "w");
-               if (f == NULL)
-                       goto fail;
-#if !defined(ANDROID) || !defined(OPENSSL_IS_BORINGSSL)
-               X509_REQ_print_fp(f, req);
-#endif
-               if (!PEM_write_X509_REQ(f, req)) {
-                       fclose(f);
-                       goto fail;
-               }
-               fclose(f);
-       }
-
-       if (est_req) {
-               BIO *mem = BIO_new(BIO_s_mem());
-               BUF_MEM *ptr;
-               char *pos, *end, *buf_end;
-               FILE *f;
-
-               if (mem == NULL)
-                       goto fail;
-               if (!PEM_write_bio_X509_REQ(mem, req)) {
-                       BIO_free(mem);
-                       goto fail;
-               }
-
-               BIO_get_mem_ptr(mem, &ptr);
-               pos = ptr->data;
-               buf_end = pos + ptr->length;
-
-               /* Remove START/END lines */
-               while (pos < buf_end && *pos != '\n')
-                       pos++;
-               if (pos == buf_end) {
-                       BIO_free(mem);
-                       goto fail;
-               }
-               pos++;
-
-               end = pos;
-               while (end < buf_end && *end != '-')
-                       end++;
-
-               f = fopen(est_req, "w");
-               if (f == NULL) {
-                       BIO_free(mem);
-                       goto fail;
-               }
-               fwrite(pos, end - pos, 1, f);
-               fclose(f);
-
-               BIO_free(mem);
-       }
-
-       ret = 0;
-fail:
-       if (exts)
-               sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free);
-       if (subj)
-               X509_NAME_free(subj);
-       if (req)
-               X509_REQ_free(req);
-       if (pkey)
-               EVP_PKEY_free(pkey);
-       if (pctx)
-               EVP_PKEY_CTX_free(pctx);
-       return ret;
-}
-
-
-int est_build_csr(struct hs20_osu_client *ctx, const char *url)
-{
-       char *buf;
-       size_t buflen;
-       int res;
-       char old_cert_buf[200];
-       char *old_cert = NULL;
-       CsrAttrs *csrattrs = NULL;
-
-       buflen = os_strlen(url) + 100;
-       buf = os_malloc(buflen);
-       if (buf == NULL)
-               return -1;
-
-       os_snprintf(buf, buflen, "%s/csrattrs", url);
-       wpa_printf(MSG_INFO, "Download csrattrs from %s", buf);
-       write_summary(ctx, "Download EST csrattrs from %s", buf);
-       ctx->no_osu_cert_validation = 1;
-       http_ocsp_set(ctx->http, 1);
-       res = http_download_file(ctx->http, buf, "Cert/est-csrattrs.txt",
-                                ctx->ca_fname);
-       http_ocsp_set(ctx->http,
-                     (ctx->workarounds & WORKAROUND_OCSP_OPTIONAL) ? 1 : 2);
-       ctx->no_osu_cert_validation = 0;
-       os_free(buf);
-       if (res < 0) {
-               wpa_printf(MSG_INFO, "Failed to download EST csrattrs - assume no extra attributes are needed");
-       } else {
-               size_t resp_len;
-               char *resp;
-               unsigned char *attrs;
-               const unsigned char *pos;
-               size_t attrs_len;
-
-               resp = os_readfile("Cert/est-csrattrs.txt", &resp_len);
-               if (resp == NULL) {
-                       wpa_printf(MSG_INFO, "Could not read csrattrs");
-                       return -1;
-               }
-
-               attrs = base64_decode(resp, resp_len, &attrs_len);
-               os_free(resp);
-
-               if (attrs == NULL) {
-                       wpa_printf(MSG_INFO, "Could not base64 decode csrattrs");
-                       return -1;
-               }
-               unlink("Cert/est-csrattrs.txt");
-
-               pos = attrs;
-               csrattrs = d2i_CsrAttrs(NULL, &pos, attrs_len);
-               os_free(attrs);
-               if (csrattrs == NULL) {
-                       wpa_printf(MSG_INFO, "Failed to parse csrattrs ASN.1");
-                       /* Continue assuming no additional requirements */
-               }
-       }
-
-       if (ctx->client_cert_present) {
-               os_snprintf(old_cert_buf, sizeof(old_cert_buf),
-                           "SP/%s/client-cert.pem", ctx->fqdn);
-               old_cert = old_cert_buf;
-       }
-
-       res = generate_csr(ctx, "Cert/privkey-plain.pem", "Cert/est-req.pem",
-                          "Cert/est-req.b64", old_cert, csrattrs);
-       if (csrattrs)
-               CsrAttrs_free(csrattrs);
-
-       return res;
-}
-
-
-int est_simple_enroll(struct hs20_osu_client *ctx, const char *url,
-                     const char *user, const char *pw)
-{
-       char *buf, *resp, *req, *req2;
-       size_t buflen, resp_len, len, pkcs7_len;
-       unsigned char *pkcs7;
-       char client_cert_buf[200];
-       char client_key_buf[200];
-       const char *client_cert = NULL, *client_key = NULL;
-       int res;
-
-       req = os_readfile("Cert/est-req.b64", &len);
-       if (req == NULL) {
-               wpa_printf(MSG_INFO, "Could not read Cert/req.b64");
-               return -1;
-       }
-       req2 = os_realloc(req, len + 1);
-       if (req2 == NULL) {
-               os_free(req);
-               return -1;
-       }
-       req2[len] = '\0';
-       req = req2;
-       wpa_printf(MSG_DEBUG, "EST simpleenroll request: %s", req);
-
-       buflen = os_strlen(url) + 100;
-       buf = os_malloc(buflen);
-       if (buf == NULL) {
-               os_free(req);
-               return -1;
-       }
-
-       if (ctx->client_cert_present) {
-               os_snprintf(buf, buflen, "%s/simplereenroll", url);
-               os_snprintf(client_cert_buf, sizeof(client_cert_buf),
-                           "SP/%s/client-cert.pem", ctx->fqdn);
-               client_cert = client_cert_buf;
-               os_snprintf(client_key_buf, sizeof(client_key_buf),
-                           "SP/%s/client-key.pem", ctx->fqdn);
-               client_key = client_key_buf;
-       } else
-               os_snprintf(buf, buflen, "%s/simpleenroll", url);
-       wpa_printf(MSG_INFO, "EST simpleenroll URL: %s", buf);
-       write_summary(ctx, "EST simpleenroll URL: %s", buf);
-       ctx->no_osu_cert_validation = 1;
-       http_ocsp_set(ctx->http, 1);
-       resp = http_post(ctx->http, buf, req, "application/pkcs10",
-                        "Content-Transfer-Encoding: base64",
-                        ctx->ca_fname, user, pw, client_cert, client_key,
-                        &resp_len);
-       http_ocsp_set(ctx->http,
-                     (ctx->workarounds & WORKAROUND_OCSP_OPTIONAL) ? 1 : 2);
-       ctx->no_osu_cert_validation = 0;
-       os_free(buf);
-       if (resp == NULL) {
-               wpa_printf(MSG_INFO, "EST certificate enrollment failed");
-               write_result(ctx, "EST certificate enrollment failed");
-               return -1;
-       }
-       wpa_printf(MSG_DEBUG, "EST simpleenroll response: %s", resp);
-
-       pkcs7 = base64_decode(resp, resp_len, &pkcs7_len);
-       if (pkcs7 == NULL) {
-               wpa_printf(MSG_INFO, "EST workaround - Could not decode base64, assume this is DER encoded PKCS7");
-               pkcs7 = os_malloc(resp_len);
-               if (pkcs7) {
-                       os_memcpy(pkcs7, resp, resp_len);
-                       pkcs7_len = resp_len;
-               }
-       }
-       os_free(resp);
-
-       if (pkcs7 == NULL) {
-               wpa_printf(MSG_INFO, "Failed to parse simpleenroll base64 response");
-               write_result(ctx, "Failed to parse EST simpleenroll base64 response");
-               return -1;
-       }
-
-       res = pkcs7_to_cert(ctx, pkcs7, pkcs7_len, "Cert/est_cert.pem",
-                           "Cert/est_cert.der");
-       os_free(pkcs7);
-
-       if (res < 0) {
-               wpa_printf(MSG_INFO, "EST: Failed to extract certificate from PKCS7 file");
-               write_result(ctx, "EST: Failed to extract certificate from EST PKCS7 file");
-               return -1;
-       }
-
-       wpa_printf(MSG_INFO, "EST simple%senroll completed successfully",
-                  ctx->client_cert_present ? "re" : "");
-       write_summary(ctx, "EST simple%senroll completed successfully",
-                     ctx->client_cert_present ? "re" : "");
-
-       return 0;
-}
diff --git a/hs20/client/oma_dm_client.c b/hs20/client/oma_dm_client.c
deleted file mode 100644 (file)
index bcd68b8..0000000
+++ /dev/null
@@ -1,1398 +0,0 @@
-/*
- * Hotspot 2.0 - OMA DM client
- * Copyright (c) 2013-2014, Qualcomm Atheros, Inc.
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "wpa_helpers.h"
-#include "xml-utils.h"
-#include "http-utils.h"
-#include "utils/browser.h"
-#include "osu_client.h"
-
-
-#define DM_SERVER_INITIATED_MGMT 1200
-#define DM_CLIENT_INITIATED_MGMT 1201
-#define DM_GENERIC_ALERT 1226
-
-/* OMA-TS-SyncML-RepPro-V1_2_2 - 10. Response Status Codes */
-#define DM_RESP_OK 200
-#define DM_RESP_AUTH_ACCEPTED 212
-#define DM_RESP_CHUNKED_ITEM_ACCEPTED 213
-#define DM_RESP_NOT_EXECUTED 215
-#define DM_RESP_ATOMIC_ROLL_BACK_OK 216
-#define DM_RESP_NOT_MODIFIED 304
-#define DM_RESP_BAD_REQUEST 400
-#define DM_RESP_UNAUTHORIZED 401
-#define DM_RESP_FORBIDDEN 403
-#define DM_RESP_NOT_FOUND 404
-#define DM_RESP_COMMAND_NOT_ALLOWED 405
-#define DM_RESP_OPTIONAL_FEATURE_NOT_SUPPORTED 406
-#define DM_RESP_MISSING_CREDENTIALS 407
-#define DM_RESP_CONFLICT 409
-#define DM_RESP_GONE 410
-#define DM_RESP_INCOMPLETE_COMMAND 412
-#define DM_RESP_REQ_ENTITY_TOO_LARGE 413
-#define DM_RESP_URI_TOO_LONG 414
-#define DM_RESP_UNSUPPORTED_MEDIA_TYPE_OR_FORMAT 415
-#define DM_RESP_REQ_TOO_BIG 416
-#define DM_RESP_ALREADY_EXISTS 418
-#define DM_RESP_DEVICE_FULL 420
-#define DM_RESP_SIZE_MISMATCH 424
-#define DM_RESP_PERMISSION_DENIED 425
-#define DM_RESP_COMMAND_FAILED 500
-#define DM_RESP_COMMAND_NOT_IMPLEMENTED 501
-#define DM_RESP_ATOMIC_ROLL_BACK_FAILED 516
-
-#define DM_HS20_SUBSCRIPTION_CREATION \
-       "org.wi-fi.hotspot2dot0.SubscriptionCreation"
-#define DM_HS20_SUBSCRIPTION_PROVISIONING \
-       "org.wi-fi.hotspot2dot0.SubscriptionProvisioning"
-#define DM_HS20_SUBSCRIPTION_REMEDIATION \
-       "org.wi-fi.hotspot2dot0.SubscriptionRemediation"
-#define DM_HS20_POLICY_UPDATE \
-       "org.wi-fi.hotspot2dot0.PolicyUpdate"
-
-#define DM_URI_PPS "./Wi-Fi/org.wi-fi/PerProviderSubscription"
-#define DM_URI_LAUNCH_BROWSER \
-       "./DevDetail/Ext/org.wi-fi/Wi-Fi/Ops/launchBrowserToURI"
-
-
-static void add_item(struct hs20_osu_client *ctx, xml_node_t *parent,
-                    const char *locuri, const char *data);
-
-
-static const char * int2str(int val)
-{
-       static char buf[20];
-       snprintf(buf, sizeof(buf), "%d", val);
-       return buf;
-}
-
-
-static char * oma_dm_get_target_locuri(struct hs20_osu_client *ctx,
-                                      xml_node_t *node)
-{
-       xml_node_t *locuri;
-       char *uri, *ret = NULL;
-
-       locuri = get_node(ctx->xml, node, "Item/Target/LocURI");
-       if (locuri == NULL)
-               return NULL;
-
-       uri = xml_node_get_text(ctx->xml, locuri);
-       if (uri)
-               ret = os_strdup(uri);
-       xml_node_get_text_free(ctx->xml, uri);
-       return ret;
-}
-
-
-static void oma_dm_add_locuri(struct hs20_osu_client *ctx, xml_node_t *parent,
-                             const char *element, const char *uri)
-{
-       xml_node_t *node;
-
-       node = xml_node_create(ctx->xml, parent, NULL, element);
-       if (node == NULL)
-               return;
-       xml_node_create_text(ctx->xml, node, NULL, "LocURI", uri);
-}
-
-
-static xml_node_t * oma_dm_build_hdr(struct hs20_osu_client *ctx,
-                                    const char *url, int msgid)
-{
-       xml_node_t *syncml, *synchdr;
-       xml_namespace_t *ns;
-
-       if (!ctx->devid) {
-               wpa_printf(MSG_ERROR,
-                          "DevId from devinfo.xml is not available - cannot use OMA DM");
-               return NULL;
-       }
-
-       syncml = xml_node_create_root(ctx->xml, "SYNCML:SYNCML1.2", NULL, &ns,
-                                     "SyncML");
-
-       synchdr = xml_node_create(ctx->xml, syncml, NULL, "SyncHdr");
-       xml_node_create_text(ctx->xml, synchdr, NULL, "VerDTD", "1.2");
-       xml_node_create_text(ctx->xml, synchdr, NULL, "VerProto", "DM/1.2");
-       xml_node_create_text(ctx->xml, synchdr, NULL, "SessionID", "1");
-       xml_node_create_text(ctx->xml, synchdr, NULL, "MsgID", int2str(msgid));
-
-       oma_dm_add_locuri(ctx, synchdr, "Target", url);
-       oma_dm_add_locuri(ctx, synchdr, "Source", ctx->devid);
-
-       return syncml;
-}
-
-
-static void oma_dm_add_cmdid(struct hs20_osu_client *ctx, xml_node_t *parent,
-                            int cmdid)
-{
-       xml_node_create_text(ctx->xml, parent, NULL, "CmdID", int2str(cmdid));
-}
-
-
-static xml_node_t * add_alert(struct hs20_osu_client *ctx, xml_node_t *parent,
-                             int cmdid, int data)
-{
-       xml_node_t *node;
-
-       node = xml_node_create(ctx->xml, parent, NULL, "Alert");
-       if (node == NULL)
-               return NULL;
-       oma_dm_add_cmdid(ctx, node, cmdid);
-       xml_node_create_text(ctx->xml, node, NULL, "Data", int2str(data));
-
-       return node;
-}
-
-
-static xml_node_t * add_status(struct hs20_osu_client *ctx, xml_node_t *parent,
-                              int msgref, int cmdref, int cmdid,
-                              const char *cmd, int data, const char *targetref)
-{
-       xml_node_t *node;
-
-       node = xml_node_create(ctx->xml, parent, NULL, "Status");
-       if (node == NULL)
-               return NULL;
-       oma_dm_add_cmdid(ctx, node, cmdid);
-       xml_node_create_text(ctx->xml, node, NULL, "MsgRef", int2str(msgref));
-       if (cmdref)
-               xml_node_create_text(ctx->xml, node, NULL, "CmdRef",
-                                    int2str(cmdref));
-       xml_node_create_text(ctx->xml, node, NULL, "Cmd", cmd);
-       xml_node_create_text(ctx->xml, node, NULL, "Data", int2str(data));
-       if (targetref) {
-               xml_node_create_text(ctx->xml, node, NULL, "TargetRef",
-                                    targetref);
-       }
-
-       return node;
-}
-
-
-static xml_node_t * add_results(struct hs20_osu_client *ctx, xml_node_t *parent,
-                               int msgref, int cmdref, int cmdid,
-                               const char *locuri, const char *data)
-{
-       xml_node_t *node;
-
-       node = xml_node_create(ctx->xml, parent, NULL, "Results");
-       if (node == NULL)
-               return NULL;
-
-       oma_dm_add_cmdid(ctx, node, cmdid);
-       xml_node_create_text(ctx->xml, node, NULL, "MsgRef", int2str(msgref));
-       xml_node_create_text(ctx->xml, node, NULL, "CmdRef", int2str(cmdref));
-       add_item(ctx, node, locuri, data);
-
-       return node;
-}
-
-
-static char * mo_str(struct hs20_osu_client *ctx, const char *urn,
-                    const char *fname)
-{
-       xml_node_t *fnode, *tnds;
-       char *str;
-
-       fnode = node_from_file(ctx->xml, fname);
-       if (!fnode)
-               return NULL;
-       tnds = mo_to_tnds(ctx->xml, fnode, 0, urn, "syncml:dmddf1.2");
-       xml_node_free(ctx->xml, fnode);
-       if (!tnds)
-               return NULL;
-
-       str = xml_node_to_str(ctx->xml, tnds);
-       xml_node_free(ctx->xml, tnds);
-       if (str == NULL)
-               return NULL;
-       wpa_printf(MSG_INFO, "MgmtTree: %s", str);
-
-       return str;
-}
-
-
-static void add_item(struct hs20_osu_client *ctx, xml_node_t *parent,
-                    const char *locuri, const char *data)
-{
-       xml_node_t *item, *node;
-
-       item = xml_node_create(ctx->xml, parent, NULL, "Item");
-       oma_dm_add_locuri(ctx, item, "Source", locuri);
-       node = xml_node_create(ctx->xml, item, NULL, "Meta");
-       xml_node_create_text_ns(ctx->xml, node, "syncml:metinf", "Format",
-                               "Chr");
-       xml_node_create_text_ns(ctx->xml, node, "syncml:metinf", "Type",
-                               "text/plain");
-       xml_node_create_text(ctx->xml, item, NULL, "Data", data);
-}
-
-
-static void add_replace_devinfo(struct hs20_osu_client *ctx, xml_node_t *parent,
-                               int cmdid)
-{
-       xml_node_t *info, *child, *replace;
-       const char *name;
-       char locuri[200], *txt;
-
-       info = node_from_file(ctx->xml, "devinfo.xml");
-       if (info == NULL) {
-               wpa_printf(MSG_INFO, "Could not read devinfo.xml");
-               return;
-       }
-
-       replace = xml_node_create(ctx->xml, parent, NULL, "Replace");
-       if (replace == NULL) {
-               xml_node_free(ctx->xml, info);
-               return;
-       }
-       oma_dm_add_cmdid(ctx, replace, cmdid);
-
-       xml_node_for_each_child(ctx->xml, child, info) {
-               xml_node_for_each_check(ctx->xml, child);
-               name = xml_node_get_localname(ctx->xml, child);
-               os_snprintf(locuri, sizeof(locuri), "./DevInfo/%s", name);
-               txt = xml_node_get_text(ctx->xml, child);
-               if (txt) {
-                       add_item(ctx, replace, locuri, txt);
-                       xml_node_get_text_free(ctx->xml, txt);
-               }
-       }
-
-       xml_node_free(ctx->xml, info);
-}
-
-
-static void oma_dm_add_hs20_generic_alert(struct hs20_osu_client *ctx,
-                                         xml_node_t *syncbody,
-                                         int cmdid, const char *oper,
-                                         const char *data)
-{
-       xml_node_t *node, *item;
-       char buf[200];
-
-       node = add_alert(ctx, syncbody, cmdid, DM_GENERIC_ALERT);
-
-       item = xml_node_create(ctx->xml, node, NULL, "Item");
-       oma_dm_add_locuri(ctx, item, "Source", DM_URI_PPS);
-       node = xml_node_create(ctx->xml, item, NULL, "Meta");
-       snprintf(buf, sizeof(buf), "Reversed-Domain-Name: %s", oper);
-       xml_node_create_text_ns(ctx->xml, node, "syncml:metinf", "Type", buf);
-       xml_node_create_text_ns(ctx->xml, node, "syncml:metinf", "Format",
-                               "xml");
-       xml_node_create_text(ctx->xml, item, NULL, "Data", data);
-}
-
-
-static xml_node_t * build_oma_dm_1(struct hs20_osu_client *ctx,
-                                  const char *url, int msgid, const char *oper)
-{
-       xml_node_t *syncml, *syncbody;
-       char *str;
-       int cmdid = 0;
-
-       syncml = oma_dm_build_hdr(ctx, url, msgid);
-       if (syncml == NULL)
-               return NULL;
-
-       syncbody = xml_node_create(ctx->xml, syncml, NULL, "SyncBody");
-       if (syncbody == NULL) {
-               xml_node_free(ctx->xml, syncml);
-               return NULL;
-       }
-
-       cmdid++;
-       add_alert(ctx, syncbody, cmdid, DM_CLIENT_INITIATED_MGMT);
-
-       str = mo_str(ctx, NULL, "devdetail.xml");
-       if (str == NULL) {
-               xml_node_free(ctx->xml, syncml);
-               return NULL;
-       }
-       cmdid++;
-       oma_dm_add_hs20_generic_alert(ctx, syncbody, cmdid, oper, str);
-       os_free(str);
-
-       cmdid++;
-       add_replace_devinfo(ctx, syncbody, cmdid);
-
-       xml_node_create(ctx->xml, syncbody, NULL, "Final");
-
-       return syncml;
-}
-
-
-static xml_node_t * build_oma_dm_1_sub_reg(struct hs20_osu_client *ctx,
-                                          const char *url, int msgid)
-{
-       xml_node_t *syncml;
-
-       syncml = build_oma_dm_1(ctx, url, msgid, DM_HS20_SUBSCRIPTION_CREATION);
-       if (syncml)
-               debug_dump_node(ctx, "OMA-DM Package 1 (sub reg)", syncml);
-
-       return syncml;
-}
-
-
-static xml_node_t * build_oma_dm_1_sub_prov(struct hs20_osu_client *ctx,
-                                           const char *url, int msgid)
-{
-       xml_node_t *syncml;
-
-       syncml = build_oma_dm_1(ctx, url, msgid,
-                               DM_HS20_SUBSCRIPTION_PROVISIONING);
-       if (syncml)
-               debug_dump_node(ctx, "OMA-DM Package 1 (sub prov)", syncml);
-
-       return syncml;
-}
-
-
-static xml_node_t * build_oma_dm_1_pol_upd(struct hs20_osu_client *ctx,
-                                          const char *url, int msgid)
-{
-       xml_node_t *syncml;
-
-       syncml = build_oma_dm_1(ctx, url, msgid, DM_HS20_POLICY_UPDATE);
-       if (syncml)
-               debug_dump_node(ctx, "OMA-DM Package 1 (pol upd)", syncml);
-
-       return syncml;
-}
-
-
-static xml_node_t * build_oma_dm_1_sub_rem(struct hs20_osu_client *ctx,
-                                          const char *url, int msgid)
-{
-       xml_node_t *syncml;
-
-       syncml = build_oma_dm_1(ctx, url, msgid,
-                               DM_HS20_SUBSCRIPTION_REMEDIATION);
-       if (syncml)
-               debug_dump_node(ctx, "OMA-DM Package 1 (sub rem)", syncml);
-
-       return syncml;
-}
-
-
-static int oma_dm_exec_browser(struct hs20_osu_client *ctx, xml_node_t *exec)
-{
-       xml_node_t *node;
-       char *data;
-       int res;
-
-       node = get_node(ctx->xml, exec, "Item/Data");
-       if (node == NULL) {
-               wpa_printf(MSG_INFO, "No Data node found");
-               return DM_RESP_BAD_REQUEST;
-       }
-
-       data = xml_node_get_text(ctx->xml, node);
-       if (data == NULL) {
-               wpa_printf(MSG_INFO, "Invalid data");
-               return DM_RESP_BAD_REQUEST;
-       }
-       wpa_printf(MSG_INFO, "Data: %s", data);
-       wpa_printf(MSG_INFO, "Launch browser to URI '%s'", data);
-       write_summary(ctx, "Launch browser to URI '%s'", data);
-       res = hs20_web_browser(data, 1);
-       xml_node_get_text_free(ctx->xml, data);
-       if (res > 0) {
-               wpa_printf(MSG_INFO, "User response in browser completed successfully");
-               write_summary(ctx, "User response in browser completed successfully");
-               return DM_RESP_OK;
-       } else {
-               wpa_printf(MSG_INFO, "Failed to receive user response");
-               write_summary(ctx, "Failed to receive user response");
-               return DM_RESP_COMMAND_FAILED;
-       }
-}
-
-
-static int oma_dm_exec_get_cert(struct hs20_osu_client *ctx, xml_node_t *exec)
-{
-       xml_node_t *node, *getcert;
-       char *data;
-       const char *name;
-       int res;
-
-       wpa_printf(MSG_INFO, "Client certificate enrollment");
-       write_summary(ctx, "Client certificate enrollment");
-
-       node = get_node(ctx->xml, exec, "Item/Data");
-       if (node == NULL) {
-               wpa_printf(MSG_INFO, "No Data node found");
-               return DM_RESP_BAD_REQUEST;
-       }
-
-       data = xml_node_get_text(ctx->xml, node);
-       if (data == NULL) {
-               wpa_printf(MSG_INFO, "Invalid data");
-               return DM_RESP_BAD_REQUEST;
-       }
-       wpa_printf(MSG_INFO, "Data: %s", data);
-       getcert = xml_node_from_buf(ctx->xml, data);
-       xml_node_get_text_free(ctx->xml, data);
-
-       if (getcert == NULL) {
-               wpa_printf(MSG_INFO, "Could not parse Item/Data node contents");
-               return DM_RESP_BAD_REQUEST;
-       }
-
-       debug_dump_node(ctx, "OMA-DM getCertificate", getcert);
-
-       name = xml_node_get_localname(ctx->xml, getcert);
-       if (name == NULL || os_strcasecmp(name, "getCertificate") != 0) {
-               wpa_printf(MSG_INFO, "Unexpected getCertificate node name '%s'",
-                          name);
-               return DM_RESP_BAD_REQUEST;
-       }
-
-       res = osu_get_certificate(ctx, getcert);
-
-       xml_node_free(ctx->xml, getcert);
-
-       return res == 0 ? DM_RESP_OK : DM_RESP_COMMAND_FAILED;
-}
-
-
-static int oma_dm_exec(struct hs20_osu_client *ctx, xml_node_t *exec)
-{
-       char *locuri;
-       int ret;
-
-       locuri = oma_dm_get_target_locuri(ctx, exec);
-       if (locuri == NULL) {
-               wpa_printf(MSG_INFO, "No Target LocURI node found");
-               return DM_RESP_BAD_REQUEST;
-       }
-
-       wpa_printf(MSG_INFO, "Target LocURI: %s", locuri);
-
-       if (os_strcasecmp(locuri, "./DevDetail/Ext/org.wi-fi/Wi-Fi/Ops/"
-                         "launchBrowserToURI") == 0) {
-               ret = oma_dm_exec_browser(ctx, exec);
-       } else if (os_strcasecmp(locuri, "./DevDetail/Ext/org.wi-fi/Wi-Fi/Ops/"
-                         "getCertificate") == 0) {
-               ret = oma_dm_exec_get_cert(ctx, exec);
-       } else {
-               wpa_printf(MSG_INFO, "Unsupported exec Target LocURI");
-               ret = DM_RESP_NOT_FOUND;
-       }
-       os_free(locuri);
-
-       return ret;
-}
-
-
-static int oma_dm_run_add(struct hs20_osu_client *ctx, const char *locuri,
-                         xml_node_t *add, xml_node_t *pps,
-                         const char *pps_fname)
-{
-       const char *pos;
-       size_t fqdn_len;
-       xml_node_t *node, *tnds, *unode, *pps_node;
-       char *data, *uri, *upos, *end;
-       int use_tnds = 0;
-       size_t uri_len;
-
-       wpa_printf(MSG_INFO, "Add command target LocURI: %s", locuri);
-
-       if (os_strncasecmp(locuri, "./Wi-Fi/", 8) != 0) {
-               wpa_printf(MSG_INFO, "Do not allow Add outside ./Wi-Fi");
-               return DM_RESP_PERMISSION_DENIED;
-       }
-       pos = locuri + 8;
-
-       if (ctx->fqdn == NULL)
-               return DM_RESP_COMMAND_FAILED;
-       fqdn_len = os_strlen(ctx->fqdn);
-       if (os_strncasecmp(pos, ctx->fqdn, fqdn_len) != 0 ||
-           pos[fqdn_len] != '/') {
-               wpa_printf(MSG_INFO, "Do not allow Add outside ./Wi-Fi/%s",
-                          ctx->fqdn);
-               return DM_RESP_PERMISSION_DENIED;
-       }
-       pos += fqdn_len + 1;
-
-       if (os_strncasecmp(pos, "PerProviderSubscription/", 24) != 0) {
-               wpa_printf(MSG_INFO,
-                          "Do not allow Add outside ./Wi-Fi/%s/PerProviderSubscription",
-                          ctx->fqdn);
-               return DM_RESP_PERMISSION_DENIED;
-       }
-       pos += 24;
-
-       wpa_printf(MSG_INFO, "Add command for PPS node %s", pos);
-
-       pps_node = get_node(ctx->xml, pps, pos);
-       if (pps_node) {
-               wpa_printf(MSG_INFO, "Specified PPS node exists already");
-               return DM_RESP_ALREADY_EXISTS;
-       }
-
-       uri = os_strdup(pos);
-       if (uri == NULL)
-               return DM_RESP_COMMAND_FAILED;
-       while (!pps_node) {
-               upos = os_strrchr(uri, '/');
-               if (!upos)
-                       break;
-               upos[0] = '\0';
-               pps_node = get_node(ctx->xml, pps, uri);
-               wpa_printf(MSG_INFO, "Node %s %s", uri,
-                          pps_node ? "exists" : "does not exist");
-       }
-
-       wpa_printf(MSG_INFO, "Parent URI: %s", uri);
-
-       if (!pps_node) {
-               /* Add at root of PPS MO */
-               pps_node = pps;
-       }
-
-       uri_len = os_strlen(uri);
-       os_strlcpy(uri, pos + uri_len, os_strlen(pos));
-       upos = uri;
-       while (*upos == '/')
-               upos++;
-       wpa_printf(MSG_INFO, "Nodes to add: %s", upos);
-
-       for (;;) {
-               end = os_strchr(upos, '/');
-               if (!end)
-                       break;
-               *end = '\0';
-               wpa_printf(MSG_INFO, "Adding interim node %s", upos);
-               pps_node = xml_node_create(ctx->xml, pps_node, NULL, upos);
-               if (pps_node == NULL) {
-                       os_free(uri);
-                       return DM_RESP_COMMAND_FAILED;
-               }
-               upos = end + 1;
-       }
-
-       wpa_printf(MSG_INFO, "Adding node %s", upos);
-
-       node = get_node(ctx->xml, add, "Item/Meta/Type");
-       if (node) {
-               char *type;
-               type = xml_node_get_text(ctx->xml, node);
-               if (type == NULL) {
-                       wpa_printf(MSG_ERROR, "Could not find type text");
-                       os_free(uri);
-                       return DM_RESP_BAD_REQUEST;
-               }
-               use_tnds = node &&
-                       os_strstr(type, "application/vnd.syncml.dmtnds+xml");
-       }
-
-       node = get_node(ctx->xml, add, "Item/Data");
-       if (node == NULL) {
-               wpa_printf(MSG_INFO, "No Add/Item/Data found");
-               os_free(uri);
-               return DM_RESP_BAD_REQUEST;
-       }
-
-       data = xml_node_get_text(ctx->xml, node);
-       if (data == NULL) {
-               wpa_printf(MSG_INFO, "Could not get Add/Item/Data text");
-               os_free(uri);
-               return DM_RESP_BAD_REQUEST;
-       }
-
-       wpa_printf(MSG_DEBUG, "Add/Item/Data: %s", data);
-
-       if (use_tnds) {
-               tnds = xml_node_from_buf(ctx->xml, data);
-               xml_node_get_text_free(ctx->xml, data);
-               if (tnds == NULL) {
-                       wpa_printf(MSG_INFO,
-                                  "Could not parse Add/Item/Data text");
-                       os_free(uri);
-                       return DM_RESP_BAD_REQUEST;
-               }
-
-               unode = tnds_to_mo(ctx->xml, tnds);
-               xml_node_free(ctx->xml, tnds);
-               if (unode == NULL) {
-                       wpa_printf(MSG_INFO, "Could not parse TNDS text");
-                       os_free(uri);
-                       return DM_RESP_BAD_REQUEST;
-               }
-
-               debug_dump_node(ctx, "Parsed TNDS", unode);
-
-               xml_node_add_child(ctx->xml, pps_node, unode);
-       } else {
-               /* TODO: What to do here? */
-               os_free(uri);
-               return DM_RESP_BAD_REQUEST;
-       }
-
-       os_free(uri);
-
-       if (update_pps_file(ctx, pps_fname, pps) < 0)
-               return DM_RESP_COMMAND_FAILED;
-
-       ctx->pps_updated = 1;
-
-       return DM_RESP_OK;
-}
-
-
-static int oma_dm_add(struct hs20_osu_client *ctx, xml_node_t *add,
-                     xml_node_t *pps, const char *pps_fname)
-{
-       xml_node_t *node;
-       char *locuri;
-       char fname[300];
-       int ret;
-
-       node = get_node(ctx->xml, add, "Item/Target/LocURI");
-       if (node == NULL) {
-               wpa_printf(MSG_INFO, "No Target LocURI node found");
-               return DM_RESP_BAD_REQUEST;
-       }
-       locuri = xml_node_get_text(ctx->xml, node);
-       if (locuri == NULL) {
-               wpa_printf(MSG_ERROR, "No LocURI node text found");
-               return DM_RESP_BAD_REQUEST;
-       }
-       wpa_printf(MSG_INFO, "Target LocURI: %s", locuri);
-       if (os_strncasecmp(locuri, "./Wi-Fi/", 8) != 0) {
-               wpa_printf(MSG_INFO, "Unsupported Add Target LocURI");
-               xml_node_get_text_free(ctx->xml, locuri);
-               return DM_RESP_PERMISSION_DENIED;
-       }
-
-       node = get_node(ctx->xml, add, "Item/Data");
-       if (node == NULL) {
-               wpa_printf(MSG_INFO, "No Data node found");
-               xml_node_get_text_free(ctx->xml, locuri);
-               return DM_RESP_BAD_REQUEST;
-       }
-
-       if (pps_fname && os_file_exists(pps_fname)) {
-               ret = oma_dm_run_add(ctx, locuri, add, pps, pps_fname);
-               if (ret != DM_RESP_OK) {
-                       xml_node_get_text_free(ctx->xml, locuri);
-                       return ret;
-               }
-               ret = 0;
-               os_strlcpy(fname, pps_fname, sizeof(fname));
-       } else
-               ret = hs20_add_pps_mo(ctx, locuri, node, fname, sizeof(fname));
-       xml_node_get_text_free(ctx->xml, locuri);
-       if (ret < 0)
-               return ret == -2 ? DM_RESP_ALREADY_EXISTS :
-                       DM_RESP_COMMAND_FAILED;
-
-       if (ctx->no_reconnect == 2) {
-               os_snprintf(ctx->pps_fname, sizeof(ctx->pps_fname), "%s",
-                           fname);
-               ctx->pps_cred_set = 1;
-               return DM_RESP_OK;
-       }
-
-       wpa_printf(MSG_INFO, "Updating wpa_supplicant credentials");
-       cmd_set_pps(ctx, fname);
-
-       if (ctx->no_reconnect)
-               return DM_RESP_OK;
-
-       wpa_printf(MSG_INFO, "Requesting reconnection with updated configuration");
-       if (wpa_command(ctx->ifname, "INTERWORKING_SELECT auto") < 0)
-               wpa_printf(MSG_INFO, "Failed to request wpa_supplicant to reconnect");
-
-       return DM_RESP_OK;
-}
-
-
-static int oma_dm_replace(struct hs20_osu_client *ctx, xml_node_t *replace,
-                         xml_node_t *pps, const char *pps_fname)
-{
-       char *locuri, *pos;
-       size_t fqdn_len;
-       xml_node_t *node, *tnds, *unode, *pps_node, *parent;
-       char *data;
-       int use_tnds = 0;
-
-       locuri = oma_dm_get_target_locuri(ctx, replace);
-       if (locuri == NULL)
-               return DM_RESP_BAD_REQUEST;
-
-       wpa_printf(MSG_INFO, "Replace command target LocURI: %s", locuri);
-       if (os_strncasecmp(locuri, "./Wi-Fi/", 8) != 0) {
-               wpa_printf(MSG_INFO, "Do not allow Replace outside ./Wi-Fi");
-               os_free(locuri);
-               return DM_RESP_PERMISSION_DENIED;
-       }
-       pos = locuri + 8;
-
-       if (ctx->fqdn == NULL) {
-               os_free(locuri);
-               return DM_RESP_COMMAND_FAILED;
-       }
-       fqdn_len = os_strlen(ctx->fqdn);
-       if (os_strncasecmp(pos, ctx->fqdn, fqdn_len) != 0 ||
-           pos[fqdn_len] != '/') {
-               wpa_printf(MSG_INFO, "Do not allow Replace outside ./Wi-Fi/%s",
-                          ctx->fqdn);
-               os_free(locuri);
-               return DM_RESP_PERMISSION_DENIED;
-       }
-       pos += fqdn_len + 1;
-
-       if (os_strncasecmp(pos, "PerProviderSubscription/", 24) != 0) {
-               wpa_printf(MSG_INFO,
-                          "Do not allow Replace outside ./Wi-Fi/%s/PerProviderSubscription",
-                          ctx->fqdn);
-               os_free(locuri);
-               return DM_RESP_PERMISSION_DENIED;
-       }
-       pos += 24;
-
-       wpa_printf(MSG_INFO, "Replace command for PPS node %s", pos);
-
-       pps_node = get_node(ctx->xml, pps, pos);
-       if (pps_node == NULL) {
-               wpa_printf(MSG_INFO, "Specified PPS node not found");
-               os_free(locuri);
-               return DM_RESP_NOT_FOUND;
-       }
-
-       node = get_node(ctx->xml, replace, "Item/Meta/Type");
-       if (node) {
-               char *type;
-               type = xml_node_get_text(ctx->xml, node);
-               if (type == NULL) {
-                       wpa_printf(MSG_INFO, "Could not find type text");
-                       os_free(locuri);
-                       return DM_RESP_BAD_REQUEST;
-               }
-               use_tnds = node &&
-                       os_strstr(type, "application/vnd.syncml.dmtnds+xml");
-       }
-
-       node = get_node(ctx->xml, replace, "Item/Data");
-       if (node == NULL) {
-               wpa_printf(MSG_INFO, "No Replace/Item/Data found");
-               os_free(locuri);
-               return DM_RESP_BAD_REQUEST;
-       }
-
-       data = xml_node_get_text(ctx->xml, node);
-       if (data == NULL) {
-               wpa_printf(MSG_INFO, "Could not get Replace/Item/Data text");
-               os_free(locuri);
-               return DM_RESP_BAD_REQUEST;
-       }
-
-       wpa_printf(MSG_DEBUG, "Replace/Item/Data: %s", data);
-
-       if (use_tnds) {
-               tnds = xml_node_from_buf(ctx->xml, data);
-               xml_node_get_text_free(ctx->xml, data);
-               if (tnds == NULL) {
-                       wpa_printf(MSG_INFO,
-                                  "Could not parse Replace/Item/Data text");
-                       os_free(locuri);
-                       return DM_RESP_BAD_REQUEST;
-               }
-
-               unode = tnds_to_mo(ctx->xml, tnds);
-               xml_node_free(ctx->xml, tnds);
-               if (unode == NULL) {
-                       wpa_printf(MSG_INFO, "Could not parse TNDS text");
-                       os_free(locuri);
-                       return DM_RESP_BAD_REQUEST;
-               }
-
-               debug_dump_node(ctx, "Parsed TNDS", unode);
-
-               parent = xml_node_get_parent(ctx->xml, pps_node);
-               xml_node_detach(ctx->xml, pps_node);
-               xml_node_add_child(ctx->xml, parent, unode);
-       } else {
-               xml_node_set_text(ctx->xml, pps_node, data);
-               xml_node_get_text_free(ctx->xml, data);
-       }
-
-       os_free(locuri);
-
-       if (update_pps_file(ctx, pps_fname, pps) < 0)
-               return DM_RESP_COMMAND_FAILED;
-
-       ctx->pps_updated = 1;
-
-       return DM_RESP_OK;
-}
-
-
-static int oma_dm_get(struct hs20_osu_client *ctx, xml_node_t *get,
-                     xml_node_t *pps, const char *pps_fname, char **value)
-{
-       char *locuri, *pos;
-       size_t fqdn_len;
-       xml_node_t *pps_node;
-       const char *name;
-
-       *value = NULL;
-
-       locuri = oma_dm_get_target_locuri(ctx, get);
-       if (locuri == NULL)
-               return DM_RESP_BAD_REQUEST;
-
-       wpa_printf(MSG_INFO, "Get command target LocURI: %s", locuri);
-       if (os_strncasecmp(locuri, "./Wi-Fi/", 8) != 0) {
-               wpa_printf(MSG_INFO, "Do not allow Get outside ./Wi-Fi");
-               os_free(locuri);
-               return DM_RESP_PERMISSION_DENIED;
-       }
-       pos = locuri + 8;
-
-       if (ctx->fqdn == NULL)
-               return DM_RESP_COMMAND_FAILED;
-       fqdn_len = os_strlen(ctx->fqdn);
-       if (os_strncasecmp(pos, ctx->fqdn, fqdn_len) != 0 ||
-           pos[fqdn_len] != '/') {
-               wpa_printf(MSG_INFO, "Do not allow Get outside ./Wi-Fi/%s",
-                          ctx->fqdn);
-               os_free(locuri);
-               return DM_RESP_PERMISSION_DENIED;
-       }
-       pos += fqdn_len + 1;
-
-       if (os_strncasecmp(pos, "PerProviderSubscription/", 24) != 0) {
-               wpa_printf(MSG_INFO,
-                          "Do not allow Get outside ./Wi-Fi/%s/PerProviderSubscription",
-                          ctx->fqdn);
-               os_free(locuri);
-               return DM_RESP_PERMISSION_DENIED;
-       }
-       pos += 24;
-
-       wpa_printf(MSG_INFO, "Get command for PPS node %s", pos);
-
-       pps_node = get_node(ctx->xml, pps, pos);
-       if (pps_node == NULL) {
-               wpa_printf(MSG_INFO, "Specified PPS node not found");
-               os_free(locuri);
-               return DM_RESP_NOT_FOUND;
-       }
-
-       name = xml_node_get_localname(ctx->xml, pps_node);
-       wpa_printf(MSG_INFO, "Get command returned node with name '%s'", name);
-       if (os_strcasecmp(name, "Password") == 0) {
-               wpa_printf(MSG_INFO, "Do not allow Get for Password node");
-               os_free(locuri);
-               return DM_RESP_PERMISSION_DENIED;
-       }
-
-       /*
-        * TODO: No support for DMTNDS, so if interior node, reply with a
-        * list of children node names in Results element. The child list type is
-        * defined in [DMTND].
-        */
-
-       *value = xml_node_get_text(ctx->xml, pps_node);
-       if (*value == NULL)
-               return DM_RESP_COMMAND_FAILED;
-
-       return DM_RESP_OK;
-}
-
-
-static int oma_dm_get_cmdid(struct hs20_osu_client *ctx, xml_node_t *node)
-{
-       xml_node_t *cnode;
-       char *str;
-       int ret;
-
-       cnode = get_node(ctx->xml, node, "CmdID");
-       if (cnode == NULL)
-               return 0;
-
-       str = xml_node_get_text(ctx->xml, cnode);
-       if (str == NULL)
-               return 0;
-       ret = atoi(str);
-       xml_node_get_text_free(ctx->xml, str);
-       return ret;
-}
-
-
-static xml_node_t * oma_dm_send_recv(struct hs20_osu_client *ctx,
-                                    const char *url, xml_node_t *syncml,
-                                    const char *ext_hdr,
-                                    const char *username, const char *password,
-                                    const char *client_cert,
-                                    const char *client_key)
-{
-       xml_node_t *resp;
-       char *str, *res;
-       char *resp_uri = NULL;
-
-       str = xml_node_to_str(ctx->xml, syncml);
-       xml_node_free(ctx->xml, syncml);
-       if (str == NULL)
-               return NULL;
-
-       wpa_printf(MSG_INFO, "Send OMA DM Package");
-       write_summary(ctx, "Send OMA DM Package");
-       os_free(ctx->server_url);
-       ctx->server_url = os_strdup(url);
-       res = http_post(ctx->http, url, str, "application/vnd.syncml.dm+xml",
-                       ext_hdr, ctx->ca_fname, username, password,
-                       client_cert, client_key, NULL);
-       os_free(str);
-       os_free(resp_uri);
-       resp_uri = NULL;
-
-       if (res == NULL) {
-               const char *err = http_get_err(ctx->http);
-               if (err) {
-                       wpa_printf(MSG_INFO, "HTTP error: %s", err);
-                       write_result(ctx, "HTTP error: %s", err);
-               } else {
-                       write_summary(ctx, "Failed to send OMA DM Package");
-               }
-               return NULL;
-       }
-       wpa_printf(MSG_DEBUG, "Server response: %s", res);
-
-       wpa_printf(MSG_INFO, "Process OMA DM Package");
-       write_summary(ctx, "Process received OMA DM Package");
-       resp = xml_node_from_buf(ctx->xml, res);
-       os_free(res);
-       if (resp == NULL) {
-               wpa_printf(MSG_INFO, "Failed to parse OMA DM response");
-               return NULL;
-       }
-
-       debug_dump_node(ctx, "OMA DM Package", resp);
-
-       return resp;
-}
-
-
-static xml_node_t * oma_dm_process(struct hs20_osu_client *ctx, const char *url,
-                                  xml_node_t *resp, int msgid,
-                                  char **ret_resp_uri,
-                                  xml_node_t *pps, const char *pps_fname)
-{
-       xml_node_t *syncml, *syncbody, *hdr, *body, *child;
-       const char *name;
-       char *resp_uri = NULL;
-       int server_msgid = 0;
-       int cmdid = 0;
-       int server_cmdid;
-       int resp_needed = 0;
-       char *tmp;
-       int final = 0;
-       char *locuri;
-
-       *ret_resp_uri = NULL;
-
-       name = xml_node_get_localname(ctx->xml, resp);
-       if (name == NULL || os_strcasecmp(name, "SyncML") != 0) {
-               wpa_printf(MSG_INFO, "SyncML node not found");
-               return NULL;
-       }
-
-       hdr = get_node(ctx->xml, resp, "SyncHdr");
-       body = get_node(ctx->xml, resp, "SyncBody");
-       if (hdr == NULL || body == NULL) {
-               wpa_printf(MSG_INFO, "Could not find SyncHdr or SyncBody");
-               return NULL;
-       }
-
-       xml_node_for_each_child(ctx->xml, child, hdr) {
-               xml_node_for_each_check(ctx->xml, child);
-               name = xml_node_get_localname(ctx->xml, child);
-               wpa_printf(MSG_INFO, "SyncHdr %s", name);
-               if (os_strcasecmp(name, "RespURI") == 0) {
-                       tmp = xml_node_get_text(ctx->xml, child);
-                       if (tmp)
-                               resp_uri = os_strdup(tmp);
-                       xml_node_get_text_free(ctx->xml, tmp);
-               } else if (os_strcasecmp(name, "MsgID") == 0) {
-                       tmp = xml_node_get_text(ctx->xml, child);
-                       if (tmp)
-                               server_msgid = atoi(tmp);
-                       xml_node_get_text_free(ctx->xml, tmp);
-               }
-       }
-
-       wpa_printf(MSG_INFO, "Server MsgID: %d", server_msgid);
-       if (resp_uri)
-               wpa_printf(MSG_INFO, "RespURI: %s", resp_uri);
-
-       syncml = oma_dm_build_hdr(ctx, resp_uri ? resp_uri : url, msgid);
-       if (syncml == NULL) {
-               os_free(resp_uri);
-               return NULL;
-       }
-
-       syncbody = xml_node_create(ctx->xml, syncml, NULL, "SyncBody");
-       cmdid++;
-       add_status(ctx, syncbody, server_msgid, 0, cmdid, "SyncHdr",
-                  DM_RESP_AUTH_ACCEPTED, NULL);
-
-       xml_node_for_each_child(ctx->xml, child, body) {
-               xml_node_for_each_check(ctx->xml, child);
-               server_cmdid = oma_dm_get_cmdid(ctx, child);
-               name = xml_node_get_localname(ctx->xml, child);
-               wpa_printf(MSG_INFO, "SyncBody CmdID=%d - %s",
-                          server_cmdid, name);
-               if (os_strcasecmp(name, "Exec") == 0) {
-                       int res = oma_dm_exec(ctx, child);
-                       cmdid++;
-                       locuri = oma_dm_get_target_locuri(ctx, child);
-                       if (locuri == NULL)
-                               res = DM_RESP_BAD_REQUEST;
-                       add_status(ctx, syncbody, server_msgid, server_cmdid,
-                                  cmdid, name, res, locuri);
-                       os_free(locuri);
-                       resp_needed = 1;
-               } else if (os_strcasecmp(name, "Add") == 0) {
-                       int res = oma_dm_add(ctx, child, pps, pps_fname);
-                       cmdid++;
-                       locuri = oma_dm_get_target_locuri(ctx, child);
-                       if (locuri == NULL)
-                               res = DM_RESP_BAD_REQUEST;
-                       add_status(ctx, syncbody, server_msgid, server_cmdid,
-                                  cmdid, name, res, locuri);
-                       os_free(locuri);
-                       resp_needed = 1;
-               } else if (os_strcasecmp(name, "Replace") == 0) {
-                       int res;
-                       res = oma_dm_replace(ctx, child, pps, pps_fname);
-                       cmdid++;
-                       locuri = oma_dm_get_target_locuri(ctx, child);
-                       if (locuri == NULL)
-                               res = DM_RESP_BAD_REQUEST;
-                       add_status(ctx, syncbody, server_msgid, server_cmdid,
-                                  cmdid, name, res, locuri);
-                       os_free(locuri);
-                       resp_needed = 1;
-               } else if (os_strcasecmp(name, "Status") == 0) {
-                       /* TODO: Verify success */
-               } else if (os_strcasecmp(name, "Get") == 0) {
-                       int res;
-                       char *value;
-                       res = oma_dm_get(ctx, child, pps, pps_fname, &value);
-                       cmdid++;
-                       locuri = oma_dm_get_target_locuri(ctx, child);
-                       if (locuri == NULL)
-                               res = DM_RESP_BAD_REQUEST;
-                       add_status(ctx, syncbody, server_msgid, server_cmdid,
-                                  cmdid, name, res, locuri);
-                       if (res == DM_RESP_OK && value) {
-                               cmdid++;
-                               add_results(ctx, syncbody, server_msgid,
-                                           server_cmdid, cmdid, locuri, value);
-                       }
-                       os_free(locuri);
-                       xml_node_get_text_free(ctx->xml, value);
-                       resp_needed = 1;
-#if 0 /* TODO: MUST support */
-               } else if (os_strcasecmp(name, "Delete") == 0) {
-#endif
-#if 0 /* TODO: MUST support */
-               } else if (os_strcasecmp(name, "Sequence") == 0) {
-#endif
-               } else if (os_strcasecmp(name, "Final") == 0) {
-                       final = 1;
-                       break;
-               } else {
-                       locuri = oma_dm_get_target_locuri(ctx, child);
-                       add_status(ctx, syncbody, server_msgid, server_cmdid,
-                                  cmdid, name, DM_RESP_COMMAND_NOT_IMPLEMENTED,
-                                  locuri);
-                       os_free(locuri);
-                       resp_needed = 1;
-               }
-       }
-
-       if (!final) {
-               wpa_printf(MSG_INFO, "Final node not found");
-               xml_node_free(ctx->xml, syncml);
-               os_free(resp_uri);
-               return NULL;
-       }
-
-       if (!resp_needed) {
-               wpa_printf(MSG_INFO, "Exchange completed - no response needed");
-               xml_node_free(ctx->xml, syncml);
-               os_free(resp_uri);
-               return NULL;
-       }
-
-       xml_node_create(ctx->xml, syncbody, NULL, "Final");
-
-       debug_dump_node(ctx, "OMA-DM Package 3", syncml);
-
-       *ret_resp_uri = resp_uri;
-       return syncml;
-}
-
-
-int cmd_oma_dm_prov(struct hs20_osu_client *ctx, const char *url)
-{
-       xml_node_t *syncml, *resp;
-       char *resp_uri = NULL;
-       int msgid = 0;
-
-       if (url == NULL) {
-               wpa_printf(MSG_INFO, "Invalid prov command (missing URL)");
-               return -1;
-       }
-
-       wpa_printf(MSG_INFO, "OMA-DM credential provisioning requested");
-       write_summary(ctx, "OMA-DM credential provisioning");
-
-       msgid++;
-       syncml = build_oma_dm_1_sub_reg(ctx, url, msgid);
-       if (syncml == NULL)
-               return -1;
-
-       while (syncml) {
-               resp = oma_dm_send_recv(ctx, resp_uri ? resp_uri : url,
-                                       syncml, NULL, NULL, NULL, NULL, NULL);
-               if (resp == NULL)
-                       return -1;
-
-               msgid++;
-               syncml = oma_dm_process(ctx, url, resp, msgid, &resp_uri,
-                                       NULL, NULL);
-               xml_node_free(ctx->xml, resp);
-       }
-
-       os_free(resp_uri);
-
-       return ctx->pps_cred_set ? 0 : -1;
-}
-
-
-int cmd_oma_dm_sim_prov(struct hs20_osu_client *ctx, const char *url)
-{
-       xml_node_t *syncml, *resp;
-       char *resp_uri = NULL;
-       int msgid = 0;
-
-       if (url == NULL) {
-               wpa_printf(MSG_INFO, "Invalid prov command (missing URL)");
-               return -1;
-       }
-
-       wpa_printf(MSG_INFO, "OMA-DM SIM provisioning requested");
-       ctx->no_reconnect = 2;
-
-       wpa_printf(MSG_INFO, "Wait for IP address before starting SIM provisioning");
-       write_summary(ctx, "Wait for IP address before starting SIM provisioning");
-
-       if (wait_ip_addr(ctx->ifname, 15) < 0) {
-               wpa_printf(MSG_INFO, "Could not get IP address for WLAN - try connection anyway");
-       }
-       write_summary(ctx, "OMA-DM SIM provisioning");
-
-       msgid++;
-       syncml = build_oma_dm_1_sub_prov(ctx, url, msgid);
-       if (syncml == NULL)
-               return -1;
-
-       while (syncml) {
-               resp = oma_dm_send_recv(ctx, resp_uri ? resp_uri : url,
-                                       syncml, NULL, NULL, NULL, NULL, NULL);
-               if (resp == NULL)
-                       return -1;
-
-               msgid++;
-               syncml = oma_dm_process(ctx, url, resp, msgid, &resp_uri,
-                                       NULL, NULL);
-               xml_node_free(ctx->xml, resp);
-       }
-
-       os_free(resp_uri);
-
-       if (ctx->pps_cred_set) {
-               wpa_printf(MSG_INFO, "Updating wpa_supplicant credentials");
-               cmd_set_pps(ctx, ctx->pps_fname);
-
-               wpa_printf(MSG_INFO, "Requesting reconnection with updated configuration");
-               write_summary(ctx, "Requesting reconnection with updated configuration");
-               if (wpa_command(ctx->ifname, "INTERWORKING_SELECT auto") < 0) {
-                       wpa_printf(MSG_INFO, "Failed to request wpa_supplicant to reconnect");
-                       write_summary(ctx, "Failed to request wpa_supplicant to reconnect");
-                       return -1;
-               }
-       }
-
-       return ctx->pps_cred_set ? 0 : -1;
-}
-
-
-void oma_dm_pol_upd(struct hs20_osu_client *ctx, const char *address,
-                   const char *pps_fname,
-                   const char *client_cert, const char *client_key,
-                   const char *cred_username, const char *cred_password,
-                   xml_node_t *pps)
-{
-       xml_node_t *syncml, *resp;
-       char *resp_uri = NULL;
-       int msgid = 0;
-
-       wpa_printf(MSG_INFO, "OMA-DM policy update");
-       write_summary(ctx, "OMA-DM policy update");
-
-       msgid++;
-       syncml = build_oma_dm_1_pol_upd(ctx, address, msgid);
-       if (syncml == NULL)
-               return;
-
-       while (syncml) {
-               resp = oma_dm_send_recv(ctx, resp_uri ? resp_uri : address,
-                                       syncml, NULL, cred_username,
-                                       cred_password, client_cert, client_key);
-               if (resp == NULL)
-                       return;
-
-               msgid++;
-               syncml = oma_dm_process(ctx, address, resp, msgid, &resp_uri,
-                                       pps, pps_fname);
-               xml_node_free(ctx->xml, resp);
-       }
-
-       os_free(resp_uri);
-
-       if (ctx->pps_updated) {
-               wpa_printf(MSG_INFO, "Update wpa_supplicant credential based on updated PPS MO");
-               write_summary(ctx, "Update wpa_supplicant credential based on updated PPS MO and request connection");
-               cmd_set_pps(ctx, pps_fname);
-               if (wpa_command(ctx->ifname, "INTERWORKING_SELECT auto") < 0) {
-                       wpa_printf(MSG_INFO,
-                                  "Failed to request wpa_supplicant to reconnect");
-                       write_summary(ctx,
-                                     "Failed to request wpa_supplicant to reconnect");
-               }
-       }
-}
-
-
-void oma_dm_sub_rem(struct hs20_osu_client *ctx, const char *address,
-                   const char *pps_fname,
-                   const char *client_cert, const char *client_key,
-                   const char *cred_username, const char *cred_password,
-                   xml_node_t *pps)
-{
-       xml_node_t *syncml, *resp;
-       char *resp_uri = NULL;
-       int msgid = 0;
-
-       wpa_printf(MSG_INFO, "OMA-DM subscription remediation");
-       write_summary(ctx, "OMA-DM subscription remediation");
-
-       msgid++;
-       syncml = build_oma_dm_1_sub_rem(ctx, address, msgid);
-       if (syncml == NULL)
-               return;
-
-       while (syncml) {
-               resp = oma_dm_send_recv(ctx, resp_uri ? resp_uri : address,
-                                       syncml, NULL, cred_username,
-                                       cred_password, client_cert, client_key);
-               if (resp == NULL)
-                       return;
-
-               msgid++;
-               syncml = oma_dm_process(ctx, address, resp, msgid, &resp_uri,
-                                       pps, pps_fname);
-               xml_node_free(ctx->xml, resp);
-       }
-
-       os_free(resp_uri);
-
-       wpa_printf(MSG_INFO, "Update wpa_supplicant credential based on updated PPS MO and request reconnection");
-       write_summary(ctx, "Update wpa_supplicant credential based on updated PPS MO and request reconnection");
-       cmd_set_pps(ctx, pps_fname);
-       if (wpa_command(ctx->ifname, "INTERWORKING_SELECT auto") < 0) {
-               wpa_printf(MSG_INFO, "Failed to request wpa_supplicant to reconnect");
-               write_summary(ctx, "Failed to request wpa_supplicant to reconnect");
-       }
-}
-
-
-void cmd_oma_dm_add(struct hs20_osu_client *ctx, const char *pps_fname,
-                   const char *add_fname)
-{
-       xml_node_t *pps, *add;
-       int res;
-
-       ctx->fqdn = os_strdup("wi-fi.org");
-
-       pps = node_from_file(ctx->xml, pps_fname);
-       if (pps == NULL) {
-               wpa_printf(MSG_INFO, "PPS file %s could not be parsed",
-                          pps_fname);
-               return;
-       }
-
-       add = node_from_file(ctx->xml, add_fname);
-       if (add == NULL) {
-               wpa_printf(MSG_INFO, "Add file %s could not be parsed",
-                          add_fname);
-               xml_node_free(ctx->xml, pps);
-               return;
-       }
-
-       res = oma_dm_add(ctx, add, pps, pps_fname);
-       wpa_printf(MSG_INFO, "oma_dm_add --> %d", res);
-
-       xml_node_free(ctx->xml, pps);
-       xml_node_free(ctx->xml, add);
-}
-
-
-void cmd_oma_dm_replace(struct hs20_osu_client *ctx, const char *pps_fname,
-                       const char *replace_fname)
-{
-       xml_node_t *pps, *replace;
-       int res;
-
-       ctx->fqdn = os_strdup("wi-fi.org");
-
-       pps = node_from_file(ctx->xml, pps_fname);
-       if (pps == NULL) {
-               wpa_printf(MSG_INFO, "PPS file %s could not be parsed",
-                          pps_fname);
-               return;
-       }
-
-       replace = node_from_file(ctx->xml, replace_fname);
-       if (replace == NULL) {
-               wpa_printf(MSG_INFO, "Replace file %s could not be parsed",
-                          replace_fname);
-               xml_node_free(ctx->xml, pps);
-               return;
-       }
-
-       res = oma_dm_replace(ctx, replace, pps, pps_fname);
-       wpa_printf(MSG_INFO, "oma_dm_replace --> %d", res);
-
-       xml_node_free(ctx->xml, pps);
-       xml_node_free(ctx->xml, replace);
-}
index 2ca85f96ce3f8cd77282c204b418a1e0c30e06af..f679df4b18bf7721ee048460d0df8ba0ae7468e5 100644 (file)
@@ -9,9 +9,6 @@
 #include "includes.h"
 #include <time.h>
 #include <sys/stat.h>
-#ifdef ANDROID
-#include "private/android_filesystem_config.h"
-#endif /* ANDROID */
 
 #include "common.h"
 #include "utils/browser.h"
 #include "crypto/sha256.h"
 #include "osu_client.h"
 
-const char *spp_xsd_fname = "spp.xsd";
+static void write_summary(struct hs20_osu_client *ctx, const char *fmt, ...);
 
-
-void write_result(struct hs20_osu_client *ctx, const char *fmt, ...)
+static void write_result(struct hs20_osu_client *ctx, const char *fmt, ...)
 {
        va_list ap;
        FILE *f;
@@ -54,7 +50,7 @@ void write_result(struct hs20_osu_client *ctx, const char *fmt, ...)
 }
 
 
-void write_summary(struct hs20_osu_client *ctx, const char *fmt, ...)
+static void write_summary(struct hs20_osu_client *ctx, const char *fmt, ...)
 {
        va_list ap;
        FILE *f;
@@ -74,231 +70,6 @@ void write_summary(struct hs20_osu_client *ctx, const char *fmt, ...)
 }
 
 
-void debug_dump_node(struct hs20_osu_client *ctx, const char *title,
-                    xml_node_t *node)
-{
-       char *str = xml_node_to_str(ctx->xml, node);
-       wpa_printf(MSG_DEBUG, "[hs20] %s: '%s'", title, str);
-       free(str);
-}
-
-
-static int valid_fqdn(const char *fqdn)
-{
-       const char *pos;
-
-       /* TODO: could make this more complete.. */
-       if (strchr(fqdn, '.') == 0 || strlen(fqdn) > 255)
-               return 0;
-       for (pos = fqdn; *pos; pos++) {
-               if (*pos >= 'a' && *pos <= 'z')
-                       continue;
-               if (*pos >= 'A' && *pos <= 'Z')
-                       continue;
-               if (*pos >= '0' && *pos <= '9')
-                       continue;
-               if (*pos == '-' || *pos == '.' || *pos == '_')
-                       continue;
-               return 0;
-       }
-       return 1;
-}
-
-
-static int android_update_permission(const char *path, mode_t mode)
-{
-#ifdef ANDROID
-       /* we need to change file/folder permission for Android */
-
-       if (!path) {
-               wpa_printf(MSG_ERROR, "file path null");
-               return -1;
-       }
-
-       /* Allow processes running with Group ID as AID_WIFI,
-        * to read files from SP, SP/<fqdn>, Cert and osu-info directories */
-       if (lchown(path, -1, AID_WIFI)) {
-               wpa_printf(MSG_INFO, "CTRL: Could not lchown directory: %s",
-                          strerror(errno));
-               return -1;
-       }
-
-       if (chmod(path, mode) < 0) {
-               wpa_printf(MSG_INFO, "CTRL: Could not chmod directory: %s",
-                          strerror(errno));
-               return -1;
-       }
-#endif  /* ANDROID */
-
-       return 0;
-}
-
-
-int osu_get_certificate(struct hs20_osu_client *ctx, xml_node_t *getcert)
-{
-       xml_node_t *node;
-       char *url, *user = NULL, *pw = NULL;
-       char *proto;
-       int ret = -1;
-
-       proto = xml_node_get_attr_value(ctx->xml, getcert,
-                                       "enrollmentProtocol");
-       if (!proto)
-               return -1;
-       wpa_printf(MSG_INFO, "getCertificate - enrollmentProtocol=%s", proto);
-       write_summary(ctx, "getCertificate - enrollmentProtocol=%s", proto);
-       if (os_strcasecmp(proto, "EST") != 0) {
-               wpa_printf(MSG_INFO, "Unsupported enrollmentProtocol");
-               xml_node_get_attr_value_free(ctx->xml, proto);
-               return -1;
-       }
-       xml_node_get_attr_value_free(ctx->xml, proto);
-
-       node = get_node(ctx->xml, getcert, "enrollmentServerURI");
-       if (node == NULL) {
-               wpa_printf(MSG_INFO, "Could not find enrollmentServerURI node");
-               xml_node_get_attr_value_free(ctx->xml, proto);
-               return -1;
-       }
-       url = xml_node_get_text(ctx->xml, node);
-       if (url == NULL) {
-               wpa_printf(MSG_INFO, "Could not get URL text");
-               return -1;
-       }
-       wpa_printf(MSG_INFO, "enrollmentServerURI: %s", url);
-       write_summary(ctx, "enrollmentServerURI: %s", url);
-
-       node = get_node(ctx->xml, getcert, "estUserID");
-       if (node == NULL && !ctx->client_cert_present) {
-               wpa_printf(MSG_INFO, "Could not find estUserID node");
-               goto fail;
-       }
-       if (node) {
-               user = xml_node_get_text(ctx->xml, node);
-               if (user == NULL) {
-                       wpa_printf(MSG_INFO, "Could not get estUserID text");
-                       goto fail;
-               }
-               wpa_printf(MSG_INFO, "estUserID: %s", user);
-               write_summary(ctx, "estUserID: %s", user);
-       }
-
-       node = get_node(ctx->xml, getcert, "estPassword");
-       if (node == NULL && !ctx->client_cert_present) {
-               wpa_printf(MSG_INFO, "Could not find estPassword node");
-               goto fail;
-       }
-       if (node) {
-               pw = xml_node_get_base64_text(ctx->xml, node, NULL);
-               if (pw == NULL) {
-                       wpa_printf(MSG_INFO, "Could not get estPassword text");
-                       goto fail;
-               }
-               wpa_printf(MSG_INFO, "estPassword: %s", pw);
-       }
-
-       mkdir("Cert", S_IRWXU);
-       android_update_permission("Cert", S_IRWXU | S_IRWXG);
-
-       if (est_load_cacerts(ctx, url) < 0 ||
-           est_build_csr(ctx, url) < 0 ||
-           est_simple_enroll(ctx, url, user, pw) < 0)
-               goto fail;
-
-       ret = 0;
-fail:
-       xml_node_get_text_free(ctx->xml, url);
-       xml_node_get_text_free(ctx->xml, user);
-       xml_node_get_text_free(ctx->xml, pw);
-
-       return ret;
-}
-
-
-static int process_est_cert(struct hs20_osu_client *ctx, xml_node_t *cert,
-                           const char *fqdn)
-{
-       u8 digest1[SHA256_MAC_LEN], digest2[SHA256_MAC_LEN];
-       char *der, *pem;
-       size_t der_len, pem_len;
-       char *fingerprint;
-       char buf[200];
-
-       wpa_printf(MSG_INFO, "PPS for certificate credential - fqdn=%s", fqdn);
-
-       fingerprint = xml_node_get_text(ctx->xml, cert);
-       if (fingerprint == NULL)
-               return -1;
-       if (hexstr2bin(fingerprint, digest1, SHA256_MAC_LEN) < 0) {
-               wpa_printf(MSG_INFO, "Invalid SHA256 hash value");
-               write_result(ctx, "Invalid client certificate SHA256 hash value in PPS");
-               xml_node_get_text_free(ctx->xml, fingerprint);
-               return -1;
-       }
-       xml_node_get_text_free(ctx->xml, fingerprint);
-
-       der = os_readfile("Cert/est_cert.der", &der_len);
-       if (der == NULL) {
-               wpa_printf(MSG_INFO, "Could not find client certificate from EST");
-               write_result(ctx, "Could not find client certificate from EST");
-               return -1;
-       }
-
-       if (sha256_vector(1, (const u8 **) &der, &der_len, digest2) < 0) {
-               os_free(der);
-               return -1;
-       }
-       os_free(der);
-
-       if (os_memcmp(digest1, digest2, sizeof(digest1)) != 0) {
-               wpa_printf(MSG_INFO, "Client certificate from EST does not match fingerprint from PPS MO");
-               write_result(ctx, "Client certificate from EST does not match fingerprint from PPS MO");
-               return -1;
-       }
-
-       wpa_printf(MSG_INFO, "Client certificate from EST matches PPS MO");
-       unlink("Cert/est_cert.der");
-
-       os_snprintf(buf, sizeof(buf), "SP/%s/client-ca.pem", fqdn);
-       if (rename("Cert/est-cacerts.pem", buf) < 0) {
-               wpa_printf(MSG_INFO, "Could not move est-cacerts.pem to client-ca.pem: %s",
-                          strerror(errno));
-               return -1;
-       }
-       pem = os_readfile(buf, &pem_len);
-
-       os_snprintf(buf, sizeof(buf), "SP/%s/client-cert.pem", fqdn);
-       if (rename("Cert/est_cert.pem", buf) < 0) {
-               wpa_printf(MSG_INFO, "Could not move est_cert.pem to client-cert.pem: %s",
-                          strerror(errno));
-               os_free(pem);
-               return -1;
-       }
-
-       if (pem) {
-               FILE *f = fopen(buf, "a");
-               if (f) {
-                       fwrite(pem, pem_len, 1, f);
-                       fclose(f);
-               }
-               os_free(pem);
-       }
-
-       os_snprintf(buf, sizeof(buf), "SP/%s/client-key.pem", fqdn);
-       if (rename("Cert/privkey-plain.pem", buf) < 0) {
-               wpa_printf(MSG_INFO, "Could not move privkey-plain.pem to client-key.pem: %s",
-                          strerror(errno));
-               return -1;
-       }
-
-       unlink("Cert/est-req.b64");
-       unlink("Cert/est-req.pem");
-       rmdir("Cert");
-
-       return 0;
-}
-
-
 #define TMP_CERT_DL_FILE "tmp-cert-download"
 
 static int download_cert(struct hs20_osu_client *ctx, xml_node_t *params,
@@ -337,12 +108,10 @@ static int download_cert(struct hs20_osu_client *ctx, xml_node_t *params,
        xml_node_get_text_free(ctx->xml, hash);
 
        write_summary(ctx, "Download certificate from %s", url);
-       ctx->no_osu_cert_validation = 1;
        http_ocsp_set(ctx->http, 1);
        res = http_download_file(ctx->http, url, TMP_CERT_DL_FILE, NULL);
        http_ocsp_set(ctx->http,
                      (ctx->workarounds & WORKAROUND_OCSP_OPTIONAL) ? 1 : 2);
-       ctx->no_osu_cert_validation = 0;
        xml_node_get_text_free(ctx->xml, url);
        if (res < 0)
                return -1;
@@ -392,60 +161,6 @@ static int download_cert(struct hs20_osu_client *ctx, xml_node_t *params,
 }
 
 
-static int cmd_dl_osu_ca(struct hs20_osu_client *ctx, const char *pps_fname,
-                        const char *ca_fname)
-{
-       xml_node_t *pps, *node;
-       int ret;
-
-       pps = node_from_file(ctx->xml, pps_fname);
-       if (pps == NULL) {
-               wpa_printf(MSG_INFO, "Could not read or parse '%s'", pps_fname);
-               return -1;
-       }
-
-       node = get_child_node(ctx->xml, pps,
-                             "SubscriptionUpdate/TrustRoot");
-       if (node == NULL) {
-               wpa_printf(MSG_INFO, "No SubscriptionUpdate/TrustRoot/CertURL found from PPS");
-               xml_node_free(ctx->xml, pps);
-               return -1;
-       }
-
-       ret = download_cert(ctx, node, ca_fname);
-       xml_node_free(ctx->xml, pps);
-
-       return ret;
-}
-
-
-static int cmd_dl_polupd_ca(struct hs20_osu_client *ctx, const char *pps_fname,
-                           const char *ca_fname)
-{
-       xml_node_t *pps, *node;
-       int ret;
-
-       pps = node_from_file(ctx->xml, pps_fname);
-       if (pps == NULL) {
-               wpa_printf(MSG_INFO, "Could not read or parse '%s'", pps_fname);
-               return -1;
-       }
-
-       node = get_child_node(ctx->xml, pps,
-                             "Policy/PolicyUpdate/TrustRoot");
-       if (node == NULL) {
-               wpa_printf(MSG_INFO, "No Policy/PolicyUpdate/TrustRoot/CertURL found from PPS");
-               xml_node_free(ctx->xml, pps);
-               return -2;
-       }
-
-       ret = download_cert(ctx, node, ca_fname);
-       xml_node_free(ctx->xml, pps);
-
-       return ret;
-}
-
-
 static int cmd_dl_aaa_ca(struct hs20_osu_client *ctx, const char *pps_fname,
                         const char *ca_fname)
 {
@@ -480,418 +195,126 @@ static int cmd_dl_aaa_ca(struct hs20_osu_client *ctx, const char *pps_fname,
 }
 
 
-static int download_trust_roots(struct hs20_osu_client *ctx,
-                               const char *pps_fname)
+/* Remove old credentials based on HomeSP/FQDN */
+static void remove_sp_creds(struct hs20_osu_client *ctx, const char *fqdn)
 {
-       char *dir, *pos;
-       char fname[300];
-       int ret, ret1;
+       char cmd[300];
+       os_snprintf(cmd, sizeof(cmd), "REMOVE_CRED provisioning_sp=%s", fqdn);
+       if (wpa_command(ctx->ifname, cmd) < 0)
+               wpa_printf(MSG_INFO, "Failed to remove old credential(s)");
+}
 
-       dir = os_strdup(pps_fname);
-       if (dir == NULL)
-               return -1;
-       pos = os_strrchr(dir, '/');
-       if (pos == NULL) {
-               os_free(dir);
-               return -1;
-       }
-       *pos = '\0';
 
-       snprintf(fname, sizeof(fname), "%s/ca.pem", dir);
-       ret = cmd_dl_osu_ca(ctx, pps_fname, fname);
-       snprintf(fname, sizeof(fname), "%s/polupd-ca.pem", dir);
-       ret1 = cmd_dl_polupd_ca(ctx, pps_fname, fname);
-       if (ret == 0 && ret1 == -1)
-               ret = -1;
-       snprintf(fname, sizeof(fname), "%s/aaa-ca.pem", dir);
-       ret1 = cmd_dl_aaa_ca(ctx, pps_fname, fname);
-       if (ret == 0 && ret1 == -1)
-               ret = -1;
+static void set_pps_cred_policy_spe(struct hs20_osu_client *ctx, int id,
+                                   xml_node_t *spe)
+{
+       xml_node_t *ssid;
+       char *txt;
+
+       ssid = get_node(ctx->xml, spe, "SSID");
+       if (ssid == NULL)
+               return;
+       txt = xml_node_get_text(ctx->xml, ssid);
+       if (txt == NULL)
+               return;
+       wpa_printf(MSG_DEBUG, "- Policy/SPExclusionList/<X+>/SSID = %s", txt);
+       if (set_cred_quoted(ctx->ifname, id, "excluded_ssid", txt) < 0)
+               wpa_printf(MSG_INFO, "Failed to set cred excluded_ssid");
+       xml_node_get_text_free(ctx->xml, txt);
+}
 
-       os_free(dir);
 
-       return ret;
+static void set_pps_cred_policy_spel(struct hs20_osu_client *ctx, int id,
+                                    xml_node_t *spel)
+{
+       xml_node_t *child;
+
+       xml_node_for_each_child(ctx->xml, child, spel) {
+               xml_node_for_each_check(ctx->xml, child);
+               set_pps_cred_policy_spe(ctx, id, child);
+       }
 }
 
 
-static int server_dnsname_suffix_match(struct hs20_osu_client *ctx,
-                                      const char *fqdn)
+static void set_pps_cred_policy_prp(struct hs20_osu_client *ctx, int id,
+                                   xml_node_t *prp)
 {
-       size_t match_len, len, i;
-       const char *val;
+       xml_node_t *node;
+       char *txt = NULL, *pos;
+       char *prio, *country_buf = NULL;
+       const char *country;
+       char val[200];
+       int priority;
 
-       match_len = os_strlen(fqdn);
+       node = get_node(ctx->xml, prp, "Priority");
+       if (node == NULL)
+               return;
+       prio = xml_node_get_text(ctx->xml, node);
+       if (prio == NULL)
+               return;
+       wpa_printf(MSG_INFO, "- Policy/PreferredRoamingPartnerList/<X+>/Priority = %s",
+                  prio);
+       priority = atoi(prio);
+       xml_node_get_text_free(ctx->xml, prio);
 
-       for (i = 0; i < ctx->server_dnsname_count; i++) {
-               wpa_printf(MSG_INFO,
-                          "Checking suffix match against server dNSName %s",
-                          ctx->server_dnsname[i]);
-               val = ctx->server_dnsname[i];
-               len = os_strlen(val);
+       node = get_node(ctx->xml, prp, "Country");
+       if (node) {
+               country_buf = xml_node_get_text(ctx->xml, node);
+               if (country_buf == NULL)
+                       return;
+               country = country_buf;
+               wpa_printf(MSG_INFO, "- Policy/PreferredRoamingPartnerList/<X+>/Country = %s",
+                          country);
+       } else {
+               country = "*";
+       }
 
-               if (match_len > len)
-                       continue;
+       node = get_node(ctx->xml, prp, "FQDN_Match");
+       if (node == NULL)
+               goto out;
+       txt = xml_node_get_text(ctx->xml, node);
+       if (txt == NULL)
+               goto out;
+       wpa_printf(MSG_INFO, "- Policy/PreferredRoamingPartnerList/<X+>/FQDN_Match = %s",
+                  txt);
+       pos = strrchr(txt, ',');
+       if (pos == NULL)
+               goto out;
+       *pos++ = '\0';
 
-               if (os_strncasecmp(val + len - match_len, fqdn, match_len) != 0)
-                       continue; /* no match */
+       snprintf(val, sizeof(val), "%s,%d,%d,%s", txt,
+                strcmp(pos, "includeSubdomains") != 0, priority, country);
+       if (set_cred_quoted(ctx->ifname, id, "roaming_partner", val) < 0)
+               wpa_printf(MSG_INFO, "Failed to set cred roaming_partner");
+out:
+       xml_node_get_text_free(ctx->xml, country_buf);
+       xml_node_get_text_free(ctx->xml, txt);
+}
 
-               if (match_len == len)
-                       return 1; /* exact match */
 
-               if (val[len - match_len - 1] == '.')
-                       return 1; /* full label match completes suffix match */
+static void set_pps_cred_policy_prpl(struct hs20_osu_client *ctx, int id,
+                                    xml_node_t *prpl)
+{
+       xml_node_t *child;
 
-               /* Reject due to incomplete label match */
+       xml_node_for_each_child(ctx->xml, child, prpl) {
+               xml_node_for_each_check(ctx->xml, child);
+               set_pps_cred_policy_prp(ctx, id, child);
        }
-
-       /* None of the dNSName(s) matched */
-       return 0;
 }
 
 
-int hs20_add_pps_mo(struct hs20_osu_client *ctx, const char *uri,
-                   xml_node_t *add_mo, char *fname, size_t fname_len)
+static void set_pps_cred_policy_min_backhaul(struct hs20_osu_client *ctx, int id,
+                                            xml_node_t *min_backhaul)
 {
-       char *str;
-       char *fqdn, *pos;
-       xml_node_t *tnds, *mo, *cert;
-       const char *name;
-       int ret;
+       xml_node_t *node;
+       char *type, *dl = NULL, *ul = NULL;
+       int home;
 
-       if (strncmp(uri, "./Wi-Fi/", 8) != 0) {
-               wpa_printf(MSG_INFO, "Unsupported location for addMO to add PPS MO: '%s'",
-                          uri);
-               write_result(ctx, "Unsupported location for addMO to add PPS MO: '%s'",
-                            uri);
-               return -1;
-       }
-
-       fqdn = strdup(uri + 8);
-       if (fqdn == NULL)
-               return -1;
-       pos = strchr(fqdn, '/');
-       if (pos) {
-               if (os_strcasecmp(pos, "/PerProviderSubscription") != 0) {
-                       wpa_printf(MSG_INFO, "Unsupported location for addMO to add PPS MO (extra directory): '%s'",
-                                  uri);
-                       write_result(ctx, "Unsupported location for addMO to "
-                                    "add PPS MO (extra directory): '%s'", uri);
-                       free(fqdn);
-                       return -1;
-               }
-               *pos = '\0'; /* remove trailing slash and PPS node name */
-       }
-       wpa_printf(MSG_INFO, "SP FQDN: %s", fqdn);
-
-       if (!server_dnsname_suffix_match(ctx, fqdn)) {
-               wpa_printf(MSG_INFO,
-                          "FQDN '%s' for new PPS MO did not have suffix match with server's dNSName values, count: %d",
-                          fqdn, (int) ctx->server_dnsname_count);
-               write_result(ctx, "FQDN '%s' for new PPS MO did not have suffix match with server's dNSName values",
-                            fqdn);
-               free(fqdn);
-               return -1;
-       }
-
-       if (!valid_fqdn(fqdn)) {
-               wpa_printf(MSG_INFO, "Invalid FQDN '%s'", fqdn);
-               write_result(ctx, "Invalid FQDN '%s'", fqdn);
-               free(fqdn);
-               return -1;
-       }
-
-       mkdir("SP", S_IRWXU);
-       snprintf(fname, fname_len, "SP/%s", fqdn);
-       if (mkdir(fname, S_IRWXU) < 0) {
-               if (errno != EEXIST) {
-                       int err = errno;
-                       wpa_printf(MSG_INFO, "mkdir(%s) failed: %s",
-                                  fname, strerror(err));
-                       free(fqdn);
-                       return -1;
-               }
-       }
-
-       android_update_permission("SP", S_IRWXU | S_IRWXG);
-       android_update_permission(fname, S_IRWXU | S_IRWXG);
-
-       snprintf(fname, fname_len, "SP/%s/pps.xml", fqdn);
-
-       if (os_file_exists(fname)) {
-               wpa_printf(MSG_INFO, "PPS file '%s' exists - reject addMO",
-                          fname);
-               write_result(ctx, "PPS file '%s' exists - reject addMO",
-                            fname);
-               free(fqdn);
-               return -2;
-       }
-       wpa_printf(MSG_INFO, "Using PPS file: %s", fname);
-
-       str = xml_node_get_text(ctx->xml, add_mo);
-       if (str == NULL) {
-               wpa_printf(MSG_INFO, "Could not extract MO text");
-               free(fqdn);
-               return -1;
-       }
-       wpa_printf(MSG_DEBUG, "[hs20] addMO text: '%s'", str);
-
-       tnds = xml_node_from_buf(ctx->xml, str);
-       xml_node_get_text_free(ctx->xml, str);
-       if (tnds == NULL) {
-               wpa_printf(MSG_INFO, "[hs20] Could not parse addMO text");
-               free(fqdn);
-               return -1;
-       }
-
-       mo = tnds_to_mo(ctx->xml, tnds);
-       if (mo == NULL) {
-               wpa_printf(MSG_INFO, "[hs20] Could not parse addMO TNDS text");
-               free(fqdn);
-               return -1;
-       }
-
-       debug_dump_node(ctx, "Parsed TNDS", mo);
-
-       name = xml_node_get_localname(ctx->xml, mo);
-       if (os_strcasecmp(name, "PerProviderSubscription") != 0) {
-               wpa_printf(MSG_INFO, "[hs20] Unexpected PPS MO root node name '%s'",
-                          name);
-               free(fqdn);
-               return -1;
-       }
-
-       cert = get_child_node(ctx->xml, mo,
-                             "Credential/DigitalCertificate/"
-                             "CertSHA256Fingerprint");
-       if (cert && process_est_cert(ctx, cert, fqdn) < 0) {
-               xml_node_free(ctx->xml, mo);
-               free(fqdn);
-               return -1;
-       }
-       free(fqdn);
-
-       if (node_to_file(ctx->xml, fname, mo) < 0) {
-               wpa_printf(MSG_INFO, "Could not write MO to file");
-               xml_node_free(ctx->xml, mo);
-               return -1;
-       }
-       xml_node_free(ctx->xml, mo);
-
-       wpa_printf(MSG_INFO, "A new PPS MO added as '%s'", fname);
-       write_summary(ctx, "A new PPS MO added as '%s'", fname);
-
-       ret = download_trust_roots(ctx, fname);
-       if (ret < 0) {
-               wpa_printf(MSG_INFO, "Remove invalid PPS MO file");
-               write_summary(ctx, "Remove invalid PPS MO file");
-               unlink(fname);
-       }
-
-       return ret;
-}
-
-
-int update_pps_file(struct hs20_osu_client *ctx, const char *pps_fname,
-                   xml_node_t *pps)
-{
-       char *str;
-       FILE *f;
-       char backup[300];
-
-       if (ctx->client_cert_present) {
-               xml_node_t *cert;
-               cert = get_child_node(ctx->xml, pps,
-                                     "Credential/DigitalCertificate/"
-                                     "CertSHA256Fingerprint");
-               if (cert && os_file_exists("Cert/est_cert.der") &&
-                   process_est_cert(ctx, cert, ctx->fqdn) < 0) {
-                       wpa_printf(MSG_INFO, "EST certificate update processing failed on PPS MO update");
-                       return -1;
-               }
-       }
-
-       wpa_printf(MSG_INFO, "Updating PPS MO %s", pps_fname);
-
-       str = xml_node_to_str(ctx->xml, pps);
-       if (str == NULL) {
-               wpa_printf(MSG_ERROR, "No node found");
-               return -1;
-       }
-       wpa_printf(MSG_MSGDUMP, "[hs20] Updated PPS: '%s'", str);
-
-       snprintf(backup, sizeof(backup), "%s.bak", pps_fname);
-       rename(pps_fname, backup);
-       f = fopen(pps_fname, "w");
-       if (f == NULL) {
-               wpa_printf(MSG_INFO, "Could not write PPS");
-               rename(backup, pps_fname);
-               free(str);
-               return -1;
-       }
-       fprintf(f, "%s\n", str);
-       fclose(f);
-
-       free(str);
-
-       return 0;
-}
-
-
-void get_user_pw(struct hs20_osu_client *ctx, xml_node_t *pps,
-                const char *alt_loc, char **user, char **pw)
-{
-       xml_node_t *node;
-
-       node = get_child_node(ctx->xml, pps,
-                             "Credential/UsernamePassword/Username");
-       if (node)
-               *user = xml_node_get_text(ctx->xml, node);
-
-       node = get_child_node(ctx->xml, pps,
-                             "Credential/UsernamePassword/Password");
-       if (node)
-               *pw = xml_node_get_base64_text(ctx->xml, node, NULL);
-
-       node = get_child_node(ctx->xml, pps, alt_loc);
-       if (node) {
-               xml_node_t *a;
-               a = get_node(ctx->xml, node, "Username");
-               if (a) {
-                       xml_node_get_text_free(ctx->xml, *user);
-                       *user = xml_node_get_text(ctx->xml, a);
-                       wpa_printf(MSG_INFO, "Use OSU username '%s'", *user);
-               }
-
-               a = get_node(ctx->xml, node, "Password");
-               if (a) {
-                       free(*pw);
-                       *pw = xml_node_get_base64_text(ctx->xml, a, NULL);
-                       wpa_printf(MSG_INFO, "Use OSU password");
-               }
-       }
-}
-
-
-/* Remove old credentials based on HomeSP/FQDN */
-static void remove_sp_creds(struct hs20_osu_client *ctx, const char *fqdn)
-{
-       char cmd[300];
-       os_snprintf(cmd, sizeof(cmd), "REMOVE_CRED provisioning_sp=%s", fqdn);
-       if (wpa_command(ctx->ifname, cmd) < 0)
-               wpa_printf(MSG_INFO, "Failed to remove old credential(s)");
-}
-
-
-static void set_pps_cred_policy_spe(struct hs20_osu_client *ctx, int id,
-                                   xml_node_t *spe)
-{
-       xml_node_t *ssid;
-       char *txt;
-
-       ssid = get_node(ctx->xml, spe, "SSID");
-       if (ssid == NULL)
-               return;
-       txt = xml_node_get_text(ctx->xml, ssid);
-       if (txt == NULL)
-               return;
-       wpa_printf(MSG_DEBUG, "- Policy/SPExclusionList/<X+>/SSID = %s", txt);
-       if (set_cred_quoted(ctx->ifname, id, "excluded_ssid", txt) < 0)
-               wpa_printf(MSG_INFO, "Failed to set cred excluded_ssid");
-       xml_node_get_text_free(ctx->xml, txt);
-}
-
-
-static void set_pps_cred_policy_spel(struct hs20_osu_client *ctx, int id,
-                                    xml_node_t *spel)
-{
-       xml_node_t *child;
-
-       xml_node_for_each_child(ctx->xml, child, spel) {
-               xml_node_for_each_check(ctx->xml, child);
-               set_pps_cred_policy_spe(ctx, id, child);
-       }
-}
-
-
-static void set_pps_cred_policy_prp(struct hs20_osu_client *ctx, int id,
-                                   xml_node_t *prp)
-{
-       xml_node_t *node;
-       char *txt = NULL, *pos;
-       char *prio, *country_buf = NULL;
-       const char *country;
-       char val[200];
-       int priority;
-
-       node = get_node(ctx->xml, prp, "Priority");
-       if (node == NULL)
-               return;
-       prio = xml_node_get_text(ctx->xml, node);
-       if (prio == NULL)
-               return;
-       wpa_printf(MSG_INFO, "- Policy/PreferredRoamingPartnerList/<X+>/Priority = %s",
-                  prio);
-       priority = atoi(prio);
-       xml_node_get_text_free(ctx->xml, prio);
-
-       node = get_node(ctx->xml, prp, "Country");
-       if (node) {
-               country_buf = xml_node_get_text(ctx->xml, node);
-               if (country_buf == NULL)
-                       return;
-               country = country_buf;
-               wpa_printf(MSG_INFO, "- Policy/PreferredRoamingPartnerList/<X+>/Country = %s",
-                          country);
-       } else {
-               country = "*";
-       }
-
-       node = get_node(ctx->xml, prp, "FQDN_Match");
-       if (node == NULL)
-               goto out;
-       txt = xml_node_get_text(ctx->xml, node);
-       if (txt == NULL)
-               goto out;
-       wpa_printf(MSG_INFO, "- Policy/PreferredRoamingPartnerList/<X+>/FQDN_Match = %s",
-                  txt);
-       pos = strrchr(txt, ',');
-       if (pos == NULL)
-               goto out;
-       *pos++ = '\0';
-
-       snprintf(val, sizeof(val), "%s,%d,%d,%s", txt,
-                strcmp(pos, "includeSubdomains") != 0, priority, country);
-       if (set_cred_quoted(ctx->ifname, id, "roaming_partner", val) < 0)
-               wpa_printf(MSG_INFO, "Failed to set cred roaming_partner");
-out:
-       xml_node_get_text_free(ctx->xml, country_buf);
-       xml_node_get_text_free(ctx->xml, txt);
-}
-
-
-static void set_pps_cred_policy_prpl(struct hs20_osu_client *ctx, int id,
-                                    xml_node_t *prpl)
-{
-       xml_node_t *child;
-
-       xml_node_for_each_child(ctx->xml, child, prpl) {
-               xml_node_for_each_check(ctx->xml, child);
-               set_pps_cred_policy_prp(ctx, id, child);
-       }
-}
-
-
-static void set_pps_cred_policy_min_backhaul(struct hs20_osu_client *ctx, int id,
-                                            xml_node_t *min_backhaul)
-{
-       xml_node_t *node;
-       char *type, *dl = NULL, *ul = NULL;
-       int home;
-
-       node = get_node(ctx->xml, min_backhaul, "NetworkType");
-       if (node == NULL) {
-               wpa_printf(MSG_INFO, "Ignore MinBackhaulThreshold without mandatory NetworkType node");
-               return;
+       node = get_node(ctx->xml, min_backhaul, "NetworkType");
+       if (node == NULL) {
+               wpa_printf(MSG_INFO, "Ignore MinBackhaulThreshold without mandatory NetworkType node");
+               return;
        }
 
        type = xml_node_get_text(ctx->xml, node);
@@ -1814,1341 +1237,193 @@ static void set_pps_credential(struct hs20_osu_client *ctx, int id,
                        set_pps_cred_sub_update(ctx, id, child);
                else if (os_strcasecmp(name, "HomeSP") == 0)
                        set_pps_cred_home_sp(ctx, id, child);
-               else if (os_strcasecmp(name, "SubscriptionParameters") == 0)
-                       set_pps_cred_sub_params(ctx, id, child);
-               else if (os_strcasecmp(name, "Credential") == 0)
-                       set_pps_cred_credential(ctx, id, child, fqdn);
-               else
-                       wpa_printf(MSG_INFO, "Unknown credential node '%s'",
-                                  name);
-       }
-}
-
-
-static void set_pps(struct hs20_osu_client *ctx, xml_node_t *pps,
-                   const char *fqdn)
-{
-       xml_node_t *child;
-       const char *name;
-       int id;
-       char *update_identifier = NULL;
-
-       /*
-        * TODO: Could consider more complex mechanism that would remove
-        * credentials only if there are changes in the information sent to
-        * wpa_supplicant.
-        */
-       remove_sp_creds(ctx, fqdn);
-
-       xml_node_for_each_child(ctx->xml, child, pps) {
-               xml_node_for_each_check(ctx->xml, child);
-               name = xml_node_get_localname(ctx->xml, child);
-               if (os_strcasecmp(name, "UpdateIdentifier") == 0) {
-                       update_identifier = xml_node_get_text(ctx->xml, child);
-                       if (update_identifier) {
-                               wpa_printf(MSG_INFO, "- UpdateIdentifier = %s",
-                                          update_identifier);
-                               break;
-                       }
-               }
-       }
-
-       xml_node_for_each_child(ctx->xml, child, pps) {
-               xml_node_for_each_check(ctx->xml, child);
-               name = xml_node_get_localname(ctx->xml, child);
-               if (os_strcasecmp(name, "UpdateIdentifier") == 0)
-                       continue;
-               id = add_cred(ctx->ifname);
-               if (id < 0) {
-                       wpa_printf(MSG_INFO, "Failed to add credential to wpa_supplicant");
-                       write_summary(ctx, "Failed to add credential to wpa_supplicant");
-                       break;
-               }
-               write_summary(ctx, "Add a credential to wpa_supplicant");
-               if (update_identifier &&
-                   set_cred(ctx->ifname, id, "update_identifier",
-                            update_identifier) < 0)
-                       wpa_printf(MSG_INFO, "Failed to set update_identifier");
-               if (set_cred_quoted(ctx->ifname, id, "provisioning_sp", fqdn) <
-                   0)
-                       wpa_printf(MSG_INFO, "Failed to set provisioning_sp");
-               wpa_printf(MSG_INFO, "credential localname: '%s'", name);
-               set_pps_credential(ctx, id, child, fqdn);
-               ctx->pps_cred_set = 1;
-       }
-
-       xml_node_get_text_free(ctx->xml, update_identifier);
-}
-
-
-void cmd_set_pps(struct hs20_osu_client *ctx, const char *pps_fname)
-{
-       xml_node_t *pps;
-       const char *fqdn;
-       char *fqdn_buf = NULL, *pos;
-
-       pps = node_from_file(ctx->xml, pps_fname);
-       if (pps == NULL) {
-               wpa_printf(MSG_INFO, "Could not read or parse '%s'", pps_fname);
-               return;
-       }
-
-       fqdn = os_strstr(pps_fname, "SP/");
-       if (fqdn) {
-               fqdn_buf = os_strdup(fqdn + 3);
-               if (fqdn_buf == NULL)
-                       return;
-               pos = os_strchr(fqdn_buf, '/');
-               if (pos)
-                       *pos = '\0';
-               fqdn = fqdn_buf;
-       } else
-               fqdn = "wi-fi.org";
-
-       wpa_printf(MSG_INFO, "Set PPS MO info to wpa_supplicant - SP FQDN %s",
-                  fqdn);
-       set_pps(ctx, pps, fqdn);
-
-       os_free(fqdn_buf);
-       xml_node_free(ctx->xml, pps);
-}
-
-
-static int cmd_get_fqdn(struct hs20_osu_client *ctx, const char *pps_fname)
-{
-       xml_node_t *pps, *node;
-       char *fqdn = NULL;
-
-       pps = node_from_file(ctx->xml, pps_fname);
-       if (pps == NULL) {
-               wpa_printf(MSG_INFO, "Could not read or parse '%s'", pps_fname);
-               return -1;
-       }
-
-       node = get_child_node(ctx->xml, pps, "HomeSP/FQDN");
-       if (node)
-               fqdn = xml_node_get_text(ctx->xml, node);
-
-       xml_node_free(ctx->xml, pps);
-
-       if (fqdn) {
-               FILE *f = fopen("pps-fqdn", "w");
-               if (f) {
-                       fprintf(f, "%s", fqdn);
-                       fclose(f);
-               }
-               xml_node_get_text_free(ctx->xml, fqdn);
-               return 0;
-       }
-
-       xml_node_get_text_free(ctx->xml, fqdn);
-       return -1;
-}
-
-
-static void cmd_to_tnds(struct hs20_osu_client *ctx, const char *in_fname,
-                       const char *out_fname, const char *urn, int use_path)
-{
-       xml_node_t *mo, *node;
-
-       mo = node_from_file(ctx->xml, in_fname);
-       if (mo == NULL) {
-               wpa_printf(MSG_INFO, "Could not read or parse '%s'", in_fname);
-               return;
-       }
-
-       node = mo_to_tnds(ctx->xml, mo, use_path, urn, NULL);
-       if (node) {
-               node_to_file(ctx->xml, out_fname, node);
-               xml_node_free(ctx->xml, node);
-       }
-
-       xml_node_free(ctx->xml, mo);
-}
-
-
-static void cmd_from_tnds(struct hs20_osu_client *ctx, const char *in_fname,
-                         const char *out_fname)
-{
-       xml_node_t *tnds, *mo;
-
-       tnds = node_from_file(ctx->xml, in_fname);
-       if (tnds == NULL) {
-               wpa_printf(MSG_INFO, "Could not read or parse '%s'", in_fname);
-               return;
-       }
-
-       mo = tnds_to_mo(ctx->xml, tnds);
-       if (mo) {
-               node_to_file(ctx->xml, out_fname, mo);
-               xml_node_free(ctx->xml, mo);
-       }
-
-       xml_node_free(ctx->xml, tnds);
-}
-
-
-struct osu_icon {
-       int id;
-       char lang[4];
-       char mime_type[256];
-       char filename[256];
-};
-
-struct osu_data {
-       char bssid[20];
-       char url[256];
-       unsigned int methods;
-       char osu_ssid[33];
-       char osu_ssid2[33];
-       char osu_nai[256];
-       char osu_nai2[256];
-       struct osu_lang_text friendly_name[MAX_OSU_VALS];
-       size_t friendly_name_count;
-       struct osu_lang_text serv_desc[MAX_OSU_VALS];
-       size_t serv_desc_count;
-       struct osu_icon icon[MAX_OSU_VALS];
-       size_t icon_count;
-};
-
-
-static struct osu_data * parse_osu_providers(const char *fname, size_t *count)
-{
-       FILE *f;
-       char buf[1000];
-       struct osu_data *osu = NULL, *last = NULL;
-       size_t osu_count = 0;
-       char *pos, *end;
-       int res;
-
-       f = fopen(fname, "r");
-       if (f == NULL) {
-               wpa_printf(MSG_ERROR, "Could not open %s", fname);
-               return NULL;
-       }
-
-       while (fgets(buf, sizeof(buf), f)) {
-               pos = strchr(buf, '\n');
-               if (pos)
-                       *pos = '\0';
-
-               if (strncmp(buf, "OSU-PROVIDER ", 13) == 0) {
-                       last = realloc(osu, (osu_count + 1) * sizeof(*osu));
-                       if (last == NULL)
-                               break;
-                       osu = last;
-                       last = &osu[osu_count++];
-                       memset(last, 0, sizeof(*last));
-                       res = os_snprintf(last->bssid, sizeof(last->bssid),
-                                         "%s", buf + 13);
-                       if (os_snprintf_error(sizeof(last->bssid), res))
-                               break;
-                       continue;
-               }
-               if (!last)
-                       continue;
-
-               if (strncmp(buf, "uri=", 4) == 0) {
-                       res = os_snprintf(last->url, sizeof(last->url),
-                                         "%s", buf + 4);
-                       if (os_snprintf_error(sizeof(last->url), res))
-                               break;
-                       continue;
-               }
-
-               if (strncmp(buf, "methods=", 8) == 0) {
-                       last->methods = strtol(buf + 8, NULL, 16);
-                       continue;
-               }
-
-               if (strncmp(buf, "osu_ssid=", 9) == 0) {
-                       res = os_snprintf(last->osu_ssid,
-                                         sizeof(last->osu_ssid),
-                                         "%s", buf + 9);
-                       if (os_snprintf_error(sizeof(last->osu_ssid), res))
-                               break;
-                       continue;
-               }
-
-               if (strncmp(buf, "osu_ssid2=", 10) == 0) {
-                       res = os_snprintf(last->osu_ssid2,
-                                         sizeof(last->osu_ssid2),
-                                         "%s", buf + 10);
-                       if (os_snprintf_error(sizeof(last->osu_ssid2), res))
-                               break;
-                       continue;
-               }
-
-               if (os_strncmp(buf, "osu_nai=", 8) == 0) {
-                       res = os_snprintf(last->osu_nai, sizeof(last->osu_nai),
-                                         "%s", buf + 8);
-                       if (os_snprintf_error(sizeof(last->osu_nai), res))
-                               break;
-                       continue;
-               }
-
-               if (os_strncmp(buf, "osu_nai2=", 9) == 0) {
-                       res = os_snprintf(last->osu_nai2,
-                                         sizeof(last->osu_nai2),
-                                         "%s", buf + 9);
-                       if (os_snprintf_error(sizeof(last->osu_nai2), res))
-                               break;
-                       continue;
-               }
-
-               if (strncmp(buf, "friendly_name=", 14) == 0) {
-                       struct osu_lang_text *txt;
-                       if (last->friendly_name_count == MAX_OSU_VALS)
-                               continue;
-                       pos = strchr(buf + 14, ':');
-                       if (pos == NULL)
-                               continue;
-                       *pos++ = '\0';
-                       txt = &last->friendly_name[last->friendly_name_count++];
-                       res = os_snprintf(txt->lang, sizeof(txt->lang),
-                                         "%s", buf + 14);
-                       if (os_snprintf_error(sizeof(txt->lang), res))
-                               break;
-                       res = os_snprintf(txt->text, sizeof(txt->text),
-                                         "%s", pos);
-                       if (os_snprintf_error(sizeof(txt->text), res))
-                               break;
-               }
-
-               if (strncmp(buf, "desc=", 5) == 0) {
-                       struct osu_lang_text *txt;
-                       if (last->serv_desc_count == MAX_OSU_VALS)
-                               continue;
-                       pos = strchr(buf + 5, ':');
-                       if (pos == NULL)
-                               continue;
-                       *pos++ = '\0';
-                       txt = &last->serv_desc[last->serv_desc_count++];
-                       res = os_snprintf(txt->lang, sizeof(txt->lang),
-                                         "%s", buf + 5);
-                       if (os_snprintf_error(sizeof(txt->lang), res))
-                               break;
-                       res = os_snprintf(txt->text, sizeof(txt->text),
-                                         "%s", pos);
-                       if (os_snprintf_error(sizeof(txt->text), res))
-                               break;
-               }
-
-               if (strncmp(buf, "icon=", 5) == 0) {
-                       struct osu_icon *icon;
-                       if (last->icon_count == MAX_OSU_VALS)
-                               continue;
-                       icon = &last->icon[last->icon_count++];
-                       icon->id = atoi(buf + 5);
-                       pos = strchr(buf, ':');
-                       if (pos == NULL)
-                               continue;
-                       pos = strchr(pos + 1, ':');
-                       if (pos == NULL)
-                               continue;
-                       pos = strchr(pos + 1, ':');
-                       if (pos == NULL)
-                               continue;
-                       pos++;
-                       end = strchr(pos, ':');
-                       if (!end)
-                               continue;
-                       *end = '\0';
-                       res = os_snprintf(icon->lang, sizeof(icon->lang),
-                                         "%s", pos);
-                       if (os_snprintf_error(sizeof(icon->lang), res))
-                               break;
-                       pos = end + 1;
-
-                       end = strchr(pos, ':');
-                       if (end)
-                               *end = '\0';
-                       res = os_snprintf(icon->mime_type,
-                                         sizeof(icon->mime_type), "%s", pos);
-                       if (os_snprintf_error(sizeof(icon->mime_type), res))
-                               break;
-                       if (!end)
-                               continue;
-                       pos = end + 1;
-
-                       end = strchr(pos, ':');
-                       if (end)
-                               *end = '\0';
-                       res = os_snprintf(icon->filename,
-                                         sizeof(icon->filename), "%s", pos);
-                       if (os_snprintf_error(sizeof(icon->filename), res))
-                               break;
-                       continue;
-               }
-       }
-
-       fclose(f);
-
-       *count = osu_count;
-       return osu;
-}
-
-
-static int osu_connect(struct hs20_osu_client *ctx, const char *bssid,
-                      const char *ssid, const char *ssid2, const char *url,
-                      unsigned int methods, int no_prod_assoc,
-                      const char *osu_nai, const char *osu_nai2)
-{
-       int id;
-       const char *ifname = ctx->ifname;
-       char buf[200];
-       struct wpa_ctrl *mon;
-       int res;
-
-       if (ssid2 && ssid2[0] == '\0')
-               ssid2 = NULL;
-
-       if (ctx->osu_ssid) {
-               if (os_strcmp(ssid, ctx->osu_ssid) == 0) {
-                       wpa_printf(MSG_DEBUG,
-                                  "Enforced OSU SSID matches ANQP info");
-                       ssid2 = NULL;
-               } else if (ssid2 && os_strcmp(ssid2, ctx->osu_ssid) == 0) {
-                       wpa_printf(MSG_DEBUG,
-                                  "Enforced OSU SSID matches RSN[OSEN] info");
-                       ssid = ssid2;
-               } else {
-                       wpa_printf(MSG_INFO, "Enforced OSU SSID did not match");
-                       write_summary(ctx, "Enforced OSU SSID did not match");
-                       return -1;
-               }
-       }
-
-       id = add_network(ifname);
-       if (id < 0)
-               return -1;
-       if (set_network_quoted(ifname, id, "ssid", ssid) < 0)
-               return -1;
-       if (ssid2)
-               osu_nai = osu_nai2;
-       if (osu_nai && os_strlen(osu_nai) > 0) {
-               char dir[255], fname[300];
-               if (getcwd(dir, sizeof(dir)) == NULL)
-                       return -1;
-               os_snprintf(fname, sizeof(fname), "%s/osu-ca.pem", dir);
-
-               if (ssid2 && set_network_quoted(ifname, id, "ssid", ssid2) < 0)
-                       return -1;
-
-               if (set_network(ifname, id, "proto", "OSEN") < 0 ||
-                   set_network(ifname, id, "key_mgmt", "OSEN") < 0 ||
-                   set_network(ifname, id, "pairwise", "CCMP") < 0 ||
-                   set_network(ifname, id, "group", "GTK_NOT_USED CCMP") < 0 ||
-                   set_network(ifname, id, "eap", "WFA-UNAUTH-TLS") < 0 ||
-                   set_network(ifname, id, "ocsp", "2") < 0 ||
-                   set_network_quoted(ifname, id, "identity", osu_nai) < 0 ||
-                   set_network_quoted(ifname, id, "ca_cert", fname) < 0)
-                       return -1;
-       } else if (ssid2) {
-               wpa_printf(MSG_INFO, "No OSU_NAI set for RSN[OSEN]");
-               write_summary(ctx, "No OSU_NAI set for RSN[OSEN]");
-               return -1;
-       } else {
-               if (set_network(ifname, id, "key_mgmt", "NONE") < 0)
-                       return -1;
-       }
-
-       mon = open_wpa_mon(ifname);
-       if (mon == NULL)
-               return -1;
-
-       wpa_printf(MSG_INFO, "Associate with OSU SSID");
-       write_summary(ctx, "Associate with OSU SSID");
-       snprintf(buf, sizeof(buf), "SELECT_NETWORK %d", id);
-       if (wpa_command(ifname, buf) < 0)
-               return -1;
-
-       res = get_wpa_cli_event(mon, "CTRL-EVENT-CONNECTED",
-                               buf, sizeof(buf));
-
-       wpa_ctrl_detach(mon);
-       wpa_ctrl_close(mon);
-
-       if (res < 0) {
-               wpa_printf(MSG_INFO, "Could not connect to OSU network");
-               write_summary(ctx, "Could not connect to OSU network");
-               wpa_printf(MSG_INFO, "Remove OSU network connection");
-               snprintf(buf, sizeof(buf), "REMOVE_NETWORK %d", id);
-               wpa_command(ifname, buf);
-               return -1;
-       }
-
-       write_summary(ctx, "Waiting for IP address for subscription registration");
-       if (wait_ip_addr(ifname, 15) < 0) {
-               wpa_printf(MSG_INFO, "Could not get IP address for WLAN - try connection anyway");
-       }
-
-       if (no_prod_assoc) {
-               if (res < 0)
-                       return -1;
-               wpa_printf(MSG_INFO, "No production connection used for testing purposes");
-               write_summary(ctx, "No production connection used for testing purposes");
-               return 0;
-       }
-
-       ctx->no_reconnect = 1;
-       if (methods & 0x02) {
-               wpa_printf(MSG_DEBUG, "Calling cmd_prov from osu_connect");
-               res = cmd_prov(ctx, url);
-       } else if (methods & 0x01) {
-               wpa_printf(MSG_DEBUG,
-                          "Calling cmd_oma_dm_prov from osu_connect");
-               res = cmd_oma_dm_prov(ctx, url);
-       }
-
-       wpa_printf(MSG_INFO, "Remove OSU network connection");
-       write_summary(ctx, "Remove OSU network connection");
-       snprintf(buf, sizeof(buf), "REMOVE_NETWORK %d", id);
-       wpa_command(ifname, buf);
-
-       if (res < 0)
-               return -1;
-
-       wpa_printf(MSG_INFO, "Requesting reconnection with updated configuration");
-       write_summary(ctx, "Requesting reconnection with updated configuration");
-       if (wpa_command(ctx->ifname, "INTERWORKING_SELECT auto") < 0) {
-               wpa_printf(MSG_INFO, "Failed to request wpa_supplicant to reconnect");
-               write_summary(ctx, "Failed to request wpa_supplicant to reconnect");
-               return -1;
-       }
-
-       return 0;
-}
-
-
-static int cmd_osu_select(struct hs20_osu_client *ctx, const char *dir,
-                         int connect, int no_prod_assoc,
-                         const char *friendly_name)
-{
-       char fname[255];
-       FILE *f;
-       struct osu_data *osu = NULL, *last = NULL;
-       size_t osu_count = 0, i, j;
-       int ret;
-
-       write_summary(ctx, "OSU provider selection");
-
-       if (dir == NULL) {
-               wpa_printf(MSG_INFO, "Missing dir parameter to osu_select");
-               return -1;
-       }
-
-       snprintf(fname, sizeof(fname), "%s/osu-providers.txt", dir);
-       osu = parse_osu_providers(fname, &osu_count);
-       if (osu == NULL) {
-               wpa_printf(MSG_INFO, "Could not find any OSU providers from %s",
-                          fname);
-               write_result(ctx, "No OSU providers available");
-               return -1;
-       }
-
-       if (friendly_name) {
-               for (i = 0; i < osu_count; i++) {
-                       last = &osu[i];
-                       for (j = 0; j < last->friendly_name_count; j++) {
-                               if (os_strcmp(last->friendly_name[j].text,
-                                             friendly_name) == 0)
-                                       break;
-                       }
-                       if (j < last->friendly_name_count)
-                               break;
-               }
-               if (i == osu_count) {
-                       wpa_printf(MSG_INFO, "Requested operator friendly name '%s' not found in the list of available providers",
-                                  friendly_name);
-                       write_summary(ctx, "Requested operator friendly name '%s' not found in the list of available providers",
-                                     friendly_name);
-                       free(osu);
-                       return -1;
-               }
-
-               wpa_printf(MSG_INFO, "OSU Provider selected based on requested operator friendly name '%s'",
-                          friendly_name);
-               write_summary(ctx, "OSU Provider selected based on requested operator friendly name '%s'",
-                             friendly_name);
-               ret = i + 1;
-               goto selected;
-       }
-
-       snprintf(fname, sizeof(fname), "%s/osu-providers.html", dir);
-       f = fopen(fname, "w");
-       if (f == NULL) {
-               wpa_printf(MSG_INFO, "Could not open %s", fname);
-               free(osu);
-               return -1;
-       }
-
-       fprintf(f, "<html><head>"
-               "<meta http-equiv=\"Content-type\" content=\"text/html; "
-               "charset=utf-8\"<title>Select service operator</title>"
-               "</head><body><h1>Select service operator</h1>\n");
-
-       if (osu_count == 0)
-               fprintf(f, "No online signup available\n");
-
-       for (i = 0; i < osu_count; i++) {
-               last = &osu[i];
-#ifdef ANDROID
-               fprintf(f, "<p>\n"
-                       "<a href=\"http://localhost:12345/osu/%d\">"
-                       "<table><tr><td>", (int) i + 1);
-#else /* ANDROID */
-               fprintf(f, "<p>\n"
-                       "<a href=\"osu://%d\">"
-                       "<table><tr><td>", (int) i + 1);
-#endif /* ANDROID */
-               for (j = 0; j < last->icon_count; j++) {
-                       fprintf(f, "<img src=\"osu-icon-%d.%s\">\n",
-                               last->icon[j].id,
-                               strcasecmp(last->icon[j].mime_type,
-                                          "image/png") == 0 ? "png" : "icon");
-               }
-               fprintf(f, "<td>");
-               for (j = 0; j < last->friendly_name_count; j++) {
-                       fprintf(f, "<small>[%s]</small> %s<br>\n",
-                               last->friendly_name[j].lang,
-                               last->friendly_name[j].text);
-               }
-               fprintf(f, "<tr><td colspan=2>");
-               for (j = 0; j < last->serv_desc_count; j++) {
-                       fprintf(f, "<small>[%s]</small> %s<br>\n",
-                               last->serv_desc[j].lang,
-                               last->serv_desc[j].text);
-               }
-               fprintf(f, "</table></a><br><small>BSSID: %s<br>\n"
-                       "SSID: %s<br>\n",
-                       last->bssid, last->osu_ssid);
-               if (last->osu_ssid2[0])
-                       fprintf(f, "SSID2: %s<br>\n", last->osu_ssid2);
-               if (last->osu_nai[0])
-                       fprintf(f, "NAI: %s<br>\n", last->osu_nai);
-               if (last->osu_nai2[0])
-                       fprintf(f, "NAI2: %s<br>\n", last->osu_nai2);
-               fprintf(f, "URL: %s<br>\n"
-                       "methods:%s%s<br>\n"
-                       "</small></p>\n",
-                       last->url,
-                       last->methods & 0x01 ? " OMA-DM" : "",
-                       last->methods & 0x02 ? " SOAP-XML-SPP" : "");
-       }
-
-       fprintf(f, "</body></html>\n");
-
-       fclose(f);
-
-       snprintf(fname, sizeof(fname), "file://%s/osu-providers.html", dir);
-       write_summary(ctx, "Start web browser with OSU provider selection page");
-       ret = hs20_web_browser(fname, 0);
-
-selected:
-       if (ret > 0 && (size_t) ret <= osu_count) {
-               char *data;
-               size_t data_len;
-
-               wpa_printf(MSG_INFO, "Selected OSU id=%d", ret);
-               last = &osu[ret - 1];
-               ret = 0;
-               wpa_printf(MSG_INFO, "BSSID: %s", last->bssid);
-               wpa_printf(MSG_INFO, "SSID: %s", last->osu_ssid);
-               if (last->osu_ssid2[0])
-                       wpa_printf(MSG_INFO, "SSID2: %s", last->osu_ssid2);
-               wpa_printf(MSG_INFO, "URL: %s", last->url);
-               write_summary(ctx, "Selected OSU provider id=%d BSSID=%s SSID=%s URL=%s",
-                             ret, last->bssid, last->osu_ssid, last->url);
-
-               ctx->friendly_name_count = last->friendly_name_count;
-               for (j = 0; j < last->friendly_name_count; j++) {
-                       wpa_printf(MSG_INFO, "FRIENDLY_NAME: [%s]%s",
-                                  last->friendly_name[j].lang,
-                                  last->friendly_name[j].text);
-                       os_strlcpy(ctx->friendly_name[j].lang,
-                                  last->friendly_name[j].lang,
-                                  sizeof(ctx->friendly_name[j].lang));
-                       os_strlcpy(ctx->friendly_name[j].text,
-                                  last->friendly_name[j].text,
-                                  sizeof(ctx->friendly_name[j].text));
-               }
-
-               ctx->icon_count = last->icon_count;
-               for (j = 0; j < last->icon_count; j++) {
-                       char fname[256];
-
-                       os_snprintf(fname, sizeof(fname), "%s/osu-icon-%d.%s",
-                                   dir, last->icon[j].id,
-                                   strcasecmp(last->icon[j].mime_type,
-                                              "image/png") == 0 ?
-                                   "png" : "icon");
-                       wpa_printf(MSG_INFO, "ICON: %s (%s)",
-                                  fname, last->icon[j].filename);
-                       os_strlcpy(ctx->icon_filename[j],
-                                  last->icon[j].filename,
-                                  sizeof(ctx->icon_filename[j]));
-
-                       data = os_readfile(fname, &data_len);
-                       if (data) {
-                               sha256_vector(1, (const u8 **) &data, &data_len,
-                                             ctx->icon_hash[j]);
-                               os_free(data);
-                       }
-               }
-
-               if (connect == 2) {
-                       if (last->methods & 0x02) {
-                               wpa_printf(MSG_DEBUG,
-                                          "Calling cmd_prov from cmd_osu_select");
-                               ret = cmd_prov(ctx, last->url);
-                       } else if (last->methods & 0x01) {
-                               wpa_printf(MSG_DEBUG,
-                                          "Calling cmd_oma_dm_prov from cmd_osu_select");
-                               ret = cmd_oma_dm_prov(ctx, last->url);
-                       } else {
-                               wpa_printf(MSG_DEBUG,
-                                          "No supported OSU provisioning method");
-                               ret = -1;
-                       }
-               } else if (connect) {
-                       ret = osu_connect(ctx, last->bssid, last->osu_ssid,
-                                         last->osu_ssid2,
-                                         last->url, last->methods,
-                                         no_prod_assoc, last->osu_nai,
-                                         last->osu_nai2);
-               }
-       } else
-               ret = -1;
-
-       free(osu);
-
-       return ret;
-}
-
-
-static int cmd_signup(struct hs20_osu_client *ctx, int no_prod_assoc,
-                     const char *friendly_name)
-{
-       char dir[255];
-       char fname[300], buf[400];
-       struct wpa_ctrl *mon;
-       const char *ifname;
-       int res;
-
-       ifname = ctx->ifname;
-
-       if (getcwd(dir, sizeof(dir)) == NULL)
-               return -1;
-
-       snprintf(fname, sizeof(fname), "%s/osu-info", dir);
-       if (mkdir(fname, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) < 0 &&
-           errno != EEXIST) {
-               wpa_printf(MSG_INFO, "mkdir(%s) failed: %s",
-                          fname, strerror(errno));
-               return -1;
-       }
-
-       android_update_permission(fname, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
-
-       snprintf(buf, sizeof(buf), "SET osu_dir %s", fname);
-       if (wpa_command(ifname, buf) < 0) {
-               wpa_printf(MSG_INFO, "Failed to configure osu_dir to wpa_supplicant");
-               return -1;
-       }
-
-       mon = open_wpa_mon(ifname);
-       if (mon == NULL)
-               return -1;
-
-       wpa_printf(MSG_INFO, "Starting OSU fetch");
-       write_summary(ctx, "Starting OSU provider information fetch");
-       if (wpa_command(ifname, "FETCH_OSU") < 0) {
-               wpa_printf(MSG_INFO, "Could not start OSU fetch");
-               wpa_ctrl_detach(mon);
-               wpa_ctrl_close(mon);
-               return -1;
-       }
-       res = get_wpa_cli_event(mon, "OSU provider fetch completed",
-                               buf, sizeof(buf));
-
-       wpa_ctrl_detach(mon);
-       wpa_ctrl_close(mon);
-
-       if (res < 0) {
-               wpa_printf(MSG_INFO, "OSU fetch did not complete");
-               write_summary(ctx, "OSU fetch did not complete");
-               return -1;
-       }
-       wpa_printf(MSG_INFO, "OSU provider fetch completed");
-
-       return cmd_osu_select(ctx, fname, 1, no_prod_assoc, friendly_name);
-}
-
-
-static int cmd_sub_rem(struct hs20_osu_client *ctx, const char *address,
-                      const char *pps_fname, const char *ca_fname)
-{
-       xml_node_t *pps, *node;
-       char pps_fname_buf[300];
-       char ca_fname_buf[200];
-       char *cred_username = NULL;
-       char *cred_password = NULL;
-       char *sub_rem_uri = NULL;
-       char client_cert_buf[200];
-       char *client_cert = NULL;
-       char client_key_buf[200];
-       char *client_key = NULL;
-       int spp;
-
-       wpa_printf(MSG_INFO, "Subscription remediation requested with Server URL: %s",
-                  address);
-
-       if (!pps_fname) {
-               char buf[256];
-               wpa_printf(MSG_INFO, "Determining PPS file based on Home SP information");
-               if (os_strncmp(address, "fqdn=", 5) == 0) {
-                       wpa_printf(MSG_INFO, "Use requested FQDN from command line");
-                       os_snprintf(buf, sizeof(buf), "%s", address + 5);
-                       address = NULL;
-               } else if (get_wpa_status(ctx->ifname, "provisioning_sp", buf,
-                                         sizeof(buf)) < 0) {
-                       wpa_printf(MSG_INFO, "Could not get provisioning Home SP FQDN from wpa_supplicant");
-                       return -1;
-               }
-               os_free(ctx->fqdn);
-               ctx->fqdn = os_strdup(buf);
-               if (ctx->fqdn == NULL)
-                       return -1;
-               wpa_printf(MSG_INFO, "Home SP FQDN for current credential: %s",
-                          buf);
-               os_snprintf(pps_fname_buf, sizeof(pps_fname_buf),
-                           "SP/%s/pps.xml", ctx->fqdn);
-               pps_fname = pps_fname_buf;
-
-               os_snprintf(ca_fname_buf, sizeof(ca_fname_buf), "SP/%s/ca.pem",
-                           ctx->fqdn);
-               ca_fname = ca_fname_buf;
-       }
-
-       if (!os_file_exists(pps_fname)) {
-               wpa_printf(MSG_INFO, "PPS file '%s' does not exist or is not accessible",
-                          pps_fname);
-               return -1;
-       }
-       wpa_printf(MSG_INFO, "Using PPS file: %s", pps_fname);
-
-       if (ca_fname && !os_file_exists(ca_fname)) {
-               wpa_printf(MSG_INFO, "CA file '%s' does not exist or is not accessible",
-                          ca_fname);
-               return -1;
-       }
-       wpa_printf(MSG_INFO, "Using server trust root: %s", ca_fname);
-       ctx->ca_fname = ca_fname;
-
-       pps = node_from_file(ctx->xml, pps_fname);
-       if (pps == NULL) {
-               wpa_printf(MSG_INFO, "Could not read PPS MO");
-               return -1;
-       }
-
-       if (!ctx->fqdn) {
-               char *tmp;
-               node = get_child_node(ctx->xml, pps, "HomeSP/FQDN");
-               if (node == NULL) {
-                       wpa_printf(MSG_INFO, "No HomeSP/FQDN found from PPS");
-                       return -1;
-               }
-               tmp = xml_node_get_text(ctx->xml, node);
-               if (tmp == NULL) {
-                       wpa_printf(MSG_INFO, "No HomeSP/FQDN text found from PPS");
-                       return -1;
-               }
-               ctx->fqdn = os_strdup(tmp);
-               xml_node_get_text_free(ctx->xml, tmp);
-               if (!ctx->fqdn) {
-                       wpa_printf(MSG_INFO, "No FQDN known");
-                       return -1;
-               }
-       }
-
-       node = get_child_node(ctx->xml, pps,
-                             "SubscriptionUpdate/UpdateMethod");
-       if (node) {
-               char *tmp;
-               tmp = xml_node_get_text(ctx->xml, node);
-               if (tmp && os_strcasecmp(tmp, "OMA-DM-ClientInitiated") == 0)
-                       spp = 0;
+               else if (os_strcasecmp(name, "SubscriptionParameters") == 0)
+                       set_pps_cred_sub_params(ctx, id, child);
+               else if (os_strcasecmp(name, "Credential") == 0)
+                       set_pps_cred_credential(ctx, id, child, fqdn);
                else
-                       spp = 1;
-       } else {
-               wpa_printf(MSG_INFO, "No UpdateMethod specified - assume SPP");
-               spp = 1;
-       }
-
-       get_user_pw(ctx, pps, "SubscriptionUpdate/UsernamePassword",
-                   &cred_username, &cred_password);
-       if (cred_username)
-               wpa_printf(MSG_INFO, "Using username: %s", cred_username);
-       if (cred_password)
-               wpa_printf(MSG_DEBUG, "Using password: %s", cred_password);
-
-       if (cred_username == NULL && cred_password == NULL &&
-           get_child_node(ctx->xml, pps, "Credential/DigitalCertificate")) {
-               wpa_printf(MSG_INFO, "Using client certificate");
-               os_snprintf(client_cert_buf, sizeof(client_cert_buf),
-                           "SP/%s/client-cert.pem", ctx->fqdn);
-               client_cert = client_cert_buf;
-               os_snprintf(client_key_buf, sizeof(client_key_buf),
-                           "SP/%s/client-key.pem", ctx->fqdn);
-               client_key = client_key_buf;
-               ctx->client_cert_present = 1;
-       }
-
-       node = get_child_node(ctx->xml, pps, "SubscriptionUpdate/URI");
-       if (node) {
-               sub_rem_uri = xml_node_get_text(ctx->xml, node);
-               if (sub_rem_uri &&
-                   (!address || os_strcmp(address, sub_rem_uri) != 0)) {
-                       wpa_printf(MSG_INFO, "Override sub rem URI based on PPS: %s",
-                                  sub_rem_uri);
-                       address = sub_rem_uri;
-               }
-       }
-       if (!address) {
-               wpa_printf(MSG_INFO, "Server URL not known");
-               return -1;
-       }
-
-       write_summary(ctx, "Wait for IP address for subscriptiom remediation");
-       wpa_printf(MSG_INFO, "Wait for IP address before starting subscription remediation");
-
-       if (wait_ip_addr(ctx->ifname, 15) < 0) {
-               wpa_printf(MSG_INFO, "Could not get IP address for WLAN - try connection anyway");
+                       wpa_printf(MSG_INFO, "Unknown credential node '%s'",
+                                  name);
        }
-
-       if (spp)
-               spp_sub_rem(ctx, address, pps_fname,
-                           client_cert, client_key,
-                           cred_username, cred_password, pps);
-       else
-               oma_dm_sub_rem(ctx, address, pps_fname,
-                              client_cert, client_key,
-                              cred_username, cred_password, pps);
-
-       xml_node_get_text_free(ctx->xml, sub_rem_uri);
-       xml_node_get_text_free(ctx->xml, cred_username);
-       str_clear_free(cred_password);
-       xml_node_free(ctx->xml, pps);
-       return 0;
 }
 
 
-static int cmd_pol_upd(struct hs20_osu_client *ctx, const char *address,
-                      const char *pps_fname, const char *ca_fname)
+static void set_pps(struct hs20_osu_client *ctx, xml_node_t *pps,
+                   const char *fqdn)
 {
-       xml_node_t *pps;
-       xml_node_t *node;
-       char pps_fname_buf[300];
-       char ca_fname_buf[200];
-       char *uri = NULL;
-       char *cred_username = NULL;
-       char *cred_password = NULL;
-       char client_cert_buf[200];
-       char *client_cert = NULL;
-       char client_key_buf[200];
-       char *client_key = NULL;
-       int spp;
-
-       wpa_printf(MSG_INFO, "Policy update requested");
-
-       if (!pps_fname) {
-               char buf[256];
-               int res;
-
-               wpa_printf(MSG_INFO, "Determining PPS file based on Home SP information");
-               if (address && os_strncmp(address, "fqdn=", 5) == 0) {
-                       wpa_printf(MSG_INFO, "Use requested FQDN from command line");
-                       os_snprintf(buf, sizeof(buf), "%s", address + 5);
-                       address = NULL;
-               } else if (get_wpa_status(ctx->ifname, "provisioning_sp", buf,
-                                         sizeof(buf)) < 0) {
-                       wpa_printf(MSG_INFO, "Could not get provisioning Home SP FQDN from wpa_supplicant");
-                       return -1;
-               }
-               os_free(ctx->fqdn);
-               ctx->fqdn = os_strdup(buf);
-               if (ctx->fqdn == NULL)
-                       return -1;
-               wpa_printf(MSG_INFO, "Home SP FQDN for current credential: %s",
-                          buf);
-               os_snprintf(pps_fname_buf, sizeof(pps_fname_buf),
-                           "SP/%s/pps.xml", ctx->fqdn);
-               pps_fname = pps_fname_buf;
-
-               res = os_snprintf(ca_fname_buf, sizeof(ca_fname_buf),
-                                 "SP/%s/ca.pem", buf);
-               if (os_snprintf_error(sizeof(ca_fname_buf), res)) {
-                       os_free(ctx->fqdn);
-                       ctx->fqdn = NULL;
-                       return -1;
-               }
-               ca_fname = ca_fname_buf;
-       }
-
-       if (!os_file_exists(pps_fname)) {
-               wpa_printf(MSG_INFO, "PPS file '%s' does not exist or is not accessible",
-                          pps_fname);
-               return -1;
-       }
-       wpa_printf(MSG_INFO, "Using PPS file: %s", pps_fname);
-
-       if (ca_fname && !os_file_exists(ca_fname)) {
-               wpa_printf(MSG_INFO, "CA file '%s' does not exist or is not accessible",
-                          ca_fname);
-               return -1;
-       }
-       wpa_printf(MSG_INFO, "Using server trust root: %s", ca_fname);
-       ctx->ca_fname = ca_fname;
+       xml_node_t *child;
+       const char *name;
+       int id;
+       char *update_identifier = NULL;
 
-       pps = node_from_file(ctx->xml, pps_fname);
-       if (pps == NULL) {
-               wpa_printf(MSG_INFO, "Could not read PPS MO");
-               return -1;
-       }
+       /*
+        * TODO: Could consider more complex mechanism that would remove
+        * credentials only if there are changes in the information sent to
+        * wpa_supplicant.
+        */
+       remove_sp_creds(ctx, fqdn);
 
-       if (!ctx->fqdn) {
-               char *tmp;
-               node = get_child_node(ctx->xml, pps, "HomeSP/FQDN");
-               if (node == NULL) {
-                       wpa_printf(MSG_INFO, "No HomeSP/FQDN found from PPS");
-                       return -1;
-               }
-               tmp = xml_node_get_text(ctx->xml, node);
-               if (tmp == NULL) {
-                       wpa_printf(MSG_INFO, "No HomeSP/FQDN text found from PPS");
-                       return -1;
-               }
-               ctx->fqdn = os_strdup(tmp);
-               xml_node_get_text_free(ctx->xml, tmp);
-               if (!ctx->fqdn) {
-                       wpa_printf(MSG_INFO, "No FQDN known");
-                       return -1;
+       xml_node_for_each_child(ctx->xml, child, pps) {
+               xml_node_for_each_check(ctx->xml, child);
+               name = xml_node_get_localname(ctx->xml, child);
+               if (os_strcasecmp(name, "UpdateIdentifier") == 0) {
+                       update_identifier = xml_node_get_text(ctx->xml, child);
+                       if (update_identifier) {
+                               wpa_printf(MSG_INFO, "- UpdateIdentifier = %s",
+                                          update_identifier);
+                               break;
+                       }
                }
        }
 
-       node = get_child_node(ctx->xml, pps,
-                             "Policy/PolicyUpdate/UpdateMethod");
-       if (node) {
-               char *tmp;
-               tmp = xml_node_get_text(ctx->xml, node);
-               if (tmp && os_strcasecmp(tmp, "OMA-DM-ClientInitiated") == 0)
-                       spp = 0;
-               else
-                       spp = 1;
-       } else {
-               wpa_printf(MSG_INFO, "No UpdateMethod specified - assume SPP");
-               spp = 1;
-       }
-
-       get_user_pw(ctx, pps, "Policy/PolicyUpdate/UsernamePassword",
-                   &cred_username, &cred_password);
-       if (cred_username)
-               wpa_printf(MSG_INFO, "Using username: %s", cred_username);
-       if (cred_password)
-               wpa_printf(MSG_DEBUG, "Using password: %s", cred_password);
-
-       if (cred_username == NULL && cred_password == NULL &&
-           get_child_node(ctx->xml, pps, "Credential/DigitalCertificate")) {
-               wpa_printf(MSG_INFO, "Using client certificate");
-               os_snprintf(client_cert_buf, sizeof(client_cert_buf),
-                           "SP/%s/client-cert.pem", ctx->fqdn);
-               client_cert = client_cert_buf;
-               os_snprintf(client_key_buf, sizeof(client_key_buf),
-                           "SP/%s/client-key.pem", ctx->fqdn);
-               client_key = client_key_buf;
-       }
-
-       if (!address) {
-               node = get_child_node(ctx->xml, pps, "Policy/PolicyUpdate/URI");
-               if (node) {
-                       uri = xml_node_get_text(ctx->xml, node);
-                       wpa_printf(MSG_INFO, "URI based on PPS: %s", uri);
-                       address = uri;
+       xml_node_for_each_child(ctx->xml, child, pps) {
+               xml_node_for_each_check(ctx->xml, child);
+               name = xml_node_get_localname(ctx->xml, child);
+               if (os_strcasecmp(name, "UpdateIdentifier") == 0)
+                       continue;
+               id = add_cred(ctx->ifname);
+               if (id < 0) {
+                       wpa_printf(MSG_INFO, "Failed to add credential to wpa_supplicant");
+                       write_summary(ctx, "Failed to add credential to wpa_supplicant");
+                       break;
                }
+               write_summary(ctx, "Add a credential to wpa_supplicant");
+               if (update_identifier &&
+                   set_cred(ctx->ifname, id, "update_identifier",
+                            update_identifier) < 0)
+                       wpa_printf(MSG_INFO, "Failed to set update_identifier");
+               if (set_cred_quoted(ctx->ifname, id, "provisioning_sp", fqdn) <
+                   0)
+                       wpa_printf(MSG_INFO, "Failed to set provisioning_sp");
+               wpa_printf(MSG_INFO, "credential localname: '%s'", name);
+               set_pps_credential(ctx, id, child, fqdn);
        }
-       if (!address) {
-               wpa_printf(MSG_INFO, "Server URL not known");
-               return -1;
-       }
-
-       if (spp)
-               spp_pol_upd(ctx, address, pps_fname,
-                           client_cert, client_key,
-                           cred_username, cred_password, pps);
-       else
-               oma_dm_pol_upd(ctx, address, pps_fname,
-                              client_cert, client_key,
-                              cred_username, cred_password, pps);
 
-       xml_node_get_text_free(ctx->xml, uri);
-       xml_node_get_text_free(ctx->xml, cred_username);
-       str_clear_free(cred_password);
-       xml_node_free(ctx->xml, pps);
-
-       return 0;
+       xml_node_get_text_free(ctx->xml, update_identifier);
 }
 
 
-static char * get_hostname(const char *url)
+static void cmd_set_pps(struct hs20_osu_client *ctx, const char *pps_fname)
 {
-       const char *pos, *end, *end2;
-       char *ret;
-
-       if (url == NULL)
-               return NULL;
+       xml_node_t *pps;
+       const char *fqdn;
+       char *fqdn_buf = NULL, *pos;
 
-       pos = os_strchr(url, '/');
-       if (pos == NULL)
-               return NULL;
-       pos++;
-       if (*pos != '/')
-               return NULL;
-       pos++;
-
-       end = os_strchr(pos, '/');
-       end2 = os_strchr(pos, ':');
-       if ((end && end2 && end2 < end) || (!end && end2))
-               end = end2;
-       if (end)
-               end--;
-       else {
-               end = pos;
-               while (*end)
-                       end++;
-               if (end > pos)
-                       end--;
+       pps = node_from_file(ctx->xml, pps_fname);
+       if (pps == NULL) {
+               wpa_printf(MSG_INFO, "Could not read or parse '%s'", pps_fname);
+               return;
        }
 
-       ret = os_malloc(end - pos + 2);
-       if (ret == NULL)
-               return NULL;
+       fqdn = os_strstr(pps_fname, "SP/");
+       if (fqdn) {
+               fqdn_buf = os_strdup(fqdn + 3);
+               if (fqdn_buf == NULL)
+                       return;
+               pos = os_strchr(fqdn_buf, '/');
+               if (pos)
+                       *pos = '\0';
+               fqdn = fqdn_buf;
+       } else
+               fqdn = "wi-fi.org";
 
-       os_memcpy(ret, pos, end - pos + 1);
-       ret[end - pos + 1] = '\0';
+       wpa_printf(MSG_INFO, "Set PPS MO info to wpa_supplicant - SP FQDN %s",
+                  fqdn);
+       set_pps(ctx, pps, fqdn);
 
-       return ret;
+       os_free(fqdn_buf);
+       xml_node_free(ctx->xml, pps);
 }
 
 
-static int osu_cert_cb(void *_ctx, struct http_cert *cert)
+static int cmd_get_fqdn(struct hs20_osu_client *ctx, const char *pps_fname)
 {
-       struct hs20_osu_client *ctx = _ctx;
-       size_t i, j;
-       int found;
-       char *host = NULL;
-
-       wpa_printf(MSG_INFO, "osu_cert_cb(osu_cert_validation=%d, url=%s server_url=%s)",
-                  !ctx->no_osu_cert_validation, cert->url ? cert->url : "N/A",
-                  ctx->server_url);
-
-       if (ctx->no_osu_cert_validation && cert->url)
-               host = get_hostname(cert->url);
-       else
-               host = get_hostname(ctx->server_url);
-
-       if (!ctx->no_osu_cert_validation) {
-               for (i = 0; i < ctx->server_dnsname_count; i++)
-                       os_free(ctx->server_dnsname[i]);
-               os_free(ctx->server_dnsname);
-               ctx->server_dnsname = os_calloc(cert->num_dnsname,
-                                               sizeof(char *));
-               ctx->server_dnsname_count = 0;
-       }
-
-       found = 0;
-       for (i = 0; i < cert->num_dnsname; i++) {
-               if (!ctx->no_osu_cert_validation && ctx->server_dnsname) {
-                       ctx->server_dnsname[ctx->server_dnsname_count] =
-                               os_strdup(cert->dnsname[i]);
-                       if (ctx->server_dnsname[ctx->server_dnsname_count])
-                               ctx->server_dnsname_count++;
-               }
-               if (host && os_strcasecmp(host, cert->dnsname[i]) == 0)
-                       found = 1;
-               wpa_printf(MSG_INFO, "dNSName '%s'", cert->dnsname[i]);
-       }
+       xml_node_t *pps, *node;
+       char *fqdn = NULL;
 
-       if (host && !found) {
-               wpa_printf(MSG_INFO, "Server name from URL (%s) did not match any dNSName - abort connection",
-                          host);
-               write_result(ctx, "Server name from URL (%s) did not match any dNSName - abort connection",
-                            host);
-               os_free(host);
+       pps = node_from_file(ctx->xml, pps_fname);
+       if (pps == NULL) {
+               wpa_printf(MSG_INFO, "Could not read or parse '%s'", pps_fname);
                return -1;
        }
 
-       os_free(host);
-
-       for (i = 0; i < cert->num_othername; i++) {
-               if (os_strcmp(cert->othername[i].oid,
-                             "1.3.6.1.4.1.40808.1.1.1") == 0) {
-                       wpa_hexdump_ascii(MSG_INFO,
-                                         "id-wfa-hotspot-friendlyName",
-                                         cert->othername[i].data,
-                                         cert->othername[i].len);
-               }
-       }
+       node = get_child_node(ctx->xml, pps, "HomeSP/FQDN");
+       if (node)
+               fqdn = xml_node_get_text(ctx->xml, node);
 
-       for (j = 0; !ctx->no_osu_cert_validation &&
-                    j < ctx->friendly_name_count; j++) {
-               int found = 0;
-               for (i = 0; i < cert->num_othername; i++) {
-                       if (os_strcmp(cert->othername[i].oid,
-                                     "1.3.6.1.4.1.40808.1.1.1") != 0)
-                               continue;
-                       if (cert->othername[i].len < 3)
-                               continue;
-                       if (os_strncasecmp((char *) cert->othername[i].data,
-                                          ctx->friendly_name[j].lang, 3) != 0)
-                               continue;
-                       if (os_strncmp((char *) cert->othername[i].data + 3,
-                                      ctx->friendly_name[j].text,
-                                      cert->othername[i].len - 3) == 0) {
-                               found = 1;
-                               break;
-                       }
-               }
+       xml_node_free(ctx->xml, pps);
 
-               if (!found) {
-                       wpa_printf(MSG_INFO, "No friendly name match found for '[%s]%s'",
-                                  ctx->friendly_name[j].lang,
-                                  ctx->friendly_name[j].text);
-                       write_result(ctx, "No friendly name match found for '[%s]%s'",
-                                    ctx->friendly_name[j].lang,
-                                    ctx->friendly_name[j].text);
-                       return -1;
+       if (fqdn) {
+               FILE *f = fopen("pps-fqdn", "w");
+               if (f) {
+                       fprintf(f, "%s", fqdn);
+                       fclose(f);
                }
+               xml_node_get_text_free(ctx->xml, fqdn);
+               return 0;
        }
 
-       for (i = 0; i < cert->num_logo; i++) {
-               struct http_logo *logo = &cert->logo[i];
-
-               wpa_printf(MSG_INFO, "logo hash alg %s uri '%s'",
-                          logo->alg_oid, logo->uri);
-               wpa_hexdump_ascii(MSG_INFO, "hashValue",
-                                 logo->hash, logo->hash_len);
-       }
+       xml_node_get_text_free(ctx->xml, fqdn);
+       return -1;
+}
 
-       for (j = 0; !ctx->no_osu_cert_validation && j < ctx->icon_count; j++) {
-               int found = 0;
-               char *name = ctx->icon_filename[j];
-               size_t name_len = os_strlen(name);
 
-               wpa_printf(MSG_INFO,
-                          "[%zu] Looking for icon file name '%s' match",
-                          j, name);
-               for (i = 0; i < cert->num_logo; i++) {
-                       struct http_logo *logo = &cert->logo[i];
-                       size_t uri_len = os_strlen(logo->uri);
-                       char *pos;
+static void cmd_to_tnds(struct hs20_osu_client *ctx, const char *in_fname,
+                       const char *out_fname, const char *urn, int use_path)
+{
+       xml_node_t *mo, *node;
 
-                       wpa_printf(MSG_INFO,
-                                  "[%zu] Comparing to '%s' uri_len=%d name_len=%d",
-                                  i, logo->uri, (int) uri_len, (int) name_len);
-                       if (uri_len < 1 + name_len) {
-                               wpa_printf(MSG_INFO, "URI Length is too short");
-                               continue;
-                       }
-                       pos = &logo->uri[uri_len - name_len - 1];
-                       if (*pos != '/')
-                               continue;
-                       pos++;
-                       if (os_strcmp(pos, name) == 0) {
-                               found = 1;
-                               break;
-                       }
-               }
+       mo = node_from_file(ctx->xml, in_fname);
+       if (mo == NULL) {
+               wpa_printf(MSG_INFO, "Could not read or parse '%s'", in_fname);
+               return;
+       }
 
-               if (!found) {
-                       wpa_printf(MSG_INFO, "No icon filename match found for '%s'",
-                                  name);
-                       write_result(ctx,
-                                    "No icon filename match found for '%s'",
-                                    name);
-                       return -1;
-               }
+       node = mo_to_tnds(ctx->xml, mo, use_path, urn, NULL);
+       if (node) {
+               node_to_file(ctx->xml, out_fname, node);
+               xml_node_free(ctx->xml, node);
        }
 
-       for (j = 0; !ctx->no_osu_cert_validation && j < ctx->icon_count; j++) {
-               int found = 0;
+       xml_node_free(ctx->xml, mo);
+}
 
-               for (i = 0; i < cert->num_logo; i++) {
-                       struct http_logo *logo = &cert->logo[i];
 
-                       if (logo->hash_len != 32) {
-                               wpa_printf(MSG_INFO,
-                                          "[%zu][%zu] Icon hash length invalid (should be 32): %d",
-                                          j, i, (int) logo->hash_len);
-                               continue;
-                       }
-                       if (os_memcmp(logo->hash, ctx->icon_hash[j], 32) == 0) {
-                               found = 1;
-                               break;
-                       }
+static void cmd_from_tnds(struct hs20_osu_client *ctx, const char *in_fname,
+                         const char *out_fname)
+{
+       xml_node_t *tnds, *mo;
 
-                       wpa_printf(MSG_DEBUG,
-                                  "[%zu][%zu] Icon hash did not match", j, i);
-                       wpa_hexdump_ascii(MSG_DEBUG, "logo->hash",
-                                         logo->hash, 32);
-                       wpa_hexdump_ascii(MSG_DEBUG, "ctx->icon_hash[j]",
-                                         ctx->icon_hash[j], 32);
-               }
+       tnds = node_from_file(ctx->xml, in_fname);
+       if (tnds == NULL) {
+               wpa_printf(MSG_INFO, "Could not read or parse '%s'", in_fname);
+               return;
+       }
 
-               if (!found) {
-                       wpa_printf(MSG_INFO,
-                                  "No icon hash match (by hash) found");
-                       write_result(ctx,
-                                    "No icon hash match (by hash) found");
-                       return -1;
-               }
+       mo = tnds_to_mo(ctx->xml, tnds);
+       if (mo) {
+               node_to_file(ctx->xml, out_fname, mo);
+               xml_node_free(ctx->xml, mo);
        }
 
-       return 0;
+       xml_node_free(ctx->xml, tnds);
 }
 
 
 static int init_ctx(struct hs20_osu_client *ctx)
 {
-       xml_node_t *devinfo, *devid;
-
        os_memset(ctx, 0, sizeof(*ctx));
        ctx->ifname = "wlan0";
        ctx->xml = xml_node_init_ctx(ctx, NULL);
        if (ctx->xml == NULL)
                return -1;
 
-       devinfo = node_from_file(ctx->xml, "devinfo.xml");
-       if (devinfo) {
-               devid = get_node(ctx->xml, devinfo, "DevId");
-               if (devid) {
-                       char *tmp = xml_node_get_text(ctx->xml, devid);
-
-                       if (tmp) {
-                               ctx->devid = os_strdup(tmp);
-                               xml_node_get_text_free(ctx->xml, tmp);
-                       }
-               }
-               xml_node_free(ctx->xml, devinfo);
-       }
-
        ctx->http = http_init_ctx(ctx, ctx->xml);
        if (ctx->http == NULL) {
                xml_node_deinit_ctx(ctx->xml);
                return -1;
        }
        http_ocsp_set(ctx->http, 2);
-       http_set_cert_cb(ctx->http, osu_cert_cb, ctx);
 
        return 0;
 }
@@ -3156,17 +1431,8 @@ static int init_ctx(struct hs20_osu_client *ctx)
 
 static void deinit_ctx(struct hs20_osu_client *ctx)
 {
-       size_t i;
-
        http_deinit_ctx(ctx->http);
        xml_node_deinit_ctx(ctx->xml);
-       os_free(ctx->fqdn);
-       os_free(ctx->server_url);
-       os_free(ctx->devid);
-
-       for (i = 0; i < ctx->server_dnsname_count; i++)
-               os_free(ctx->server_dnsname[i]);
-       os_free(ctx->server_dnsname);
 }
 
 
@@ -3209,19 +1475,8 @@ static void usage(void)
               "- from_tnds <XML MO in TNDS format> <XML MO>\n"
               "- set_pps <PerProviderSubscription XML file name>\n"
               "- get_fqdn <PerProviderSubscription XML file name>\n"
-              "- pol_upd [Server URL] [PPS] [CA cert]\n"
-              "- sub_rem <Server URL> [PPS] [CA cert]\n"
-              "- prov <Server URL> [CA cert]\n"
-              "- oma_dm_prov <Server URL> [CA cert]\n"
-              "- sim_prov <Server URL> [CA cert]\n"
-              "- oma_dm_sim_prov <Server URL> [CA cert]\n"
-              "- signup [CA cert]\n"
-              "- dl_osu_ca <PPS> <CA file>\n"
-              "- dl_polupd_ca <PPS> <CA file>\n"
               "- dl_aaa_ca <PPS> <CA file>\n"
-              "- browser <URL>\n"
-              "- parse_cert <X.509 certificate (DER)>\n"
-              "- osu_select <OSU info directory> [CA cert]\n");
+              "- browser <URL>\n");
 }
 
 
@@ -3230,8 +1485,6 @@ int main(int argc, char *argv[])
        struct hs20_osu_client ctx;
        int c;
        int ret = 0;
-       int no_prod_assoc = 0;
-       const char *friendly_name = NULL;
        const char *wpa_debug_file_path = NULL;
        extern char *wpas_ctrl_path;
        extern int wpa_debug_level;
@@ -3242,7 +1495,7 @@ int main(int argc, char *argv[])
                return -1;
 
        for (;;) {
-               c = getopt(argc, argv, "df:hKNo:O:qr:s:S:tTw:x:");
+               c = getopt(argc, argv, "df:hKqr:s:S:tTw:");
                if (c < 0)
                        break;
                switch (c) {
@@ -3256,15 +1509,6 @@ int main(int argc, char *argv[])
                case 'K':
                        wpa_debug_show_keys++;
                        break;
-               case 'N':
-                       no_prod_assoc = 1;
-                       break;
-               case 'o':
-                       ctx.osu_ssid = optarg;
-                       break;
-               case 'O':
-                       friendly_name = optarg;
-                       break;
                case 'q':
                        wpa_debug_level++;
                        break;
@@ -3286,9 +1530,6 @@ int main(int argc, char *argv[])
                case 'w':
                        wpas_ctrl_path = optarg;
                        break;
-               case 'x':
-                       spp_xsd_fname = optarg;
-                       break;
                case 'h':
                default:
                        usage();
@@ -3335,62 +1576,12 @@ int main(int argc, char *argv[])
                        exit(0);
                }
                cmd_from_tnds(&ctx, argv[optind + 1], argv[optind + 2]);
-       } else if (strcmp(argv[optind], "sub_rem") == 0) {
-               if (argc - optind < 2) {
-                       usage();
-                       exit(0);
-               }
-               ret = cmd_sub_rem(&ctx, argv[optind + 1],
-                                 argc > optind + 2 ? argv[optind + 2] : NULL,
-                                 argc > optind + 3 ? argv[optind + 3] : NULL);
-       } else if (strcmp(argv[optind], "pol_upd") == 0) {
-               ret = cmd_pol_upd(&ctx,
-                                 argc > optind + 1 ? argv[optind + 1] : NULL,
-                                 argc > optind + 2 ? argv[optind + 2] : NULL,
-                                 argc > optind + 3 ? argv[optind + 3] : NULL);
-       } else if (strcmp(argv[optind], "prov") == 0) {
-               if (argc - optind < 2) {
-                       usage();
-                       exit(0);
-               }
-               ctx.ca_fname = argv[optind + 2];
-               wpa_printf(MSG_DEBUG, "Calling cmd_prov from main");
-               cmd_prov(&ctx, argv[optind + 1]);
-       } else if (strcmp(argv[optind], "sim_prov") == 0) {
-               if (argc - optind < 2) {
-                       usage();
-                       exit(0);
-               }
-               ctx.ca_fname = argv[optind + 2];
-               cmd_sim_prov(&ctx, argv[optind + 1]);
-       } else if (strcmp(argv[optind], "dl_osu_ca") == 0) {
-               if (argc - optind < 2) {
-                       usage();
-                       exit(0);
-               }
-               cmd_dl_osu_ca(&ctx, argv[optind + 1], argv[optind + 2]);
-       } else if (strcmp(argv[optind], "dl_polupd_ca") == 0) {
-               if (argc - optind < 2) {
-                       usage();
-                       exit(0);
-               }
-               cmd_dl_polupd_ca(&ctx, argv[optind + 1], argv[optind + 2]);
        } else if (strcmp(argv[optind], "dl_aaa_ca") == 0) {
                if (argc - optind < 2) {
                        usage();
                        exit(0);
                }
                cmd_dl_aaa_ca(&ctx, argv[optind + 1], argv[optind + 2]);
-       } else if (strcmp(argv[optind], "osu_select") == 0) {
-               if (argc - optind < 2) {
-                       usage();
-                       exit(0);
-               }
-               ctx.ca_fname = argc > optind + 2 ? argv[optind + 2] : NULL;
-               cmd_osu_select(&ctx, argv[optind + 1], 2, 1, NULL);
-       } else if (strcmp(argv[optind], "signup") == 0) {
-               ctx.ca_fname = argc > optind + 1 ? argv[optind + 1] : NULL;
-               ret = cmd_signup(&ctx, no_prod_assoc, friendly_name);
        } else if (strcmp(argv[optind], "set_pps") == 0) {
                if (argc - optind < 2) {
                        usage();
@@ -3403,42 +1594,6 @@ int main(int argc, char *argv[])
                        exit(0);
                }
                ret = cmd_get_fqdn(&ctx, argv[optind + 1]);
-       } else if (strcmp(argv[optind], "oma_dm_prov") == 0) {
-               if (argc - optind < 2) {
-                       usage();
-                       exit(0);
-               }
-               ctx.ca_fname = argv[optind + 2];
-               cmd_oma_dm_prov(&ctx, argv[optind + 1]);
-       } else if (strcmp(argv[optind], "oma_dm_sim_prov") == 0) {
-               if (argc - optind < 2) {
-                       usage();
-                       exit(0);
-               }
-               ctx.ca_fname = argv[optind + 2];
-               if (cmd_oma_dm_sim_prov(&ctx, argv[optind + 1]) < 0) {
-                       write_summary(&ctx, "Failed to complete OMA DM SIM provisioning");
-                       return -1;
-               }
-       } else if (strcmp(argv[optind], "oma_dm_add") == 0) {
-               if (argc - optind < 2) {
-                       usage();
-                       exit(0);
-               }
-               cmd_oma_dm_add(&ctx, argv[optind + 1], argv[optind + 2]);
-       } else if (strcmp(argv[optind], "oma_dm_replace") == 0) {
-               if (argc - optind < 2) {
-                       usage();
-                       exit(0);
-               }
-               cmd_oma_dm_replace(&ctx, argv[optind + 1], argv[optind + 2]);
-       } else if (strcmp(argv[optind], "est_csr") == 0) {
-               if (argc - optind < 2) {
-                       usage();
-                       exit(0);
-               }
-               mkdir("Cert", S_IRWXU);
-               est_build_csr(&ctx, argv[optind + 1]);
        } else if (strcmp(argv[optind], "browser") == 0) {
                int ret;
 
@@ -3451,15 +1606,6 @@ int main(int argc, char *argv[])
                           argv[optind + 1]);
                ret = hs20_web_browser(argv[optind + 1], ctx.ignore_tls);
                wpa_printf(MSG_INFO, "Web browser result: %d", ret);
-       } else if (strcmp(argv[optind], "parse_cert") == 0) {
-               if (argc - optind < 2) {
-                       usage();
-                       exit(0);
-               }
-
-               wpa_debug_level = MSG_MSGDUMP;
-               http_parse_x509_certificate(ctx.http, argv[optind + 1]);
-               wpa_debug_level = MSG_INFO;
        } else {
                wpa_printf(MSG_INFO, "Unknown command '%s'", argv[optind]);
        }
index 9b45b03febe2413c6d5cf29528cd394dfb2bdaab..3bfbb0dd9e1b441ce9b575f146ede0c89060e530 100644 (file)
 #ifndef OSU_CLIENT_H
 #define OSU_CLIENT_H
 
-#define SPP_NS_URI "http://www.wi-fi.org/specifications/hotspot2dot0/v1.0/spp"
-
-#define URN_OMA_DM_DEVINFO "urn:oma:mo:oma-dm-devinfo:1.0"
-#define URN_OMA_DM_DEVDETAIL "urn:oma:mo:oma-dm-devdetail:1.0"
-#define URN_HS20_DEVDETAIL_EXT "urn:wfa:mo-ext:hotspot2dot0-devdetail-ext:1.0"
-#define URN_HS20_PPS "urn:wfa:mo:hotspot2dot0-perprovidersubscription:1.0"
-
-
-#define MAX_OSU_VALS 10
-
-struct osu_lang_text {
-       char lang[4];
-       char text[253];
-};
-
 struct hs20_osu_client {
        struct xml_node_ctx *xml;
        struct http_ctx *http;
-       int no_reconnect;
-       char pps_fname[300];
-       char *devid;
        const char *result_file;
        const char *summary_file;
        const char *ifname;
-       const char *ca_fname;
-       int no_osu_cert_validation; /* for EST operations */
-       char *fqdn;
-       char *server_url;
-       struct osu_lang_text friendly_name[MAX_OSU_VALS];
-       size_t friendly_name_count;
-       size_t icon_count;
-       char icon_filename[MAX_OSU_VALS][256];
-       u8 icon_hash[MAX_OSU_VALS][32];
-       int pps_cred_set;
-       int pps_updated;
-       int client_cert_present;
-       char **server_dnsname;
-       size_t server_dnsname_count;
-       const char *osu_ssid; /* Enforced OSU_SSID for testing purposes */
 #define WORKAROUND_OCSP_OPTIONAL 0x00000001
        unsigned long int workarounds;
        int ignore_tls; /* whether to ignore TLS validation issues with HTTPS
                         * server certificate */
 };
 
-
-/* osu_client.c */
-
-void write_result(struct hs20_osu_client *ctx, const char *fmt, ...)
-       __attribute__ ((format (printf, 2, 3)));
-void write_summary(struct hs20_osu_client *ctx, const char *fmt, ...)
-       __attribute__ ((format (printf, 2, 3)));
-
-void debug_dump_node(struct hs20_osu_client *ctx, const char *title,
-                    xml_node_t *node);
-int osu_get_certificate(struct hs20_osu_client *ctx, xml_node_t *getcert);
-int hs20_add_pps_mo(struct hs20_osu_client *ctx, const char *uri,
-                   xml_node_t *add_mo, char *fname, size_t fname_len);
-void get_user_pw(struct hs20_osu_client *ctx, xml_node_t *pps,
-                const char *alt_loc, char **user, char **pw);
-int update_pps_file(struct hs20_osu_client *ctx, const char *pps_fname,
-                   xml_node_t *pps);
-void cmd_set_pps(struct hs20_osu_client *ctx, const char *pps_fname);
-
-
-/* spp_client.c */
-
-void spp_sub_rem(struct hs20_osu_client *ctx, const char *address,
-                const char *pps_fname,
-                const char *client_cert, const char *client_key,
-                const char *cred_username, const char *cred_password,
-                xml_node_t *pps);
-void spp_pol_upd(struct hs20_osu_client *ctx, const char *address,
-                const char *pps_fname,
-                const char *client_cert, const char *client_key,
-                const char *cred_username, const char *cred_password,
-                xml_node_t *pps);
-int cmd_prov(struct hs20_osu_client *ctx, const char *url);
-int cmd_sim_prov(struct hs20_osu_client *ctx, const char *url);
-
-
-/* oma_dm_client.c */
-
-int cmd_oma_dm_prov(struct hs20_osu_client *ctx, const char *url);
-int cmd_oma_dm_sim_prov(struct hs20_osu_client *ctx, const char *url);
-void oma_dm_sub_rem(struct hs20_osu_client *ctx, const char *address,
-                   const char *pps_fname,
-                   const char *client_cert, const char *client_key,
-                   const char *cred_username, const char *cred_password,
-                   xml_node_t *pps);
-void oma_dm_pol_upd(struct hs20_osu_client *ctx, const char *address,
-                   const char *pps_fname,
-                   const char *client_cert, const char *client_key,
-                   const char *cred_username, const char *cred_password,
-                   xml_node_t *pps);
-void cmd_oma_dm_sub_rem(struct hs20_osu_client *ctx, const char *address,
-                       const char *pps_fname);
-void cmd_oma_dm_add(struct hs20_osu_client *ctx, const char *pps_fname,
-                   const char *add_fname);
-void cmd_oma_dm_replace(struct hs20_osu_client *ctx, const char *pps_fname,
-                       const char *replace_fname);
-
-/* est.c */
-
-int est_load_cacerts(struct hs20_osu_client *ctx, const char *url);
-int est_build_csr(struct hs20_osu_client *ctx, const char *url);
-int est_simple_enroll(struct hs20_osu_client *ctx, const char *url,
-                     const char *user, const char *pw);
-
 #endif /* OSU_CLIENT_H */
diff --git a/hs20/client/spp_client.c b/hs20/client/spp_client.c
deleted file mode 100644 (file)
index 194518e..0000000
+++ /dev/null
@@ -1,1003 +0,0 @@
-/*
- * Hotspot 2.0 SPP client
- * Copyright (c) 2012-2014, Qualcomm Atheros, Inc.
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#include "includes.h"
-#include <sys/stat.h>
-
-#include "common.h"
-#include "browser.h"
-#include "wpa_ctrl.h"
-#include "wpa_helpers.h"
-#include "xml-utils.h"
-#include "http-utils.h"
-#include "utils/base64.h"
-#include "crypto/crypto.h"
-#include "crypto/sha256.h"
-#include "osu_client.h"
-
-
-extern const char *spp_xsd_fname;
-
-static int hs20_spp_update_response(struct hs20_osu_client *ctx,
-                                   const char *session_id,
-                                   const char *spp_status,
-                                   const char *error_code);
-static void hs20_policy_update_complete(
-       struct hs20_osu_client *ctx, const char *pps_fname);
-
-
-static char * get_spp_attr_value(struct xml_node_ctx *ctx, xml_node_t *node,
-                                char *attr_name)
-{
-       return xml_node_get_attr_value_ns(ctx, node, SPP_NS_URI, attr_name);
-}
-
-
-static int hs20_spp_validate(struct hs20_osu_client *ctx, xml_node_t *node,
-                            const char *expected_name)
-{
-       struct xml_node_ctx *xctx = ctx->xml;
-       const char *name;
-       char *err;
-       int ret;
-
-       if (!xml_node_is_element(xctx, node))
-               return -1;
-
-       name = xml_node_get_localname(xctx, node);
-       if (name == NULL)
-               return -1;
-
-       if (strcmp(expected_name, name) != 0) {
-               wpa_printf(MSG_INFO, "Unexpected SOAP method name '%s' (expected '%s')",
-                          name, expected_name);
-               write_summary(ctx, "Unexpected SOAP method name '%s' (expected '%s')",
-                             name, expected_name);
-               return -1;
-       }
-
-       ret = xml_validate(xctx, node, spp_xsd_fname, &err);
-       if (ret < 0) {
-               wpa_printf(MSG_INFO, "XML schema validation error(s)\n%s", err);
-               write_summary(ctx, "SPP XML schema validation failed");
-               os_free(err);
-       }
-       return ret;
-}
-
-
-static void add_mo_container(struct xml_node_ctx *ctx, xml_namespace_t *ns,
-                            xml_node_t *parent, const char *urn,
-                            const char *fname)
-{
-       xml_node_t *node;
-       xml_node_t *fnode, *tnds;
-       char *str;
-
-       errno = 0;
-       fnode = node_from_file(ctx, fname);
-       if (!fnode) {
-               wpa_printf(MSG_ERROR,
-                          "Failed to create XML node from file: %s, possible error: %s",
-                          fname, strerror(errno));
-               return;
-       }
-       tnds = mo_to_tnds(ctx, fnode, 0, urn, "syncml:dmddf1.2");
-       xml_node_free(ctx, fnode);
-       if (!tnds)
-               return;
-
-       str = xml_node_to_str(ctx, tnds);
-       xml_node_free(ctx, tnds);
-       if (str == NULL)
-               return;
-
-       node = xml_node_create_text(ctx, parent, ns, "moContainer", str);
-       if (node)
-               xml_node_add_attr(ctx, node, ns, "moURN", urn);
-       os_free(str);
-}
-
-
-static xml_node_t * build_spp_post_dev_data(struct hs20_osu_client *ctx,
-                                           xml_namespace_t **ret_ns,
-                                           const char *session_id,
-                                           const char *reason)
-{
-       xml_namespace_t *ns;
-       xml_node_t *spp_node;
-
-       write_summary(ctx, "Building sppPostDevData requestReason='%s'",
-                     reason);
-       spp_node = xml_node_create_root(ctx->xml, SPP_NS_URI, "spp", &ns,
-                                       "sppPostDevData");
-       if (spp_node == NULL)
-               return NULL;
-       if (ret_ns)
-               *ret_ns = ns;
-
-       xml_node_add_attr(ctx->xml, spp_node, ns, "sppVersion", "1.0");
-       xml_node_add_attr(ctx->xml, spp_node, NULL, "requestReason", reason);
-       if (session_id)
-               xml_node_add_attr(ctx->xml, spp_node, ns, "sessionID",
-                                 session_id);
-       xml_node_add_attr(ctx->xml, spp_node, NULL, "redirectURI",
-                         "http://localhost:12345/");
-
-       xml_node_create_text(ctx->xml, spp_node, ns, "supportedSPPVersions",
-                            "1.0");
-       xml_node_create_text(ctx->xml, spp_node, ns, "supportedMOList",
-                            URN_HS20_PPS " " URN_OMA_DM_DEVINFO " "
-                            URN_OMA_DM_DEVDETAIL " " URN_HS20_DEVDETAIL_EXT);
-
-       add_mo_container(ctx->xml, ns, spp_node, URN_OMA_DM_DEVINFO,
-                        "devinfo.xml");
-       add_mo_container(ctx->xml, ns, spp_node, URN_OMA_DM_DEVDETAIL,
-                        "devdetail.xml");
-
-       return spp_node;
-}
-
-
-static int process_update_node(struct hs20_osu_client *ctx, xml_node_t *pps,
-                              xml_node_t *update)
-{
-       xml_node_t *node, *parent, *tnds, *unode;
-       char *str;
-       const char *name;
-       char *uri, *pos;
-       char *cdata, *cdata_end;
-       size_t fqdn_len;
-
-       wpa_printf(MSG_INFO, "Processing updateNode");
-       debug_dump_node(ctx, "updateNode", update);
-
-       uri = get_spp_attr_value(ctx->xml, update, "managementTreeURI");
-       if (uri == NULL) {
-               wpa_printf(MSG_INFO, "No managementTreeURI present");
-               return -1;
-       }
-       wpa_printf(MSG_INFO, "managementTreeUri: '%s'", uri);
-
-       name = os_strrchr(uri, '/');
-       if (name == NULL) {
-               wpa_printf(MSG_INFO, "Unexpected URI");
-               xml_node_get_attr_value_free(ctx->xml, uri);
-               return -1;
-       }
-       name++;
-       wpa_printf(MSG_INFO, "Update interior node: '%s'", name);
-
-       str = xml_node_get_text(ctx->xml, update);
-       if (str == NULL) {
-               wpa_printf(MSG_INFO, "Could not extract MO text");
-               xml_node_get_attr_value_free(ctx->xml, uri);
-               return -1;
-       }
-       wpa_printf(MSG_DEBUG, "[hs20] nodeContainer text: '%s'", str);
-       cdata = strstr(str, "<![CDATA[");
-       cdata_end = strstr(str, "]]>");
-       if (cdata && cdata_end && cdata_end > cdata &&
-           cdata < strstr(str, "MgmtTree") &&
-           cdata_end > strstr(str, "/MgmtTree")) {
-               char *tmp;
-               wpa_printf(MSG_DEBUG, "[hs20] Removing extra CDATA container");
-               tmp = strdup(cdata + 9);
-               if (tmp) {
-                       cdata_end = strstr(tmp, "]]>");
-                       if (cdata_end)
-                               *cdata_end = '\0';
-                       wpa_printf(MSG_DEBUG, "[hs20] nodeContainer text with CDATA container removed: '%s'",
-                                  tmp);
-                       tnds = xml_node_from_buf(ctx->xml, tmp);
-                       free(tmp);
-               } else
-                       tnds = NULL;
-       } else
-               tnds = xml_node_from_buf(ctx->xml, str);
-       xml_node_get_text_free(ctx->xml, str);
-       if (tnds == NULL) {
-               wpa_printf(MSG_INFO, "[hs20] Could not parse nodeContainer text");
-               xml_node_get_attr_value_free(ctx->xml, uri);
-               return -1;
-       }
-
-       unode = tnds_to_mo(ctx->xml, tnds);
-       xml_node_free(ctx->xml, tnds);
-       if (unode == NULL) {
-               wpa_printf(MSG_INFO, "[hs20] Could not parse nodeContainer TNDS text");
-               xml_node_get_attr_value_free(ctx->xml, uri);
-               return -1;
-       }
-
-       debug_dump_node(ctx, "Parsed TNDS", unode);
-
-       if (get_node_uri(ctx->xml, unode, name) == NULL) {
-               wpa_printf(MSG_INFO, "[hs20] %s node not found", name);
-               xml_node_free(ctx->xml, unode);
-               xml_node_get_attr_value_free(ctx->xml, uri);
-               return -1;
-       }
-
-       if (os_strncasecmp(uri, "./Wi-Fi/", 8) != 0) {
-               wpa_printf(MSG_INFO, "Do not allow update outside ./Wi-Fi");
-               xml_node_free(ctx->xml, unode);
-               xml_node_get_attr_value_free(ctx->xml, uri);
-               return -1;
-       }
-       pos = uri + 8;
-
-       if (ctx->fqdn == NULL) {
-               wpa_printf(MSG_INFO, "FQDN not known");
-               xml_node_free(ctx->xml, unode);
-               xml_node_get_attr_value_free(ctx->xml, uri);
-               return -1;
-       }
-       fqdn_len = os_strlen(ctx->fqdn);
-       if (os_strncasecmp(pos, ctx->fqdn, fqdn_len) != 0 ||
-           pos[fqdn_len] != '/') {
-               wpa_printf(MSG_INFO, "Do not allow update outside ./Wi-Fi/%s",
-                          ctx->fqdn);
-               xml_node_free(ctx->xml, unode);
-               xml_node_get_attr_value_free(ctx->xml, uri);
-               return -1;
-       }
-       pos += fqdn_len + 1;
-
-       if (os_strncasecmp(pos, "PerProviderSubscription/", 24) != 0) {
-               wpa_printf(MSG_INFO, "Do not allow update outside ./Wi-Fi/%s/PerProviderSubscription",
-                          ctx->fqdn);
-               xml_node_free(ctx->xml, unode);
-               xml_node_get_attr_value_free(ctx->xml, uri);
-               return -1;
-       }
-       pos += 24;
-
-       wpa_printf(MSG_INFO, "Update command for PPS node %s", pos);
-
-       node = get_node(ctx->xml, pps, pos);
-       if (node) {
-               parent = xml_node_get_parent(ctx->xml, node);
-               xml_node_detach(ctx->xml, node);
-               wpa_printf(MSG_INFO, "Replace '%s' node", name);
-       } else {
-               char *pos2;
-               pos2 = os_strrchr(pos, '/');
-               if (pos2 == NULL) {
-                       parent = pps;
-               } else {
-                       *pos2 = '\0';
-                       parent = get_node(ctx->xml, pps, pos);
-               }
-               if (parent == NULL) {
-                       wpa_printf(MSG_INFO, "Could not find parent %s", pos);
-                       xml_node_free(ctx->xml, unode);
-                       xml_node_get_attr_value_free(ctx->xml, uri);
-                       return -1;
-               }
-               wpa_printf(MSG_INFO, "Add '%s' node", name);
-       }
-       xml_node_add_child(ctx->xml, parent, unode);
-
-       xml_node_get_attr_value_free(ctx->xml, uri);
-
-       return 0;
-}
-
-
-static int update_pps(struct hs20_osu_client *ctx, xml_node_t *update,
-                     const char *pps_fname, xml_node_t *pps)
-{
-       wpa_printf(MSG_INFO, "Updating PPS based on updateNode element(s)");
-       xml_node_for_each_sibling(ctx->xml, update) {
-               xml_node_for_each_check(ctx->xml, update);
-               if (process_update_node(ctx, pps, update) < 0)
-                       return -1;
-       }
-
-       return update_pps_file(ctx, pps_fname, pps);
-}
-
-
-static void hs20_sub_rem_complete(struct hs20_osu_client *ctx,
-                                 const char *pps_fname)
-{
-       /*
-        * Update wpa_supplicant credentials and reconnect using updated
-        * information.
-        */
-       wpa_printf(MSG_INFO, "Updating wpa_supplicant credentials");
-       cmd_set_pps(ctx, pps_fname);
-
-       if (ctx->no_reconnect)
-               return;
-
-       wpa_printf(MSG_INFO, "Requesting reconnection with updated configuration");
-       if (wpa_command(ctx->ifname, "INTERWORKING_SELECT auto") < 0)
-               wpa_printf(MSG_ERROR, "Failed to request wpa_supplicant to reconnect");
-}
-
-
-static xml_node_t * hs20_spp_upload_mo(struct hs20_osu_client *ctx,
-                                      xml_node_t *cmd,
-                                      const char *session_id,
-                                      const char *pps_fname)
-{
-       xml_namespace_t *ns;
-       xml_node_t *node, *ret_node;
-       char *urn;
-
-       urn = get_spp_attr_value(ctx->xml, cmd, "moURN");
-       if (!urn) {
-               wpa_printf(MSG_INFO, "No URN included");
-               return NULL;
-       }
-       wpa_printf(MSG_INFO, "Upload MO request - URN=%s", urn);
-       if (strcasecmp(urn, URN_HS20_PPS) != 0) {
-               wpa_printf(MSG_INFO, "Unsupported moURN");
-               xml_node_get_attr_value_free(ctx->xml, urn);
-               return NULL;
-       }
-       xml_node_get_attr_value_free(ctx->xml, urn);
-
-       if (!pps_fname) {
-               wpa_printf(MSG_INFO, "PPS file name no known");
-               return NULL;
-       }
-
-       node = build_spp_post_dev_data(ctx, &ns, session_id,
-                                      "MO upload");
-       if (node == NULL)
-               return NULL;
-       add_mo_container(ctx->xml, ns, node, URN_HS20_PPS, pps_fname);
-
-       ret_node = soap_send_receive(ctx->http, node);
-       if (ret_node == NULL)
-               return NULL;
-
-       debug_dump_node(ctx, "Received response to MO upload", ret_node);
-
-       if (hs20_spp_validate(ctx, ret_node, "sppPostDevDataResponse") < 0) {
-               wpa_printf(MSG_INFO, "SPP validation failed");
-               xml_node_free(ctx->xml, ret_node);
-               return NULL;
-       }
-
-       return ret_node;
-}
-
-
-static int hs20_add_mo(struct hs20_osu_client *ctx, xml_node_t *add_mo,
-                      char *fname, size_t fname_len)
-{
-       char *uri, *urn;
-       int ret;
-
-       debug_dump_node(ctx, "Received addMO", add_mo);
-
-       urn = get_spp_attr_value(ctx->xml, add_mo, "moURN");
-       if (urn == NULL) {
-               wpa_printf(MSG_INFO, "[hs20] No moURN in addMO");
-               return -1;
-       }
-       wpa_printf(MSG_INFO, "addMO - moURN: '%s'", urn);
-       if (strcasecmp(urn, URN_HS20_PPS) != 0) {
-               wpa_printf(MSG_INFO, "[hs20] Unsupported MO in addMO");
-               xml_node_get_attr_value_free(ctx->xml, urn);
-               return -1;
-       }
-       xml_node_get_attr_value_free(ctx->xml, urn);
-
-       uri = get_spp_attr_value(ctx->xml, add_mo, "managementTreeURI");
-       if (uri == NULL) {
-               wpa_printf(MSG_INFO, "[hs20] No managementTreeURI in addMO");
-               return -1;
-       }
-       wpa_printf(MSG_INFO, "addMO - managementTreeURI: '%s'", uri);
-
-       ret = hs20_add_pps_mo(ctx, uri, add_mo, fname, fname_len);
-       xml_node_get_attr_value_free(ctx->xml, uri);
-       return ret;
-}
-
-
-static int process_spp_user_input_response(struct hs20_osu_client *ctx,
-                                          const char *session_id,
-                                          xml_node_t *add_mo)
-{
-       int ret;
-       char fname[300];
-
-       debug_dump_node(ctx, "addMO", add_mo);
-
-       wpa_printf(MSG_INFO, "Subscription registration completed");
-
-       if (hs20_add_mo(ctx, add_mo, fname, sizeof(fname)) < 0) {
-               wpa_printf(MSG_INFO, "Could not add MO");
-               ret = hs20_spp_update_response(
-                       ctx, session_id,
-                       "Error occurred",
-                       "MO addition or update failed");
-               return 0;
-       }
-
-       ret = hs20_spp_update_response(ctx, session_id, "OK", NULL);
-       if (ret == 0)
-               hs20_sub_rem_complete(ctx, fname);
-
-       return 0;
-}
-
-
-static xml_node_t * hs20_spp_user_input_completed(struct hs20_osu_client *ctx,
-                                                   const char *session_id)
-{
-       xml_node_t *node, *ret_node;
-
-       node = build_spp_post_dev_data(ctx, NULL, session_id,
-                                      "User input completed");
-       if (node == NULL)
-               return NULL;
-
-       ret_node = soap_send_receive(ctx->http, node);
-       if (!ret_node) {
-               if (soap_reinit_client(ctx->http) < 0)
-                       return NULL;
-               wpa_printf(MSG_INFO, "Try to finish with re-opened connection");
-               node = build_spp_post_dev_data(ctx, NULL, session_id,
-                                              "User input completed");
-               if (node == NULL)
-                       return NULL;
-               ret_node = soap_send_receive(ctx->http, node);
-               if (ret_node == NULL)
-                       return NULL;
-               wpa_printf(MSG_INFO, "Continue with new connection");
-       }
-
-       if (hs20_spp_validate(ctx, ret_node, "sppPostDevDataResponse") < 0) {
-               wpa_printf(MSG_INFO, "SPP validation failed");
-               xml_node_free(ctx->xml, ret_node);
-               return NULL;
-       }
-
-       return ret_node;
-}
-
-
-static xml_node_t * hs20_spp_get_certificate(struct hs20_osu_client *ctx,
-                                            xml_node_t *cmd,
-                                            const char *session_id,
-                                            const char *pps_fname)
-{
-       xml_namespace_t *ns;
-       xml_node_t *node, *ret_node;
-       int res;
-
-       wpa_printf(MSG_INFO, "Client certificate enrollment");
-
-       res = osu_get_certificate(ctx, cmd);
-       if (res < 0)
-               wpa_printf(MSG_INFO, "EST simpleEnroll failed");
-
-       node = build_spp_post_dev_data(ctx, &ns, session_id,
-                                      res == 0 ?
-                                      "Certificate enrollment completed" :
-                                      "Certificate enrollment failed");
-       if (node == NULL)
-               return NULL;
-
-       ret_node = soap_send_receive(ctx->http, node);
-       if (ret_node == NULL)
-               return NULL;
-
-       debug_dump_node(ctx, "Received response to certificate enrollment "
-                       "completed", ret_node);
-
-       if (hs20_spp_validate(ctx, ret_node, "sppPostDevDataResponse") < 0) {
-               wpa_printf(MSG_INFO, "SPP validation failed");
-               xml_node_free(ctx->xml, ret_node);
-               return NULL;
-       }
-
-       return ret_node;
-}
-
-
-static int hs20_spp_exec(struct hs20_osu_client *ctx, xml_node_t *exec,
-                        const char *session_id, const char *pps_fname,
-                        xml_node_t *pps, xml_node_t **ret_node)
-{
-       xml_node_t *cmd;
-       const char *name;
-       char *uri;
-       char *id = strdup(session_id);
-
-       if (id == NULL)
-               return -1;
-
-       *ret_node = NULL;
-
-       debug_dump_node(ctx, "exec", exec);
-
-       xml_node_for_each_child(ctx->xml, cmd, exec) {
-               xml_node_for_each_check(ctx->xml, cmd);
-               break;
-       }
-       if (!cmd) {
-               wpa_printf(MSG_INFO, "exec command element not found (cmd=%p)",
-                          cmd);
-               free(id);
-               return -1;
-       }
-
-       name = xml_node_get_localname(ctx->xml, cmd);
-
-       if (strcasecmp(name, "launchBrowserToURI") == 0) {
-               int res;
-               uri = xml_node_get_text(ctx->xml, cmd);
-               if (!uri) {
-                       wpa_printf(MSG_INFO, "No URI found");
-                       free(id);
-                       return -1;
-               }
-               wpa_printf(MSG_INFO, "Launch browser to URI '%s'", uri);
-               write_summary(ctx, "Launch browser to URI '%s'", uri);
-               res = hs20_web_browser(uri, 1);
-               xml_node_get_text_free(ctx->xml, uri);
-               if (res > 0) {
-                       wpa_printf(MSG_INFO, "User response in browser completed successfully - sessionid='%s'",
-                                  id);
-                       write_summary(ctx, "User response in browser completed successfully");
-                       *ret_node = hs20_spp_user_input_completed(ctx, id);
-                       free(id);
-                       return *ret_node ? 0 : -1;
-               } else {
-                       wpa_printf(MSG_INFO, "Failed to receive user response");
-                       write_summary(ctx, "Failed to receive user response");
-                       hs20_spp_update_response(
-                               ctx, id, "Error occurred", "Other");
-                       free(id);
-                       return -1;
-               }
-       }
-
-       if (strcasecmp(name, "uploadMO") == 0) {
-               if (pps_fname == NULL)
-                       return -1;
-               *ret_node = hs20_spp_upload_mo(ctx, cmd, id,
-                                              pps_fname);
-               free(id);
-               return *ret_node ? 0 : -1;
-       }
-
-       if (strcasecmp(name, "getCertificate") == 0) {
-               *ret_node = hs20_spp_get_certificate(ctx, cmd, id,
-                                                    pps_fname);
-               free(id);
-               return *ret_node ? 0 : -1;
-       }
-
-       wpa_printf(MSG_INFO, "Unsupported exec command: '%s'", name);
-       free(id);
-       return -1;
-}
-
-
-enum spp_post_dev_data_use {
-       SPP_SUBSCRIPTION_REMEDIATION,
-       SPP_POLICY_UPDATE,
-       SPP_SUBSCRIPTION_REGISTRATION,
-};
-
-static void process_spp_post_dev_data_response(
-       struct hs20_osu_client *ctx,
-       enum spp_post_dev_data_use use, xml_node_t *node,
-       const char *pps_fname, xml_node_t *pps)
-{
-       xml_node_t *child;
-       char *status = NULL;
-       xml_node_t *update = NULL, *exec = NULL, *add_mo = NULL, *no_mo = NULL;
-       char *session_id = NULL;
-
-       debug_dump_node(ctx, "sppPostDevDataResponse node", node);
-
-       status = get_spp_attr_value(ctx->xml, node, "sppStatus");
-       if (status == NULL) {
-               wpa_printf(MSG_INFO, "No sppStatus attribute");
-               goto out;
-       }
-       write_summary(ctx, "Received sppPostDevDataResponse sppStatus='%s'",
-                     status);
-
-       session_id = get_spp_attr_value(ctx->xml, node, "sessionID");
-       if (session_id == NULL) {
-               wpa_printf(MSG_INFO, "No sessionID attribute");
-               goto out;
-       }
-
-       wpa_printf(MSG_INFO, "[hs20] sppPostDevDataResponse - sppStatus: '%s'  sessionID: '%s'",
-                  status, session_id);
-
-       xml_node_for_each_child(ctx->xml, child, node) {
-               const char *name;
-               xml_node_for_each_check(ctx->xml, child);
-               debug_dump_node(ctx, "child", child);
-               name = xml_node_get_localname(ctx->xml, child);
-               wpa_printf(MSG_INFO, "localname: '%s'", name);
-               if (!update && strcasecmp(name, "updateNode") == 0)
-                       update = child;
-               if (!exec && strcasecmp(name, "exec") == 0)
-                       exec = child;
-               if (!add_mo && strcasecmp(name, "addMO") == 0)
-                       add_mo = child;
-               if (!no_mo && strcasecmp(name, "noMOUpdate") == 0)
-                       no_mo = child;
-       }
-
-       if (use == SPP_SUBSCRIPTION_REMEDIATION &&
-           strcasecmp(status,
-                      "Remediation complete, request sppUpdateResponse") == 0)
-       {
-               int res, ret;
-               if (!update && !no_mo) {
-                       wpa_printf(MSG_INFO, "No updateNode or noMOUpdate element");
-                       goto out;
-               }
-               wpa_printf(MSG_INFO, "Subscription remediation completed");
-               res = update_pps(ctx, update, pps_fname, pps);
-               if (res < 0)
-                       wpa_printf(MSG_INFO, "Failed to update PPS MO");
-               ret = hs20_spp_update_response(
-                       ctx, session_id,
-                       res < 0 ? "Error occurred" : "OK",
-                       res < 0 ? "MO addition or update failed" : NULL);
-               if (res == 0 && ret == 0)
-                       hs20_sub_rem_complete(ctx, pps_fname);
-               goto out;
-       }
-
-       if (use == SPP_SUBSCRIPTION_REMEDIATION &&
-           strcasecmp(status, "Exchange complete, release TLS connection") ==
-           0) {
-               if (!no_mo) {
-                       wpa_printf(MSG_INFO, "No noMOUpdate element");
-                       goto out;
-               }
-               wpa_printf(MSG_INFO, "Subscription remediation completed (no MO update)");
-               goto out;
-       }
-
-       if (use == SPP_POLICY_UPDATE &&
-           strcasecmp(status, "Update complete, request sppUpdateResponse") ==
-           0) {
-               int res, ret;
-               wpa_printf(MSG_INFO, "Policy update received - update PPS");
-               res = update_pps(ctx, update, pps_fname, pps);
-               ret = hs20_spp_update_response(
-                       ctx, session_id,
-                       res < 0 ? "Error occurred" : "OK",
-                       res < 0 ? "MO addition or update failed" : NULL);
-               if (res == 0 && ret == 0)
-                       hs20_policy_update_complete(ctx, pps_fname);
-               goto out;
-       }
-
-       if (use == SPP_SUBSCRIPTION_REGISTRATION &&
-           strcasecmp(status, "Provisioning complete, request "
-                      "sppUpdateResponse")  == 0) {
-               if (!add_mo) {
-                       wpa_printf(MSG_INFO, "No addMO element - not sure what to do next");
-                       goto out;
-               }
-               process_spp_user_input_response(ctx, session_id, add_mo);
-               node = NULL;
-               goto out;
-       }
-
-       if (strcasecmp(status, "No update available at this time") == 0) {
-               wpa_printf(MSG_INFO, "No update available at this time");
-               goto out;
-       }
-
-       if (strcasecmp(status, "OK") == 0) {
-               int res;
-               xml_node_t *ret;
-
-               if (!exec) {
-                       wpa_printf(MSG_INFO, "No exec element - not sure what to do next");
-                       goto out;
-               }
-               res = hs20_spp_exec(ctx, exec, session_id,
-                                   pps_fname, pps, &ret);
-               /* xml_node_free(ctx->xml, node); */
-               node = NULL;
-               if (res == 0 && ret)
-                       process_spp_post_dev_data_response(ctx, use,
-                                                          ret, pps_fname, pps);
-               goto out;
-       }
-
-       if (strcasecmp(status, "Error occurred") == 0) {
-               xml_node_t *err;
-               char *code = NULL;
-               err = get_node(ctx->xml, node, "sppError");
-               if (err)
-                       code = xml_node_get_attr_value(ctx->xml, err,
-                                                      "errorCode");
-               wpa_printf(MSG_INFO, "Error occurred - errorCode=%s",
-                          code ? code : "N/A");
-               xml_node_get_attr_value_free(ctx->xml, code);
-               goto out;
-       }
-
-       wpa_printf(MSG_INFO,
-                  "[hs20] Unsupported sppPostDevDataResponse sppStatus '%s'",
-                  status);
-out:
-       xml_node_get_attr_value_free(ctx->xml, status);
-       xml_node_get_attr_value_free(ctx->xml, session_id);
-       xml_node_free(ctx->xml, node);
-}
-
-
-static int spp_post_dev_data(struct hs20_osu_client *ctx,
-                            enum spp_post_dev_data_use use,
-                            const char *reason,
-                            const char *pps_fname, xml_node_t *pps)
-{
-       xml_node_t *payload;
-       xml_node_t *ret_node;
-
-       payload = build_spp_post_dev_data(ctx, NULL, NULL, reason);
-       if (payload == NULL)
-               return -1;
-
-       ret_node = soap_send_receive(ctx->http, payload);
-       if (!ret_node) {
-               const char *err = http_get_err(ctx->http);
-               if (err) {
-                       wpa_printf(MSG_INFO, "HTTP error: %s", err);
-                       write_result(ctx, "HTTP error: %s", err);
-               } else {
-                       write_summary(ctx, "Failed to send SOAP message");
-               }
-               return -1;
-       }
-
-       if (hs20_spp_validate(ctx, ret_node, "sppPostDevDataResponse") < 0) {
-               wpa_printf(MSG_INFO, "SPP validation failed");
-               xml_node_free(ctx->xml, ret_node);
-               return -1;
-       }
-
-       process_spp_post_dev_data_response(ctx, use, ret_node,
-                                          pps_fname, pps);
-       return 0;
-}
-
-
-void spp_sub_rem(struct hs20_osu_client *ctx, const char *address,
-                const char *pps_fname,
-                const char *client_cert, const char *client_key,
-                const char *cred_username, const char *cred_password,
-                xml_node_t *pps)
-{
-       wpa_printf(MSG_INFO, "SPP subscription remediation");
-       write_summary(ctx, "SPP subscription remediation");
-
-       os_free(ctx->server_url);
-       ctx->server_url = os_strdup(address);
-
-       if (soap_init_client(ctx->http, address, ctx->ca_fname,
-                            cred_username, cred_password, client_cert,
-                            client_key) == 0) {
-               spp_post_dev_data(ctx, SPP_SUBSCRIPTION_REMEDIATION,
-                                 "Subscription remediation", pps_fname, pps);
-       }
-}
-
-
-static void hs20_policy_update_complete(struct hs20_osu_client *ctx,
-                                       const char *pps_fname)
-{
-       wpa_printf(MSG_INFO, "Policy update completed");
-
-       /*
-        * Update wpa_supplicant credentials and reconnect using updated
-        * information.
-        */
-       wpa_printf(MSG_INFO, "Updating wpa_supplicant credentials");
-       cmd_set_pps(ctx, pps_fname);
-
-       wpa_printf(MSG_INFO, "Requesting reconnection with updated configuration");
-       if (wpa_command(ctx->ifname, "INTERWORKING_SELECT auto") < 0)
-               wpa_printf(MSG_ERROR, "Failed to request wpa_supplicant to reconnect");
-}
-
-
-static int process_spp_exchange_complete(struct hs20_osu_client *ctx,
-                                        xml_node_t *node)
-{
-       char *status, *session_id;
-
-       debug_dump_node(ctx, "sppExchangeComplete", node);
-
-       status = get_spp_attr_value(ctx->xml, node, "sppStatus");
-       if (status == NULL) {
-               wpa_printf(MSG_INFO, "No sppStatus attribute");
-               return -1;
-       }
-       write_summary(ctx, "Received sppExchangeComplete sppStatus='%s'",
-                     status);
-
-       session_id = get_spp_attr_value(ctx->xml, node, "sessionID");
-       if (session_id == NULL) {
-               wpa_printf(MSG_INFO, "No sessionID attribute");
-               xml_node_get_attr_value_free(ctx->xml, status);
-               return -1;
-       }
-
-       wpa_printf(MSG_INFO, "[hs20] sppStatus: '%s'  sessionID: '%s'",
-                  status, session_id);
-       xml_node_get_attr_value_free(ctx->xml, session_id);
-
-       if (strcasecmp(status, "Exchange complete, release TLS connection") ==
-           0) {
-               xml_node_get_attr_value_free(ctx->xml, status);
-               return 0;
-       }
-
-       wpa_printf(MSG_INFO, "Unexpected sppStatus '%s'", status);
-       write_summary(ctx, "Unexpected sppStatus '%s'", status);
-       xml_node_get_attr_value_free(ctx->xml, status);
-       return -1;
-}
-
-
-static xml_node_t * build_spp_update_response(struct hs20_osu_client *ctx,
-                                             const char *session_id,
-                                             const char *spp_status,
-                                             const char *error_code)
-{
-       xml_namespace_t *ns;
-       xml_node_t *spp_node, *node;
-
-       spp_node = xml_node_create_root(ctx->xml, SPP_NS_URI, "spp", &ns,
-                                       "sppUpdateResponse");
-       if (spp_node == NULL)
-               return NULL;
-
-       xml_node_add_attr(ctx->xml, spp_node, ns, "sppVersion", "1.0");
-       xml_node_add_attr(ctx->xml, spp_node, ns, "sessionID", session_id);
-       xml_node_add_attr(ctx->xml, spp_node, ns, "sppStatus", spp_status);
-
-       if (error_code) {
-               node = xml_node_create(ctx->xml, spp_node, ns, "sppError");
-               if (node)
-                       xml_node_add_attr(ctx->xml, node, NULL, "errorCode",
-                                         error_code);
-       }
-
-       return spp_node;
-}
-
-
-static int hs20_spp_update_response(struct hs20_osu_client *ctx,
-                                   const char *session_id,
-                                   const char *spp_status,
-                                   const char *error_code)
-{
-       xml_node_t *node, *ret_node;
-       int ret;
-
-       write_summary(ctx, "Building sppUpdateResponse sppStatus='%s' error_code='%s'",
-                     spp_status, error_code);
-       node = build_spp_update_response(ctx, session_id, spp_status,
-                                        error_code);
-       if (node == NULL)
-               return -1;
-       ret_node = soap_send_receive(ctx->http, node);
-       if (!ret_node) {
-               if (soap_reinit_client(ctx->http) < 0)
-                       return -1;
-               wpa_printf(MSG_INFO, "Try to finish with re-opened connection");
-               node = build_spp_update_response(ctx, session_id, spp_status,
-                                                error_code);
-               if (node == NULL)
-                       return -1;
-               ret_node = soap_send_receive(ctx->http, node);
-               if (ret_node == NULL)
-                       return -1;
-               wpa_printf(MSG_INFO, "Continue with new connection");
-       }
-
-       if (hs20_spp_validate(ctx, ret_node, "sppExchangeComplete") < 0) {
-               wpa_printf(MSG_INFO, "SPP validation failed");
-               xml_node_free(ctx->xml, ret_node);
-               return -1;
-       }
-
-       ret = process_spp_exchange_complete(ctx, ret_node);
-       xml_node_free(ctx->xml, ret_node);
-       return ret;
-}
-
-
-void spp_pol_upd(struct hs20_osu_client *ctx, const char *address,
-                const char *pps_fname,
-                const char *client_cert, const char *client_key,
-                const char *cred_username, const char *cred_password,
-                xml_node_t *pps)
-{
-       wpa_printf(MSG_INFO, "SPP policy update");
-       write_summary(ctx, "SPP policy update");
-
-       os_free(ctx->server_url);
-       ctx->server_url = os_strdup(address);
-
-       if (soap_init_client(ctx->http, address, ctx->ca_fname, cred_username,
-                            cred_password, client_cert, client_key) == 0) {
-               spp_post_dev_data(ctx, SPP_POLICY_UPDATE, "Policy update",
-                                 pps_fname, pps);
-       }
-}
-
-
-int cmd_prov(struct hs20_osu_client *ctx, const char *url)
-{
-       unlink("Cert/est_cert.der");
-       unlink("Cert/est_cert.pem");
-
-       if (url == NULL) {
-               wpa_printf(MSG_INFO, "Invalid prov command (missing URL)");
-               return -1;
-       }
-
-       wpa_printf(MSG_INFO,
-                  "Credential provisioning requested - URL: %s ca_fname: %s",
-                  url, ctx->ca_fname ? ctx->ca_fname : "N/A");
-
-       os_free(ctx->server_url);
-       ctx->server_url = os_strdup(url);
-
-       if (soap_init_client(ctx->http, url, ctx->ca_fname, NULL, NULL, NULL,
-                            NULL) < 0)
-               return -1;
-       spp_post_dev_data(ctx, SPP_SUBSCRIPTION_REGISTRATION,
-                         "Subscription registration", NULL, NULL);
-
-       return ctx->pps_cred_set ? 0 : -1;
-}
-
-
-int cmd_sim_prov(struct hs20_osu_client *ctx, const char *url)
-{
-       if (url == NULL) {
-               wpa_printf(MSG_INFO, "Invalid prov command (missing URL)");
-               return -1;
-       }
-
-       wpa_printf(MSG_INFO, "SIM provisioning requested");
-
-       os_free(ctx->server_url);
-       ctx->server_url = os_strdup(url);
-
-       wpa_printf(MSG_INFO, "Wait for IP address before starting SIM provisioning");
-
-       if (wait_ip_addr(ctx->ifname, 15) < 0) {
-               wpa_printf(MSG_INFO, "Could not get IP address for WLAN - try connection anyway");
-       }
-
-       if (soap_init_client(ctx->http, url, ctx->ca_fname, NULL, NULL, NULL,
-                            NULL) < 0)
-               return -1;
-       spp_post_dev_data(ctx, SPP_SUBSCRIPTION_REGISTRATION,
-                         "Subscription provisioning", NULL, NULL);
-
-       return ctx->pps_cred_set ? 0 : -1;
-}