diff options
author | Cy Schubert <cy@FreeBSD.org> | 2022-01-17 21:12:36 +0000 |
---|---|---|
committer | Cy Schubert <cy@FreeBSD.org> | 2022-01-17 21:12:36 +0000 |
commit | df0c787c3ece1d65fd6fef34aa8f56da557b5ac0 (patch) | |
tree | 51273e0a1286e1afda45143bd0aba2f369d95ea4 | |
parent | 03f33dd0772867358dffaf3a8b5ddf42842aaf55 (diff) | |
download | src-vendor/wpa.tar.gz src-vendor/wpa.zip |
wpa: Import wpa 2.10 (second part)vendor/wpa
WPA is in fact two distfiles. Import the second distfile.
234 files changed, 170785 insertions, 0 deletions
diff --git a/hs20/client/Android.mk b/hs20/client/Android.mk new file mode 100644 index 000000000000..e4db32208d50 --- /dev/null +++ b/hs20/client/Android.mk @@ -0,0 +1,81 @@ +LOCAL_PATH := $(call my-dir) + +INCLUDES = $(LOCAL_PATH) +INCLUDES += $(LOCAL_PATH)/../../src/utils +INCLUDES += $(LOCAL_PATH)/../../src/common +INCLUDES += $(LOCAL_PATH)/../../src +INCLUDES += external/libxml2/include +INCLUDES += external/curl/include +INCLUDES += external/webkit/Source/WebKit/gtk + +# We try to keep this compiling against older platform versions. +# The new icu location (external/icu) exports its own headers, but +# the older versions in external/icu4c don't, and we need to add those +# headers to the include path by hand. +ifeq ($(wildcard external/icu),) +INCLUDES += external/icu4c/common +else +# The LOCAL_EXPORT_C_INCLUDE_DIRS from ICU did not seem to fully resolve the +# build (e.g., "mm -B" failed to build, but following that with "mm" allowed +# the build to complete). For now, add the include directory manually here for +# Android 5.0. +ver = $(filter 5.0%,$(PLATFORM_VERSION)) +ifneq (,$(strip $(ver))) +INCLUDES += external/icu/icu4c/source/common +endif +endif + + +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 += ../../src/common/wpa_ctrl.c +OBJS += ../../src/common/wpa_helpers.c +OBJS += ../../src/utils/xml-utils.c +#OBJS += ../../src/utils/browser-android.c +OBJS += ../../src/utils/browser-wpadebug.c +OBJS += ../../src/utils/wpabuf.c +OBJS += ../../src/utils/eloop.c +OBJS += ../../src/wps/httpread.c +OBJS += ../../src/wps/http_server.c +OBJS += ../../src/utils/xml_libxml2.c +OBJS += ../../src/utils/http_curl.c +OBJS += ../../src/utils/base64.c +OBJS += ../../src/utils/os_unix.c +L_CFLAGS += -DCONFIG_DEBUG_FILE +OBJS += ../../src/utils/wpa_debug.c +OBJS += ../../src/utils/common.c +OBJS += ../../src/crypto/crypto_internal.c +OBJS += ../../src/crypto/md5-internal.c +OBJS += ../../src/crypto/sha1-internal.c +OBJS += ../../src/crypto/sha256-internal.c +OBJS += ../../src/crypto/tls_openssl_ocsp.c + +L_CFLAGS += -DEAP_TLS_OPENSSL + +L_CFLAGS += -Wno-unused-parameter + + +######################## +include $(CLEAR_VARS) +LOCAL_MODULE := hs20-osu-client +LOCAL_MODULE_TAGS := optional + +LOCAL_SHARED_LIBRARIES := libc libcutils +LOCAL_SHARED_LIBRARIES += libcrypto libssl +#LOCAL_SHARED_LIBRARIES += libxml2 +LOCAL_STATIC_LIBRARIES += libxml2 +LOCAL_SHARED_LIBRARIES += libicuuc +LOCAL_SHARED_LIBRARIES += libcurl + +LOCAL_CFLAGS := $(L_CFLAGS) +LOCAL_SRC_FILES := $(OBJS) +LOCAL_C_INCLUDES := $(INCLUDES) +include $(BUILD_EXECUTABLE) + +######################## diff --git a/hs20/client/Makefile b/hs20/client/Makefile new file mode 100644 index 000000000000..4dcfe2d3bf2c --- /dev/null +++ b/hs20/client/Makefile @@ -0,0 +1,81 @@ +ALL=hs20-osu-client + +include ../../src/build.rules + +CFLAGS += -I../../src/utils +CFLAGS += -I../../src/common +CFLAGS += -I../../src + +ifndef CONFIG_NO_BROWSER +ifndef CONFIG_BROWSER_SYSTEM +TEST_WK := $(shell pkg-config --silence-errors --cflags webkitgtk-3.0) +ifeq ($(TEST_WK),) +# Try webkit2 +GTKCFLAGS := $(shell pkg-config --cflags gtk+-3.0 webkit2gtk-4.0) +GTKLIBS := $(shell pkg-config --libs gtk+-3.0 webkit2gtk-4.0) +CFLAGS += -DUSE_WEBKIT2 +else +GTKCFLAGS := $(shell pkg-config --cflags gtk+-3.0 webkitgtk-3.0) +GTKLIBS := $(shell pkg-config --libs gtk+-3.0 webkitgtk-3.0) +endif + +CFLAGS += $(GTKCFLAGS) +LIBS += $(GTKLIBS) +endif +endif + +OBJS=spp_client.o +OBJS += oma_dm_client.o +OBJS += osu_client.o +OBJS += est.o +OBJS += ../../src/utils/xml-utils.o +CFLAGS += -DCONFIG_CTRL_IFACE +CFLAGS += -DCONFIG_CTRL_IFACE_UNIX +OBJS += ../../src/common/wpa_ctrl.o ../../src/common/wpa_helpers.o +ifdef CONFIG_NO_BROWSER +CFLAGS += -DCONFIG_NO_BROWSER +else +ifdef CONFIG_BROWSER_SYSTEM +OBJS += ../../src/utils/eloop.o +OBJS += ../../src/utils/wpabuf.o +OBJS += ../../src/wps/httpread.o +OBJS += ../../src/wps/http_server.o +OBJS += ../../src/utils/browser-system.o +else +OBJS += ../../src/utils/browser.o +endif +endif +OBJS += ../../src/utils/xml_libxml2.o +OBJS += ../../src/utils/http_curl.o +OBJS += ../../src/utils/base64.o +OBJS += ../../src/utils/os_unix.o +CFLAGS += -DCONFIG_DEBUG_FILE +OBJS += ../../src/utils/wpa_debug.o +OBJS += ../../src/utils/common.o +OBJS += ../../src/crypto/crypto_internal.o +OBJS += ../../src/crypto/md5-internal.o +OBJS += ../../src/crypto/sha1-internal.o +OBJS += ../../src/crypto/sha256-internal.o + +CFLAGS += $(shell xml2-config --cflags) +LIBS += $(shell xml2-config --libs) + +# Allow static/custom linking of libcurl. +ifdef CUST_CURL_LINKAGE +LIBS += ${CUST_CURL_LINKAGE} +else +LIBS += -lcurl +endif + +CFLAGS += -DEAP_TLS_OPENSSL +OBJS += ../../src/crypto/tls_openssl_ocsp.o +LIBS += -lssl -lcrypto + +_OBJS_VAR := OBJS +include ../../src/objs.mk +hs20-osu-client: $(OBJS) + $(Q)$(LDO) $(LDFLAGS) -o hs20-osu-client $(OBJS) $(LIBS) + @$(E) " LD " $@ + +clean: common-clean + rm -f core *~ diff --git a/hs20/client/devdetail.xml b/hs20/client/devdetail.xml new file mode 100644 index 000000000000..6d0389e8a133 --- /dev/null +++ b/hs20/client/devdetail.xml @@ -0,0 +1,47 @@ +<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 new file mode 100644 index 000000000000..d48a520a98a1 --- /dev/null +++ b/hs20/client/devinfo.xml @@ -0,0 +1,7 @@ +<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 new file mode 100644 index 000000000000..97f9132100c4 --- /dev/null +++ b/hs20/client/est.c @@ -0,0 +1,769 @@ +/* + * 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/rsa.h> +#include <openssl/asn1.h> +#include <openssl/asn1t.h> +#include <openssl/x509.h> +#include <openssl/x509v3.h> +#include <openssl/opensslv.h> +#ifdef OPENSSL_IS_BORINGSSL +#include <openssl/buf.h> +#endif /* OPENSSL_IS_BORINGSSL */ + +#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 && !defined(OPENSSL_IS_BORINGSSL) +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; + +#ifdef OPENSSL_IS_BORINGSSL + num = sk_num(CHECKED_CAST(_STACK *, STACK_OF(AttrOrOID) *, + csrattrs->attrs)); + for (i = 0; i < num; i++) { + AttrOrOID *ao = sk_value( + CHECKED_CAST(_STACK *, const STACK_OF(AttrOrOID) *, + csrattrs->attrs), i); + 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; + } + } +#else /* OPENSSL_IS_BORINGSSL */ +#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(OPENSSL_IS_BORINGSSL) + 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 && !defined(OPENSSL_IS_BORINGSSL) + 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; + } + } +#endif /* OPENSSL_IS_BORINGSSL */ +} + + +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; + RSA *rsa; + 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; + + rsa = EVP_PKEY_get1_RSA(pkey); + if (rsa == NULL) + goto fail; + + if (key_pem) { + FILE *f = fopen(key_pem, "wb"); + if (f == NULL) + goto fail; + if (!PEM_write_RSAPrivateKey(f, rsa, 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 new file mode 100644 index 000000000000..bcd68b8775d5 --- /dev/null +++ b/hs20/client/oma_dm_client.c @@ -0,0 +1,1398 @@ +/* + * 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); +} diff --git a/hs20/client/osu_client.c b/hs20/client/osu_client.c new file mode 100644 index 000000000000..11bf0db35e93 --- /dev/null +++ b/hs20/client/osu_client.c @@ -0,0 +1,3431 @@ +/* + * Hotspot 2.0 OSU 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 <time.h> +#include <sys/stat.h> +#ifdef ANDROID +#include "private/android_filesystem_config.h" +#endif /* ANDROID */ + +#include "common.h" +#include "utils/browser.h" +#include "utils/base64.h" +#include "utils/xml-utils.h" +#include "utils/http-utils.h" +#include "common/wpa_ctrl.h" +#include "common/wpa_helpers.h" +#include "eap_common/eap_defs.h" +#include "crypto/crypto.h" +#include "crypto/sha256.h" +#include "osu_client.h" + +const char *spp_xsd_fname = "spp.xsd"; + + +void write_result(struct hs20_osu_client *ctx, const char *fmt, ...) +{ + va_list ap; + FILE *f; + char buf[500]; + + va_start(ap, fmt); + vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + write_summary(ctx, "%s", buf); + + if (!ctx->result_file) + return; + + f = fopen(ctx->result_file, "w"); + if (f == NULL) + return; + + va_start(ap, fmt); + vfprintf(f, fmt, ap); + va_end(ap); + fprintf(f, "\n"); + fclose(f); +} + + +void write_summary(struct hs20_osu_client *ctx, const char *fmt, ...) +{ + va_list ap; + FILE *f; + + if (!ctx->summary_file) + return; + + f = fopen(ctx->summary_file, "a"); + if (f == NULL) + return; + + va_start(ap, fmt); + vfprintf(f, fmt, ap); + va_end(ap); + fprintf(f, "\n"); + fclose(f); +} + + +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, + const char *fname) +{ + xml_node_t *url_node, *hash_node; + char *url, *hash; + char *cert; + size_t len; + u8 digest1[SHA256_MAC_LEN], digest2[SHA256_MAC_LEN]; + int res; + char *b64; + FILE *f; + + url_node = get_node(ctx->xml, params, "CertURL"); + hash_node = get_node(ctx->xml, params, "CertSHA256Fingerprint"); + if (url_node == NULL || hash_node == NULL) + return -1; + url = xml_node_get_text(ctx->xml, url_node); + hash = xml_node_get_text(ctx->xml, hash_node); + if (url == NULL || hash == NULL) { + xml_node_get_text_free(ctx->xml, url); + xml_node_get_text_free(ctx->xml, hash); + return -1; + } + + wpa_printf(MSG_INFO, "CertURL: %s", url); + wpa_printf(MSG_INFO, "SHA256 hash: %s", hash); + + if (hexstr2bin(hash, digest1, SHA256_MAC_LEN) < 0) { + wpa_printf(MSG_INFO, "Invalid SHA256 hash value"); + write_result(ctx, "Invalid SHA256 hash value for downloaded certificate"); + xml_node_get_text_free(ctx->xml, hash); + return -1; + } + 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; + + cert = os_readfile(TMP_CERT_DL_FILE, &len); + remove(TMP_CERT_DL_FILE); + if (cert == NULL) + return -1; + + if (sha256_vector(1, (const u8 **) &cert, &len, digest2) < 0) { + os_free(cert); + return -1; + } + + if (os_memcmp(digest1, digest2, sizeof(digest1)) != 0) { + wpa_printf(MSG_INFO, "Downloaded certificate fingerprint did not match"); + write_result(ctx, "Downloaded certificate fingerprint did not match"); + os_free(cert); + return -1; + } + + b64 = base64_encode(cert, len, NULL); + os_free(cert); + if (b64 == NULL) + return -1; + + f = fopen(fname, "wb"); + if (f == NULL) { + os_free(b64); + return -1; + } + + fprintf(f, "-----BEGIN CERTIFICATE-----\n" + "%s" + "-----END CERTIFICATE-----\n", + b64); + + os_free(b64); + fclose(f); + + wpa_printf(MSG_INFO, "Downloaded certificate into %s and validated fingerprint", + fname); + write_summary(ctx, "Downloaded certificate into %s and validated fingerprint", + fname); + + return 0; +} + + +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) +{ + xml_node_t *pps, *node, *aaa; + 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, + "AAAServerTrustRoot"); + if (node == NULL) { + wpa_printf(MSG_INFO, "No AAAServerTrustRoot/CertURL found from PPS"); + xml_node_free(ctx->xml, pps); + return -2; + } + + aaa = xml_node_first_child(ctx->xml, node); + if (aaa == NULL) { + wpa_printf(MSG_INFO, "No AAAServerTrustRoot/CertURL found from PPS"); + xml_node_free(ctx->xml, pps); + return -1; + } + + ret = download_cert(ctx, aaa, ca_fname); + xml_node_free(ctx->xml, pps); + + return ret; +} + + +static int download_trust_roots(struct hs20_osu_client *ctx, + const char *pps_fname) +{ + char *dir, *pos; + char fname[300]; + int ret, ret1; + + 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; + + os_free(dir); + + return ret; +} + + +static int server_dnsname_suffix_match(struct hs20_osu_client *ctx, + const char *fqdn) +{ + size_t match_len, len, i; + const char *val; + + match_len = os_strlen(fqdn); + + 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); + + if (match_len > len) + continue; + + if (os_strncasecmp(val + len - match_len, fqdn, match_len) != 0) + continue; /* no match */ + + if (match_len == len) + return 1; /* exact match */ + + if (val[len - match_len - 1] == '.') + return 1; /* full label match completes suffix match */ + + /* Reject due to incomplete label match */ + } + + /* 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) +{ + char *str; + char *fqdn, *pos; + xml_node_t *tnds, *mo, *cert; + const char *name; + int ret; + + 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; + } + + type = xml_node_get_text(ctx->xml, node); + if (type == NULL) + return; + wpa_printf(MSG_INFO, "- Policy/MinBackhaulThreshold/<X+>/NetworkType = %s", + type); + if (os_strcasecmp(type, "home") == 0) + home = 1; + else if (os_strcasecmp(type, "roaming") == 0) + home = 0; + else { + wpa_printf(MSG_INFO, "Ignore MinBackhaulThreshold with invalid NetworkType"); + xml_node_get_text_free(ctx->xml, type); + return; + } + xml_node_get_text_free(ctx->xml, type); + + node = get_node(ctx->xml, min_backhaul, "DLBandwidth"); + if (node) + dl = xml_node_get_text(ctx->xml, node); + + node = get_node(ctx->xml, min_backhaul, "ULBandwidth"); + if (node) + ul = xml_node_get_text(ctx->xml, node); + + if (dl == NULL && ul == NULL) { + wpa_printf(MSG_INFO, "Ignore MinBackhaulThreshold without either DLBandwidth or ULBandwidth nodes"); + return; + } + + if (dl) + wpa_printf(MSG_INFO, "- Policy/MinBackhaulThreshold/<X+>/DLBandwidth = %s", + dl); + if (ul) + wpa_printf(MSG_INFO, "- Policy/MinBackhaulThreshold/<X+>/ULBandwidth = %s", + ul); + + if (home) { + if (dl && + set_cred(ctx->ifname, id, "min_dl_bandwidth_home", dl) < 0) + wpa_printf(MSG_INFO, "Failed to set cred bandwidth limit"); + if (ul && + set_cred(ctx->ifname, id, "min_ul_bandwidth_home", ul) < 0) + wpa_printf(MSG_INFO, "Failed to set cred bandwidth limit"); + } else { + if (dl && + set_cred(ctx->ifname, id, "min_dl_bandwidth_roaming", dl) < + 0) + wpa_printf(MSG_INFO, "Failed to set cred bandwidth limit"); + if (ul && + set_cred(ctx->ifname, id, "min_ul_bandwidth_roaming", ul) < + 0) + wpa_printf(MSG_INFO, "Failed to set cred bandwidth limit"); + } + + xml_node_get_text_free(ctx->xml, dl); + xml_node_get_text_free(ctx->xml, ul); +} + + +static void set_pps_cred_policy_min_backhaul_list(struct hs20_osu_client *ctx, + int id, xml_node_t *node) +{ + xml_node_t *child; + + wpa_printf(MSG_INFO, "- Policy/MinBackhaulThreshold"); + + xml_node_for_each_child(ctx->xml, child, node) { + xml_node_for_each_check(ctx->xml, child); + set_pps_cred_policy_min_backhaul(ctx, id, child); + } +} + + +static void set_pps_cred_policy_update(struct hs20_osu_client *ctx, int id, + xml_node_t *node) +{ + wpa_printf(MSG_INFO, "- Policy/PolicyUpdate"); + /* Not used in wpa_supplicant */ +} + + +static void set_pps_cred_policy_required_proto_port(struct hs20_osu_client *ctx, + int id, xml_node_t *tuple) +{ + xml_node_t *node; + char *proto, *port; + char *buf; + size_t buflen; + + node = get_node(ctx->xml, tuple, "IPProtocol"); + if (node == NULL) { + wpa_printf(MSG_INFO, "Ignore RequiredProtoPortTuple without mandatory IPProtocol node"); + return; + } + + proto = xml_node_get_text(ctx->xml, node); + if (proto == NULL) + return; + + wpa_printf(MSG_INFO, "- Policy/RequiredProtoPortTuple/<X+>/IPProtocol = %s", + proto); + + node = get_node(ctx->xml, tuple, "PortNumber"); + port = node ? xml_node_get_text(ctx->xml, node) : NULL; + if (port) { + wpa_printf(MSG_INFO, "- Policy/RequiredProtoPortTuple/<X+>/PortNumber = %s", + port); + buflen = os_strlen(proto) + os_strlen(port) + 10; + buf = os_malloc(buflen); + if (buf) + os_snprintf(buf, buflen, "%s:%s", proto, port); + xml_node_get_text_free(ctx->xml, port); + } else { + buflen = os_strlen(proto) + 10; + buf = os_malloc(buflen); + if (buf) + os_snprintf(buf, buflen, "%s", proto); + } + + xml_node_get_text_free(ctx->xml, proto); + + if (buf == NULL) + return; + + if (set_cred(ctx->ifname, id, "req_conn_capab", buf) < 0) + wpa_printf(MSG_INFO, "Could not set req_conn_capab"); + + os_free(buf); +} + + +static void set_pps_cred_policy_required_proto_ports(struct hs20_osu_client *ctx, + int id, xml_node_t *node) +{ + xml_node_t *child; + + wpa_printf(MSG_INFO, "- Policy/RequiredProtoPortTuple"); + + xml_node_for_each_child(ctx->xml, child, node) { + xml_node_for_each_check(ctx->xml, child); + set_pps_cred_policy_required_proto_port(ctx, id, child); + } +} + + +static void set_pps_cred_policy_max_bss_load(struct hs20_osu_client *ctx, int id, + xml_node_t *node) +{ + char *str = xml_node_get_text(ctx->xml, node); + if (str == NULL) + return; + wpa_printf(MSG_INFO, "- Policy/MaximumBSSLoadValue - %s", str); + if (set_cred(ctx->ifname, id, "max_bss_load", str) < 0) + wpa_printf(MSG_INFO, "Failed to set cred max_bss_load limit"); + xml_node_get_text_free(ctx->xml, str); +} + + +static void set_pps_cred_policy(struct hs20_osu_client *ctx, int id, + xml_node_t *node) +{ + xml_node_t *child; + const char *name; + + wpa_printf(MSG_INFO, "- Policy"); + + xml_node_for_each_child(ctx->xml, child, node) { + xml_node_for_each_check(ctx->xml, child); + name = xml_node_get_localname(ctx->xml, child); + if (os_strcasecmp(name, "PreferredRoamingPartnerList") == 0) + set_pps_cred_policy_prpl(ctx, id, child); + else if (os_strcasecmp(name, "MinBackhaulThreshold") == 0) + set_pps_cred_policy_min_backhaul_list(ctx, id, child); + else if (os_strcasecmp(name, "PolicyUpdate") == 0) + set_pps_cred_policy_update(ctx, id, child); + else if (os_strcasecmp(name, "SPExclusionList") == 0) + set_pps_cred_policy_spel(ctx, id, child); + else if (os_strcasecmp(name, "RequiredProtoPortTuple") == 0) + set_pps_cred_policy_required_proto_ports(ctx, id, child); + else if (os_strcasecmp(name, "MaximumBSSLoadValue") == 0) + set_pps_cred_policy_max_bss_load(ctx, id, child); + else + wpa_printf(MSG_INFO, "Unknown Policy node '%s'", name); + } +} + + +static void set_pps_cred_priority(struct hs20_osu_client *ctx, int id, + xml_node_t *node) +{ + char *str = xml_node_get_text(ctx->xml, node); + if (str == NULL) + return; + wpa_printf(MSG_INFO, "- CredentialPriority = %s", str); + if (set_cred(ctx->ifname, id, "sp_priority", str) < 0) + wpa_printf(MSG_INFO, "Failed to set cred sp_priority"); + xml_node_get_text_free(ctx->xml, str); +} + + +static void set_pps_cred_aaa_server_trust_root(struct hs20_osu_client *ctx, + int id, xml_node_t *node) +{ + wpa_printf(MSG_INFO, "- AAAServerTrustRoot - TODO"); +} + + +static void set_pps_cred_sub_update(struct hs20_osu_client *ctx, int id, + xml_node_t *node) +{ + wpa_printf(MSG_INFO, "- SubscriptionUpdate"); + /* not used within wpa_supplicant */ +} + + +static void set_pps_cred_home_sp_network_id(struct hs20_osu_client *ctx, + int id, xml_node_t *node) +{ + xml_node_t *ssid_node, *hessid_node; + char *ssid, *hessid; + + ssid_node = get_node(ctx->xml, node, "SSID"); + if (ssid_node == NULL) { + wpa_printf(MSG_INFO, "Ignore HomeSP/NetworkID without mandatory SSID node"); + return; + } + + hessid_node = get_node(ctx->xml, node, "HESSID"); + + ssid = xml_node_get_text(ctx->xml, ssid_node); + if (ssid == NULL) + return; + hessid = hessid_node ? xml_node_get_text(ctx->xml, hessid_node) : NULL; + + wpa_printf(MSG_INFO, "- HomeSP/NetworkID/<X+>/SSID = %s", ssid); + if (hessid) + wpa_printf(MSG_INFO, "- HomeSP/NetworkID/<X+>/HESSID = %s", + hessid); + + /* TODO: Configure to wpa_supplicant */ + + xml_node_get_text_free(ctx->xml, ssid); + xml_node_get_text_free(ctx->xml, hessid); +} + + +static void set_pps_cred_home_sp_network_ids(struct hs20_osu_client *ctx, + int id, xml_node_t *node) +{ + xml_node_t *child; + + wpa_printf(MSG_INFO, "- HomeSP/NetworkID"); + + xml_node_for_each_child(ctx->xml, child, node) { + xml_node_for_each_check(ctx->xml, child); + set_pps_cred_home_sp_network_id(ctx, id, child); + } +} + + +static void set_pps_cred_home_sp_friendly_name(struct hs20_osu_client *ctx, + int id, xml_node_t *node) +{ + char *str = xml_node_get_text(ctx->xml, node); + if (str == NULL) + return; + wpa_printf(MSG_INFO, "- HomeSP/FriendlyName = %s", str); + /* not used within wpa_supplicant(?) */ + xml_node_get_text_free(ctx->xml, str); +} + + +static void set_pps_cred_home_sp_icon_url(struct hs20_osu_client *ctx, + int id, xml_node_t *node) +{ + char *str = xml_node_get_text(ctx->xml, node); + if (str == NULL) + return; + wpa_printf(MSG_INFO, "- HomeSP/IconURL = %s", str); + /* not used within wpa_supplicant */ + xml_node_get_text_free(ctx->xml, str); +} + + +static void set_pps_cred_home_sp_fqdn(struct hs20_osu_client *ctx, int id, + xml_node_t *node) +{ + char *str = xml_node_get_text(ctx->xml, node); + if (str == NULL) + return; + wpa_printf(MSG_INFO, "- HomeSP/FQDN = %s", str); + if (set_cred_quoted(ctx->ifname, id, "domain", str) < 0) + wpa_printf(MSG_INFO, "Failed to set cred domain"); + if (set_cred_quoted(ctx->ifname, id, "domain_suffix_match", str) < 0) + wpa_printf(MSG_INFO, "Failed to set cred domain_suffix_match"); + xml_node_get_text_free(ctx->xml, str); +} + + +static void set_pps_cred_home_sp_oi(struct hs20_osu_client *ctx, int id, + xml_node_t *node) +{ + xml_node_t *child; + const char *name; + char *homeoi = NULL; + int required = 0; + char *str; + + xml_node_for_each_child(ctx->xml, child, node) { + xml_node_for_each_check(ctx->xml, child); + name = xml_node_get_localname(ctx->xml, child); + if (strcasecmp(name, "HomeOI") == 0 && !homeoi) { + homeoi = xml_node_get_text(ctx->xml, child); + wpa_printf(MSG_INFO, "- HomeSP/HomeOIList/<X+>/HomeOI = %s", + homeoi); + } else if (strcasecmp(name, "HomeOIRequired") == 0) { + str = xml_node_get_text(ctx->xml, child); + wpa_printf(MSG_INFO, "- HomeSP/HomeOIList/<X+>/HomeOIRequired = '%s'", + str); + if (str == NULL) + continue; + required = strcasecmp(str, "true") == 0; + xml_node_get_text_free(ctx->xml, str); + } else + wpa_printf(MSG_INFO, "Unknown HomeOIList node '%s'", + name); + } + + if (homeoi == NULL) { + wpa_printf(MSG_INFO, "- HomeSP/HomeOIList/<X+> without HomeOI ignored"); + return; + } + + wpa_printf(MSG_INFO, "- HomeSP/HomeOIList/<X+> '%s' required=%d", + homeoi, required); + + if (required) { + if (set_cred(ctx->ifname, id, "required_roaming_consortium", + homeoi) < 0) + wpa_printf(MSG_INFO, "Failed to set cred required_roaming_consortium"); + } else { + if (set_cred(ctx->ifname, id, "roaming_consortium", homeoi) < 0) + wpa_printf(MSG_INFO, "Failed to set cred roaming_consortium"); + } + + xml_node_get_text_free(ctx->xml, homeoi); +} + + +static void set_pps_cred_home_sp_oi_list(struct hs20_osu_client *ctx, int id, + xml_node_t *node) +{ + xml_node_t *child; + + wpa_printf(MSG_INFO, "- HomeSP/HomeOIList"); + + xml_node_for_each_child(ctx->xml, child, node) { + xml_node_for_each_check(ctx->xml, child); + set_pps_cred_home_sp_oi(ctx, id, child); + } +} + + +static void set_pps_cred_home_sp_other_partner(struct hs20_osu_client *ctx, + int id, xml_node_t *node) +{ + xml_node_t *child; + const char *name; + char *fqdn = NULL; + + xml_node_for_each_child(ctx->xml, child, node) { + xml_node_for_each_check(ctx->xml, child); + name = xml_node_get_localname(ctx->xml, child); + if (os_strcasecmp(name, "FQDN") == 0 && !fqdn) { + fqdn = xml_node_get_text(ctx->xml, child); + wpa_printf(MSG_INFO, "- HomeSP/OtherHomePartners/<X+>/FQDN = %s", + fqdn); + } else + wpa_printf(MSG_INFO, "Unknown OtherHomePartners node '%s'", + name); + } + + if (fqdn == NULL) { + wpa_printf(MSG_INFO, "- HomeSP/OtherHomePartners/<X+> without FQDN ignored"); + return; + } + + if (set_cred_quoted(ctx->ifname, id, "domain", fqdn) < 0) + wpa_printf(MSG_INFO, "Failed to set cred domain for OtherHomePartners node"); + + xml_node_get_text_free(ctx->xml, fqdn); +} + + +static void set_pps_cred_home_sp_other_partners(struct hs20_osu_client *ctx, + int id, + xml_node_t *node) +{ + xml_node_t *child; + + wpa_printf(MSG_INFO, "- HomeSP/OtherHomePartners"); + + xml_node_for_each_child(ctx->xml, child, node) { + xml_node_for_each_check(ctx->xml, child); + set_pps_cred_home_sp_other_partner(ctx, id, child); + } +} + + +static void set_pps_cred_home_sp_roaming_consortium_oi( + struct hs20_osu_client *ctx, int id, xml_node_t *node) +{ + char *str = xml_node_get_text(ctx->xml, node); + if (str == NULL) + return; + wpa_printf(MSG_INFO, "- HomeSP/RoamingConsortiumOI = %s", str); + if (set_cred_quoted(ctx->ifname, id, "roaming_consortiums", + str) < 0) + wpa_printf(MSG_INFO, "Failed to set cred roaming_consortiums"); + xml_node_get_text_free(ctx->xml, str); +} + + +static void set_pps_cred_home_sp(struct hs20_osu_client *ctx, int id, + xml_node_t *node) +{ + xml_node_t *child; + const char *name; + + wpa_printf(MSG_INFO, "- HomeSP"); + + xml_node_for_each_child(ctx->xml, child, node) { + xml_node_for_each_check(ctx->xml, child); + name = xml_node_get_localname(ctx->xml, child); + if (os_strcasecmp(name, "NetworkID") == 0) + set_pps_cred_home_sp_network_ids(ctx, id, child); + else if (os_strcasecmp(name, "FriendlyName") == 0) + set_pps_cred_home_sp_friendly_name(ctx, id, child); + else if (os_strcasecmp(name, "IconURL") == 0) + set_pps_cred_home_sp_icon_url(ctx, id, child); + else if (os_strcasecmp(name, "FQDN") == 0) + set_pps_cred_home_sp_fqdn(ctx, id, child); + else if (os_strcasecmp(name, "HomeOIList") == 0) + set_pps_cred_home_sp_oi_list(ctx, id, child); + else if (os_strcasecmp(name, "OtherHomePartners") == 0) + set_pps_cred_home_sp_other_partners(ctx, id, child); + else if (os_strcasecmp(name, "RoamingConsortiumOI") == 0) + set_pps_cred_home_sp_roaming_consortium_oi(ctx, id, + child); + else + wpa_printf(MSG_INFO, "Unknown HomeSP node '%s'", name); + } +} + + +static void set_pps_cred_sub_params(struct hs20_osu_client *ctx, int id, + xml_node_t *node) +{ + wpa_printf(MSG_INFO, "- SubscriptionParameters"); + /* not used within wpa_supplicant */ +} + + +static void set_pps_cred_creation_date(struct hs20_osu_client *ctx, int id, + xml_node_t *node) +{ + char *str = xml_node_get_text(ctx->xml, node); + if (str == NULL) + return; + wpa_printf(MSG_INFO, "- Credential/CreationDate = %s", str); + /* not used within wpa_supplicant */ + xml_node_get_text_free(ctx->xml, str); +} + + +static void set_pps_cred_expiration_date(struct hs20_osu_client *ctx, int id, + xml_node_t *node) +{ + char *str = xml_node_get_text(ctx->xml, node); + if (str == NULL) + return; + wpa_printf(MSG_INFO, "- Credential/ExpirationDate = %s", str); + /* not used within wpa_supplicant */ + xml_node_get_text_free(ctx->xml, str); +} + + +static void set_pps_cred_username(struct hs20_osu_client *ctx, int id, + xml_node_t *node) +{ + char *str = xml_node_get_text(ctx->xml, node); + if (str == NULL) + return; + wpa_printf(MSG_INFO, "- Credential/UsernamePassword/Username = %s", + str); + if (set_cred_quoted(ctx->ifname, id, "username", str) < 0) + wpa_printf(MSG_INFO, "Failed to set cred username"); + xml_node_get_text_free(ctx->xml, str); +} + + +static void set_pps_cred_password(struct hs20_osu_client *ctx, int id, + xml_node_t *node) +{ + int len, i; + char *pw, *hex, *pos, *end; + + pw = xml_node_get_base64_text(ctx->xml, node, &len); + if (pw == NULL) + return; + + wpa_printf(MSG_INFO, "- Credential/UsernamePassword/Password = %s", pw); + + hex = malloc(len * 2 + 1); + if (hex == NULL) { + free(pw); + return; + } + end = hex + len * 2 + 1; + pos = hex; + for (i = 0; i < len; i++) { + snprintf(pos, end - pos, "%02x", pw[i]); + pos += 2; + } + free(pw); + + if (set_cred(ctx->ifname, id, "password", hex) < 0) + wpa_printf(MSG_INFO, "Failed to set cred password"); + free(hex); +} + + +static void set_pps_cred_machine_managed(struct hs20_osu_client *ctx, int id, + xml_node_t *node) +{ + char *str = xml_node_get_text(ctx->xml, node); + if (str == NULL) + return; + wpa_printf(MSG_INFO, "- Credential/UsernamePassword/MachineManaged = %s", + str); + /* not used within wpa_supplicant */ + xml_node_get_text_free(ctx->xml, str); +} + + +static void set_pps_cred_soft_token_app(struct hs20_osu_client *ctx, int id, + xml_node_t *node) +{ + char *str = xml_node_get_text(ctx->xml, node); + if (str == NULL) + return; + wpa_printf(MSG_INFO, "- Credential/UsernamePassword/SoftTokenApp = %s", + str); + /* not used within wpa_supplicant */ + xml_node_get_text_free(ctx->xml, str); +} + + +static void set_pps_cred_able_to_share(struct hs20_osu_client *ctx, int id, + xml_node_t *node) +{ + char *str = xml_node_get_text(ctx->xml, node); + if (str == NULL) + return; + wpa_printf(MSG_INFO, "- Credential/UsernamePassword/AbleToShare = %s", + str); + /* not used within wpa_supplicant */ + xml_node_get_text_free(ctx->xml, str); +} + + +static void set_pps_cred_eap_method_eap_type(struct hs20_osu_client *ctx, + int id, xml_node_t *node) +{ + char *str = xml_node_get_text(ctx->xml, node); + int type; + const char *eap_method = NULL; + + if (!str) + return; + wpa_printf(MSG_INFO, + "- Credential/UsernamePassword/EAPMethod/EAPType = %s", str); + type = atoi(str); + switch (type) { + case EAP_TYPE_TLS: + eap_method = "TLS"; + break; + case EAP_TYPE_TTLS: + eap_method = "TTLS"; + break; + case EAP_TYPE_PEAP: + eap_method = "PEAP"; + break; + case EAP_TYPE_PWD: + eap_method = "PWD"; + break; + } + xml_node_get_text_free(ctx->xml, str); + if (!eap_method) { + wpa_printf(MSG_INFO, "Unknown EAPType value"); + return; + } + + if (set_cred(ctx->ifname, id, "eap", eap_method) < 0) + wpa_printf(MSG_INFO, "Failed to set cred eap"); +} + + +static void set_pps_cred_eap_method_inner_method(struct hs20_osu_client *ctx, + int id, xml_node_t *node) +{ + char *str = xml_node_get_text(ctx->xml, node); + const char *phase2 = NULL; + + if (!str) + return; + wpa_printf(MSG_INFO, + "- Credential/UsernamePassword/EAPMethod/InnerMethod = %s", + str); + if (os_strcmp(str, "PAP") == 0) + phase2 = "auth=PAP"; + else if (os_strcmp(str, "CHAP") == 0) + phase2 = "auth=CHAP"; + else if (os_strcmp(str, "MS-CHAP") == 0) + phase2 = "auth=MSCHAP"; + else if (os_strcmp(str, "MS-CHAP-V2") == 0) + phase2 = "auth=MSCHAPV2"; + xml_node_get_text_free(ctx->xml, str); + if (!phase2) { + wpa_printf(MSG_INFO, "Unknown InnerMethod value"); + return; + } + + if (set_cred_quoted(ctx->ifname, id, "phase2", phase2) < 0) + wpa_printf(MSG_INFO, "Failed to set cred phase2"); +} + + +static void set_pps_cred_eap_method(struct hs20_osu_client *ctx, int id, + xml_node_t *node) +{ + xml_node_t *child; + const char *name; + + wpa_printf(MSG_INFO, "- Credential/UsernamePassword/EAPMethod"); + + xml_node_for_each_child(ctx->xml, child, node) { + xml_node_for_each_check(ctx->xml, child); + name = xml_node_get_localname(ctx->xml, child); + if (os_strcasecmp(name, "EAPType") == 0) + set_pps_cred_eap_method_eap_type(ctx, id, child); + else if (os_strcasecmp(name, "InnerMethod") == 0) + set_pps_cred_eap_method_inner_method(ctx, id, child); + else + wpa_printf(MSG_INFO, "Unknown Credential/UsernamePassword/EAPMethod node '%s'", + name); + } +} + + +static void set_pps_cred_username_password(struct hs20_osu_client *ctx, int id, + xml_node_t *node) +{ + xml_node_t *child; + const char *name; + + wpa_printf(MSG_INFO, "- Credential/UsernamePassword"); + + xml_node_for_each_child(ctx->xml, child, node) { + xml_node_for_each_check(ctx->xml, child); + name = xml_node_get_localname(ctx->xml, child); + if (os_strcasecmp(name, "Username") == 0) + set_pps_cred_username(ctx, id, child); + else if (os_strcasecmp(name, "Password") == 0) + set_pps_cred_password(ctx, id, child); + else if (os_strcasecmp(name, "MachineManaged") == 0) + set_pps_cred_machine_managed(ctx, id, child); + else if (os_strcasecmp(name, "SoftTokenApp") == 0) + set_pps_cred_soft_token_app(ctx, id, child); + else if (os_strcasecmp(name, "AbleToShare") == 0) + set_pps_cred_able_to_share(ctx, id, child); + else if (os_strcasecmp(name, "EAPMethod") == 0) + set_pps_cred_eap_method(ctx, id, child); + else + wpa_printf(MSG_INFO, "Unknown Credential/UsernamePassword node '%s'", + name); + } +} + + +static void set_pps_cred_digital_cert(struct hs20_osu_client *ctx, int id, + xml_node_t *node, const char *fqdn) +{ + char buf[200], dir[200]; + int res; + + wpa_printf(MSG_INFO, "- Credential/DigitalCertificate"); + + if (getcwd(dir, sizeof(dir)) == NULL) + return; + + /* TODO: could build username from Subject of Subject AltName */ + if (set_cred_quoted(ctx->ifname, id, "username", "cert") < 0) { + wpa_printf(MSG_INFO, "Failed to set username"); + } + + res = os_snprintf(buf, sizeof(buf), "%s/SP/%s/client-cert.pem", dir, + fqdn); + if (os_snprintf_error(sizeof(buf), res)) + return; + if (os_file_exists(buf)) { + if (set_cred_quoted(ctx->ifname, id, "client_cert", buf) < 0) { + wpa_printf(MSG_INFO, "Failed to set client_cert"); + } + } + + res = os_snprintf(buf, sizeof(buf), "%s/SP/%s/client-key.pem", dir, + fqdn); + if (os_snprintf_error(sizeof(buf), res)) + return; + if (os_file_exists(buf)) { + if (set_cred_quoted(ctx->ifname, id, "private_key", buf) < 0) { + wpa_printf(MSG_INFO, "Failed to set private_key"); + } + } +} + + +static void set_pps_cred_realm(struct hs20_osu_client *ctx, int id, + xml_node_t *node, const char *fqdn, int sim) +{ + char *str = xml_node_get_text(ctx->xml, node); + char buf[200], dir[200]; + int res; + + if (str == NULL) + return; + + wpa_printf(MSG_INFO, "- Credential/Realm = %s", str); + if (set_cred_quoted(ctx->ifname, id, "realm", str) < 0) + wpa_printf(MSG_INFO, "Failed to set cred realm"); + xml_node_get_text_free(ctx->xml, str); + + if (sim) + return; + + if (getcwd(dir, sizeof(dir)) == NULL) + return; + res = os_snprintf(buf, sizeof(buf), "%s/SP/%s/aaa-ca.pem", dir, fqdn); + if (os_snprintf_error(sizeof(buf), res)) + return; + if (os_file_exists(buf)) { + if (set_cred_quoted(ctx->ifname, id, "ca_cert", buf) < 0) { + wpa_printf(MSG_INFO, "Failed to set CA cert"); + } + } +} + + +static void set_pps_cred_check_aaa_cert_status(struct hs20_osu_client *ctx, + int id, xml_node_t *node) +{ + char *str = xml_node_get_text(ctx->xml, node); + + if (str == NULL) + return; + + wpa_printf(MSG_INFO, "- Credential/CheckAAAServerCertStatus = %s", str); + if (os_strcasecmp(str, "true") == 0 && + set_cred(ctx->ifname, id, "ocsp", "2") < 0) + wpa_printf(MSG_INFO, "Failed to set cred ocsp"); + xml_node_get_text_free(ctx->xml, str); +} + + +static void set_pps_cred_sim(struct hs20_osu_client *ctx, int id, + xml_node_t *sim, xml_node_t *realm) +{ + xml_node_t *node; + char *imsi, *eaptype, *str, buf[20]; + int type; + int mnc_len = 3; + size_t imsi_len; + + node = get_node(ctx->xml, sim, "EAPType"); + if (node == NULL) { + wpa_printf(MSG_INFO, "No SIM/EAPType node in credential"); + return; + } + eaptype = xml_node_get_text(ctx->xml, node); + if (eaptype == NULL) { + wpa_printf(MSG_INFO, "Could not extract SIM/EAPType"); + return; + } + wpa_printf(MSG_INFO, " - Credential/SIM/EAPType = %s", eaptype); + type = atoi(eaptype); + xml_node_get_text_free(ctx->xml, eaptype); + + switch (type) { + case EAP_TYPE_SIM: + if (set_cred(ctx->ifname, id, "eap", "SIM") < 0) + wpa_printf(MSG_INFO, "Could not set eap=SIM"); + break; + case EAP_TYPE_AKA: + if (set_cred(ctx->ifname, id, "eap", "AKA") < 0) + wpa_printf(MSG_INFO, "Could not set eap=SIM"); + break; + case EAP_TYPE_AKA_PRIME: + if (set_cred(ctx->ifname, id, "eap", "AKA'") < 0) + wpa_printf(MSG_INFO, "Could not set eap=SIM"); + break; + default: + wpa_printf(MSG_INFO, "Unsupported SIM/EAPType %d", type); + return; + } + + node = get_node(ctx->xml, sim, "IMSI"); + if (node == NULL) { + wpa_printf(MSG_INFO, "No SIM/IMSI node in credential"); + return; + } + imsi = xml_node_get_text(ctx->xml, node); + if (imsi == NULL) { + wpa_printf(MSG_INFO, "Could not extract SIM/IMSI"); + return; + } + wpa_printf(MSG_INFO, " - Credential/SIM/IMSI = %s", imsi); + imsi_len = os_strlen(imsi); + if (imsi_len < 7 || imsi_len + 2 > sizeof(buf)) { + wpa_printf(MSG_INFO, "Invalid IMSI length"); + xml_node_get_text_free(ctx->xml, imsi); + return; + } + + str = xml_node_get_text(ctx->xml, node); + if (str) { + char *pos; + pos = os_strstr(str, "mnc"); + if (pos && os_strlen(pos) >= 6) { + if (os_strncmp(imsi + 3, pos + 3, 3) == 0) + mnc_len = 3; + else if (os_strncmp(imsi + 3, pos + 4, 2) == 0) + mnc_len = 2; + } + xml_node_get_text_free(ctx->xml, str); + } + + os_memcpy(buf, imsi, 3 + mnc_len); + buf[3 + mnc_len] = '-'; + os_strlcpy(buf + 3 + mnc_len + 1, imsi + 3 + mnc_len, + sizeof(buf) - 3 - mnc_len - 1); + + xml_node_get_text_free(ctx->xml, imsi); + + if (set_cred_quoted(ctx->ifname, id, "imsi", buf) < 0) + wpa_printf(MSG_INFO, "Could not set IMSI"); + + if (set_cred_quoted(ctx->ifname, id, "milenage", + "90dca4eda45b53cf0f12d7c9c3bc6a89:" + "cb9cccc4b9258e6dca4760379fb82581:000000000123") < + 0) + wpa_printf(MSG_INFO, "Could not set Milenage parameters"); +} + + +static void set_pps_cred_credential(struct hs20_osu_client *ctx, int id, + xml_node_t *node, const char *fqdn) +{ + xml_node_t *child, *sim, *realm; + const char *name; + + wpa_printf(MSG_INFO, "- Credential"); + + sim = get_node(ctx->xml, node, "SIM"); + realm = get_node(ctx->xml, node, "Realm"); + + xml_node_for_each_child(ctx->xml, child, node) { + xml_node_for_each_check(ctx->xml, child); + name = xml_node_get_localname(ctx->xml, child); + if (os_strcasecmp(name, "CreationDate") == 0) + set_pps_cred_creation_date(ctx, id, child); + else if (os_strcasecmp(name, "ExpirationDate") == 0) + set_pps_cred_expiration_date(ctx, id, child); + else if (os_strcasecmp(name, "UsernamePassword") == 0) + set_pps_cred_username_password(ctx, id, child); + else if (os_strcasecmp(name, "DigitalCertificate") == 0) + set_pps_cred_digital_cert(ctx, id, child, fqdn); + else if (os_strcasecmp(name, "Realm") == 0) + set_pps_cred_realm(ctx, id, child, fqdn, sim != NULL); + else if (os_strcasecmp(name, "CheckAAAServerCertStatus") == 0) + set_pps_cred_check_aaa_cert_status(ctx, id, child); + else if (os_strcasecmp(name, "SIM") == 0) + set_pps_cred_sim(ctx, id, child, realm); + else + wpa_printf(MSG_INFO, "Unknown Credential node '%s'", + name); + } +} + + +static void set_pps_credential(struct hs20_osu_client *ctx, int id, + xml_node_t *cred, const char *fqdn) +{ + xml_node_t *child; + const char *name; + + xml_node_for_each_child(ctx->xml, child, cred) { + xml_node_for_each_check(ctx->xml, child); + name = xml_node_get_localname(ctx->xml, child); + if (os_strcasecmp(name, "Policy") == 0) + set_pps_cred_policy(ctx, id, child); + else if (os_strcasecmp(name, "CredentialPriority") == 0) + set_pps_cred_priority(ctx, id, child); + else if (os_strcasecmp(name, "AAAServerTrustRoot") == 0) + set_pps_cred_aaa_server_trust_root(ctx, id, child); + else if (os_strcasecmp(name, "SubscriptionUpdate") == 0) + 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; + + 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)); + snprintf(last->bssid, sizeof(last->bssid), "%s", + buf + 13); + continue; + } + if (!last) + continue; + + if (strncmp(buf, "uri=", 4) == 0) { + snprintf(last->url, sizeof(last->url), "%s", buf + 4); + continue; + } + + if (strncmp(buf, "methods=", 8) == 0) { + last->methods = strtol(buf + 8, NULL, 16); + continue; + } + + if (strncmp(buf, "osu_ssid=", 9) == 0) { + snprintf(last->osu_ssid, sizeof(last->osu_ssid), + "%s", buf + 9); + continue; + } + + if (strncmp(buf, "osu_ssid2=", 10) == 0) { + snprintf(last->osu_ssid2, sizeof(last->osu_ssid2), + "%s", buf + 10); + continue; + } + + if (os_strncmp(buf, "osu_nai=", 8) == 0) { + os_snprintf(last->osu_nai, sizeof(last->osu_nai), + "%s", buf + 8); + continue; + } + + if (os_strncmp(buf, "osu_nai2=", 9) == 0) { + os_snprintf(last->osu_nai2, sizeof(last->osu_nai2), + "%s", buf + 9); + 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++]; + snprintf(txt->lang, sizeof(txt->lang), "%s", buf + 14); + snprintf(txt->text, sizeof(txt->text), "%s", pos); + } + + 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++]; + snprintf(txt->lang, sizeof(txt->lang), "%s", buf + 5); + snprintf(txt->text, sizeof(txt->text), "%s", pos); + } + + 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'; + snprintf(icon->lang, sizeof(icon->lang), "%s", pos); + pos = end + 1; + + end = strchr(pos, ':'); + if (end) + *end = '\0'; + snprintf(icon->mime_type, sizeof(icon->mime_type), + "%s", pos); + if (!pos) + continue; + pos = end + 1; + + end = strchr(pos, ':'); + if (end) + *end = '\0'; + snprintf(icon->filename, sizeof(icon->filename), + "%s", pos); + 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 + 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"); + } + + 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) +{ + 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; + + 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, + "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; + } + } + 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; +} + + +static char * get_hostname(const char *url) +{ + const char *pos, *end, *end2; + char *ret; + + if (url == NULL) + return NULL; + + 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--; + } + + ret = os_malloc(end - pos + 2); + if (ret == NULL) + return NULL; + + os_memcpy(ret, pos, end - pos + 1); + ret[end - pos + 1] = '\0'; + + return ret; +} + + +static int osu_cert_cb(void *_ctx, struct http_cert *cert) +{ + 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)", + !ctx->no_osu_cert_validation, ctx->server_url); + + host = get_hostname(ctx->server_url); + + 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->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]); + } + + 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); + 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); + } + } + + 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; + } + } + + 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; + } + } + + 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); + } + + 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; + + 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; + } + } + + 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; + } + } + + for (j = 0; !ctx->no_osu_cert_validation && j < ctx->icon_count; j++) { + int found = 0; + + 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; + } + + 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); + } + + 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; + } + } + + return 0; +} + + +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; +} + + +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); +} + + +static void check_workarounds(struct hs20_osu_client *ctx) +{ + FILE *f; + char buf[100]; + unsigned long int val = 0; + + f = fopen("hs20-osu-client.workarounds", "r"); + if (f == NULL) + return; + + if (fgets(buf, sizeof(buf), f)) + val = strtoul(buf, NULL, 16); + + fclose(f); + + if (val) { + wpa_printf(MSG_INFO, "Workarounds enabled: 0x%lx", val); + ctx->workarounds = val; + if (ctx->workarounds & WORKAROUND_OCSP_OPTIONAL) + http_ocsp_set(ctx->http, 1); + } +} + + +static void usage(void) +{ + printf("usage: hs20-osu-client [-dddqqKtT] [-S<station ifname>] \\\n" + " [-w<wpa_supplicant ctrl_iface dir>] " + "[-r<result file>] [-f<debug file>] \\\n" + " [-s<summary file>] \\\n" + " [-x<spp.xsd file name>] \\\n" + " <command> [arguments..]\n" + "commands:\n" + "- to_tnds <XML MO> <XML MO in TNDS format> [URN]\n" + "- to_tnds2 <XML MO> <XML MO in TNDS format (Path) " + "[URN]>\n" + "- 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"); +} + + +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; + extern int wpa_debug_show_keys; + extern int wpa_debug_timestamp; + + if (init_ctx(&ctx) < 0) + return -1; + + for (;;) { + c = getopt(argc, argv, "df:hKNo:O:qr:s:S:tTw:x:"); + if (c < 0) + break; + switch (c) { + case 'd': + if (wpa_debug_level > 0) + wpa_debug_level--; + break; + case 'f': + wpa_debug_file_path = optarg; + break; + 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; + case 'r': + ctx.result_file = optarg; + break; + case 's': + ctx.summary_file = optarg; + break; + case 'S': + ctx.ifname = optarg; + break; + case 't': + wpa_debug_timestamp++; + break; + case 'T': + ctx.ignore_tls = 1; + break; + case 'w': + wpas_ctrl_path = optarg; + break; + case 'x': + spp_xsd_fname = optarg; + break; + case 'h': + default: + usage(); + exit(0); + break; + } + } + + if (argc - optind < 1) { + usage(); + exit(0); + } + + wpa_debug_open_file(wpa_debug_file_path); + +#ifdef __linux__ + setlinebuf(stdout); +#endif /* __linux__ */ + + if (ctx.result_file) + unlink(ctx.result_file); + wpa_printf(MSG_DEBUG, "===[hs20-osu-client START - command: %s ]======" + "================", argv[optind]); + check_workarounds(&ctx); + + if (strcmp(argv[optind], "to_tnds") == 0) { + if (argc - optind < 2) { + usage(); + exit(0); + } + cmd_to_tnds(&ctx, argv[optind + 1], argv[optind + 2], + argc > optind + 3 ? argv[optind + 3] : NULL, + 0); + } else if (strcmp(argv[optind], "to_tnds2") == 0) { + if (argc - optind < 2) { + usage(); + exit(0); + } + cmd_to_tnds(&ctx, argv[optind + 1], argv[optind + 2], + argc > optind + 3 ? argv[optind + 3] : NULL, + 1); + } else if (strcmp(argv[optind], "from_tnds") == 0) { + if (argc - optind < 2) { + usage(); + 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(); + exit(0); + } + cmd_set_pps(&ctx, argv[optind + 1]); + } else if (strcmp(argv[optind], "get_fqdn") == 0) { + if (argc - optind < 1) { + usage(); + 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; + + if (argc - optind < 2) { + usage(); + exit(0); + } + + wpa_printf(MSG_INFO, "Launch web browser to URL %s", + 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]); + } + + deinit_ctx(&ctx); + wpa_printf(MSG_DEBUG, + "===[hs20-osu-client END ]======================"); + + wpa_debug_close_file(); + + return ret; +} diff --git a/hs20/client/osu_client.h b/hs20/client/osu_client.h new file mode 100644 index 000000000000..9b45b03febe2 --- /dev/null +++ b/hs20/client/osu_client.h @@ -0,0 +1,121 @@ +/* + * Hotspot 2.0 - OSU 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. + */ + +#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 new file mode 100644 index 000000000000..39d10e0362f6 --- /dev/null +++ b/hs20/client/spp_client.c @@ -0,0 +1,1004 @@ +/* + * 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; + } + return 0; + } + + 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; +} diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk new file mode 100644 index 000000000000..7e597f396a07 --- /dev/null +++ b/wpa_supplicant/Android.mk @@ -0,0 +1,1827 @@ +# +# Copyright (C) 2008 The Android Open Source Project +# +# This software may be distributed under the terms of the BSD license. +# See README for more details. +# + +LOCAL_PATH := $(call my-dir) +PKG_CONFIG ?= pkg-config + +ifneq ($(BOARD_WPA_SUPPLICANT_DRIVER),) + CONFIG_DRIVER_$(BOARD_WPA_SUPPLICANT_DRIVER) := y +endif + +include $(LOCAL_PATH)/android.config + +# To ignore possible wrong network configurations +L_CFLAGS = -DWPA_IGNORE_CONFIG_ERRORS + +L_CFLAGS += -DVERSION_STR_POSTFIX=\"-$(PLATFORM_VERSION)\" + +# Set Android log name +L_CFLAGS += -DANDROID_LOG_NAME=\"wpa_supplicant\" + +# Disable unused parameter warnings +L_CFLAGS += -Wno-unused-parameter + +# Set Android extended P2P functionality +L_CFLAGS += -DANDROID_P2P + +ifeq ($(BOARD_WPA_SUPPLICANT_PRIVATE_LIB),) +L_CFLAGS += -DANDROID_LIB_STUB +endif + +ifneq ($(BOARD_WPA_SUPPLICANT_PRIVATE_LIB_EVENT),) +L_CFLAGS += -DANDROID_LIB_EVENT +endif + +# Disable roaming in wpa_supplicant +ifdef CONFIG_NO_ROAMING +L_CFLAGS += -DCONFIG_NO_ROAMING +endif + +# Use Android specific directory for control interface sockets +L_CFLAGS += -DCONFIG_CTRL_IFACE_CLIENT_DIR=\"/data/misc/wifi/sockets\" +L_CFLAGS += -DCONFIG_CTRL_IFACE_DIR=\"/data/misc/wifi/sockets\" + +# Use Android specific directory for wpa_cli command completion history +L_CFLAGS += -DCONFIG_WPA_CLI_HISTORY_DIR=\"/data/misc/wifi\" + +# To force sizeof(enum) = 4 +ifeq ($(TARGET_ARCH),arm) +L_CFLAGS += -mabi=aapcs-linux +endif + +# C++ flags for binder interface +L_CPPFLAGS := -std=c++11 -Wall -Werror +# TODO: Remove these allowed warnings later. +L_CPPFLAGS += -Wno-unused-variable -Wno-unused-parameter +L_CPPFLAGS += -Wno-unused-private-field + +INCLUDES = $(LOCAL_PATH) +INCLUDES += $(LOCAL_PATH)/src +INCLUDES += $(LOCAL_PATH)/src/common +# INCLUDES += $(LOCAL_PATH)/src/crypto # To force proper includes +INCLUDES += $(LOCAL_PATH)/src/drivers +INCLUDES += $(LOCAL_PATH)/src/eap_common +INCLUDES += $(LOCAL_PATH)/src/eapol_supp +INCLUDES += $(LOCAL_PATH)/src/eap_peer +INCLUDES += $(LOCAL_PATH)/src/eap_server +INCLUDES += $(LOCAL_PATH)/src/hlr_auc_gw +INCLUDES += $(LOCAL_PATH)/src/l2_packet +INCLUDES += $(LOCAL_PATH)/src/radius +INCLUDES += $(LOCAL_PATH)/src/rsn_supp +INCLUDES += $(LOCAL_PATH)/src/tls +INCLUDES += $(LOCAL_PATH)/src/utils +INCLUDES += $(LOCAL_PATH)/src/wps +INCLUDES += system/security/keystore/include +ifdef CONFIG_DRIVER_NL80211 +ifneq ($(wildcard external/libnl),) +INCLUDES += external/libnl/include +else +INCLUDES += external/libnl-headers +endif +endif + +ifdef CONFIG_FIPS +CONFIG_NO_RANDOM_POOL= +CONFIG_OPENSSL_CMAC=y +endif + +OBJS = config.c +OBJS += notify.c +OBJS += bss.c +OBJS += eap_register.c +OBJS += src/utils/common.c +OBJS += src/utils/config.c +OBJS += src/utils/wpa_debug.c +OBJS += src/utils/wpabuf.c +OBJS += src/utils/bitfield.c +OBJS += src/utils/ip_addr.c +OBJS += src/utils/crc32.c +OBJS += wmm_ac.c +OBJS += op_classes.c +OBJS += rrm.c +OBJS += twt.c +OBJS += robust_av.c +OBJS_p = wpa_passphrase.c +OBJS_p += src/utils/common.c +OBJS_p += src/utils/wpa_debug.c +OBJS_p += src/utils/wpabuf.c +OBJS_c = wpa_cli.c src/common/wpa_ctrl.c +OBJS_c += src/utils/wpa_debug.c +OBJS_c += src/utils/common.c +OBJS_c += src/common/cli.c +OBJS_d = +OBJS_priv = + +ifndef CONFIG_OS +ifdef CONFIG_NATIVE_WINDOWS +CONFIG_OS=win32 +else +CONFIG_OS=unix +endif +endif + +ifeq ($(CONFIG_OS), internal) +L_CFLAGS += -DOS_NO_C_LIB_DEFINES +endif + +OBJS += src/utils/os_$(CONFIG_OS).c +OBJS_p += src/utils/os_$(CONFIG_OS).c +OBJS_c += src/utils/os_$(CONFIG_OS).c + +ifdef CONFIG_WPA_TRACE +L_CFLAGS += -DWPA_TRACE +OBJS += src/utils/trace.c +OBJS_p += src/utils/trace.c +OBJS_c += src/utils/trace.c +LDFLAGS += -rdynamic +L_CFLAGS += -funwind-tables +ifdef CONFIG_WPA_TRACE_BFD +L_CFLAGS += -DWPA_TRACE_BFD +LIBS += -lbfd +LIBS_p += -lbfd +LIBS_c += -lbfd +endif +endif + +ifndef CONFIG_ELOOP +CONFIG_ELOOP=eloop +endif +OBJS += src/utils/$(CONFIG_ELOOP).c +OBJS_c += src/utils/$(CONFIG_ELOOP).c + +ifdef CONFIG_ELOOP_POLL +L_CFLAGS += -DCONFIG_ELOOP_POLL +endif + +ifdef CONFIG_ELOOP_EPOLL +L_CFLAGS += -DCONFIG_ELOOP_EPOLL +endif + +ifdef CONFIG_EAPOL_TEST +L_CFLAGS += -Werror -DEAPOL_TEST +endif + +ifdef CONFIG_HT_OVERRIDES +L_CFLAGS += -DCONFIG_HT_OVERRIDES +endif + +ifdef CONFIG_VHT_OVERRIDES +L_CFLAGS += -DCONFIG_VHT_OVERRIDES +endif + +ifdef CONFIG_HE_OVERRIDES +L_CFLAGS += -DCONFIG_HE_OVERRIDES +endif + +ifndef CONFIG_BACKEND +CONFIG_BACKEND=file +endif + +ifeq ($(CONFIG_BACKEND), file) +OBJS += config_file.c +ifndef CONFIG_NO_CONFIG_BLOBS +NEED_BASE64=y +endif +L_CFLAGS += -DCONFIG_BACKEND_FILE +endif + +ifeq ($(CONFIG_BACKEND), winreg) +OBJS += config_winreg.c +endif + +ifeq ($(CONFIG_BACKEND), none) +OBJS += config_none.c +endif + +ifdef CONFIG_NO_CONFIG_WRITE +L_CFLAGS += -DCONFIG_NO_CONFIG_WRITE +endif + +ifdef CONFIG_NO_CONFIG_BLOBS +L_CFLAGS += -DCONFIG_NO_CONFIG_BLOBS +endif + +ifdef CONFIG_NO_SCAN_PROCESSING +L_CFLAGS += -DCONFIG_NO_SCAN_PROCESSING +endif + +ifdef CONFIG_SUITEB +L_CFLAGS += -DCONFIG_SUITEB +endif + +ifdef CONFIG_SUITEB192 +L_CFLAGS += -DCONFIG_SUITEB192 +NEED_SHA384=y +endif + +ifdef CONFIG_OCV +L_CFLAGS += -DCONFIG_OCV +OBJS += src/common/ocv.c +endif + +ifdef CONFIG_IEEE80211R +L_CFLAGS += -DCONFIG_IEEE80211R +OBJS += src/rsn_supp/wpa_ft.c +endif + +ifdef CONFIG_MESH +NEED_80211_COMMON=y +NEED_AES_SIV=y +CONFIG_SAE=y +CONFIG_AP=y +L_CFLAGS += -DCONFIG_MESH +OBJS += mesh.c +OBJS += mesh_mpm.c +OBJS += mesh_rsn.c +endif + +ifdef CONFIG_SAE +L_CFLAGS += -DCONFIG_SAE +OBJS += src/common/sae.c +ifdef CONFIG_SAE_PK +L_CFLAGS += -DCONFIG_SAE_PK +OBJS += src/common/sae_pk.c +endif +NEED_ECC=y +NEED_DH_GROUPS=y +NEED_HMAC_SHA256_KDF=y +NEED_DRAGONFLY=y +ifdef CONFIG_TESTING_OPTIONS +NEED_DH_GROUPS_ALL=y +endif +endif + +ifdef CONFIG_DPP +L_CFLAGS += -DCONFIG_DPP +OBJS += src/common/dpp.c +OBJS += src/common/dpp_auth.c +OBJS += src/common/dpp_backup.c +OBJS += src/common/dpp_crypto.c +OBJS += src/common/dpp_pkex.c +OBJS += src/common/dpp_reconfig.c +OBJS += src/common/dpp_tcp.c +OBJS += dpp_supplicant.c +NEED_AES_SIV=y +NEED_HMAC_SHA256_KDF=y +NEED_HMAC_SHA384_KDF=y +NEED_HMAC_SHA512_KDF=y +NEED_SHA384=y +NEED_SHA512=y +NEED_ECC=y +NEED_JSON=y +NEED_GAS_SERVER=y +NEED_BASE64=y +NEED_ASN1=y +ifdef CONFIG_DPP2 +L_CFLAGS += -DCONFIG_DPP2 +endif +ifdef CONFIG_DPP3 +L_CFLAGS += -DCONFIG_DPP3 +endif +endif + +ifdef CONFIG_OWE +L_CFLAGS += -DCONFIG_OWE +NEED_ECC=y +NEED_HMAC_SHA256_KDF=y +NEED_HMAC_SHA384_KDF=y +NEED_HMAC_SHA512_KDF=y +NEED_SHA384=y +NEED_SHA512=y +endif + +ifdef CONFIG_FILS +L_CFLAGS += -DCONFIG_FILS +NEED_SHA384=y +NEED_AES_SIV=y +ifdef CONFIG_FILS_SK_PFS +L_CFLAGS += -DCONFIG_FILS_SK_PFS +NEED_ECC=y +endif +endif + +ifdef CONFIG_MBO +CONFIG_WNM=y +endif + +ifdef CONFIG_WNM +L_CFLAGS += -DCONFIG_WNM +OBJS += wnm_sta.c +endif + +ifdef CONFIG_TDLS +L_CFLAGS += -DCONFIG_TDLS +OBJS += src/rsn_supp/tdls.c +endif + +ifdef CONFIG_TDLS_TESTING +L_CFLAGS += -DCONFIG_TDLS_TESTING +endif + +ifdef CONFIG_PMKSA_CACHE_EXTERNAL +L_CFLAGS += -DCONFIG_PMKSA_CACHE_EXTERNAL +endif + +ifndef CONFIG_NO_WPA +OBJS += src/rsn_supp/wpa.c +OBJS += src/rsn_supp/preauth.c +OBJS += src/rsn_supp/pmksa_cache.c +OBJS += src/rsn_supp/wpa_ie.c +OBJS += src/common/wpa_common.c +NEED_AES=y +NEED_SHA1=y +NEED_MD5=y +NEED_RC4=y +else +L_CFLAGS += -DCONFIG_NO_WPA +endif + +ifdef CONFIG_IBSS_RSN +NEED_RSN_AUTHENTICATOR=y +L_CFLAGS += -DCONFIG_IBSS_RSN +L_CFLAGS += -DCONFIG_NO_VLAN +OBJS += ibss_rsn.c +endif + +ifdef CONFIG_P2P +OBJS += p2p_supplicant.c +OBJS += p2p_supplicant_sd.c +OBJS += src/p2p/p2p.c +OBJS += src/p2p/p2p_utils.c +OBJS += src/p2p/p2p_parse.c +OBJS += src/p2p/p2p_build.c +OBJS += src/p2p/p2p_go_neg.c +OBJS += src/p2p/p2p_sd.c +OBJS += src/p2p/p2p_pd.c +OBJS += src/p2p/p2p_invitation.c +OBJS += src/p2p/p2p_dev_disc.c +OBJS += src/p2p/p2p_group.c +OBJS += src/ap/p2p_hostapd.c +L_CFLAGS += -DCONFIG_P2P +NEED_GAS=y +NEED_OFFCHANNEL=y +CONFIG_WPS=y +CONFIG_AP=y +ifdef CONFIG_P2P_STRICT +L_CFLAGS += -DCONFIG_P2P_STRICT +endif +ifdef CONFIG_WIFI_DISPLAY +L_CFLAGS += -DCONFIG_WIFI_DISPLAY +OBJS += wifi_display.c +endif +endif + +ifdef CONFIG_PASN +L_CFLAGS += -DCONFIG_PASN +L_CFLAGS += -DCONFIG_PTKSA_CACHE +NEED_HMAC_SHA256_KDF=y +NEED_HMAC_SHA384_KDF=y +NEED_SHA256=y +NEED_SHA384=y +OBJS += src/common/ptksa_cache.c +OBJS += pasn_supplicant.c +endif + +ifdef CONFIG_HS20 +OBJS += hs20_supplicant.c +L_CFLAGS += -DCONFIG_HS20 +CONFIG_INTERWORKING=y +endif + +ifdef CONFIG_INTERWORKING +OBJS += interworking.c +L_CFLAGS += -DCONFIG_INTERWORKING +NEED_GAS=y +endif + +ifdef CONFIG_FST +L_CFLAGS += -DCONFIG_FST +OBJS += src/fst/fst.c +OBJS += src/fst/fst_session.c +OBJS += src/fst/fst_iface.c +OBJS += src/fst/fst_group.c +OBJS += src/fst/fst_ctrl_aux.c +ifdef CONFIG_FST_TEST +L_CFLAGS += -DCONFIG_FST_TEST +endif +ifdef CONFIG_CTRL_IFACE +OBJS += src/fst/fst_ctrl_iface.c +endif +endif + +ifdef CONFIG_WEP +L_CFLAGS += -DCONFIG_WEP +endif + +ifdef CONFIG_NO_TKIP +L_CFLAGS += -DCONFIG_NO_TKIP +endif + + +include $(LOCAL_PATH)/src/drivers/drivers.mk + +ifdef CONFIG_AP +OBJS_d += $(DRV_BOTH_OBJS) +L_CFLAGS += $(DRV_BOTH_CFLAGS) +LDFLAGS += $(DRV_BOTH_LDFLAGS) +LIBS += $(DRV_BOTH_LIBS) +else +NEED_AP_MLME= +OBJS_d += $(DRV_WPA_OBJS) +L_CFLAGS += $(DRV_WPA_CFLAGS) +LDFLAGS += $(DRV_WPA_LDFLAGS) +LIBS += $(DRV_WPA_LIBS) +endif + +ifndef CONFIG_L2_PACKET +CONFIG_L2_PACKET=linux +endif + +OBJS_l2 += src/l2_packet/l2_packet_$(CONFIG_L2_PACKET).c + +ifeq ($(CONFIG_L2_PACKET), pcap) +ifdef CONFIG_WINPCAP +L_CFLAGS += -DCONFIG_WINPCAP +LIBS += -lwpcap -lpacket +LIBS_w += -lwpcap +else +LIBS += -ldnet -lpcap +endif +endif + +ifeq ($(CONFIG_L2_PACKET), winpcap) +LIBS += -lwpcap -lpacket +LIBS_w += -lwpcap +endif + +ifeq ($(CONFIG_L2_PACKET), freebsd) +LIBS += -lpcap +endif + +ifdef CONFIG_ERP +L_CFLAGS += -DCONFIG_ERP +NEED_HMAC_SHA256_KDF=y +endif + +ifdef CONFIG_EAP_TLS +# EAP-TLS +ifeq ($(CONFIG_EAP_TLS), dyn) +L_CFLAGS += -DEAP_TLS_DYNAMIC +EAPDYN += src/eap_peer/eap_tls.so +else +L_CFLAGS += -DEAP_TLS +OBJS += src/eap_peer/eap_tls.c +endif +TLS_FUNCS=y +CONFIG_IEEE8021X_EAPOL=y +endif + +ifdef CONFIG_EAP_UNAUTH_TLS +# EAP-UNAUTH-TLS +L_CFLAGS += -DEAP_UNAUTH_TLS +ifndef CONFIG_EAP_TLS +OBJS += src/eap_peer/eap_tls.c +TLS_FUNCS=y +endif +CONFIG_IEEE8021X_EAPOL=y +endif + +ifdef CONFIG_EAP_PEAP +# EAP-PEAP +ifeq ($(CONFIG_EAP_PEAP), dyn) +L_CFLAGS += -DEAP_PEAP_DYNAMIC +EAPDYN += src/eap_peer/eap_peap.so +else +L_CFLAGS += -DEAP_PEAP +OBJS += src/eap_peer/eap_peap.c +OBJS += src/eap_common/eap_peap_common.c +endif +TLS_FUNCS=y +CONFIG_IEEE8021X_EAPOL=y +endif + +ifdef CONFIG_EAP_TTLS +# EAP-TTLS +ifeq ($(CONFIG_EAP_TTLS), dyn) +L_CFLAGS += -DEAP_TTLS_DYNAMIC +EAPDYN += src/eap_peer/eap_ttls.so +else +L_CFLAGS += -DEAP_TTLS +OBJS += src/eap_peer/eap_ttls.c +endif +TLS_FUNCS=y +ifndef CONFIG_FIPS +MS_FUNCS=y +CHAP=y +endif +CONFIG_IEEE8021X_EAPOL=y +endif + +ifdef CONFIG_EAP_MD5 +# EAP-MD5 +ifeq ($(CONFIG_EAP_MD5), dyn) +L_CFLAGS += -DEAP_MD5_DYNAMIC +EAPDYN += src/eap_peer/eap_md5.so +else +L_CFLAGS += -DEAP_MD5 +OBJS += src/eap_peer/eap_md5.c +endif +CHAP=y +CONFIG_IEEE8021X_EAPOL=y +endif + +# backwards compatibility for old spelling +ifdef CONFIG_MSCHAPV2 +ifndef CONFIG_EAP_MSCHAPV2 +CONFIG_EAP_MSCHAPV2=y +endif +endif + +ifdef CONFIG_EAP_MSCHAPV2 +# EAP-MSCHAPv2 +ifeq ($(CONFIG_EAP_MSCHAPV2), dyn) +L_CFLAGS += -DEAP_MSCHAPv2_DYNAMIC +EAPDYN += src/eap_peer/eap_mschapv2.so +EAPDYN += src/eap_peer/mschapv2.so +else +L_CFLAGS += -DEAP_MSCHAPv2 +OBJS += src/eap_peer/eap_mschapv2.c +OBJS += src/eap_peer/mschapv2.c +endif +MS_FUNCS=y +CONFIG_IEEE8021X_EAPOL=y +endif + +ifdef CONFIG_EAP_GTC +# EAP-GTC +ifeq ($(CONFIG_EAP_GTC), dyn) +L_CFLAGS += -DEAP_GTC_DYNAMIC +EAPDYN += src/eap_peer/eap_gtc.so +else +L_CFLAGS += -DEAP_GTC +OBJS += src/eap_peer/eap_gtc.c +endif +CONFIG_IEEE8021X_EAPOL=y +endif + +ifdef CONFIG_EAP_OTP +# EAP-OTP +ifeq ($(CONFIG_EAP_OTP), dyn) +L_CFLAGS += -DEAP_OTP_DYNAMIC +EAPDYN += src/eap_peer/eap_otp.so +else +L_CFLAGS += -DEAP_OTP +OBJS += src/eap_peer/eap_otp.c +endif +CONFIG_IEEE8021X_EAPOL=y +endif + +ifdef CONFIG_EAP_SIM +# EAP-SIM +ifeq ($(CONFIG_EAP_SIM), dyn) +L_CFLAGS += -DEAP_SIM_DYNAMIC +EAPDYN += src/eap_peer/eap_sim.so +else +L_CFLAGS += -DEAP_SIM +OBJS += src/eap_peer/eap_sim.c +endif +CONFIG_IEEE8021X_EAPOL=y +CONFIG_EAP_SIM_COMMON=y +NEED_AES_CBC=y +endif + +ifdef CONFIG_EAP_LEAP +# EAP-LEAP +ifeq ($(CONFIG_EAP_LEAP), dyn) +L_CFLAGS += -DEAP_LEAP_DYNAMIC +EAPDYN += src/eap_peer/eap_leap.so +else +L_CFLAGS += -DEAP_LEAP +OBJS += src/eap_peer/eap_leap.c +endif +MS_FUNCS=y +CONFIG_IEEE8021X_EAPOL=y +endif + +ifdef CONFIG_EAP_PSK +# EAP-PSK +ifeq ($(CONFIG_EAP_PSK), dyn) +L_CFLAGS += -DEAP_PSK_DYNAMIC +EAPDYN += src/eap_peer/eap_psk.so +else +L_CFLAGS += -DEAP_PSK +OBJS += src/eap_peer/eap_psk.c src/eap_common/eap_psk_common.c +endif +CONFIG_IEEE8021X_EAPOL=y +NEED_AES=y +NEED_AES_ENCBLOCK=y +NEED_AES_EAX=y +endif + +ifdef CONFIG_EAP_AKA +# EAP-AKA +ifeq ($(CONFIG_EAP_AKA), dyn) +L_CFLAGS += -DEAP_AKA_DYNAMIC +EAPDYN += src/eap_peer/eap_aka.so +else +L_CFLAGS += -DEAP_AKA +OBJS += src/eap_peer/eap_aka.c +endif +CONFIG_IEEE8021X_EAPOL=y +CONFIG_EAP_SIM_COMMON=y +NEED_AES_CBC=y +endif + +ifdef CONFIG_EAP_PROXY +L_CFLAGS += -DCONFIG_EAP_PROXY +OBJS += src/eap_peer/eap_proxy_$(CONFIG_EAP_PROXY).c +include $(LOCAL_PATH)/eap_proxy_$(CONFIG_EAP_PROXY).mk +CONFIG_IEEE8021X_EAPOL=y +endif + +ifdef CONFIG_EAP_AKA_PRIME +# EAP-AKA' +ifeq ($(CONFIG_EAP_AKA_PRIME), dyn) +L_CFLAGS += -DEAP_AKA_PRIME_DYNAMIC +else +L_CFLAGS += -DEAP_AKA_PRIME +endif +endif + +ifdef CONFIG_EAP_SIM_COMMON +OBJS += src/eap_common/eap_sim_common.c +NEED_AES=y +NEED_FIPS186_2_PRF=y +endif + +ifdef CONFIG_EAP_FAST +# EAP-FAST +ifeq ($(CONFIG_EAP_FAST), dyn) +L_CFLAGS += -DEAP_FAST_DYNAMIC +EAPDYN += src/eap_peer/eap_fast.so +EAPDYN += src/eap_common/eap_fast_common.c +else +L_CFLAGS += -DEAP_FAST +OBJS += src/eap_peer/eap_fast.c src/eap_peer/eap_fast_pac.c +OBJS += src/eap_common/eap_fast_common.c +endif +TLS_FUNCS=y +CONFIG_IEEE8021X_EAPOL=y +NEED_T_PRF=y +endif + +ifdef CONFIG_EAP_TEAP +# EAP-TEAP +ifeq ($(CONFIG_EAP_TEAP), dyn) +L_CFLAGS += -DEAP_YEAP_DYNAMIC +EAPDYN += src/eap_peer/eap_teap.so +EAPDYN += src/eap_common/eap_teap_common.c +else +L_CFLAGS += -DEAP_TEAP +OBJS += src/eap_peer/eap_teap.c src/eap_peer/eap_teap_pac.c +OBJS += src/eap_common/eap_teap_common.c +endif +TLS_FUNCS=y +CONFIG_IEEE8021X_EAPOL=y +NEED_T_PRF=y +NEED_SHA384=y +NEED_TLS_PRF_SHA256=y +NEED_TLS_PRF_SHA384=y +endif + +ifdef CONFIG_EAP_PAX +# EAP-PAX +ifeq ($(CONFIG_EAP_PAX), dyn) +L_CFLAGS += -DEAP_PAX_DYNAMIC +EAPDYN += src/eap_peer/eap_pax.so +else +L_CFLAGS += -DEAP_PAX +OBJS += src/eap_peer/eap_pax.c src/eap_common/eap_pax_common.c +endif +CONFIG_IEEE8021X_EAPOL=y +endif + +ifdef CONFIG_EAP_SAKE +# EAP-SAKE +ifeq ($(CONFIG_EAP_SAKE), dyn) +L_CFLAGS += -DEAP_SAKE_DYNAMIC +EAPDYN += src/eap_peer/eap_sake.so +else +L_CFLAGS += -DEAP_SAKE +OBJS += src/eap_peer/eap_sake.c src/eap_common/eap_sake_common.c +endif +CONFIG_IEEE8021X_EAPOL=y +endif + +ifdef CONFIG_EAP_GPSK +# EAP-GPSK +ifeq ($(CONFIG_EAP_GPSK), dyn) +L_CFLAGS += -DEAP_GPSK_DYNAMIC +EAPDYN += src/eap_peer/eap_gpsk.so +else +L_CFLAGS += -DEAP_GPSK +OBJS += src/eap_peer/eap_gpsk.c src/eap_common/eap_gpsk_common.c +endif +CONFIG_IEEE8021X_EAPOL=y +ifdef CONFIG_EAP_GPSK_SHA256 +L_CFLAGS += -DEAP_GPSK_SHA256 +endif +endif + +ifdef CONFIG_EAP_PWD +L_CFLAGS += -DEAP_PWD +OBJS += src/eap_peer/eap_pwd.c src/eap_common/eap_pwd_common.c +CONFIG_IEEE8021X_EAPOL=y +NEED_ECC=y +NEED_DRAGONFLY=y +endif + +ifdef CONFIG_EAP_EKE +# EAP-EKE +ifeq ($(CONFIG_EAP_EKE), dyn) +L_CFLAGS += -DEAP_EKE_DYNAMIC +EAPDYN += src/eap_peer/eap_eke.so +else +L_CFLAGS += -DEAP_EKE +OBJS += src/eap_peer/eap_eke.c src/eap_common/eap_eke_common.c +endif +CONFIG_IEEE8021X_EAPOL=y +NEED_DH_GROUPS=y +NEED_DH_GROUPS_ALL=y +NEED_AES_CBC=y +endif + +ifdef CONFIG_WPS +# EAP-WSC +L_CFLAGS += -DCONFIG_WPS -DEAP_WSC +OBJS += wps_supplicant.c +OBJS += src/utils/uuid.c +OBJS += src/eap_peer/eap_wsc.c src/eap_common/eap_wsc_common.c +OBJS += src/wps/wps.c +OBJS += src/wps/wps_common.c +OBJS += src/wps/wps_attr_parse.c +OBJS += src/wps/wps_attr_build.c +OBJS += src/wps/wps_attr_process.c +OBJS += src/wps/wps_dev_attr.c +OBJS += src/wps/wps_enrollee.c +OBJS += src/wps/wps_registrar.c +CONFIG_IEEE8021X_EAPOL=y +NEED_DH_GROUPS=y +NEED_BASE64=y +NEED_AES_CBC=y +NEED_MODEXP=y + +ifdef CONFIG_WPS_NFC +L_CFLAGS += -DCONFIG_WPS_NFC +OBJS += src/wps/ndef.c +NEED_WPS_OOB=y +endif + +ifdef NEED_WPS_OOB +L_CFLAGS += -DCONFIG_WPS_OOB +endif + +ifdef CONFIG_WPS_ER +CONFIG_WPS_UPNP=y +L_CFLAGS += -DCONFIG_WPS_ER +OBJS += src/wps/wps_er.c +OBJS += src/wps/wps_er_ssdp.c +endif + +ifdef CONFIG_WPS_UPNP +L_CFLAGS += -DCONFIG_WPS_UPNP +OBJS += src/wps/wps_upnp.c +OBJS += src/wps/wps_upnp_ssdp.c +OBJS += src/wps/wps_upnp_web.c +OBJS += src/wps/wps_upnp_event.c +OBJS += src/wps/wps_upnp_ap.c +OBJS += src/wps/upnp_xml.c +OBJS += src/wps/httpread.c +OBJS += src/wps/http_client.c +OBJS += src/wps/http_server.c +endif + +ifdef CONFIG_WPS_STRICT +L_CFLAGS += -DCONFIG_WPS_STRICT +OBJS += src/wps/wps_validate.c +endif + +ifdef CONFIG_WPS_TESTING +L_CFLAGS += -DCONFIG_WPS_TESTING +endif + +ifdef CONFIG_WPS_REG_DISABLE_OPEN +L_CFLAGS += -DCONFIG_WPS_REG_DISABLE_OPEN +endif + +endif + +ifdef CONFIG_EAP_IKEV2 +# EAP-IKEv2 +ifeq ($(CONFIG_EAP_IKEV2), dyn) +L_CFLAGS += -DEAP_IKEV2_DYNAMIC +EAPDYN += src/eap_peer/eap_ikev2.so src/eap_peer/ikev2.c +EAPDYN += src/eap_common/eap_ikev2_common.c src/eap_common/ikev2_common.c +else +L_CFLAGS += -DEAP_IKEV2 +OBJS += src/eap_peer/eap_ikev2.c src/eap_peer/ikev2.c +OBJS += src/eap_common/eap_ikev2_common.c src/eap_common/ikev2_common.c +endif +CONFIG_IEEE8021X_EAPOL=y +NEED_DH_GROUPS=y +NEED_DH_GROUPS_ALL=y +NEED_MODEXP=y +NEED_CIPHER=y +endif + +ifdef CONFIG_EAP_VENDOR_TEST +ifeq ($(CONFIG_EAP_VENDOR_TEST), dyn) +L_CFLAGS += -DEAP_VENDOR_TEST_DYNAMIC +EAPDYN += src/eap_peer/eap_vendor_test.so +else +L_CFLAGS += -DEAP_VENDOR_TEST +OBJS += src/eap_peer/eap_vendor_test.c +endif +CONFIG_IEEE8021X_EAPOL=y +endif + +ifdef CONFIG_EAP_TNC +# EAP-TNC +L_CFLAGS += -DEAP_TNC +OBJS += src/eap_peer/eap_tnc.c +OBJS += src/eap_peer/tncc.c +NEED_BASE64=y +ifndef CONFIG_NATIVE_WINDOWS +ifndef CONFIG_DRIVER_BSD +LIBS += -ldl +endif +endif +endif + +ifdef CONFIG_IEEE8021X_EAPOL +# IEEE 802.1X/EAPOL state machines (e.g., for RADIUS authentication) +L_CFLAGS += -DIEEE8021X_EAPOL +OBJS += src/eapol_supp/eapol_supp_sm.c +OBJS += src/eap_peer/eap.c src/eap_peer/eap_methods.c +NEED_EAP_COMMON=y +ifdef CONFIG_DYNAMIC_EAP_METHODS +L_CFLAGS += -DCONFIG_DYNAMIC_EAP_METHODS +LIBS += -ldl -rdynamic +endif +endif + +ifdef CONFIG_AP +NEED_EAP_COMMON=y +NEED_RSN_AUTHENTICATOR=y +L_CFLAGS += -DCONFIG_AP +OBJS += ap.c +L_CFLAGS += -DCONFIG_NO_RADIUS +L_CFLAGS += -DCONFIG_NO_ACCOUNTING +L_CFLAGS += -DCONFIG_NO_VLAN +OBJS += src/ap/hostapd.c +OBJS += src/ap/wpa_auth_glue.c +OBJS += src/ap/utils.c +OBJS += src/ap/authsrv.c +OBJS += src/ap/ap_config.c +OBJS += src/ap/sta_info.c +OBJS += src/ap/tkip_countermeasures.c +OBJS += src/ap/ap_mlme.c +OBJS += src/ap/ieee802_1x.c +OBJS += src/eapol_auth/eapol_auth_sm.c +OBJS += src/ap/ieee802_11_auth.c +OBJS += src/ap/ieee802_11_shared.c +OBJS += src/ap/drv_callbacks.c +OBJS += src/ap/ap_drv_ops.c +OBJS += src/ap/beacon.c +OBJS += src/ap/bss_load.c +OBJS += src/ap/eap_user_db.c +OBJS += src/ap/neighbor_db.c +OBJS += src/ap/rrm.c +OBJS += src/ap/ieee802_11_ht.c +ifdef CONFIG_IEEE80211AC +OBJS += src/ap/ieee802_11_vht.c +endif +ifdef CONFIG_IEEE80211AX +OBJS += src/ap/ieee802_11_he.c +endif +ifdef CONFIG_WNM_AP +L_CFLAGS += -DCONFIG_WNM_AP +OBJS += src/ap/wnm_ap.c +endif +ifdef CONFIG_MBO +OBJS += src/ap/mbo_ap.c +endif +ifdef CONFIG_FILS +OBJS += src/ap/fils_hlp.c +endif +ifdef CONFIG_CTRL_IFACE +OBJS += src/ap/ctrl_iface_ap.c +endif + +L_CFLAGS += -DEAP_SERVER -DEAP_SERVER_IDENTITY +OBJS += src/eap_server/eap_server.c +OBJS += src/eap_server/eap_server_identity.c +OBJS += src/eap_server/eap_server_methods.c + +ifdef CONFIG_IEEE80211AC +L_CFLAGS += -DCONFIG_IEEE80211AC +endif +ifdef CONFIG_IEEE80211AX +L_CFLAGS += -DCONFIG_IEEE80211AX +endif + +ifdef NEED_AP_MLME +OBJS += src/ap/wmm.c +OBJS += src/ap/ap_list.c +OBJS += src/ap/ieee802_11.c +OBJS += src/ap/hw_features.c +OBJS += src/ap/dfs.c +L_CFLAGS += -DNEED_AP_MLME +endif +ifdef CONFIG_WPS +L_CFLAGS += -DEAP_SERVER_WSC +OBJS += src/ap/wps_hostapd.c +OBJS += src/eap_server/eap_server_wsc.c +endif +ifdef CONFIG_DPP +OBJS += src/ap/dpp_hostapd.c +OBJS += src/ap/gas_query_ap.c +NEED_AP_GAS_SERV=y +endif +ifdef CONFIG_INTERWORKING +NEED_AP_GAS_SERV=y +endif +ifdef NEED_AP_GAS_SERV +OBJS += src/ap/gas_serv.c +endif +ifdef CONFIG_HS20 +OBJS += src/ap/hs20.c +endif +endif + +ifdef CONFIG_MBO +OBJS += mbo.c +L_CFLAGS += -DCONFIG_MBO +endif + +ifdef CONFIG_TESTING_OPTIONS +L_CFLAGS += -DCONFIG_TESTING_OPTIONS +endif + +ifdef NEED_RSN_AUTHENTICATOR +L_CFLAGS += -DCONFIG_NO_RADIUS +NEED_AES_WRAP=y +OBJS += src/ap/wpa_auth.c +OBJS += src/ap/wpa_auth_ie.c +OBJS += src/ap/pmksa_cache_auth.c +endif + +ifdef CONFIG_ACS +L_CFLAGS += -DCONFIG_ACS +OBJS += src/ap/acs.c +LIBS += -lm +endif + +ifdef CONFIG_PCSC +# PC/SC interface for smartcards (USIM, GSM SIM) +L_CFLAGS += -DPCSC_FUNCS -I/usr/include/PCSC +OBJS += src/utils/pcsc_funcs.c +# -lpthread may not be needed depending on how pcsc-lite was configured +ifdef CONFIG_NATIVE_WINDOWS +#Once MinGW gets support for WinScard, -lwinscard could be used instead of the +#dynamic symbol loading that is now used in pcsc_funcs.c +#LIBS += -lwinscard +else +LIBS += -lpcsclite -lpthread +endif +endif + +ifdef CONFIG_SIM_SIMULATOR +L_CFLAGS += -DCONFIG_SIM_SIMULATOR +NEED_MILENAGE=y +endif + +ifdef CONFIG_USIM_SIMULATOR +L_CFLAGS += -DCONFIG_USIM_SIMULATOR +NEED_MILENAGE=y +endif + +ifdef NEED_MILENAGE +OBJS += src/crypto/milenage.c +NEED_AES_ENCBLOCK=y +endif + +ifdef CONFIG_PKCS12 +L_CFLAGS += -DPKCS12_FUNCS +endif + +ifdef CONFIG_SMARTCARD +L_CFLAGS += -DCONFIG_SMARTCARD +endif + +ifdef NEED_DRAGONFLY +OBJS += src/common/dragonfly.c +endif + +ifdef MS_FUNCS +OBJS += src/crypto/ms_funcs.c +NEED_DES=y +NEED_MD4=y +endif + +ifdef CHAP +OBJS += src/eap_common/chap.c +endif + +ifdef TLS_FUNCS +NEED_DES=y +# Shared TLS functions (needed for EAP_TLS, EAP_PEAP, EAP_TTLS, and EAP_FAST) +OBJS += src/eap_peer/eap_tls_common.c +ifndef CONFIG_FIPS +NEED_TLS_PRF=y +NEED_SHA1=y +NEED_MD5=y +endif +endif + +ifndef CONFIG_TLS +CONFIG_TLS=openssl +endif + +ifdef CONFIG_TLSV11 +L_CFLAGS += -DCONFIG_TLSV11 +endif + +ifdef CONFIG_TLSV12 +L_CFLAGS += -DCONFIG_TLSV12 +endif + +ifeq ($(CONFIG_TLS), openssl) +ifdef TLS_FUNCS +L_CFLAGS += -DEAP_TLS_OPENSSL +OBJS += src/crypto/tls_openssl.c +OBJS += src/crypto/tls_openssl_ocsp.c +LIBS += -lssl +endif +OBJS += src/crypto/crypto_openssl.c +OBJS_p += src/crypto/crypto_openssl.c +ifdef NEED_FIPS186_2_PRF +OBJS += src/crypto/fips_prf_openssl.c +endif +NEED_TLS_PRF_SHA256=y +LIBS += -lcrypto +LIBS_p += -lcrypto +ifdef CONFIG_TLS_ADD_DL +LIBS += -ldl +LIBS_p += -ldl +endif +ifndef CONFIG_TLS_DEFAULT_CIPHERS +CONFIG_TLS_DEFAULT_CIPHERS = "DEFAULT:!EXP:!LOW" +endif +L_CFLAGS += -DTLS_DEFAULT_CIPHERS=\"$(CONFIG_TLS_DEFAULT_CIPHERS)\" +endif + +ifeq ($(CONFIG_TLS), gnutls) +ifndef CONFIG_CRYPTO +# default to libgcrypt +CONFIG_CRYPTO=gnutls +endif +ifdef TLS_FUNCS +OBJS += src/crypto/tls_gnutls.c +LIBS += -lgnutls -lgpg-error +endif +OBJS += src/crypto/crypto_$(CONFIG_CRYPTO).c +OBJS_p += src/crypto/crypto_$(CONFIG_CRYPTO).c +ifdef NEED_FIPS186_2_PRF +OBJS += src/crypto/fips_prf_internal.c +OBJS += src/crypto/sha1-internal.c +endif +ifeq ($(CONFIG_CRYPTO), gnutls) +LIBS += -lgcrypt +LIBS_p += -lgcrypt +CONFIG_INTERNAL_RC4=y +CONFIG_INTERNAL_DH_GROUP5=y +endif +ifeq ($(CONFIG_CRYPTO), nettle) +LIBS += -lnettle -lgmp +LIBS_p += -lnettle -lgmp +CONFIG_INTERNAL_RC4=y +CONFIG_INTERNAL_DH_GROUP5=y +endif +endif + +ifeq ($(CONFIG_TLS), internal) +ifndef CONFIG_CRYPTO +CONFIG_CRYPTO=internal +endif +ifdef TLS_FUNCS +OBJS += src/crypto/crypto_internal-rsa.c +OBJS += src/crypto/tls_internal.c +OBJS += src/tls/tlsv1_common.c +OBJS += src/tls/tlsv1_record.c +OBJS += src/tls/tlsv1_cred.c +OBJS += src/tls/tlsv1_client.c +OBJS += src/tls/tlsv1_client_write.c +OBJS += src/tls/tlsv1_client_read.c +OBJS += src/tls/tlsv1_client_ocsp.c +NEED_ASN1=y +OBJS += src/tls/rsa.c +OBJS += src/tls/x509v3.c +OBJS += src/tls/pkcs1.c +OBJS += src/tls/pkcs5.c +OBJS += src/tls/pkcs8.c +NEED_BASE64=y +NEED_TLS_PRF=y +ifdef CONFIG_TLSV12 +NEED_TLS_PRF_SHA256=y +endif +NEED_MODEXP=y +NEED_CIPHER=y +L_CFLAGS += -DCONFIG_TLS_INTERNAL_CLIENT +endif +ifdef NEED_CIPHER +NEED_DES=y +OBJS += src/crypto/crypto_internal-cipher.c +endif +ifdef NEED_MODEXP +OBJS += src/crypto/crypto_internal-modexp.c +OBJS += src/tls/bignum.c +endif +ifeq ($(CONFIG_CRYPTO), libtomcrypt) +OBJS += src/crypto/crypto_libtomcrypt.c +OBJS_p += src/crypto/crypto_libtomcrypt.c +LIBS += -ltomcrypt -ltfm +LIBS_p += -ltomcrypt -ltfm +CONFIG_INTERNAL_SHA256=y +CONFIG_INTERNAL_RC4=y +CONFIG_INTERNAL_DH_GROUP5=y +endif +ifeq ($(CONFIG_CRYPTO), internal) +OBJS += src/crypto/crypto_internal.c +OBJS_p += src/crypto/crypto_internal.c +NEED_AES_ENC=y +L_CFLAGS += -DCONFIG_CRYPTO_INTERNAL +ifdef CONFIG_INTERNAL_LIBTOMMATH +L_CFLAGS += -DCONFIG_INTERNAL_LIBTOMMATH +ifdef CONFIG_INTERNAL_LIBTOMMATH_FAST +L_CFLAGS += -DLTM_FAST +endif +else +LIBS += -ltommath +LIBS_p += -ltommath +endif +CONFIG_INTERNAL_AES=y +CONFIG_INTERNAL_DES=y +CONFIG_INTERNAL_SHA1=y +CONFIG_INTERNAL_MD4=y +CONFIG_INTERNAL_MD5=y +CONFIG_INTERNAL_SHA256=y +CONFIG_INTERNAL_SHA384=y +CONFIG_INTERNAL_SHA512=y +CONFIG_INTERNAL_RC4=y +CONFIG_INTERNAL_DH_GROUP5=y +endif +ifeq ($(CONFIG_CRYPTO), cryptoapi) +OBJS += src/crypto/crypto_cryptoapi.c +OBJS_p += src/crypto/crypto_cryptoapi.c +L_CFLAGS += -DCONFIG_CRYPTO_CRYPTOAPI +CONFIG_INTERNAL_SHA256=y +CONFIG_INTERNAL_RC4=y +endif +endif + +ifeq ($(CONFIG_TLS), none) +ifdef TLS_FUNCS +OBJS += src/crypto/tls_none.c +L_CFLAGS += -DEAP_TLS_NONE +CONFIG_INTERNAL_AES=y +CONFIG_INTERNAL_SHA1=y +CONFIG_INTERNAL_MD5=y +endif +OBJS += src/crypto/crypto_none.c +OBJS_p += src/crypto/crypto_none.c +CONFIG_INTERNAL_SHA256=y +CONFIG_INTERNAL_RC4=y +endif + +ifdef TLS_FUNCS +ifdef CONFIG_SMARTCARD +ifndef CONFIG_NATIVE_WINDOWS +ifneq ($(CONFIG_L2_PACKET), freebsd) +LIBS += -ldl +endif +endif +endif +endif + +ifndef TLS_FUNCS +OBJS += src/crypto/tls_none.c +ifeq ($(CONFIG_TLS), internal) +CONFIG_INTERNAL_AES=y +CONFIG_INTERNAL_SHA1=y +CONFIG_INTERNAL_MD5=y +CONFIG_INTERNAL_RC4=y +endif +endif + +AESOBJS = # none so far (see below) +ifdef CONFIG_INTERNAL_AES +AESOBJS += src/crypto/aes-internal.c src/crypto/aes-internal-dec.c +endif + +ifneq ($(CONFIG_TLS), openssl) +NEED_INTERNAL_AES_WRAP=y +endif +ifdef CONFIG_OPENSSL_INTERNAL_AES_WRAP +# Seems to be needed at least with BoringSSL +NEED_INTERNAL_AES_WRAP=y +L_CFLAGS += -DCONFIG_OPENSSL_INTERNAL_AES_WRAP +endif +ifdef CONFIG_FIPS +# Have to use internal AES key wrap routines to use OpenSSL EVP since the +# OpenSSL AES_wrap_key()/AES_unwrap_key() API is not available in FIPS mode. +NEED_INTERNAL_AES_WRAP=y +endif + +ifdef NEED_INTERNAL_AES_WRAP +AESOBJS += src/crypto/aes-unwrap.c +endif +ifdef NEED_AES_EAX +AESOBJS += src/crypto/aes-eax.c +NEED_AES_CTR=y +endif +ifdef NEED_AES_SIV +AESOBJS += src/crypto/aes-siv.c +NEED_AES_CTR=y +endif +ifdef NEED_AES_CTR +AESOBJS += src/crypto/aes-ctr.c +endif +ifdef NEED_AES_ENCBLOCK +AESOBJS += src/crypto/aes-encblock.c +endif +NEED_AES_ENC=y +ifdef CONFIG_OPENSSL_CMAC +L_CFLAGS += -DCONFIG_OPENSSL_CMAC +else +AESOBJS += src/crypto/aes-omac1.c +endif +ifdef NEED_AES_WRAP +NEED_AES_ENC=y +ifdef NEED_INTERNAL_AES_WRAP +AESOBJS += src/crypto/aes-wrap.c +endif +endif +ifdef NEED_AES_CBC +NEED_AES_ENC=y +ifneq ($(CONFIG_TLS), openssl) +AESOBJS += src/crypto/aes-cbc.c +endif +endif +ifdef NEED_AES_ENC +ifdef CONFIG_INTERNAL_AES +AESOBJS += src/crypto/aes-internal-enc.c +endif +endif +ifdef NEED_AES +OBJS += $(AESOBJS) +endif + +SHA1OBJS = +ifdef NEED_SHA1 +ifneq ($(CONFIG_TLS), openssl) +ifneq ($(CONFIG_TLS), gnutls) +SHA1OBJS += src/crypto/sha1.c +endif +endif +SHA1OBJS += src/crypto/sha1-prf.c +ifdef CONFIG_INTERNAL_SHA1 +SHA1OBJS += src/crypto/sha1-internal.c +ifdef NEED_FIPS186_2_PRF +SHA1OBJS += src/crypto/fips_prf_internal.c +endif +endif +ifdef CONFIG_NO_WPA_PASSPHRASE +L_CFLAGS += -DCONFIG_NO_PBKDF2 +else +ifneq ($(CONFIG_TLS), openssl) +SHA1OBJS += src/crypto/sha1-pbkdf2.c +endif +endif +ifdef NEED_T_PRF +SHA1OBJS += src/crypto/sha1-tprf.c +endif +ifdef NEED_TLS_PRF +SHA1OBJS += src/crypto/sha1-tlsprf.c +endif +endif + +MD5OBJS = +ifndef CONFIG_FIPS +ifneq ($(CONFIG_TLS), openssl) +ifneq ($(CONFIG_TLS), gnutls) +MD5OBJS += src/crypto/md5.c +endif +endif +endif +ifdef NEED_MD5 +ifdef CONFIG_INTERNAL_MD5 +MD5OBJS += src/crypto/md5-internal.c +endif +OBJS += $(MD5OBJS) +OBJS_p += $(MD5OBJS) +endif + +ifdef NEED_MD4 +ifdef CONFIG_INTERNAL_MD4 +OBJS += src/crypto/md4-internal.c +endif +endif + +DESOBJS = # none needed when not internal +ifdef NEED_DES +ifdef CONFIG_INTERNAL_DES +DESOBJS += src/crypto/des-internal.c +endif +endif + +ifdef CONFIG_NO_RC4 +L_CFLAGS += -DCONFIG_NO_RC4 +endif + +ifdef NEED_RC4 +ifdef CONFIG_INTERNAL_RC4 +ifndef CONFIG_NO_RC4 +OBJS += src/crypto/rc4.c +endif +endif +endif + +SHA256OBJS = # none by default +L_CFLAGS += -DCONFIG_SHA256 +ifneq ($(CONFIG_TLS), openssl) +ifneq ($(CONFIG_TLS), gnutls) +SHA256OBJS += src/crypto/sha256.c +endif +endif +SHA256OBJS += src/crypto/sha256-prf.c +ifdef CONFIG_INTERNAL_SHA256 +SHA256OBJS += src/crypto/sha256-internal.c +endif +ifdef CONFIG_INTERNAL_SHA384 +L_CFLAGS += -DCONFIG_INTERNAL_SHA384 +SHA256OBJS += src/crypto/sha384-internal.c +endif +ifdef CONFIG_INTERNAL_SHA512 +L_CFLAGS += -DCONFIG_INTERNAL_SHA512 +SHA256OBJS += src/crypto/sha512-internal.c +endif +ifdef NEED_TLS_PRF_SHA256 +SHA256OBJS += src/crypto/sha256-tlsprf.c +endif +ifdef NEED_TLS_PRF_SHA384 +SHA256OBJS += src/crypto/sha384-tlsprf.c +endif +ifdef NEED_HMAC_SHA256_KDF +L_CFLAGS += -DCONFIG_HMAC_SHA256_KDF +SHA256OBJS += src/crypto/sha256-kdf.c +endif +ifdef NEED_HMAC_SHA384_KDF +L_CFLAGS += -DCONFIG_HMAC_SHA384_KDF +SHA256OBJS += src/crypto/sha384-kdf.c +endif +ifdef NEED_HMAC_SHA512_KDF +L_CFLAGS += -DCONFIG_HMAC_SHA512_KDF +SHA256OBJS += src/crypto/sha512-kdf.c +endif +OBJS += $(SHA256OBJS) +ifdef NEED_SHA384 +L_CFLAGS += -DCONFIG_SHA384 +ifneq ($(CONFIG_TLS), openssl) +ifneq ($(CONFIG_TLS), gnutls) +OBJS += src/crypto/sha384.c +endif +endif +OBJS += src/crypto/sha384-prf.c +endif +ifdef NEED_SHA512 +L_CFLAGS += -DCONFIG_SHA512 +ifneq ($(CONFIG_TLS), openssl) +ifneq ($(CONFIG_TLS), gnutls) +OBJS += src/crypto/sha512.c +endif +endif +OBJS += src/crypto/sha512-prf.c +endif + +ifdef NEED_ASN1 +OBJS += src/tls/asn1.c +endif + +ifdef NEED_DH_GROUPS +OBJS += src/crypto/dh_groups.c +endif +ifdef NEED_DH_GROUPS_ALL +L_CFLAGS += -DALL_DH_GROUPS +endif +ifdef CONFIG_INTERNAL_DH_GROUP5 +ifdef NEED_DH_GROUPS +OBJS += src/crypto/dh_group5.c +endif +endif + +ifdef NEED_ECC +L_CFLAGS += -DCONFIG_ECC +endif + +ifdef CONFIG_NO_RANDOM_POOL +L_CFLAGS += -DCONFIG_NO_RANDOM_POOL +else +OBJS += src/crypto/random.c +endif + +ifdef CONFIG_CTRL_IFACE +ifeq ($(CONFIG_CTRL_IFACE), y) +ifdef CONFIG_NATIVE_WINDOWS +CONFIG_CTRL_IFACE=named_pipe +else +CONFIG_CTRL_IFACE=unix +endif +endif +L_CFLAGS += -DCONFIG_CTRL_IFACE +ifeq ($(CONFIG_CTRL_IFACE), unix) +L_CFLAGS += -DCONFIG_CTRL_IFACE_UNIX +OBJS += src/common/ctrl_iface_common.c +endif +ifeq ($(CONFIG_CTRL_IFACE), udp) +L_CFLAGS += -DCONFIG_CTRL_IFACE_UDP +endif +ifeq ($(CONFIG_CTRL_IFACE), named_pipe) +L_CFLAGS += -DCONFIG_CTRL_IFACE_NAMED_PIPE +endif +ifeq ($(CONFIG_CTRL_IFACE), udp-remote) +CONFIG_CTRL_IFACE=udp +L_CFLAGS += -DCONFIG_CTRL_IFACE_UDP +L_CFLAGS += -DCONFIG_CTRL_IFACE_UDP_REMOTE +endif +OBJS += ctrl_iface.c ctrl_iface_$(CONFIG_CTRL_IFACE).c +endif + +ifdef CONFIG_CTRL_IFACE_DBUS_NEW +L_CFLAGS += -DCONFIG_CTRL_IFACE_DBUS_NEW +OBJS += dbus/dbus_dict_helpers.c +OBJS += dbus/dbus_new_helpers.c +OBJS += dbus/dbus_new.c dbus/dbus_new_handlers.c +OBJS += dbus/dbus_common.c +ifdef CONFIG_WPS +OBJS += dbus/dbus_new_handlers_wps.c +endif +ifdef CONFIG_P2P +OBJS += dbus/dbus_new_handlers_p2p.c +endif +ifdef CONFIG_CTRL_IFACE_DBUS_INTRO +OBJS += dbus/dbus_new_introspect.c +L_CFLAGS += -DCONFIG_CTRL_IFACE_DBUS_INTRO +endif +L_CFLAGS += $(DBUS_INCLUDE) +endif + +ifdef CONFIG_CTRL_IFACE_BINDER +WPA_SUPPLICANT_USE_BINDER=y +L_CFLAGS += -DCONFIG_BINDER -DCONFIG_CTRL_IFACE_BINDER +endif + +ifdef CONFIG_READLINE +OBJS_c += src/utils/edit_readline.c +LIBS_c += -lncurses -lreadline +else +ifdef CONFIG_WPA_CLI_EDIT +OBJS_c += src/utils/edit.c +else +OBJS_c += src/utils/edit_simple.c +endif +endif + +ifdef CONFIG_NATIVE_WINDOWS +L_CFLAGS += -DCONFIG_NATIVE_WINDOWS +LIBS += -lws2_32 -lgdi32 -lcrypt32 +LIBS_c += -lws2_32 +LIBS_p += -lws2_32 -lgdi32 +ifeq ($(CONFIG_CRYPTO), cryptoapi) +LIBS_p += -lcrypt32 +endif +endif + +ifdef CONFIG_NO_STDOUT_DEBUG +L_CFLAGS += -DCONFIG_NO_STDOUT_DEBUG +ifndef CONFIG_CTRL_IFACE +L_CFLAGS += -DCONFIG_NO_WPA_MSG +endif +endif + +ifdef CONFIG_ANDROID_LOG +L_CFLAGS += -DCONFIG_ANDROID_LOG +endif + +ifdef CONFIG_IPV6 +# for eapol_test only +L_CFLAGS += -DCONFIG_IPV6 +endif + +ifdef NEED_BASE64 +OBJS += src/utils/base64.c +endif + +ifdef NEED_SME +OBJS += sme.c +L_CFLAGS += -DCONFIG_SME +endif + +OBJS += src/common/ieee802_11_common.c +OBJS += src/common/hw_features_common.c + +ifdef NEED_EAP_COMMON +OBJS += src/eap_common/eap_common.c +endif + +ifndef CONFIG_MAIN +CONFIG_MAIN=main +endif + +ifdef CONFIG_DEBUG_SYSLOG +L_CFLAGS += -DCONFIG_DEBUG_SYSLOG +ifdef CONFIG_DEBUG_SYSLOG_FACILITY +L_CFLAGS += -DLOG_HOSTAPD="$(CONFIG_DEBUG_SYSLOG_FACILITY)" +endif +endif + +ifdef CONFIG_DEBUG_LINUX_TRACING +L_CFLAGS += -DCONFIG_DEBUG_LINUX_TRACING +endif + +ifdef CONFIG_DEBUG_FILE +L_CFLAGS += -DCONFIG_DEBUG_FILE +endif + +ifdef CONFIG_DELAYED_MIC_ERROR_REPORT +L_CFLAGS += -DCONFIG_DELAYED_MIC_ERROR_REPORT +endif + +ifdef CONFIG_FIPS +L_CFLAGS += -DCONFIG_FIPS +endif + +OBJS += $(SHA1OBJS) $(DESOBJS) + +OBJS_p += $(SHA1OBJS) +OBJS_p += $(SHA256OBJS) + +ifdef CONFIG_BGSCAN_SIMPLE +L_CFLAGS += -DCONFIG_BGSCAN_SIMPLE +OBJS += bgscan_simple.c +NEED_BGSCAN=y +endif + +ifdef CONFIG_BGSCAN_LEARN +L_CFLAGS += -DCONFIG_BGSCAN_LEARN +OBJS += bgscan_learn.c +NEED_BGSCAN=y +endif + +ifdef NEED_BGSCAN +L_CFLAGS += -DCONFIG_BGSCAN +OBJS += bgscan.c +endif + +ifdef CONFIG_AUTOSCAN_EXPONENTIAL +L_CFLAGS += -DCONFIG_AUTOSCAN_EXPONENTIAL +OBJS += autoscan_exponential.c +NEED_AUTOSCAN=y +endif + +ifdef CONFIG_AUTOSCAN_PERIODIC +L_CFLAGS += -DCONFIG_AUTOSCAN_PERIODIC +OBJS += autoscan_periodic.c +NEED_AUTOSCAN=y +endif + +ifdef NEED_AUTOSCAN +L_CFLAGS += -DCONFIG_AUTOSCAN +OBJS += autoscan.c +endif + +ifdef CONFIG_EXT_PASSWORD_TEST +OBJS += src/utils/ext_password_test.c +L_CFLAGS += -DCONFIG_EXT_PASSWORD_TEST +NEED_EXT_PASSWORD=y +endif + +ifdef CONFIG_EXT_PASSWORD_FILE +OBJS += src/utils/ext_password_file.c +L_CFLAGS += -DCONFIG_EXT_PASSWORD_FILE +NEED_EXT_PASSWORD=y +endif + +ifdef NEED_EXT_PASSWORD +OBJS += src/utils/ext_password.c +L_CFLAGS += -DCONFIG_EXT_PASSWORD +endif + +ifdef NEED_GAS_SERVER +OBJS += src/common/gas_server.c +L_CFLAGS += -DCONFIG_GAS_SERVER +NEED_GAS=y +endif + +ifdef NEED_GAS +OBJS += src/common/gas.c +OBJS += gas_query.c +L_CFLAGS += -DCONFIG_GAS +NEED_OFFCHANNEL=y +endif + +ifdef NEED_OFFCHANNEL +OBJS += offchannel.c +L_CFLAGS += -DCONFIG_OFFCHANNEL +endif + +ifdef NEED_JSON +OBJS += src/utils/json.c +L_CFLAGS += -DCONFIG_JSON +endif + +OBJS += src/drivers/driver_common.c + +OBJS += wpa_supplicant.c events.c bssid_ignore.c wpas_glue.c scan.c +OBJS_t := $(OBJS) $(OBJS_l2) eapol_test.c +OBJS_t += src/radius/radius_client.c +OBJS_t += src/radius/radius.c +OBJS_t2 := $(OBJS) $(OBJS_l2) preauth_test.c +OBJS += $(CONFIG_MAIN).c + +ifdef CONFIG_PRIVSEP +OBJS_priv += $(OBJS_d) src/drivers/drivers.c +OBJS_priv += $(OBJS_l2) +OBJS_priv += src/utils/os_$(CONFIG_OS).c +OBJS_priv += src/utils/$(CONFIG_ELOOP).c +OBJS_priv += src/utils/common.c +OBJS_priv += src/utils/wpa_debug.c +OBJS_priv += src/utils/wpabuf.c +OBJS_priv += wpa_priv.c +ifdef CONFIG_DRIVER_NL80211 +OBJS_priv += src/common/ieee802_11_common.c +endif +OBJS += src/l2_packet/l2_packet_privsep.c +OBJS += src/drivers/driver_privsep.c +EXTRA_progs += wpa_priv +else +OBJS += $(OBJS_d) src/drivers/drivers.c +OBJS += $(OBJS_l2) +endif + +ifdef CONFIG_NDIS_EVENTS_INTEGRATED +L_CFLAGS += -DCONFIG_NDIS_EVENTS_INTEGRATED +OBJS += src/drivers/ndis_events.c +EXTRALIBS += -loleaut32 -lole32 -luuid +ifdef PLATFORMSDKLIB +EXTRALIBS += $(PLATFORMSDKLIB)/WbemUuid.Lib +else +EXTRALIBS += WbemUuid.Lib +endif +endif + +ifndef LDO +LDO=$(CC) +endif + +######################## + +include $(CLEAR_VARS) +LOCAL_MODULE := wpa_cli +LOCAL_MODULE_TAGS := debug +LOCAL_SHARED_LIBRARIES := libc libcutils liblog +LOCAL_CFLAGS := $(L_CFLAGS) +LOCAL_SRC_FILES := $(OBJS_c) +LOCAL_C_INCLUDES := $(INCLUDES) +include $(BUILD_EXECUTABLE) + +######################## +include $(CLEAR_VARS) +LOCAL_MODULE := wpa_supplicant +ifdef CONFIG_DRIVER_CUSTOM +LOCAL_STATIC_LIBRARIES := libCustomWifi +endif +ifneq ($(BOARD_WPA_SUPPLICANT_PRIVATE_LIB),) +LOCAL_STATIC_LIBRARIES += $(BOARD_WPA_SUPPLICANT_PRIVATE_LIB) +endif +LOCAL_SHARED_LIBRARIES := libc libcutils liblog +ifdef CONFIG_EAP_PROXY +LOCAL_STATIC_LIBRARIES += $(LIB_STATIC_EAP_PROXY) +LOCAL_SHARED_LIBRARIES += $(LIB_SHARED_EAP_PROXY) +endif +ifeq ($(CONFIG_TLS), openssl) +LOCAL_SHARED_LIBRARIES += libcrypto libssl libkeystore_binder +endif + +# With BoringSSL we need libkeystore-engine in order to provide access to +# keystore keys. +LOCAL_SHARED_LIBRARIES += libkeystore-engine + +ifdef CONFIG_DRIVER_NL80211 +ifneq ($(wildcard external/libnl),) +LOCAL_SHARED_LIBRARIES += libnl +else +LOCAL_STATIC_LIBRARIES += libnl_2 +endif +endif +LOCAL_CFLAGS := $(L_CFLAGS) +LOCAL_SRC_FILES := $(OBJS) +LOCAL_C_INCLUDES := $(INCLUDES) +ifeq ($(DBUS), y) +LOCAL_SHARED_LIBRARIES += libdbus +endif +ifeq ($(WPA_SUPPLICANT_USE_BINDER), y) +LOCAL_SHARED_LIBRARIES += libbinder libutils +LOCAL_STATIC_LIBRARIES += libwpa_binder libwpa_binder_interface +endif +include $(BUILD_EXECUTABLE) + +######################## +# +#include $(CLEAR_VARS) +#LOCAL_MODULE := eapol_test +#ifdef CONFIG_DRIVER_CUSTOM +#LOCAL_STATIC_LIBRARIES := libCustomWifi +#endif +#LOCAL_SHARED_LIBRARIES := libc libcrypto libssl +#LOCAL_CFLAGS := $(L_CFLAGS) +#LOCAL_SRC_FILES := $(OBJS_t) +#LOCAL_C_INCLUDES := $(INCLUDES) +#include $(BUILD_EXECUTABLE) +# +######################## +# +#local_target_dir := $(TARGET_OUT)/etc/wifi +# +#include $(CLEAR_VARS) +#LOCAL_MODULE := wpa_supplicant.conf +#LOCAL_MODULE_CLASS := ETC +#LOCAL_MODULE_PATH := $(local_target_dir) +#LOCAL_SRC_FILES := $(LOCAL_MODULE) +#include $(BUILD_PREBUILT) +# +######################## + +include $(CLEAR_VARS) +LOCAL_MODULE = libwpa_client +LOCAL_CFLAGS = $(L_CFLAGS) +LOCAL_SRC_FILES = src/common/wpa_ctrl.c src/utils/os_$(CONFIG_OS).c +LOCAL_C_INCLUDES = $(INCLUDES) +LOCAL_SHARED_LIBRARIES := libcutils liblog +LOCAL_COPY_HEADERS_TO := libwpa_client +LOCAL_COPY_HEADERS := src/common/wpa_ctrl.h +LOCAL_COPY_HEADERS += src/common/qca-vendor.h +include $(BUILD_SHARED_LIBRARY) + +ifeq ($(WPA_SUPPLICANT_USE_BINDER), y) +### Binder interface library ### +######################## + +include $(CLEAR_VARS) +LOCAL_MODULE := libwpa_binder_interface +LOCAL_AIDL_INCLUDES := \ + $(LOCAL_PATH)/binder \ + frameworks/native/aidl/binder +LOCAL_EXPORT_C_INCLUDE_DIRS := \ + $(LOCAL_PATH)/binder +LOCAL_CPPFLAGS := $(L_CPPFLAGS) +LOCAL_SRC_FILES := \ + binder/binder_constants.cpp \ + binder/fi/w1/wpa_supplicant/ISupplicant.aidl \ + binder/fi/w1/wpa_supplicant/ISupplicantCallbacks.aidl \ + binder/fi/w1/wpa_supplicant/IIface.aidl +LOCAL_SHARED_LIBRARIES := libbinder +include $(BUILD_STATIC_LIBRARY) + +### Binder service library ### +######################## + +include $(CLEAR_VARS) +LOCAL_MODULE := libwpa_binder +LOCAL_CPPFLAGS := $(L_CPPFLAGS) +LOCAL_CFLAGS := $(L_CFLAGS) +LOCAL_C_INCLUDES := $(INCLUDES) +LOCAL_SRC_FILES := \ + binder/binder.cpp binder/binder_manager.cpp \ + binder/supplicant.cpp binder/iface.cpp +LOCAL_SHARED_LIBRARIES := \ + libbinder \ + libutils +LOCAL_STATIC_LIBRARIES := libwpa_binder_interface +include $(BUILD_STATIC_LIBRARY) + +endif # BINDER == y diff --git a/wpa_supplicant/ChangeLog b/wpa_supplicant/ChangeLog new file mode 100644 index 000000000000..efcc6cd9c9ba --- /dev/null +++ b/wpa_supplicant/ChangeLog @@ -0,0 +1,2500 @@ +ChangeLog for wpa_supplicant + +2022-01-16 - v2.10 + * SAE changes + - improved protection against side channel attacks + [https://w1.fi/security/2022-1/] + - added support for the hash-to-element mechanism (sae_pwe=1 or + sae_pwe=2); this is currently disabled by default, but will likely + get enabled by default in the future + - fixed PMKSA caching with OKC + - added support for SAE-PK + * EAP-pwd changes + - improved protection against side channel attacks + [https://w1.fi/security/2022-1/] + * fixed P2P provision discovery processing of a specially constructed + invalid frame + [https://w1.fi/security/2021-1/] + * fixed P2P group information processing of a specially constructed + invalid frame + [https://w1.fi/security/2020-2/] + * fixed PMF disconnection protection bypass in AP mode + [https://w1.fi/security/2019-7/] + * added support for using OpenSSL 3.0 + * increased the maximum number of EAP message exchanges (mainly to + support cases with very large certificates) + * fixed various issues in experimental support for EAP-TEAP peer + * added support for DPP release 2 (Wi-Fi Device Provisioning Protocol) + * a number of MKA/MACsec fixes and extensions + * added support for SAE (WPA3-Personal) AP mode configuration + * added P2P support for EDMG (IEEE 802.11ay) channels + * fixed EAP-FAST peer with TLS GCM/CCM ciphers + * improved throughput estimation and BSS selection + * dropped support for libnl 1.1 + * added support for nl80211 control port for EAPOL frame TX/RX + * fixed OWE key derivation with groups 20 and 21; this breaks backwards + compatibility for these groups while the default group 19 remains + backwards compatible + * added support for Beacon protection + * added support for Extended Key ID for pairwise keys + * removed WEP support from the default build (CONFIG_WEP=y can be used + to enable it, if really needed) + * added a build option to remove TKIP support (CONFIG_NO_TKIP=y) + * added support for Transition Disable mechanism to allow the AP to + automatically disable transition mode to improve security + * extended D-Bus interface + * added support for PASN + * added a file-based backend for external password storage to allow + secret information to be moved away from the main configuration file + without requiring external tools + * added EAP-TLS peer support for TLS 1.3 (disabled by default for now) + * added support for SCS, MSCS, DSCP policy + * changed driver interface selection to default to automatic fallback + to other compiled in options + * a large number of other fixes, cleanup, and extensions + +2019-08-07 - v2.9 + * SAE changes + - disable use of groups using Brainpool curves + - improved protection against side channel attacks + [https://w1.fi/security/2019-6/] + * EAP-pwd changes + - disable use of groups using Brainpool curves + - allow the set of groups to be configured (eap_pwd_groups) + - improved protection against side channel attacks + [https://w1.fi/security/2019-6/] + * fixed FT-EAP initial mobility domain association using PMKSA caching + (disabled by default for backwards compatibility; can be enabled + with ft_eap_pmksa_caching=1) + * fixed a regression in OpenSSL 1.1+ engine loading + * added validation of RSNE in (Re)Association Response frames + * fixed DPP bootstrapping URI parser of channel list + * extended EAP-SIM/AKA fast re-authentication to allow use with FILS + * extended ca_cert_blob to support PEM format + * improved robustness of P2P Action frame scheduling + * added support for EAP-SIM/AKA using anonymous@realm identity + * fixed Hotspot 2.0 credential selection based on roaming consortium + to ignore credentials without a specific EAP method + * added experimental support for EAP-TEAP peer (RFC 7170) + * added experimental support for EAP-TLS peer with TLS v1.3 + * fixed a regression in WMM parameter configuration for a TDLS peer + * fixed a regression in operation with drivers that offload 802.1X + 4-way handshake + * fixed an ECDH operation corner case with OpenSSL + +2019-04-21 - v2.8 + * SAE changes + - added support for SAE Password Identifier + - changed default configuration to enable only groups 19, 20, 21 + (i.e., disable groups 25 and 26) and disable all unsuitable groups + completely based on REVmd changes + - do not regenerate PWE unnecessarily when the AP uses the + anti-clogging token mechanisms + - fixed some association cases where both SAE and FT-SAE were enabled + on both the station and the selected AP + - started to prefer FT-SAE over SAE AKM if both are enabled + - started to prefer FT-SAE over FT-PSK if both are enabled + - fixed FT-SAE when SAE PMKSA caching is used + - reject use of unsuitable groups based on new implementation guidance + in REVmd (allow only FFC groups with prime >= 3072 bits and ECC + groups with prime >= 256) + - minimize timing and memory use differences in PWE derivation + [https://w1.fi/security/2019-1/] (CVE-2019-9494) + * EAP-pwd changes + - minimize timing and memory use differences in PWE derivation + [https://w1.fi/security/2019-2/] (CVE-2019-9495) + - verify server scalar/element + [https://w1.fi/security/2019-4/] (CVE-2019-9499) + - fix message reassembly issue with unexpected fragment + [https://w1.fi/security/2019-5/] + - enforce rand,mask generation rules more strictly + - fix a memory leak in PWE derivation + - disallow ECC groups with a prime under 256 bits (groups 25, 26, and + 27) + * fixed CONFIG_IEEE80211R=y (FT) build without CONFIG_FILS=y + * Hotspot 2.0 changes + - do not indicate release number that is higher than the one + AP supports + - added support for release number 3 + - enable PMF automatically for network profiles created from + credentials + * fixed OWE network profile saving + * fixed DPP network profile saving + * added support for RSN operating channel validation + (CONFIG_OCV=y and network profile parameter ocv=1) + * added Multi-AP backhaul STA support + * fixed build with LibreSSL + * number of MKA/MACsec fixes and extensions + * extended domain_match and domain_suffix_match to allow list of values + * fixed dNSName matching in domain_match and domain_suffix_match when + using wolfSSL + * started to prefer FT-EAP-SHA384 over WPA-EAP-SUITE-B-192 AKM if both + are enabled + * extended nl80211 Connect and external authentication to support + SAE, FT-SAE, FT-EAP-SHA384 + * fixed KEK2 derivation for FILS+FT + * extended client_cert file to allow loading of a chain of PEM + encoded certificates + * extended beacon reporting functionality + * extended D-Bus interface with number of new properties + * fixed a regression in FT-over-DS with mac80211-based drivers + * OpenSSL: allow systemwide policies to be overridden + * extended driver flags indication for separate 802.1X and PSK + 4-way handshake offload capability + * added support for random P2P Device/Interface Address use + * extended PEAP to derive EMSK to enable use with ERP/FILS + * extended WPS to allow SAE configuration to be added automatically + for PSK (wps_cred_add_sae=1) + * removed support for the old D-Bus interface (CONFIG_CTRL_IFACE_DBUS) + * extended domain_match and domain_suffix_match to allow list of values + * added a RSN workaround for misbehaving PMF APs that advertise + IGTK/BIP KeyID using incorrect byte order + * fixed PTK rekeying with FILS and FT + +2018-12-02 - v2.7 + * fixed WPA packet number reuse with replayed messages and key + reinstallation + [https://w1.fi/security/2017-1/] (CVE-2017-13077, CVE-2017-13078, + CVE-2017-13079, CVE-2017-13080, CVE-2017-13081, CVE-2017-13082, + CVE-2017-13086, CVE-2017-13087, CVE-2017-13088) + * fixed unauthenticated EAPOL-Key decryption in wpa_supplicant + [https://w1.fi/security/2018-1/] (CVE-2018-14526) + * added support for FILS (IEEE 802.11ai) shared key authentication + * added support for OWE (Opportunistic Wireless Encryption, RFC 8110; + and transition mode defined by WFA) + * added support for DPP (Wi-Fi Device Provisioning Protocol) + * added support for RSA 3k key case with Suite B 192-bit level + * fixed Suite B PMKSA caching not to update PMKID during each 4-way + handshake + * fixed EAP-pwd pre-processing with PasswordHashHash + * added EAP-pwd client support for salted passwords + * fixed a regression in TDLS prohibited bit validation + * started to use estimated throughput to avoid undesired signal + strength based roaming decision + * MACsec/MKA: + - new macsec_linux driver interface support for the Linux + kernel macsec module + - number of fixes and extensions + * added support for external persistent storage of PMKSA cache + (PMKSA_GET/PMKSA_ADD control interface commands; and + MESH_PMKSA_GET/MESH_PMKSA_SET for the mesh case) + * fixed mesh channel configuration pri/sec switch case + * added support for beacon report + * large number of other fixes, cleanup, and extensions + * added support for randomizing local address for GAS queries + (gas_rand_mac_addr parameter) + * fixed EAP-SIM/AKA/AKA' ext auth cases within TLS tunnel + * added option for using random WPS UUID (auto_uuid=1) + * added SHA256-hash support for OCSP certificate matching + * fixed EAP-AKA' to add AT_KDF into Synchronization-Failure + * fixed a regression in RSN pre-authentication candidate selection + * added option to configure allowed group management cipher suites + (group_mgmt network profile parameter) + * removed all PeerKey functionality + * fixed nl80211 AP and mesh mode configuration regression with + Linux 4.15 and newer + * added ap_isolate configuration option for AP mode + * added support for nl80211 to offload 4-way handshake into the driver + * added support for using wolfSSL cryptographic library + * SAE + - added support for configuring SAE password separately of the + WPA2 PSK/passphrase + - fixed PTK and EAPOL-Key integrity and key-wrap algorithm selection + for SAE; + note: this is not backwards compatible, i.e., both the AP and + station side implementations will need to be update at the same + time to maintain interoperability + - added support for Password Identifier + - fixed FT-SAE PMKID matching + * Hotspot 2.0 + - added support for fetching of Operator Icon Metadata ANQP-element + - added support for Roaming Consortium Selection element + - added support for Terms and Conditions + - added support for OSEN connection in a shared RSN BSS + - added support for fetching Venue URL information + * added support for using OpenSSL 1.1.1 + * FT + - disabled PMKSA caching with FT since it is not fully functional + - added support for SHA384 based AKM + - added support for BIP ciphers BIP-CMAC-256, BIP-GMAC-128, + BIP-GMAC-256 in addition to previously supported BIP-CMAC-128 + - fixed additional IE inclusion in Reassociation Request frame when + using FT protocol + +2016-10-02 - v2.6 + * fixed WNM Sleep Mode processing when PMF is not enabled + [http://w1.fi/security/2015-6/] (CVE-2015-5310) + * fixed EAP-pwd last fragment validation + [http://w1.fi/security/2015-7/] (CVE-2015-5315) + * fixed EAP-pwd unexpected Confirm message processing + [http://w1.fi/security/2015-8/] (CVE-2015-5316) + * fixed WPS configuration update vulnerability with malformed passphrase + [http://w1.fi/security/2016-1/] (CVE-2016-4476) + * fixed configuration update vulnerability with malformed parameters set + over the local control interface + [http://w1.fi/security/2016-1/] (CVE-2016-4477) + * fixed TK configuration to the driver in EAPOL-Key 3/4 retry case + * extended channel switch support for P2P GO + * started to throttle control interface event message bursts to avoid + issues with monitor sockets running out of buffer space + * mesh mode fixes/improvements + - generate proper AID for peer + - enable WMM by default + - add VHT support + - fix PMKID derivation + - improve robustness on various exchanges + - fix peer link counting in reconnect case + - improve mesh joining behavior + - allow DTIM period to be configured + - allow HT to be disabled (disable_ht=1) + - add MESH_PEER_ADD and MESH_PEER_REMOVE commands + - add support for PMKSA caching + - add minimal support for SAE group negotiation + - allow pairwise/group cipher to be configured in the network profile + - use ieee80211w profile parameter to enable/disable PMF and derive + a separate TX IGTK if PMF is enabled instead of using MGTK + incorrectly + - fix AEK and MTK derivation + - remove GTKdata and IGTKdata from Mesh Peering Confirm/Close + - note: these changes are not fully backwards compatible for secure + (RSN) mesh network + * fixed PMKID derivation with SAE + * added support for requesting and fetching arbitrary ANQP-elements + without internal support in wpa_supplicant for the specific element + (anqp[265]=<hexdump> in "BSS <BSSID>" command output) + * P2P + - filter control characters in group client device names to be + consistent with other P2P peer cases + - support VHT 80+80 MHz and 160 MHz + - indicate group completion in P2P Client role after data association + instead of already after the WPS provisioning step + - improve group-join operation to use SSID, if known, to filter BSS + entries + - added optional ssid=<hexdump> argument to P2P_CONNECT for join case + - added P2P_GROUP_MEMBER command to fetch client interface address + * P2PS + - fix follow-on PD Response behavior + - fix PD Response generation for unknown peer + - fix persistent group reporting + - add channel policy to PD Request + - add group SSID to the P2PS-PROV-DONE event + - allow "P2P_CONNECT <addr> p2ps" to be used without specifying the + default PIN + * BoringSSL + - support for OCSP stapling + - support building of h20-osu-client + * D-Bus + - add ExpectDisconnect() + - add global config parameters as properties + - add SaveConfig() + - add VendorElemAdd(), VendorElemGet(), VendorElemRem() + * fixed Suite B 192-bit AKM to use proper PMK length + (note: this makes old releases incompatible with the fixed behavior) + * improved PMF behavior for cases where the AP and STA has different + configuration by not trying to connect in some corner cases where the + connection cannot succeed + * added option to reopen debug log (e.g., to rotate the file) upon + receipt of SIGHUP signal + * EAP-pwd: added support for Brainpool Elliptic Curves + (with OpenSSL 1.0.2 and newer) + * fixed EAPOL reauthentication after FT protocol run + * fixed FTIE generation for 4-way handshake after FT protocol run + * extended INTERFACE_ADD command to allow certain type (sta/ap) + interface to be created + * fixed and improved various FST operations + * added 80+80 MHz and 160 MHz VHT support for IBSS/mesh + * fixed SIGNAL_POLL in IBSS and mesh cases + * added an option to abort an ongoing scan (used to speed up connection + and can also be done with the new ABORT_SCAN command) + * TLS client + - do not verify CA certificates when ca_cert is not specified + - support validating server certificate hash + - support SHA384 and SHA512 hashes + - add signature_algorithms extension into ClientHello + - support TLS v1.2 signature algorithm with SHA384 and SHA512 + - support server certificate probing + - allow specific TLS versions to be disabled with phase2 parameter + - support extKeyUsage + - support PKCS #5 v2.0 PBES2 + - support PKCS #5 with PKCS #12 style key decryption + - minimal support for PKCS #12 + - support OCSP stapling (including ocsp_multi) + * OpenSSL + - support OpenSSL 1.1 API changes + - drop support for OpenSSL 0.9.8 + - drop support for OpenSSL 1.0.0 + * added support for multiple schedule scan plans (sched_scan_plans) + * added support for external server certificate chain validation + (tls_ext_cert_check=1 in the network profile phase1 parameter) + * made phase2 parser more strict about correct use of auth=<val> and + autheap=<val> values + * improved GAS offchannel operations with comeback request + * added SIGNAL_MONITOR command to request signal strength monitoring + events + * added command for retrieving HS 2.0 icons with in-memory storage + (REQ_HS20_ICON, GET_HS20_ICON, DEL_HS20_ICON commands and + RX-HS20-ICON event) + * enabled ACS support for AP mode operations with wpa_supplicant + * EAP-PEAP: fixed interoperability issue with Windows 2012r2 server + ("Invalid Compound_MAC in cryptobinding TLV") + * EAP-TTLS: fixed success after fragmented final Phase 2 message + * VHT: added interoperability workaround for 80+80 and 160 MHz channels + * WNM: workaround for broken AP operating class behavior + * added kqueue(2) support for eloop (CONFIG_ELOOP_KQUEUE) + * nl80211: + - add support for full station state operations + - do not add NL80211_ATTR_SMPS_MODE attribute if HT is disabled + - add NL80211_ATTR_PREV_BSSID with Connect command + - fix IEEE 802.1X/WEP EAP reauthentication and rekeying to use + unencrypted EAPOL frames + * added initial MBO support; number of extensions to WNM BSS Transition + Management + * added support for PBSS/PCP and P2P on 60 GHz + * Interworking: add credential realm to EAP-TLS identity + * fixed EAPOL-Key Request Secure bit to be 1 if PTK is set + * HS 2.0: add support for configuring frame filters + * added POLL_STA command to check connectivity in AP mode + * added initial functionality for location related operations + * started to ignore pmf=1/2 parameter for non-RSN networks + * added wps_disabled=1 network profile parameter to allow AP mode to + be started without enabling WPS + * wpa_cli: added action script support for AP-ENABLED and AP-DISABLED + events + * improved Public Action frame addressing + - add gas_address3 configuration parameter to control Address 3 + behavior + * number of small fixes + +2015-09-27 - v2.5 + * fixed P2P validation of SSID element length before copying it + [http://w1.fi/security/2015-1/] (CVE-2015-1863) + * fixed WPS UPnP vulnerability with HTTP chunked transfer encoding + [http://w1.fi/security/2015-2/] (CVE-2015-4141) + * fixed WMM Action frame parser (AP mode) + [http://w1.fi/security/2015-3/] (CVE-2015-4142) + * fixed EAP-pwd peer missing payload length validation + [http://w1.fi/security/2015-4/] + (CVE-2015-4143, CVE-2015-4144, CVE-2015-4145, CVE-2015-4146) + * fixed validation of WPS and P2P NFC NDEF record payload length + [http://w1.fi/security/2015-5/] + * nl80211: + - added VHT configuration for IBSS + - fixed vendor command handling to check OUI properly + - allow driver-based roaming to change ESS + * added AVG_BEACON_RSSI to SIGNAL_POLL output + * wpa_cli: added tab completion for number of commands + * removed unmaintained and not yet completed SChannel/CryptoAPI support + * modified Extended Capabilities element use in Probe Request frames to + include all cases if any of the values are non-zero + * added support for dynamically creating/removing a virtual interface + with interface_add/interface_remove + * added support for hashed password (NtHash) in EAP-pwd peer + * added support for memory-only PSK/passphrase (mem_only_psk=1 and + CTRL-REQ/RSP-PSK_PASSPHRASE) + * P2P + - optimize scan frequencies list when re-joining a persistent group + - fixed number of sequences with nl80211 P2P Device interface + - added operating class 125 for P2P use cases (this allows 5 GHz + channels 161 and 169 to be used if they are enabled in the current + regulatory domain) + - number of fixes to P2PS functionality + - do not allow 40 MHz co-ex PRI/SEC switch to force MCC + - extended support for preferred channel listing + * D-Bus: + - fixed WPS property of fi.w1.wpa_supplicant1.BSS interface + - fixed PresenceRequest to use group interface + - added new signals: FindStopped, WPS pbc-overlap, + GroupFormationFailure, WPS timeout, InvitationReceived + - added new methods: WPS Cancel, P2P Cancel, Reconnect, RemoveClient + - added manufacturer info + * added EAP-EKE peer support for deriving Session-Id + * added wps_priority configuration parameter to set the default priority + for all network profiles added by WPS + * added support to request a scan with specific SSIDs with the SCAN + command (optional "ssid <hexdump>" arguments) + * removed support for WEP40/WEP104 as a group cipher with WPA/WPA2 + * fixed SAE group selection in an error case + * modified SAE routines to be more robust and PWE generation to be + stronger against timing attacks + * added support for Brainpool Elliptic Curves with SAE + * added support for CCMP-256 and GCMP-256 as group ciphers with FT + * fixed BSS selection based on estimated throughput + * added option to disable TLSv1.0 with OpenSSL + (phase1="tls_disable_tlsv1_0=1") + * added Fast Session Transfer (FST) module + * fixed OpenSSL PKCS#12 extra certificate handling + * fixed key derivation for Suite B 192-bit AKM (this breaks + compatibility with the earlier version) + * added RSN IE to Mesh Peering Open/Confirm frames + * number of small fixes + +2015-03-15 - v2.4 + * allow OpenSSL cipher configuration to be set for internal EAP server + (openssl_ciphers parameter) + * fixed number of small issues based on hwsim test case failures and + static analyzer reports + * P2P: + - add new=<0/1> flag to P2P-DEVICE-FOUND events + - add passive channels in invitation response from P2P Client + - enable nl80211 P2P_DEVICE support by default + - fix regresssion in disallow_freq preventing search on social + channels + - fix regressions in P2P SD query processing + - try to re-invite with social operating channel if no common channels + in invitation + - allow cross connection on parent interface (this fixes number of + use cases with nl80211) + - add support for P2P services (P2PS) + - add p2p_go_ctwindow configuration parameter to allow GO CTWindow to + be configured + * increase postponing of EAPOL-Start by one second with AP/GO that + supports WPS 2.0 (this makes it less likely to trigger extra roundtrip + of identity frames) + * add support for PMKSA caching with SAE + * add support for control mesh BSS (IEEE 802.11s) operations + * fixed number of issues with D-Bus P2P commands + * fixed regression in ap_scan=2 special case for WPS + * fixed macsec_validate configuration + * add a workaround for incorrectly behaving APs that try to use + EAPOL-Key descriptor version 3 when the station supports PMF even if + PMF is not enabled on the AP + * allow TLS v1.1 and v1.2 to be negotiated by default; previous behavior + of disabling these can be configured to work around issues with broken + servers with phase1="tls_disable_tlsv1_1=1 tls_disable_tlsv1_2=1" + * add support for Suite B (128-bit and 192-bit level) key management and + cipher suites + * add WMM-AC support (WMM_AC_ADDTS/WMM_AC_DELTS) + * improved BSS Transition Management processing + * add support for neighbor report + * add support for link measurement + * fixed expiration of BSS entry with all-zeros BSSID + * add optional LAST_ID=x argument to LIST_NETWORK to allow all + configured networks to be listed even with huge number of network + profiles + * add support for EAP Re-Authentication Protocol (ERP) + * fixed EAP-IKEv2 fragmentation reassembly + * improved PKCS#11 configuration for OpenSSL + * set stdout to be line-buffered + * add TDLS channel switch configuration + * add support for MAC address randomization in scans with nl80211 + * enable HT for IBSS if supported by the driver + * add BSSID black and white lists (bssid_blacklist, bssid_whitelist) + * add support for domain_suffix_match with GnuTLS + * add OCSP stapling client support with GnuTLS + * include peer certificate in EAP events even without a separate probe + operation; old behavior can be restored with cert_in_cb=0 + * add peer ceritficate alt subject name to EAP events + (CTRL-EVENT-EAP-PEER-ALT) + * add domain_match network profile parameter (similar to + domain_suffix_match, but full match is required) + * enable AP/GO mode HT Tx STBC automatically based on driver support + * add ANQP-QUERY-DONE event to provide information on ANQP parsing + status + * allow passive scanning to be forced with passive_scan=1 + * add a workaround for Linux packet socket behavior when interface is in + bridge + * increase 5 GHz band preference in BSS selection (estimate SNR, if info + not available from driver; estimate maximum throughput based on common + HT/VHT/specific TX rate support) + * add INTERWORKING_ADD_NETWORK ctrl_iface command; this can be used to + implement Interworking network selection behavior in upper layers + software components + * add optional reassoc_same_bss_optim=1 (disabled by default) + optimization to avoid unnecessary Authentication frame exchange + * extend TDLS frame padding workaround to cover all packets + * allow wpa_supplicant to recover nl80211 functionality if the cfg80211 + module gets removed and reloaded without restarting wpa_supplicant + * allow hostapd DFS implementation to be used in wpa_supplicant AP mode + +2014-10-09 - v2.3 + * fixed number of minor issues identified in static analyzer warnings + * fixed wfd_dev_info to be more careful and not read beyond the buffer + when parsing invalid information for P2P-DEVICE-FOUND + * extended P2P and GAS query operations to support drivers that have + maximum remain-on-channel time below 1000 ms (500 ms is the current + minimum supported value) + * added p2p_search_delay parameter to make the default p2p_find delay + configurable + * improved P2P operating channel selection for various multi-channel + concurrency cases + * fixed some TDLS failure cases to clean up driver state + * fixed dynamic interface addition cases with nl80211 to avoid adding + ifindex values to incorrect interface to skip foreign interface events + properly + * added TDLS workaround for some APs that may add extra data to the + end of a short frame + * fixed EAP-AKA' message parser with multiple AT_KDF attributes + * added configuration option (p2p_passphrase_len) to allow longer + passphrases to be generated for P2P groups + * fixed IBSS channel configuration in some corner cases + * improved HT/VHT/QoS parameter setup for TDLS + * modified D-Bus interface for P2P peers/groups + * started to use constant time comparison for various password and hash + values to reduce possibility of any externally measurable timing + differences + * extended explicit clearing of freed memory and expired keys to avoid + keeping private data in memory longer than necessary + * added optional scan_id parameter to the SCAN command to allow manual + scan requests for active scans for specific configured SSIDs + * fixed CTRL-EVENT-REGDOM-CHANGE event init parameter value + * added option to set Hotspot 2.0 Rel 2 update_identifier in network + configuration to support external configuration + * modified Android PNO functionality to send Probe Request frames only + for hidden SSIDs (based on scan_ssid=1) + * added generic mechanism for adding vendor elements into frames at + runtime (VENDOR_ELEM_ADD, VENDOR_ELEM_GET, VENDOR_ELEM_REMOVE) + * added fields to show unrecognized vendor elements in P2P_PEER + * removed EAP-TTLS/MSCHAPv2 interoperability workaround so that + MS-CHAP2-Success is required to be present regardless of + eap_workaround configuration + * modified EAP fast session resumption to allow results to be used only + with the same network block that generated them + * extended freq_list configuration to apply for sched_scan as well as + normal scan + * modified WPS to merge mixed-WPA/WPA2 credentials from a single session + * fixed nl80211/RTM_DELLINK processing when a P2P GO interface is + removed from a bridge + * fixed number of small P2P issues to make negotiations more robust in + corner cases + * added experimental support for using temporary, random local MAC + address (mac_addr and preassoc_mac_addr parameters); this is disabled + by default (i.e., previous behavior of using permanent address is + maintained if configuration is not changed) + * added D-Bus interface for setting/clearing WFD IEs + * fixed TDLS AID configuration for VHT + * modified -m<conf> configuration file to be used only for the P2P + non-netdev management device and do not load this for the default + station interface or load the station interface configuration for + the P2P management interface + * fixed external MAC address changes while wpa_supplicant is running + * started to enable HT (if supported by the driver) for IBSS + * fixed wpa_cli action script execution to use more robust mechanism + (CVE-2014-3686) + +2014-06-04 - v2.2 + * added DFS indicator to get_capability freq + * added/fixed nl80211 functionality + - BSSID/frequency hint for driver-based BSS selection + - fix tearing down WDS STA interfaces + - support vendor specific driver command + (VENDOR <vendor id> <sub command id> [<hex formatted data>]) + - GO interface teardown optimization + - allow beacon interval to be configured for IBSS + - add SHA256-based AKM suites to CONNECT/ASSOCIATE commands + * removed unused NFC_RX_HANDOVER_REQ and NFC_RX_HANDOVER_SEL control + interface commands (the more generic NFC_REPORT_HANDOVER is now used) + * fixed MSCHAP UTF-8 to UCS-2 conversion for three-byte encoding; + this fixes password with include UTF-8 characters that use + three-byte encoding EAP methods that use NtPasswordHash + * fixed couple of sequences where radio work items could get stuck, + e.g., when rfkill blocking happens during scanning or when + scan-for-auth workaround is used + * P2P enhancements/fixes + - enable enable U-APSD on GO automatically if the driver indicates + support for this + - fixed some service discovery cases with broadcast queries not being + sent to all stations + - fixed Probe Request frame triggering invitation to trigger only a + single invitation instance even if multiple Probe Request frames are + received + - fixed a potential NULL pointer dereference crash when processing an + invalid Invitation Request frame + - add optional configuration file for the P2P_DEVICE parameters + - optimize scan for GO during persistent group invocation + - fix possible segmentation fault when PBC overlap is detected while + using a separate P2P group interface + - improve GO Negotiation robustness by allowing GO Negotiation + Confirmation to be retransmitted + - do use freed memory on device found event when P2P NFC + * added phase1 network parameter options for disabling TLS v1.1 and v1.2 + to allow workarounds with misbehaving AAA servers + (tls_disable_tlsv1_1=1 and tls_disable_tlsv1_2=1) + * added support for OCSP stapling to validate AAA server certificate + during TLS exchange + * Interworking/Hotspot 2.0 enhancements + - prefer the last added network in Interworking connection to make the + behavior more consistent with likely user expectation + - roaming partner configuration (roaming_partner within a cred block) + - support Hotspot 2.0 Release 2 + * "hs20_anqp_get <BSSID> 8" to request OSU Providers list + * "hs20_icon_request <BSSID> <icon filename>" to request icon files + * "fetch_osu" and "cancel_osu_fetch" to start/stop full OSU provider + search (all suitable APs in scan results) + * OSEN network for online signup connection + * min_{dl,ul}_bandwidth_{home,roaming} cred parameters + * max_bss_load cred parameter + * req_conn_capab cred parameter + * sp_priority cred parameter + * ocsp cred parameter + * slow down automatic connection attempts on EAP failure to meet + required behavior (no more than 10 retries within a 10-minute + interval) + * sample implementation of online signup client (both SPP and + OMA-DM protocols) (hs20/client/*) + - fixed GAS indication for additional comeback delay with status + code 95 + - extend ANQP_GET to accept Hotspot 2.0 subtypes + ANQP_GET <addr> <info id>[,<info id>]... + [,hs20:<subtype>][...,hs20:<subtype>] + - add control interface events CRED-ADDED <id>, + CRED-MODIFIED <id> <field>, CRED-REMOVED <id> + - add "GET_CRED <id> <field>" command + - enable FT for the connection automatically if the AP advertises + support for this + - fix a case where auto_interworking=1 could end up stopping scanning + * fixed TDLS interoperability issues with supported operating class in + some deployed stations + * internal TLS implementation enhancements/fixes + - add SHA256-based cipher suites + - add DHE-RSA cipher suites + - fix X.509 validation of PKCS#1 signature to check for extra data + * fixed PTK derivation for CCMP-256 and GCMP-256 + * added "reattach" command for fast reassociate-back-to-same-BSS + * allow PMF to be enabled for AP mode operation with the ieee80211w + parameter + * added "get_capability tdls" command + * added option to set config blobs through control interface with + "SET blob <name> <hexdump>" + * D-Bus interface extensions/fixes + - make p2p_no_group_iface configurable + - declare ServiceDiscoveryRequest method properly + - export peer's device address as a property + - make reassociate command behave like the control interface one, + i.e., to allow connection from disconnected state + * added optional "freq=<channel ranges>" parameter to SET pno + * added optional "freq=<channel ranges>" parameter to SELECT_NETWORK + * fixed OBSS scan result processing for 20/40 MHz co-ex report + * remove WPS 1.0 only support, i.e., WSC 2.0 support is now enabled + whenever CONFIG_WPS=y is set + * fixed regression in parsing of WNM Sleep Mode exit key data + * fixed potential segmentation fault and memory leaks in WNM neighbor + report processing + * EAP-pwd fixes + - fragmentation of PWD-Confirm-Resp + - fix memory leak when fragmentation is used + - fix possible segmentation fault on EAP method deinit if an invalid + group is negotiated + * added MACsec/IEEE Std 802.1X-2010 PAE implementation (currently + available only with the macsec_qca driver wrapper) + * fixed EAP-SIM counter-too-small message + * added 'dup_network <id_s> <id_d> <name>' command; this can be used to + clone the psk field without having toextract it from wpa_supplicant + * fixed GSM authentication on USIM + * added support for using epoll in eloop (CONFIG_ELOOP_EPOLL=y) + * fixed some concurrent virtual interface cases with dedicated P2P + management interface to not catch events from removed interface (this + could result in the management interface getting disabled) + * fixed a memory leak in SAE random number generation + * fixed off-by-one bounds checking in printf_encode() + - this could result in some control interface ATTACH command cases + terminating wpa_supplicant + * fixed EAPOL-Key exchange when GCMP is used with SHA256-based AKM + * various bug fixes + +2014-02-04 - v2.1 + * added support for simultaneous authentication of equals (SAE) for + stronger password-based authentication with WPA2-Personal + * improved P2P negotiation and group formation robustness + - avoid unnecessary Dialog Token value changes during retries + - avoid more concurrent scanning cases during full group formation + sequence + - do not use potentially obsolete scan result data from driver + cache for peer discovery/updates + - avoid undesired re-starting of GO negotiation based on Probe + Request frames + - increase GO Negotiation and Invitation timeouts to address busy + environments and peers that take long time to react to messages, + e.g., due to power saving + - P2P Device interface type + * improved P2P channel selection (use more peer information and allow + more local options) + * added support for optional per-device PSK assignment by P2P GO + (wpa_cli p2p_set per_sta_psk <0/1>) + * added P2P_REMOVE_CLIENT for removing a client from P2P groups + (including persistent groups); this can be used to securely remove + a client from a group if per-device PSKs are used + * added more configuration flexibility for allowed P2P GO/client + channels (p2p_no_go_freq list and p2p_add_cli_chan=0/1) + * added nl80211 functionality + - VHT configuration for nl80211 + - MFP (IEEE 802.11w) information for nl80211 command API + - support split wiphy dump + - FT (IEEE 802.11r) with driver-based SME + - use advertised number of supported concurrent channels + - QoS Mapping configuration + * improved TDLS negotiation robustness + * added more TDLS peer parameters to be configured to the driver + * optimized connection time by allowing recently received scan results + to be used instead of having to run through a new scan + * fixed ctrl_iface BSS command iteration with RANGE argument and no + exact matches; also fixed argument parsing for some cases with + multiple arguments + * added 'SCAN TYPE=ONLY' ctrl_iface command to request manual scan + without executing roaming/network re-selection on scan results + * added Session-Id derivation for EAP peer methods + * added fully automated regression testing with mac80211_hwsim + * changed configuration parser to reject invalid integer values + * allow AP/Enrollee to be specified with BSSID instead of UUID for + WPS ER operations + * disable network block temporarily on repeated connection failures + * changed the default driver interface from wext to nl80211 if both are + included in the build + * remove duplicate networks if WPS provisioning is run multiple times + * remove duplicate networks when Interworking network selection uses the + same network + * added global freq_list configuration to allow scan frequencies to be + limited for all cases instead of just for a specific network block + * added support for BSS Transition Management + * added option to use "IFNAME=<ifname> " prefix to use the global + control interface connection to perform per-interface commands; + similarly, allow global control interface to be used as a monitor + interface to receive events from all interfaces + * fixed OKC-based PMKSA cache entry clearing + * fixed TKIP group key configuration with FT + * added support for using OCSP stapling to validate server certificate + (ocsp=1 as optional and ocsp=2 as mandatory) + * added EAP-EKE peer + * added peer restart detection for IBSS RSN + * added domain_suffix_match (and domain_suffix_match2 for Phase 2 + EAP-TLS) to specify additional constraint for the server certificate + domain name + * added support for external SIM/USIM processing in EAP-SIM, EAP-AKA, + and EAP-AKA' (CTRL-REQ-SIM and CTRL-RSP-SIM commands over control + interface) + * added global bgscan configuration option as a default for all network + blocks that do not specify their own bgscan parameters + * added D-Bus methods for TDLS + * added more control to scan requests + - "SCAN freq=<freq list>" can be used to specify which channels are + scanned (comma-separated frequency ranges in MHz) + - "SCAN passive=1" can be used to request a passive scan (no Probe + Request frames are sent) + - "SCAN use_id" can be used to request a scan id to be returned and + included in event messages related to this specific scan operation + - "SCAN only_new=1" can be used to request the driver/cfg80211 to + report only BSS entries that have been updated during this scan + round + - these optional arguments to the SCAN command can be combined with + each other + * modified behavior on externally triggered scans + - avoid concurrent operations requiring full control of the radio when + an externally triggered scan is detected + - do not use results for internal roaming decision + * added a new cred block parameter 'temporary' to allow credential + blocks to be stored separately even if wpa_supplicant configuration + file is used to maintain other network information + * added "radio work" framework to schedule exclusive radio operations + for off-channel functionality + - reduce issues with concurrent operations that try to control which + channel is used + - allow external programs to request exclusive radio control in a way + that avoids conflicts with wpa_supplicant + * added support for using Protected Dual of Public Action frames for + GAS/ANQP exchanges when associated with PMF + * added support for WPS+NFC updates and P2P+NFC + - improved protocol for WPS + - P2P group formation/join based on NFC connection handover + - new IPv4 address assignment for P2P groups (ip_addr_* configuration + parameters on the GO) to replace DHCP + - option to fetch and report alternative carrier records for external + NFC operations + * various bug fixes + +2013-01-12 - v2.0 + * removed Qt3-based wpa_gui (obsoleted by wpa_qui-qt4) + * removed unmaintained driver wrappers broadcom, iphone, osx, ralink, + hostap, madwifi (hostap and madwifi remain available for hostapd; + their wpa_supplicant functionality is obsoleted by wext) + * improved debug logging (human readable event names, interface name + included in more entries) + * changed AP mode behavior to enable WPS only for open and + WPA/WPA2-Personal configuration + * improved P2P concurrency operations + - better coordination of concurrent scan and P2P search operations + - avoid concurrent remain-on-channel operation requests by canceling + previous operations prior to starting a new one + - reject operations that would require multi-channel concurrency if + the driver does not support it + - add parameter to select whether STA or P2P connection is preferred + if the driver cannot support both at the same time + - allow driver to indicate channel changes + - added optional delay=<search delay in milliseconds> parameter for + p2p_find to avoid taking all radio resources + - use 500 ms p2p_find search delay by default during concurrent + operations + - allow all channels in GO Negotiation if the driver supports + multi-channel concurrency + * added number of small changes to make it easier for static analyzers + to understand the implementation + * fixed number of small bugs (see git logs for more details) + * nl80211: number of updates to use new cfg80211/nl80211 functionality + - replace monitor interface with nl80211 commands for AP mode + - additional information for driver-based AP SME + - STA entry authorization in RSN IBSS + * EAP-pwd: + - fixed KDF for group 21 and zero-padding + - added support for fragmentation + - increased maximum number of hunting-and-pecking iterations + * avoid excessive Probe Response retries for broadcast Probe Request + frames (only with drivers using wpa_supplicant AP mode SME/MLME) + * added "GET country" ctrl_iface command + * do not save an invalid network block in wpa_supplicant.conf to avoid + problems reading the file on next start + * send STA connected/disconnected ctrl_iface events to both the P2P + group and parent interfaces + * added preliminary support for using TLS v1.2 (CONFIG_TLSV12=y) + * added "SET pno <1/0>" ctrl_iface command to start/stop preferred + network offload with sched_scan driver command + * merged in number of changes from Android repository for P2P, nl80211, + and build parameters + * changed P2P GO mode configuration to use driver capabilities to + automatically enable HT operations when supported + * added "wpa_cli status wps" command to fetch WPA2-Personal passhrase + for WPS use cases in AP mode + * EAP-AKA: keep pseudonym identity across EAP exchanges to match EAP-SIM + behavior + * improved reassociation behavior in cases where association is rejected + or when an AP disconnects us to handle common load balancing + mechanisms + - try to avoid extra scans when the needed information is available + * added optional "join" argument for p2p_prov_disc ctrl_iface command + * added group ifname to P2P-PROV-DISC-* events + * added P2P Device Address to AP-STA-DISCONNECTED event and use + p2p_dev_addr parameter name with AP-STA-CONNECTED + * added workarounds for WPS PBC overlap detection for some P2P use cases + where deployed stations work incorrectly + * optimize WPS connection speed by disconnecting prior to WPS scan and + by using single channel scans when AP channel is known + * PCSC and SIM/USIM improvements: + - accept 0x67 (Wrong length) as a response to READ RECORD to fix + issues with some USIM cards + - try to read MNC length from SIM/USIM + - build realm according to 3GPP TS 23.003 with identity from the SIM + - allow T1 protocol to be enabled + * added more WPS and P2P information available through D-Bus + * improve P2P negotiation robustness + - extra waits to get ACK frames through + - longer timeouts for cases where deployed devices have been + identified have issues meeting the specification requirements + - more retries for some P2P frames + - handle race conditions in GO Negotiation start by both devices + - ignore unexpected GO Negotiation Response frame + * added support for libnl 3.2 and newer + * added P2P persistent group info to P2P_PEER data + * maintain a list of P2P Clients for persistent group on GO + * AP: increased initial group key handshake retransmit timeout to 500 ms + * added optional dev_id parameter for p2p_find + * added P2P-FIND-STOPPED ctrl_iface event + * fixed issues in WPA/RSN element validation when roaming with ap_scan=1 + and driver-based BSS selection + * do not expire P2P peer entries while connected with the peer in a + group + * fixed WSC element inclusion in cases where P2P is disabled + * AP: added a WPS workaround for mixed mode AP Settings with Windows 7 + * EAP-SIM: fixed AT_COUNTER_TOO_SMALL use + * EAP-SIM/AKA: append realm to pseudonym identity + * EAP-SIM/AKA: store pseudonym identity in network configuration to + allow it to persist over multiple EAP sessions and wpa_supplicant + restarts + * EAP-AKA': updated to RFC 5448 (username prefixes changed); note: this + breaks interoperability with older versions + * added support for WFA Hotspot 2.0 + - GAS/ANQP to fetch network information + - credential configuration and automatic network selections based on + credential match with ANQP information + * limited PMKSA cache entries to be used only with the network context + that was used to create them + * improved PMKSA cache expiration to avoid unnecessary disconnections + * adjusted bgscan_simple fast-scan backoff to avoid too frequent + background scans + * removed ctrl_iface event on P2P PD Response in join-group case + * added option to fetch BSS table entry based on P2P Device Address + ("BSS p2p_dev_addr=<P2P Device Address>") + * added BSS entry age to ctrl_iface BSS command output + * added optional MASK=0xH option for ctrl_iface BSS command to select + which fields are included in the response + * added optional RANGE=ALL|N1-N2 option for ctrl_iface BSS command to + fetch information about several BSSes in one call + * simplified licensing terms by selecting the BSD license as the only + alternative + * added "P2P_SET disallow_freq <freq list>" ctrl_iface command to + disable channels from P2P use + * added p2p_pref_chan configuration parameter to allow preferred P2P + channels to be specified + * added support for advertising immediate availability of a WPS + credential for P2P use cases + * optimized scan operations for P2P use cases (use single channel scan + for a specific SSID when possible) + * EAP-TTLS: fixed peer challenge generation for MSCHAPv2 + * SME: do not use reassociation after explicit disconnection request + (local or a notification from an AP) + * added support for sending debug info to Linux tracing (-T on command + line) + * added support for using Deauthentication reason code 3 as an + indication of P2P group termination + * added wps_vendor_ext_m1 configuration parameter to allow vendor + specific attributes to be added to WPS M1 + * started using separate TLS library context for tunneled TLS + (EAP-PEAP/TLS, EAP-TTLS/TLS, EAP-FAST/TLS) to support different CA + certificate configuration between Phase 1 and Phase 2 + * added optional "auto" parameter for p2p_connect to request automatic + GO Negotiation vs. join-a-group selection + * added disabled_scan_offload parameter to disable automatic scan + offloading (sched_scan) + * added optional persistent=<network id> parameter for p2p_connect to + allow forcing of a specific SSID/passphrase for GO Negotiation + * added support for OBSS scan requests and 20/40 BSS coexistence reports + * reject PD Request for unknown group + * removed scripts and notes related to Windows binary releases (which + have not been used starting from 1.x) + * added initial support for WNM operations + - Keep-alive based on BSS max idle period + - WNM-Sleep Mode + - minimal BSS Transition Management processing + * added autoscan module to control scanning behavior while not connected + - autoscan_periodic and autoscan_exponential modules + * added new WPS NFC ctrl_iface mechanism + - added initial support NFC connection handover + - removed obsoleted WPS_OOB command (including support for deprecated + UFD config_method) + * added optional framework for external password storage ("ext:<name>") + * wpa_cli: added optional support for controlling wpa_supplicant + remotely over UDP (CONFIG_CTRL_IFACE=udp-remote) for testing purposes + * wpa_cli: extended tab completion to more commands + * changed SSID output to use printf-escaped strings instead of masking + of non-ASCII characters + - SSID can now be configured in the same format: ssid=P"abc\x00test" + * removed default ACM=1 from AC_VO and AC_VI + * added optional "ht40" argument for P2P ctrl_iface commands to allow + 40 MHz channels to be requested on the 5 GHz band + * added optional parameters for p2p_invite command to specify channel + when reinvoking a persistent group as the GO + * improved FIPS mode builds with OpenSSL + - "make fips" with CONFIG_FIPS=y to build wpa_supplicant with the + OpenSSL FIPS object module + - replace low level OpenSSL AES API calls to use EVP + - use OpenSSL keying material exporter when possible + - do not export TLS keys in FIPS mode + - remove MD5 from CONFIG_FIPS=y builds + - use OpenSSL function for PKBDF2 passphrase-to-PSK + - use OpenSSL HMAC implementation + - mix RAND_bytes() output into random_get_bytes() to force OpenSSL + DRBG to be used in FIPS mode + - use OpenSSL CMAC implementation + * added mechanism to disable TLS Session Ticket extension + - a workaround for servers that do not support TLS extensions that + was enabled by default in recent OpenSSL versions + - tls_disable_session_ticket=1 + - automatically disable TLS Session Ticket extension by default when + using EAP-TLS/PEAP/TTLS (i.e., only use it with EAP-FAST) + * changed VENDOR-TEST EAP method to use proper private enterprise number + (this will not interoperate with older versions) + * disable network block temporarily on authentication failures + * improved WPS AP selection during WPS PIN iteration + * added support for configuring GCMP cipher for IEEE 802.11ad + * added support for Wi-Fi Display extensions + - WFD_SUBELEMENT_SET ctrl_iface command to configure WFD subelements + - SET wifi_display <0/1> to disable/enable WFD support + - WFD service discovery + - an external program is needed to manage the audio/video streaming + and codecs + * optimized scan result use for network selection + - use the internal BSS table instead of raw scan results + - allow unnecessary scans to be skipped if fresh information is + available (e.g., after GAS/ANQP round for Interworking) + * added support for 256-bit AES with internal TLS implementation + * allow peer to propose channel in P2P invitation process for a + persistent group + * added disallow_aps parameter to allow BSSIDs/SSIDs to be disallowed + from network selection + * re-enable the networks disabled during WPS operations + * allow P2P functionality to be disabled per interface (p2p_disabled=1) + * added secondary device types into P2P_PEER output + * added an option to disable use of a separate P2P group interface + (p2p_no_group_iface=1) + * fixed P2P Bonjour SD to match entries with both compressed and not + compressed domain name format and support multiple Bonjour PTR matches + for the same key + * use deauthentication instead of disassociation for all disconnection + operations; this removes the now unused disassociate() wpa_driver_ops + callback + * optimized PSK generation on P2P GO by caching results to avoid + multiple PBKDF2 operations + * added okc=1 global configuration parameter to allow OKC to be enabled + by default for all network blocks + * added a workaround for WPS PBC session overlap detection to avoid + interop issues with deployed station implementations that do not + remove active PBC indication from Probe Request frames properly + * added basic support for 60 GHz band + * extend EAPOL frames processing workaround for roaming cases + (postpone processing of unexpected EAPOL frame until association + event to handle reordered events) + +2012-05-10 - v1.0 + * bsd: Add support for setting HT values in IFM_MMASK. + * Delay STA entry removal until Deauth/Disassoc TX status in AP mode. + This allows the driver to use PS buffering of Deauthentication and + Disassociation frames when the STA is in power save sleep. Only + available with drivers that provide TX status events for Deauth/ + Disassoc frames (nl80211). + * Drop oldest unknown BSS table entries first. This makes it less + likely to hit connection issues in environments with huge number + of visible APs. + * Add systemd support. + * Add support for setting the syslog facility from the config file + at build time. + * atheros: Add support for IEEE 802.11w configuration. + * AP mode: Allow enable HT20 if driver supports it, by setting the + config parameter ieee80211n. + * Allow AP mode to disconnect STAs based on low ACK condition (when + the data connection is not working properly, e.g., due to the STA + going outside the range of the AP). Disabled by default, enable by + config option disassoc_low_ack. + * nl80211: + - Support GTK rekey offload. + - Support PMKSA candidate events. This adds support for RSN + pre-authentication with nl80211 interface and drivers that handle + roaming internally. + * dbus: + - Add a DBus signal for EAP SM requests, emitted on the Interface + object. + - Export max scan ssids supported by the driver as MaxScanSSID. + - Add signal Certification for information about server certification. + - Add BSSExpireAge and BSSExpireCount interface properties and + support set/get, which allows for setting BSS cache expiration age + and expiration scan count. + - Add ConfigFile to AddInterface properties. + - Add Interface.Country property and support to get/set the value. + - Add DBus property CurrentAuthMode. + - P2P DBus API added. + - Emit property changed events (for property BSSs) when adding/ + removing BSSs. + - Treat '' in SSIDs of Interface.Scan as a request for broadcast + scan, instead of ignoring it. + - Add DBus getter/setter for FastReauth. + - Raise PropertiesChanged on org.freedesktop.DBus.Properties. + * wpa_cli: + - Send AP-STA-DISCONNECTED event when an AP disconnects a station + due to inactivity. + - Make second argument to set command optional. This can be used to + indicate a zero length value. + - Add signal_poll command. + - Add bss_expire_age and bss_expire_count commands to set/get BSS + cache expiration age and expiration scan count. + - Add ability to set scan interval (the time in seconds wpa_s waits + before requesting a new scan after failing to find a suitable + network in scan results) using scan_interval command. + - Add event CTRL-EVENT-ASSOC-REJECT for association rejected. + - Add command get version, that returns wpa_supplicant version string. + - Add command sta_autoconnect for disabling automatic reconnection + on receiving disconnection event. + - Setting bssid parameter to an empty string "" or any can now be + used to clear the bssid_set flag in a network block, i.e., to remove + bssid filtering. + - Add tdls_testing command to add a special testing feature for + changing TDLS behavior. Build param CONFIG_TDLS_TESTING must be + enabled as well. + - For interworking, add wpa_cli commands interworking_select, + interworking_connect, anqp_get, fetch_anqp, and stop_fetch_anqp. + - Many P2P commands were added. See README-P2P. + - Many WPS/WPS ER commands - see WPS/WPS ER sections for details. + - Allow set command to change global config parameters. + - Add log_level command, which can be used to display the current + debugging level and to change the log level during run time. + - Add note command, which can be used to insert notes to the debug + log. + - Add internal line edit implementation. CONFIG_WPA_CLI_EDIT=y + can now be used to build wpa_cli with internal implementation of + line editing and history support. This can be used as a replacement + for CONFIG_READLINE=y. + * AP mode: Add max_num_sta config option, which can be used to limit + the number of stations allowed to connect to the AP. + * Add WPA_IGNORE_CONFIG_ERRORS build option to continue in case of bad + config file. + * wext: Increase scan timeout from 5 to 10 seconds. + * Add blacklist command, allowing an external program to + manage the BSS blacklist and display its current contents. + * WPS: + - Add wpa_cli wps_pin get command for generating random PINs. This can + be used in a UI to generate a PIN without starting WPS (or P2P) + operation. + - Set RF bands based on driver capabilities, instead of hardcoding + them. + - Add mechanism for indicating non-standard WPS errors. + - Add CONFIG_WPS_REG_DISABLE_OPEN=y option to disable open networks + by default. + - Add wps_ap_pin cli command for wpa_supplicant AP mode. + - Add wps_check_pin cli command for processing PIN from user input. + UIs can use this command to process a PIN entered by a user and to + validate the checksum digit (if present). + - Cancel WPS operation on PBC session overlap detection. + - New wps_cancel command in wpa_cli will cancel a pending WPS + operation. + - wpa_cli action: Add WPS_EVENT_SUCCESS and WPS_EVENT_FAIL handlers. + - Trigger WPS config update on Manufacturer, Model Name, Model + Number, and Serial Number changes. + - Fragment size is now configurable for EAP-WSC peer. Use + wpa_cli set wps_fragment_size <val>. + - Disable AP PIN after 10 consecutive failures. Slow down attacks on + failures up to 10. + - Allow AP to start in Enrollee mode without AP PIN for probing, to + be compatible with Windows 7. + - Add Config Error into WPS-FAIL events to provide more info to the + user on how to resolve the issue. + - Label and Display config methods are not allowed to be enabled + at the same time, since it is unclear which PIN to use if both + methods are advertised. + - When controlling multiple interfaces: + - apply WPS commands to all interfaces configured to use WPS + - apply WPS config changes to all interfaces that use WPS + - when an attack is detected on any interface, disable AP PIN on + all interfaces + * WPS ER: + - Add special AP Setup Locked mode to allow read only ER. + ap_setup_locked=2 can now be used to enable a special mode where + WPS ER can learn the current AP settings, but cannot change them. + - Show SetSelectedRegistrar events as ctrl_iface events + - Add wps_er_set_config to enroll a network based on a local + network configuration block instead of having to (re-)learn the + current AP settings with wps_er_learn. + - Allow AP filtering based on IP address, add ctrl_iface event for + learned AP settings, add wps_er_config command to configure an AP. + * WPS 2.0: Add support for WPS 2.0 (CONFIG_WPS2) + - Add build option CONFIG_WPS_EXTENSIBILITY_TESTING to enable tool + for testing protocol extensibility. + - Add build option CONFIG_WPS_STRICT to allow disabling of WPS + workarounds. + - Add support for AuthorizedMACs attribute. + * TDLS: + - Propagate TDLS related nl80211 capability flags from kernel and + add them as driver capability flags. If the driver doesn't support + capabilities, assume TDLS is supported internally. When TDLS is + explicitly not supported, disable all user facing TDLS operations. + - Allow TDLS to be disabled at runtime (mostly for testing). + Use set tdls_disabled. + - Honor AP TDLS settings that prohibit/allow TDLS. + - Add a special testing feature for changing TDLS behavior. Use + CONFIG_TDLS_TESTING build param to enable. Configure at runtime + with tdls_testing cli command. + - Add support for TDLS 802.11z. + * wlantest: Add a tool wlantest for IEEE802.11 protocol testing. + wlantest can be used to capture frames from a monitor interface + for realtime capturing or from pcap files for offline analysis. + * Interworking: Support added for 802.11u. Enable in .config with + CONFIG_INTERWORKING. See wpa_supplicant.conf for config parameters + for interworking. wpa_cli commands added to support this are + interworking_select, interworking_connect, anqp_get, fetch_anqp, + and stop_fetch_anqp. + * Android: Add build and runtime support for Android wpa_supplicant. + * bgscan learn: Add new bgscan that learns BSS information based on + previous scans, and uses that information to dynamically generate + the list of channels for background scans. + * Add a new debug message level for excessive information. Use + -ddd to enable. + * TLS: Add support for tls_disable_time_checks=1 in client mode. + * Internal TLS: + - Add support for TLS v1.1 (RFC 4346). Enable with build parameter + CONFIG_TLSV11. + - Add domainComponent parser for X.509 names. + * Linux: Add RFKill support by adding an interface state "disabled". + * Reorder some IEs to get closer to IEEE 802.11 standard. Move + WMM into end of Beacon, Probe Resp and (Re)Assoc Resp frames. + Move HT IEs to be later in (Re)Assoc Resp. + * Solaris: Add support for wired 802.1X client. + * Wi-Fi Direct support. See README-P2P for more information. + * Many bugfixes. + +2010-04-18 - v0.7.2 + * nl80211: fixed number of issues with roaming + * avoid unnecessary roaming if multiple APs with similar signal + strength are present in scan results + * add TLS client events and server probing to ease design of + automatic detection of EAP parameters + * add option for server certificate matching (SHA256 hash of the + certificate) instead of trusted CA certificate configuration + * bsd: Cleaned up driver wrapper and added various low-level + configuration options + * wpa_gui-qt4: do not show too frequent WPS AP available events as + tray messages + * TNC: fixed issues with fragmentation + * EAP-TNC: add Flags field into fragment acknowledgement (needed to + interoperate with other implementations; may potentially breaks + compatibility with older wpa_supplicant/hostapd versions) + * wpa_cli: added option for using a separate process to receive event + messages to reduce latency in showing these + (CFLAGS += -DCONFIG_WPA_CLI_FORK=y in .config to enable this) + * maximum BSS table size can now be configured (bss_max_count) + * BSSes to be included in the BSS table can be filtered based on + configured SSIDs to save memory (filter_ssids) + * fix number of issues with IEEE 802.11r/FT; this version is not + backwards compatible with old versions + * nl80211: add support for IEEE 802.11r/FT protocol (both over-the-air + and over-the-DS) + * add freq_list network configuration parameter to allow the AP + selection to filter out entries based on the operating channel + * add signal strength change events for bgscan; this allows more + dynamic changes to background scanning interval based on changes in + the signal strength with the current AP; this improves roaming within + ESS quite a bit, e.g., with bgscan="simple:30:-45:300" in the network + configuration block to request background scans less frequently when + signal strength remains good and to automatically trigger background + scans whenever signal strength drops noticeably + (this is currently only available with nl80211) + * add BSSID and reason code (if available) to disconnect event messages + * wpa_gui-qt4: more complete support for translating the GUI with + linguist and add German translation + * fix DH padding with internal crypto code (mainly, for WPS) + * do not trigger initial scan automatically anymore if there are no + enabled networks + +2010-01-16 - v0.7.1 + * cleaned up driver wrapper API (struct wpa_driver_ops); the new API + is not fully backwards compatible, so out-of-tree driver wrappers + will need modifications + * cleaned up various module interfaces + * merge hostapd and wpa_supplicant developers' documentation into a + single document + * nl80211: use explicit deauthentication to clear cfg80211 state to + avoid issues when roaming between APs + * dbus: major design changes in the new D-Bus API + (fi.w1.wpa_supplicant1) + * nl80211: added support for IBSS networks + * added internal debugging mechanism with backtrace support and memory + allocation/freeing validation, etc. tests (CONFIG_WPA_TRACE=y) + * added WPS ER unsubscription command to more cleanly unregister from + receiving UPnP events when ER is terminated + * cleaned up AP mode operations to avoid need for virtual driver_ops + wrapper + * added BSS table to maintain more complete scan result information + over multiple scans (that may include only partial results) + * wpa_gui-qt4: update Peers dialog information more dynamically while + the dialog is kept open + * fixed PKCS#12 use with OpenSSL 1.0.0 + * driver_wext: Added cfg80211-specific optimization to avoid some + unnecessary scans and to speed up association + +2009-11-21 - v0.7.0 + * increased wpa_cli ping interval to 5 seconds and made this + configurable with a new command line options (-G<seconds>) + * fixed scan buffer processing with WEXT to handle up to 65535 + byte result buffer (previously, limited to 32768 bytes) + * allow multiple driver wrappers to be specified on command line + (e.g., -Dnl80211,wext); the first one that is able to initialize the + interface will be used + * added support for multiple SSIDs per scan request to optimize + scan_ssid=1 operations in ap_scan=1 mode (i.e., search for hidden + SSIDs); this requires driver support and can currently be used only + with nl80211 + * added support for WPS USBA out-of-band mechanism with USB Flash + Drives (UFD) (CONFIG_WPS_UFD=y) + * driver_ndis: add PAE group address to the multicast address list to + fix wired IEEE 802.1X authentication + * fixed IEEE 802.11r key derivation function to match with the standard + (note: this breaks interoperability with previous version) [Bug 303] + * added better support for drivers that allow separate authentication + and association commands (e.g., mac80211-based Linux drivers with + nl80211; SME in wpa_supplicant); this allows over-the-air FT protocol + to be used (IEEE 802.11r) + * fixed SHA-256 based key derivation function to match with the + standard when using CCMP (for IEEE 802.11r and IEEE 802.11w) + (note: this breaks interoperability with previous version) [Bug 307] + * use shared driver wrapper files with hostapd + * added AP mode functionality (CONFIG_AP=y) with mode=2 in the network + block; this can be used for open and WPA2-Personal networks + (optionally, with WPS); this links in parts of hostapd functionality + into wpa_supplicant + * wpa_gui-qt4: added new Peers dialog to show information about peers + (other devices, including APs and stations, etc. in the neighborhood) + * added support for WPS External Registrar functionality (configure APs + and enroll new devices); can be used with wpa_gui-qt4 Peers dialog + and wpa_cli commands wps_er_start, wps_er_stop, wps_er_pin, + wps_er_pbc, wps_er_learn + (this can also be used with a new 'none' driver wrapper if no + wireless device or IEEE 802.1X on wired is needed) + * driver_nl80211: multiple updates to provide support for new Linux + nl80211/mac80211 functionality + * updated management frame protection to use IEEE Std 802.11w-2009 + * fixed number of small WPS issues and added workarounds to + interoperate with common deployed broken implementations + * added support for NFC out-of-band mechanism with WPS + * driver_ndis: fixed wired IEEE 802.1X authentication with PAE group + address frames + * added preliminary support for IEEE 802.11r RIC processing + * added support for specifying subset of enabled frequencies to scan + (scan_freq option in the network configuration block); this can speed + up scanning process considerably if it is known that only a small + subset of channels is actually used in the network (this is currently + supported only with -Dnl80211) + * added a workaround for race condition between receiving the + association event and the following EAPOL-Key + * added background scan and roaming infrastructure to allow + network-specific optimizations to be used to improve roaming within + an ESS (same SSID) + * added new DBus interface (fi.w1.wpa_supplicant1) + +2009-01-06 - v0.6.7 + * added support for Wi-Fi Protected Setup (WPS) + (wpa_supplicant can now be configured to act as a WPS Enrollee to + enroll credentials for a network using PIN and PBC methods; in + addition, wpa_supplicant can act as a wireless WPS Registrar to + configure an AP); WPS support can be enabled by adding CONFIG_WPS=y + into .config and setting the runtime configuration variables in + wpa_supplicant.conf (see WPS section in the example configuration + file); new wpa_cli commands wps_pin, wps_pbc, and wps_reg are used to + manage WPS negotiation; see README-WPS for more details + * added support for EAP-AKA' (draft-arkko-eap-aka-kdf) + * added support for using driver_test over UDP socket + * fixed PEAPv0 Cryptobinding interoperability issue with Windows Server + 2008 NPS; optional cryptobinding is now enabled (again) by default + * fixed PSK editing in wpa_gui + * changed EAP-GPSK to use the IANA assigned EAP method type 51 + * added a Windows installer that includes WinPcap and all the needed + DLLs; in addition, it set up the registry automatically so that user + will only need start wpa_gui to get prompted to start the wpasvc + servide and add a new interface if needed through wpa_gui dialog + * updated management frame protection to use IEEE 802.11w/D7.0 + +2008-11-23 - v0.6.6 + * added Milenage SIM/USIM emulator for EAP-SIM/EAP-AKA + (can be used to simulate test SIM/USIM card with a known private key; + enable with CONFIG_SIM_SIMULATOR=y/CONFIG_USIM_SIMULATOR=y in .config + and password="Ki:OPc"/password="Ki:OPc:SQN" in network configuration) + * added a new network configuration option, wpa_ptk_rekey, that can be + used to enforce frequent PTK rekeying, e.g., to mitigate some attacks + against TKIP deficiencies + * added an optional mitigation mechanism for certain attacks against + TKIP by delaying Michael MIC error reports by a random amount of time + between 0 and 60 seconds; this can be enabled with a build option + CONFIG_DELAYED_MIC_ERROR_REPORT=y in .config + * fixed EAP-AKA to use RES Length field in AT_RES as length in bits, + not bytes + * updated OpenSSL code for EAP-FAST to use an updated version of the + session ticket overriding API that was included into the upstream + OpenSSL 0.9.9 tree on 2008-11-15 (no additional OpenSSL patch is + needed with that version anymore) + * updated userspace MLME instructions to match with the current Linux + mac80211 implementation; please also note that this can only be used + with driver_nl80211.c (the old code from driver_wext.c was removed) + * added support (Linux only) for RoboSwitch chipsets (often found in + consumer grade routers); driver interface 'roboswitch' + * fixed canceling of PMKSA caching when using drivers that generate + RSN IE and refuse to drop PMKIDs that wpa_supplicant does not know + about + +2008-11-01 - v0.6.5 + * added support for SHA-256 as X.509 certificate digest when using the + internal X.509/TLSv1 implementation + * updated management frame protection to use IEEE 802.11w/D6.0 + * added support for using SHA256-based stronger key derivation for WPA2 + (IEEE 802.11w) + * fixed FT (IEEE 802.11r) authentication after a failed association to + use correct FTIE + * added support for configuring Phase 2 (inner/tunneled) authentication + method with wpa_gui-qt4 + +2008-08-10 - v0.6.4 + * added support for EAP Sequences in EAP-FAST Phase 2 + * added support for using TNC with EAP-FAST + * added driver_ps3 for the PS3 Linux wireless driver + * added support for optional cryptobinding with PEAPv0 + * fixed the OpenSSL patches (0.9.8g and 0.9.9) for EAP-FAST to + allow fallback to full handshake if server rejects PAC-Opaque + * added fragmentation support for EAP-TNC + * added support for parsing PKCS #8 formatted private keys into the + internal TLS implementation (both PKCS #1 RSA key and PKCS #8 + encapsulated RSA key can now be used) + * added option of using faster, but larger, routines in the internal + LibTomMath (for internal TLS implementation) to speed up DH and RSA + calculations (CONFIG_INTERNAL_LIBTOMMATH_FAST=y) + * fixed race condition between disassociation event and group key + handshake to avoid getting stuck in incorrect state [Bug 261] + * fixed opportunistic key caching (proactive_key_caching) + +2008-02-22 - v0.6.3 + * removed 'nai' and 'eappsk' network configuration variables that were + previously used for configuring user identity and key for EAP-PSK, + EAP-PAX, EAP-SAKE, and EAP-GPSK. 'identity' field is now used as the + replacement for 'nai' (if old configuration used a separate + 'identity' value, that would now be configured as + 'anonymous_identity'). 'password' field is now used as the + replacement for 'eappsk' (it can also be set using hexstring to + present random binary data) + * removed '-w' command line parameter (wait for interface to be added, + if needed); cleaner way of handling this functionality is to use an + external mechanism (e.g., hotplug scripts) that start wpa_supplicant + when an interface is added + * updated FT support to use the latest draft, IEEE 802.11r/D9.0 + * added ctrl_iface monitor event (CTRL-EVENT-SCAN-RESULTS) for + indicating when new scan results become available + * added new ctrl_iface command, BSS, to allow scan results to be + fetched without hitting the message size limits (this command + can be used to iterate through the scan results one BSS at the time) + * fixed EAP-SIM not to include AT_NONCE_MT and AT_SELECTED_VERSION + attributes in EAP-SIM Start/Response when using fast reauthentication + * fixed EAPOL not to end up in infinite loop when processing dynamic + WEP keys with IEEE 802.1X + * fixed problems in getting NDIS events from WMI on Windows 2000 + +2008-01-01 - v0.6.2 + * added support for Makefile builds to include debug-log-to-a-file + functionality (CONFIG_DEBUG_FILE=y and -f<path> on command line) + * fixed EAP-SIM and EAP-AKA message parser to validate attribute + lengths properly to avoid potential crash caused by invalid messages + * added data structure for storing allocated buffers (struct wpabuf); + this does not affect wpa_supplicant usage, but many of the APIs + changed and various interfaces (e.g., EAP) is not compatible with old + versions + * added support for protecting EAP-AKA/Identity messages with + AT_CHECKCODE (optional feature in RFC 4187) + * added support for protected result indication with AT_RESULT_IND for + EAP-SIM and EAP-AKA (phase1="result_ind=1") + * added driver_wext workaround for race condition between scanning and + association with drivers that take very long time to scan all + channels (e.g., madwifi with dual-band cards); wpa_supplicant is now + using a longer hardcoded timeout for the scan if the driver supports + notifications for scan completion (SIOCGIWSCAN event); this helps, + e.g., in cases where wpa_supplicant and madwifi driver ended up in + loop where the driver did not even try to associate + * stop EAPOL timer tick when no timers are in use in order to reduce + power consumption (no need to wake up the process once per second) + [Bug 237] + * added support for privilege separation (run only minimal part of + wpa_supplicant functionality as root and rest as unprivileged, + non-root process); see 'Privilege separation' in README for details; + this is disabled by default and can be enabled with CONFIG_PRIVSEP=y + in .config + * changed scan results data structure to include all information + elements to make it easier to support new IEs; old get_scan_result() + driver_ops is still supported for backwards compatibility (results + are converted internally to the new format), but all drivers should + start using the new get_scan_results2() to make them more likely to + work with new features + * Qt4 version of wpa_gui (wpa_gui-qt4 subdirectory) is now native Qt4 + application, i.e., it does not require Qt3Support anymore; Windows + binary of wpa_gui.exe is now from this directory and only requires + QtCore4.dll and QtGui4.dll libraries + * updated Windows binary build to use Qt 4.3.3 and made Qt DLLs + available as a separate package to make wpa_gui installation easier: + http://w1.fi/wpa_supplicant/qt4/wpa_gui-qt433-windows-dll.zip + * added support for EAP-IKEv2 (draft-tschofenig-eap-ikev2-15.txt); + only shared key/password authentication is supported in this version + +2007-11-24 - v0.6.1 + * added support for configuring password as NtPasswordHash + (16-byte MD4 hash of password) in hash:<32 hex digits> format + * added support for fallback from abbreviated TLS handshake to + full handshake when using EAP-FAST (e.g., due to an expired + PAC-Opaque) + * updated EAP Generalized Pre-Shared Key (EAP-GPSK) to use the latest + draft (draft-ietf-emu-eap-gpsk-07.txt) + * added support for drivers that take care of RSN 4-way handshake + internally (WPA_DRIVER_FLAGS_4WAY_HANDSHAKE in get_capa flags and + WPA_ALG_PMK in set_key) + * added an experimental port for Mac OS X (CONFIG_DRIVER_OSX=y in + .config); this version supports only ap_scan=2 mode and allow the + driver to take care of the 4-way handshake + * fixed a buffer overflow in parsing TSF from scan results when using + driver_wext.c with a driver that includes the TSF (e.g., iwl4965) + [Bug 232] + * updated FT support to use the latest draft, IEEE 802.11r/D8.0 + * fixed an integer overflow issue in the ASN.1 parser used by the + (experimental) internal TLS implementation to avoid a potential + buffer read overflow + * fixed a race condition with -W option (wait for a control interface + monitor before starting) that could have caused the first messages to + be lost + * added support for processing TNCC-TNCS-Messages to report + recommendation (allow/none/isolate) when using TNC [Bug 243] + +2007-05-28 - v0.6.0 + * added network configuration parameter 'frequency' for setting + initial channel for IBSS (adhoc) networks + * added experimental IEEE 802.11r/D6.0 support + * updated EAP-SAKE to RFC 4763 and the IANA-allocated EAP type 48 + * updated EAP-PSK to use the IANA-allocated EAP type 47 + * fixed EAP-PAX key derivation + * fixed EAP-PSK bit ordering of the Flags field + * fixed EAP-PEAP/TTLS/FAST to use the correct EAP identifier in + tunnelled identity request (previously, the identifier from the outer + method was used, not the tunnelled identifier which could be + different) + * added support for fragmentation of outer TLS packets during Phase 2 + of EAP-PEAP/TTLS/FAST + * fixed EAP-TTLS AVP parser processing for too short AVP lengths + * added support for EAP-FAST authentication with inner methods that + generate MSK (e.g., EAP-MSCHAPv2 that was previously only supported + for PAC provisioning) + * added support for authenticated EAP-FAST provisioning + * added support for configuring maximum number of EAP-FAST PACs to + store in a PAC list (fast_max_pac_list_len=<max> in phase1 string) + * added support for storing EAP-FAST PACs in binary format + (fast_pac_format=binary in phase1 string) + * fixed dbus ctrl_iface to validate message interface before + dispatching to avoid a possible segfault [Bug 190] + * fixed PeerKey key derivation to use the correct PRF label + * updated Windows binary build to link against OpenSSL 0.9.8d and + added support for EAP-FAST + * updated EAP Generalized Pre-Shared Key (EAP-GPSK) to use the latest + draft (draft-ietf-emu-eap-gpsk-04.txt) + * fixed EAP-AKA Notification processing to allow Notification to be + processed after AKA Challenge response has been sent + * updated to use IEEE 802.11w/D2.0 for management frame protection + (still experimental) + * fixed EAP-TTLS implementation not to crash on use of freed memory + if TLS library initialization fails + * added support for EAP-TNC (Trusted Network Connect) + (this version implements the EAP-TNC method and EAP-TTLS changes + needed to run two methods in sequence (IF-T) and the IF-IMC and + IF-TNCCS interfaces from TNCC) + +2006-11-24 - v0.5.6 + * added experimental, integrated TLSv1 client implementation with the + needed X.509/ASN.1/RSA/bignum processing (this can be enabled by + setting CONFIG_TLS=internal and CONFIG_INTERNAL_LIBTOMMATH=y in + .config); this can be useful, e.g., if the target system does not + have a suitable TLS library and a minimal code size is required + (total size of this internal TLS/crypto code is bit under 50 kB on + x86 and the crypto code is shared by rest of the supplicant so some + of it was already required; TLSv1/X.509/ASN.1/RSA added about 25 kB) + * removed STAKey handshake since PeerKey handshake has replaced it in + IEEE 802.11ma and there are no known deployments of STAKey + * updated EAP Generalized Pre-Shared Key (EAP-GPSK) to use the latest + draft (draft-ietf-emu-eap-gpsk-01.txt) + * added preliminary implementation of IEEE 802.11w/D1.0 (management + frame protection) + (Note: this requires driver support to work properly.) + (Note2: IEEE 802.11w is an unapproved draft and subject to change.) + * fixed Windows named pipes ctrl_iface to not stop listening for + commands if client program opens a named pipe and closes it + immediately without sending a command + * fixed USIM PIN status determination for the case that PIN is not + needed (this allows EAP-AKA to be used with USIM cards that do not + use PIN) + * added support for reading 3G USIM AID from EF_DIR to allow EAP-AKA to + be used with cards that do not support file selection based on + partial AID + * added support for matching the subjectAltName of the authentication + server certificate against multiple name components (e.g., + altsubject_match="DNS:server.example.com;DNS:server2.example.com") + * fixed EAP-SIM/AKA key derivation for re-authentication case (only + affects IEEE 802.1X with dynamic WEP keys) + * changed ctrl_iface network configuration 'get' operations to not + return password/key material; if these fields are requested, "*" + will be returned if the password/key is set, but the value of the + parameter is not exposed + +2006-08-27 - v0.5.5 + * added support for building Windows version with UNICODE defined + (wide-char functions) + * driver_ndis: fixed static WEP configuration to avoid race condition + issues with some NDIS drivers between association and setting WEP + keys + * driver_ndis: added validation for IELength value in scan results to + avoid crashes when using buggy NDIS drivers [Bug 165] + * fixed Release|Win32 target in the Visual Studio project files + (previously, only Debug|Win32 target was set properly) + * changed control interface API call wpa_ctrl_pending() to allow it to + return -1 on error (e.g., connection lost); control interface clients + will need to make sure that they verify that the value is indeed >0 + when determining whether there are pending messages + * added an alternative control interface backend for Windows targets: + Named Pipe (CONFIG_CTRL_IFACE=named_pipe); this is now the default + control interface mechanism for Windows builds (previously, UDP to + localhost was used) + * changed ctrl_interface configuration for UNIX domain sockets: + - deprecated ctrl_interface_group variable (it may be removed in + future versions) + - allow both directory and group be configured with ctrl_interface + in following format: DIR=/var/run/wpa_supplicant GROUP=wheel + - ctrl_interface=/var/run/wpa_supplicant is still supported for the + case when group is not changed + * added support for controlling more than one interface per process in + Windows version + * added a workaround for a case where the AP is using unknown address + (e.g., MAC address of the wired interface) as the source address for + EAPOL-Key frames; previously, that source address was used as the + destination for EAPOL-Key frames and in key derivation; now, BSSID is + used even if the source address does not match with it + (this resolves an interoperability issue with Thomson SpeedTouch 580) + * added a workaround for UDP-based control interface (which was used in + Windows builds before this release) to prevent packets with forged + addresses from being accepted as local control requests + * removed ndis_events.cpp and possibility of using external + ndis_events.exe; C version (ndis_events.c) is fully functional and + there is no desire to maintain two separate versions of this + implementation + * ndis_events: Changed NDIS event notification design to use WMI to + learn the adapter description through Win32_PnPEntity class; this + should fix some cases where the adapter name was not recognized + correctly (e.g., with some USB WLAN adapters, e.g., Ralink RT2500 + USB) [Bug 113] + * fixed selection of the first network in ap_scan=2 mode; previously, + wpa_supplicant could get stuck in SCANNING state when only the first + network for enabled (e.g., after 'wpa_cli select_network 0') + * winsvc: added support for configuring ctrl_interface parameters in + registry (ctrl_interface string value in + HKLM\SOFTWARE\wpa_supplicant\interfaces\0000 key); this new value is + required to enable control interface (previously, this was hardcoded + to be enabled) + * allow wpa_gui subdirectory to be built with both Qt3 and Qt4 + * converted wpa_gui-qt4 subdirectory to use Qt4 specific project format + +2006-06-20 - v0.5.4 + * fixed build with CONFIG_STAKEY=y [Bug 143] + * added support for doing MLME (IEEE 802.11 management frame + processing) in wpa_supplicant when using Devicescape IEEE 802.11 + stack (wireless-dev.git tree) + * added a new network block configuration option, fragment_size, to + configure the maximum EAP fragment size + * driver_ndis: Disable WZC automatically for the selected interface to + avoid conflicts with two programs trying to control the radio; WZC + will be re-enabled (if it was enabled originally) when wpa_supplicant + is terminated + * added an experimental TLSv1 client implementation + (CONFIG_TLS=internal) that can be used instead of an external TLS + library, e.g., to reduce total size requirement on systems that do + not include any TLS library by default (this is not yet complete; + basic functionality is there, but certificate validation is not yet + included) + * added PeerKey handshake implementation for IEEE 802.11e + direct link setup (DLS) to replace STAKey handshake + * fixed WPA PSK update through ctrl_iface for the case where the old + PSK was derived from an ASCII passphrase and the new PSK is set as + a raw PSK (hex string) + * added new configuration option for identifying which network block + was used (id_str in wpa_supplicant.conf; included on + WPA_EVENT_CONNECT monitor event and as WPA_ID_STR environmental + variable in wpa_cli action scripts; in addition WPA_ID variable is + set to the current unique identifier that wpa_supplicant assigned + automatically for the network and that can be used with + GET_NETWORK/SET_NETWORK ctrl_iface commands) + * wpa_cli action script is now called only when the connect/disconnect + status changes or when associating with a different network + * fixed configuration parser not to remove CCMP from group cipher list + if WPA-None (adhoc) is used (pairwise=NONE in that case) + * fixed integrated NDIS events processing not to hang the process due + to a missed change in eloop_win.c API in v0.5.3 [Bug 155] + * added support for EAP Generalized Pre-Shared Key (EAP-GPSK, + draft-clancy-emu-eap-shared-secret-00.txt) + * added Microsoft Visual Studio 2005 solution and project files for + build wpa_supplicant for Windows (see vs2005 subdirectory) + * eloop_win: fixed unregistration of Windows events + * l2_packet_winpcap: fixed a deadlock in deinitializing l2_packet + at the end of RSN pre-authentication and added unregistration of + a Windows event to avoid getting eloop_win stuck with an invalid + handle + * driver_ndis: added support for selecting AP based on BSSID + * added new environmental variable for wpa_cli action scripts: + WPA_CTRL_DIR is the current control interface directory + * driver_ndis: added support for using NDISUIO instead of WinPcap for + OID set/query operations (CONFIG_USE_NDISUIO=y in .config); with new + l2_packet_ndis (CONFIG_L2_PACKET=ndis), this can be used to build + wpa_supplicant without requiring WinPcap; note that using NDISUIO + requires that WZC is disabled (net stop wzcsvc) since NDISUIO allows + only one application to open the device + * changed NDIS driver naming to only include device GUID, e.g., + {7EE3EFE5-C165-472F-986D-F6FBEDFE8C8D}, instead of including WinPcap + specific \Device\NPF_ prefix before the GUID; the prefix is still + allowed for backwards compatibility, but it is not required anymore + when specifying the interface + * driver_ndis: re-initialize driver interface is the adapter is removed + and re-inserted [Bug 159] + * driver_madwifi: fixed TKIP and CCMP sequence number configuration on + big endian hosts [Bug 146] + +2006-04-27 - v0.5.3 + * fixed EAP-GTC response to include correct user identity when run as + phase 2 method of EAP-FAST (i.e., EAP-FAST did not work in v0.5.2) + * driver_ndis: Fixed encryption mode configuration for unencrypted + networks (some NDIS drivers ignored this, but others, e.g., Broadcom, + refused to associate with open networks) [Bug 106] + * driver_ndis: use BSSID OID polling to detect when IBSS network is + formed even when ndis_events code is included since some NDIS drivers + do not generate media connect events in IBSS mode + * config_winreg: allow global ctrl_interface parameter to be configured + in Windows registry + * config_winreg: added support for saving configuration data into + Windows registry + * added support for controlling network device operational state + (dormant/up) for Linux 2.6.17 to improve DHCP processing (see + http://www.flamewarmaster.de/software/dhcpclient/ for a DHCP client + that can use this information) + * driver_wext: added support for WE-21 change to SSID configuration + * driver_wext: fixed privacy configuration for static WEP keys mode + [Bug 140] + * added an optional driver_ops callback for MLME-SETPROTECTION.request + primitive + * added support for EAP-SAKE (no EAP method number allocated yet, so + this is using the same experimental type 255 as EAP-PSK) + * added support for dynamically loading EAP methods (.so files) instead + of requiring them to be statically linked in; this is disabled by + default (see CONFIG_DYNAMIC_EAP_METHODS in defconfig for information + on how to use this) + +2006-03-19 - v0.5.2 + * do not try to use USIM APDUs when initializing PC/SC for SIM card + access for a network that has not enabled EAP-AKA + * fixed EAP phase 2 Nak for EAP-{PEAP,TTLS,FAST} (this was broken in + v0.5.1 due to the new support for expanded EAP types) + * added support for generating EAP Expanded Nak + * try to fetch scan results once before requesting new scan when + starting up in ap_scan=1 mode (this can speed up initial association + a lot with, e.g., madwifi-ng driver) + * added support for receiving EAPOL frames from a Linux bridge + interface (-bbr0 on command line) + * fixed EAPOL re-authentication for sessions that used PMKSA caching + * changed EAP method registration to use a dynamic list of methods + instead of a static list generated at build time + * fixed PMKSA cache deinitialization not to use freed memory when + removing PMKSA entries + * fixed a memory leak in EAP-TTLS re-authentication + * reject WPA/WPA2 message 3/4 if it does not include any valid + WPA/RSN IE + * driver_wext: added fallback to use SIOCSIWENCODE for setting auth_alg + if the driver does not support SIOCSIWAUTH + +2006-01-29 - v0.5.1 + * driver_test: added better support for multiple APs and STAs by using + a directory with sockets that include MAC address for each device in + the name (driver_param=test_dir=/tmp/test) + * added support for EAP expanded type (vendor specific EAP methods) + * added AP_SCAN command into ctrl_iface so that ap_scan configuration + option can be changed if needed + * wpa_cli/wpa_gui: skip non-socket files in control directory when + using UNIX domain sockets; this avoids selecting an incorrect + interface (e.g., a PID file could be in this directory, even though + use of this directory for something else than socket files is not + recommended) + * fixed TLS library deinitialization after RSN pre-authentication not + to disable TLS library for normal authentication + * driver_wext: Remove null-termination from SSID length if the driver + used it; some Linux drivers do this and they were causing problems in + wpa_supplicant not finding matching configuration block. This change + would break a case where the SSID actually ends in '\0', but that is + not likely to happen in real use. + * fixed PMKSA cache processing not to trigger deauthentication if the + current PMKSA cache entry is replaced with a valid new entry + * fixed PC/SC initialization for ap_scan != 1 modes (this fixes + EAP-SIM and EAP-AKA with real SIM/USIM card when using ap_scan=0 or + ap_scan=2) + +2005-12-18 - v0.5.0 (beginning of 0.5.x development releases) + * added experimental STAKey handshake implementation for IEEE 802.11e + direct link setup (DLS); note: this is disabled by default in both + build and runtime configuration (can be enabled with CONFIG_STAKEY=y + and stakey=1) + * fixed EAP-SIM and EAP-AKA pseudonym and fast re-authentication to + decrypt AT_ENCR_DATA attributes correctly + * fixed EAP-AKA to allow resynchronization within the same session + * made code closer to ANSI C89 standard to make it easier to port to + other C libraries and compilers + * started moving operating system or C library specific functions into + wrapper functions defined in os.h and implemented in os_*.c to make + code more portable + * wpa_supplicant can now be built with Microsoft Visual C++ + (e.g., with the freely available Toolkit 2003 version or Visual + C++ 2005 Express Edition and Platform SDK); see nmake.mak for an + example makefile for nmake + * added support for using Windows registry for command line parameters + (CONFIG_MAIN=main_winsvc) and configuration data + (CONFIG_BACKEND=winreg); see win_example.reg for an example registry + contents; this version can be run both as a Windows service and as a + normal application; 'wpasvc.exe app' to start as applicant, + 'wpasvc.exe reg <full path to wpasvc.exe>' to register a service, + 'net start wpasvc' to start the service, 'wpasvc.exe unreg' to + unregister a service + * made it possible to link ndis_events.exe functionality into + wpa_supplicant.exe by defining CONFIG_NDIS_EVENTS_INTEGRATED + * added better support for multiple control interface backends + (CONFIG_CTRL_IFACE option); currently, 'unix' and 'udp' are supported + * fixed PC/SC code to use correct length for GSM AUTH command buffer + and to not use pioRecvPci with SCardTransmit() calls; these were not + causing visible problems with pcsc-lite, but Windows Winscard.dll + refused the previously used parameters; this fixes EAP-SIM and + EAP-AKA authentication using SIM/USIM card under Windows + * added new event loop implementation for Windows using + WaitForMultipleObject() instead of select() in order to allow waiting + for non-socket objects; this can be selected with + CONFIG_ELOOP=eloop_win in .config + * added support for selecting l2_packet implementation in .config + (CONFIG_L2_PACKET; following options are available now: linux, pcap, + winpcap, freebsd, none) + * added new l2_packet implementation for WinPcap + (CONFIG_L2_PACKET=winpcap) that uses a separate receive thread to + reduce latency in EAPOL receive processing from about 100 ms to about + 3 ms + * added support for EAP-FAST key derivation using other ciphers than + RC4-128-SHA for authentication and AES128-SHA for provisioning + * added support for configuring CA certificate as DER file and as a + configuration blob + * fixed private key configuration as configuration blob and added + support for using PKCS#12 as a blob + * tls_gnutls: added support for using PKCS#12 files; added support for + session resumption + * added support for loading trusted CA certificates from Windows + certificate store: ca_cert="cert_store://<name>", where <name> is + likely CA (Intermediate CA certificates) or ROOT (root certificates) + * added C version of ndis_events.cpp and made it possible to build this + with MinGW so that CONFIG_NDIS_EVENTS_INTEGRATED can be used more + easily on cross-compilation builds + * added wpasvc.exe into Windows binary release; this is an alternative + version of wpa_supplicant.exe with configuration backend using + Windows registry and with the entry point designed to run as a + Windows service + * integrated ndis_events.exe functionality into wpa_supplicant.exe and + wpasvc.exe and removed this additional tool from the Windows binary + release since it is not needed anymore + * load winscard.dll functions dynamically when building with MinGW + since MinGW does not yet include winscard library + +2005-11-20 - v0.4.7 (beginning of 0.4.x stable releases) + * l2_packet_pcap: fixed wired IEEE 802.1X authentication with libpcap + and WinPcap to receive frames sent to PAE group address + * disable EAP state machine when IEEE 802.1X authentication is not used + in order to get rid of bogus "EAP failed" messages + * fixed OpenSSL error reporting to go through all pending errors to + avoid confusing reports of old errors being reported at later point + during handshake + * fixed configuration file updating to not write empty variables + (e.g., proto or key_mgmt) that the file parser would not accept + * fixed ADD_NETWORK ctrl_iface command to use the same default values + for variables as empty network definitions read from config file + would get + * fixed EAP state machine to not discard EAP-Failure messages in many + cases (e.g., during TLS handshake) + * fixed a infinite loop in private key reading if the configured file + cannot be parsed successfully + * driver_madwifi: added support for madwifi-ng + * wpa_gui: do not display password/PSK field contents + * wpa_gui: added CA certificate configuration + * driver_ndis: fixed scan request in ap_scan=2 mode not to change SSID + * driver_ndis: include Beacon IEs in AssocInfo in order to notice if + the new AP is using different WPA/RSN IE + * use longer timeout for IEEE 802.11 association to avoid problems with + drivers that may take more than five second to associate + +2005-10-27 - v0.4.6 + * allow fallback to WPA, if mixed WPA+WPA2 networks have mismatch in + RSN IE, but WPA IE would match with wpa_supplicant configuration + * added support for named configuration blobs in order to avoid having + to use file system for external files (e.g., certificates); + variables can be set to "blob://<blob name>" instead of file path to + use a named blob; supported fields: pac_file, client_cert, + private_key + * fixed RSN pre-authentication (it was broken in the clean up of WPA + state machine interface in v0.4.5) + * driver_madwifi: set IEEE80211_KEY_GROUP flag for group keys to make + sure the driver configures broadcast decryption correctly + * added ca_path (and ca_path2) configuration variables that can be used + to configure OpenSSL CA path, e.g., /etc/ssl/certs, for using the + system-wide trusted CA list + * added support for starting wpa_supplicant without a configuration + file (-C argument must be used to set ctrl_interface parameter for + this case; in addition, -p argument can be used to provide + driver_param; these new arguments can also be used with a + configuration to override the values from the configuration) + * added global control interface that can be optionally used for adding + and removing network interfaces dynamically (-g command line argument + for both wpa_supplicant and wpa_cli) without having to restart + wpa_supplicant process + * wpa_gui: + - try to save configuration whenever something is modified + - added WEP key configuration + - added possibility to edit the current network configuration + * driver_ndis: fixed driver polling not to increase frequency on each + received EAPOL frame due to incorrectly cancelled timeout + * added simple configuration file examples (in examples subdirectory) + * fixed driver_wext.c to filter wireless events based on ifindex to + avoid interfaces receiving events from other interfaces + * delay sending initial EAPOL-Start couple of seconds to speed up + authentication for the most common case of Authenticator starting + EAP authentication immediately after association + +2005-09-25 - v0.4.5 + * added a workaround for clearing keys with ndiswrapper to allow + roaming from WPA enabled AP to plaintext one + * added docbook documentation (doc/docbook) that can be used to + generate, e.g., man pages + * l2_packet_linux: use socket type SOCK_DGRAM instead of SOCK_RAW for + PF_PACKET in order to prepare for network devices that do not use + Ethernet headers (e.g., network stack that includes IEEE 802.11 + header in the frames) + * use receipt of EAPOL-Key frame as a lower layer success indication + for EAP state machine to allow recovery from dropped EAP-Success + frame + * cleaned up internal EAPOL frame processing by not including link + layer (Ethernet) header during WPA and EAPOL/EAP processing; this + header is added only when transmitted the frame; this makes it easier + to use wpa_supplicant on link layers that use different header than + Ethernet + * updated EAP-PSK to use draft 9 by default since this can now be + tested with hostapd; removed support for draft 3, including + server_nai configuration option from network blocks + * driver_wired: add PAE address to the multicast address list in order + to be able to receive EAPOL frames with drivers that do not include + these multicast addresses by default + * driver_wext: add support for WE-19 + * added support for multiple configuration backends (CONFIG_BACKEND + option); currently, only 'file' is supported (i.e., the format used + in wpa_supplicant.conf) + * added support for updating configuration ('wpa_cli save_config'); + this is disabled by default and can be enabled with global + update_config=1 variable in wpa_supplicant.conf; this allows wpa_cli + and wpa_gui to store the configuration changes in a permanent store + * added GET_NETWORK ctrl_iface command + (e.g., 'wpa_cli get_network 0 ssid') + +2005-08-21 - v0.4.4 + * replaced OpenSSL patch for EAP-FAST support + (openssl-tls-extensions.patch) with a more generic and correct + patch (the new patch is not compatible with the previous one, so the + OpenSSL library will need to be patched with the new patch in order + to be able to build wpa_supplicant with EAP-FAST support) + * added support for using Windows certificate store (through CryptoAPI) + for client certificate and private key operations (EAP-TLS) + (see wpa_supplicant.conf for more information on how to configure + this with private_key) + * ported wpa_gui to Windows + * added Qt4 version of wpa_gui (wpa_gui-qt4 directory); this can be + built with the open source version of the Qt4 for Windows + * allow non-WPA modes (e.g., IEEE 802.1X with dynamic WEP) to be used + with drivers that do not support WPA + * ndis_events: fixed Windows 2000 support + * added support for enabling/disabling networks from the list of all + configured networks ('wpa_cli enable_network <network id>' and + 'wpa_cli disable_network <network id>') + * added support for adding and removing network from the current + configuration ('wpa_cli add_network' and 'wpa_cli remove_network + <network id>'); added networks are disabled by default and they can + be enabled with enable_network command once the configuration is done + for the new network; note: configuration file is not yet updated, so + these new networks are lost when wpa_supplicant is restarted + * added support for setting network configuration parameters through + the control interface, for example: + wpa_cli set_network 0 ssid "\"my network\"" + * fixed parsing of strings that include both " and # within double + quoted area (e.g., "start"#end") + * added EAP workaround for PEAP session resumption: allow outer, + i.e., not tunneled, EAP-Success to terminate session since; this can + be disabled with eap_workaround=0 + (this was allowed for PEAPv1 before, but now it is also allowed for + PEAPv0 since at least one RADIUS authentication server seems to be + doing this for PEAPv0, too) + * wpa_gui: added preliminary support for adding new networks to the + wpa_supplicant configuration (double click on the scan results to + open network configuration) + +2005-06-26 - v0.4.3 + * removed interface for external EAPOL/EAP supplicant (e.g., + Xsupplicant), (CONFIG_XSUPPLICANT_IFACE) since it is not required + anymore and is unlikely to be used by anyone + * driver_ndis: fixed WinPcap 3.0 support + * fixed build with CONFIG_DNET_PCAP=y on Linux + * l2_packet: moved different implementations into separate files + (l2_packet_*.c) + +2005-06-12 - v0.4.2 + * driver_ipw: updated driver structures to match with ipw2200-1.0.4 + (note: ipw2100-1.1.0 is likely to require an update to work with + this) + * added support for using ap_scan=2 mode with multiple network blocks; + wpa_supplicant will go through the networks one by one until the + driver reports a successful association; this uses the same order for + networks as scan_ssid=1 scans, i.e., the priority field is ignored + and the network block order in the file is used instead + * fixed a potential issue in RSN pre-authentication ending up using + freed memory if pre-authentication times out + * added support for matching alternative subject name extensions of the + authentication server certificate; new configuration variables + altsubject_match and altsubject_match2 + * driver_ndis: added support for IEEE 802.1X authentication with wired + NDIS drivers + * added support for querying private key password (EAP-TLS) through the + control interface (wpa_cli/wpa_gui) if one is not included in the + configuration file + * driver_broadcom: fixed couple of memory leaks in scan result + processing + * EAP-PAX is now registered as EAP type 46 + * fixed EAP-PAX MAC calculation + * fixed EAP-PAX CK and ICK key derivation + * added support for using password with EAP-PAX (as an alternative to + entering key with eappsk); SHA-1 hash of the password will be used as + the key in this case + * added support for arbitrary driver interface parameters through the + configuration file with a new driver_param field; this adds a new + driver_ops function set_param() + * added possibility to override l2_packet module with driver interface + API (new send_eapol handler); this can be used to implement driver + specific TX/RX functions for EAPOL frames + * fixed ctrl_interface_group processing for the case where gid is + entered as a number, not group name + * driver_test: added support for testing hostapd with wpa_supplicant + by using test driver interface without any kernel drivers or network + cards + +2005-05-22 - v0.4.1 + * driver_madwifi: fixed WPA/WPA2 mode configuration to allow EAPOL + packets to be encrypted; this was apparently broken by the changed + ioctl order in v0.4.0 + * driver_madwifi: added preliminary support for compiling against 'BSD' + branch of madwifi CVS tree + * added support for EAP-MSCHAPv2 password retries within the same EAP + authentication session + * added support for password changes with EAP-MSCHAPv2 (used when the + password has expired) + * added support for reading additional certificates from PKCS#12 files + and adding them to the certificate chain + * fixed association with IEEE 802.1X (no WPA) when dynamic WEP keys + were used + * fixed a possible double free in EAP-TTLS fast-reauthentication when + identity or password is entered through control interface + * display EAP Notification messages to user through control interface + with "CTRL-EVENT-EAP-NOTIFICATION" prefix + * added GUI version of wpa_cli, wpa_gui; this is not build + automatically with 'make'; use 'make wpa_gui' to build (this requires + Qt development tools) + * added 'disconnect' command to control interface for setting + wpa_supplicant in state where it will not associate before + 'reassociate' command has been used + * added support for selecting a network from the list of all configured + networks ('wpa_cli select_network <network id>'; this disabled all + other networks; to re-enable, 'wpa_cli select_network any') + * added support for getting scan results through control interface + * added EAP workaround for PEAPv1 session resumption: allow outer, + i.e., not tunneled, EAP-Success to terminate session since; this can + be disabled with eap_workaround=0 + +2005-04-25 - v0.4.0 (beginning of 0.4.x development releases) + * added a new build time option, CONFIG_NO_STDOUT_DEBUG, that can be + used to reduce the size of the wpa_supplicant considerably if + debugging code is not needed + * fixed EAPOL-Key validation to drop packets with invalid Key Data + Length; such frames could have crashed wpa_supplicant due to buffer + overflow + * added support for wired authentication (IEEE 802.1X on wired + Ethernet); driver interface 'wired' + * obsoleted set_wpa() handler in the driver interface API (it can be + replaced by moving enable/disable functionality into init()/deinit()) + (calls to set_wpa() are still present for backwards compatibility, + but they may be removed in the future) + * driver_madwifi: fixed association in plaintext mode + * modified the EAP workaround that accepts EAP-Success with incorrect + Identifier to be even less strict about verification in order to + interoperate with some authentication servers + * added support for sending TLS alerts + * added support for 'any' SSID wildcard; if ssid is not configured or + is set to an empty string, any SSID will be accepted for non-WPA AP + * added support for asking PIN (for SIM) from frontends (e.g., + wpa_cli); if a PIN is needed, but not included in the configuration + file, a control interface request is sent and EAP processing is + delayed until the PIN is available + * added support for using external devices (e.g., a smartcard) for + private key operations in EAP-TLS (CONFIG_SMARTCARD=y in .config); + new wpa_supplicant.conf variables: + - global: opensc_engine_path, pkcs11_engine_path, pkcs11_module_path + - network: engine, engine_id, key_id + * added experimental support for EAP-PAX + * added monitor mode for wpa_cli (-a<path to a program to run>) that + allows external commands (e.g., shell scripts) to be run based on + wpa_supplicant events, e.g., when authentication has been completed + and data connection is ready; other related wpa_cli arguments: + -B (run in background), -P (write PID file); wpa_supplicant has a new + command line argument (-W) that can be used to make it wait until a + control interface command is received in order to avoid missing + events + * added support for opportunistic WPA2 PMKSA key caching (disabled by + default, can be enabled with proactive_key_caching=1) + * fixed RSN IE in 4-Way Handshake message 2/4 for the case where + Authenticator rejects PMKSA caching attempt and the driver is not + using assoc_info events + * added -P<pid file> argument for wpa_supplicant to write the current + process id into a file + +2005-02-12 - v0.3.7 (beginning of 0.3.x stable releases) + * added new phase1 option parameter, include_tls_length=1, to force + wpa_supplicant to add TLS Message Length field to all TLS messages + even if the packet is not fragmented; this may be needed with some + authentication servers + * fixed WPA/RSN IE verification in message 3 of 4-Way Handshake when + using drivers that take care of AP selection (e.g., when using + ap_scan=2) + * fixed reprocessing of pending request after ctrl_iface requests for + identity/password/otp + * fixed ctrl_iface requests for identity/password/otp in Phase 2 of + EAP-PEAP and EAP-TTLS + * all drivers using driver_wext: set interface up and select Managed + mode when starting wpa_supplicant; set interface down when exiting + * renamed driver_ipw2100.c to driver_ipw.c since it now supports both + ipw2100 and ipw2200; please note that this also changed the + configuration variable in .config to CONFIG_DRIVER_IPW + +2005-01-24 - v0.3.6 + * fixed a busy loop introduced in v0.3.5 for scan result processing + when no matching AP is found + +2005-01-23 - v0.3.5 + * added a workaround for an interoperability issue with a Cisco AP + when using WPA2-PSK + * fixed non-WPA IEEE 802.1X to use the same authentication timeout as + WPA with IEEE 802.1X (i.e., timeout 10 -> 70 sec to allow + retransmission of dropped frames) + * fixed issues with 64-bit CPUs and SHA1 cleanup in previous version + (e.g., segfault when processing EAPOL-Key frames) + * fixed EAP workaround and fast reauthentication configuration for + RSN pre-authentication; previously these were disabled and + pre-authentication would fail if the used authentication server + requires EAP workarounds + * added support for blacklisting APs that fail or timeout + authentication in ap_scan=1 mode so that all APs are tried in cases + where the ones with strongest signal level are failing authentication + * fixed CA certificate loading after a failed EAP-TLS/PEAP/TTLS + authentication attempt + * allow EAP-PEAP/TTLS fast reauthentication only if Phase 2 succeeded + in the previous authentication (previously, only Phase 1 success was + verified) + +2005-01-09 - v0.3.4 + * added preliminary support for IBSS (ad-hoc) mode configuration + (mode=1 in network block); this included a new key_mgmt mode + WPA-NONE, i.e., TKIP or CCMP with a fixed key (based on psk) and no + key management; see wpa_supplicant.conf for more details and an + example on how to configure this (note: this is currently implemented + only for driver_hostapd.c, but the changes should be trivial to add + in associate() handler for other drivers, too (assuming the driver + supports WPA-None) + * added preliminary port for native Windows (i.e., no cygwin) using + mingw + +2005-01-02 - v0.3.3 + * added optional support for GNU Readline and History Libraries for + wpa_cli (CONFIG_READLINE) + * cleaned up EAP state machine <-> method interface and number of + small problems with error case processing not terminating on + EAP-Failure but waiting for timeout + * added couple of workarounds for interoperability issues with a + Cisco AP when using WPA2 + * added support for EAP-FAST (draft-cam-winget-eap-fast-00.txt); + Note: This requires a patch for openssl to add support for TLS + extensions and number of workarounds for operations without + certificates. Proof of concept type of experimental patch is + included in openssl-tls-extensions.patch. + +2004-12-19 - v0.3.2 + * fixed private key loading for cases where passphrase is not set + * fixed Windows/cygwin L2 packet handler freeing; previous version + could cause a segfault when RSN pre-authentication was completed + * added support for PMKSA caching with drivers that generate RSN IEs + (e.g., NDIS); currently, this is only implemented in driver_ndis.c, + but similar code can be easily added to driver_ndiswrapper.c once + ndiswrapper gets full support for RSN PMKSA caching + * improved recovery from PMKID mismatches by requesting full EAP + authentication in case of failed PMKSA caching attempt + * driver_ndis: added support for NDIS NdisMIncidateStatus() events + (this requires that ndis_events is ran while wpa_supplicant is + running) + * driver_ndis: use ADD_WEP/REMOVE_WEP when configuring WEP keys + * added support for driver interfaces to replace the interface name + based on driver/OS specific mapping, e.g., in case of driver_ndis, + this allows the beginning of the adapter description to be used as + the interface name + * added support for CR+LF (Windows-style) line ends in configuration + file + * driver_ndis: enable radio before starting scanning, disable radio + when exiting + * modified association event handler to set portEnabled = FALSE before + clearing port Valid in order to reset EAP state machine and avoid + problems with new authentication getting ignored because of state + machines ending up in AUTHENTICATED/SUCCESS state based on old + information + * added support for driver events to add PMKID candidates in order to + allow drivers to give priority to most likely roaming candidates + * driver_hostap: moved PrivacyInvoked configuration to associate() + function so that this will not be set for plaintext connections + * added KEY_MGMT_802_1X_NO_WPA as a new key_mgmt type so that driver + interface can distinguish plaintext and IEEE 802.1X (no WPA) + authentication + * fixed static WEP key configuration to use broadcast/default type for + all keys (previously, the default TX key was configured as pairwise/ + unicast key) + * driver_ndis: added legacy WPA capability detection for non-WPA2 + drivers + * added support for setting static WEP keys for IEEE 802.1X without + dynamic WEP keying (eapol_flags=0) + +2004-12-12 - v0.3.1 + * added support for reading PKCS#12 (PFX) files (as a replacement for + PEM/DER) to get certificate and private key (CONFIG_PKCS12) + * fixed compilation with CONFIG_PCSC=y + * added new ap_scan mode, ap_scan=2, for drivers that take care of + association, but need to be configured with security policy and SSID, + e.g., ndiswrapper and NDIS driver; this mode should allow such + drivers to work with hidden SSIDs and optimized roaming; when + ap_scan=2 is used, only the first network block in the configuration + file is used and this configuration should have explicit security + policy (i.e., only one option in the lists) for key_mgmt, pairwise, + group, proto variables + * added experimental port of wpa_supplicant for Windows + - driver_ndis.c driver interface (NDIS OIDs) + - currently, this requires cygwin and WinPcap + - small utility, win_if_list, can be used to get interface name + * control interface can now be removed at build time; add + CONFIG_CTRL_IFACE=y to .config to maintain old functionality + * optional Xsupplicant interface can now be removed at build time; + (CONFIG_XSUPPLICANT_IFACE=y in .config to bring it back) + * added auth_alg to driver interface associate() parameters to make it + easier for drivers to configure authentication algorithm as part of + the association + +2004-12-05 - v0.3.0 (beginning of 0.3.x development releases) + * driver_broadcom: added new driver interface for Broadcom wl.o driver + (a generic driver for Broadcom IEEE 802.11a/g cards) + * wpa_cli: fixed parsing of -p <path> command line argument + * PEAPv1: fixed tunneled EAP-Success reply handling to reply with TLS + ACK, not tunneled EAP-Success (of which only the first byte was + actually send due to a bug in previous code); this seems to + interoperate with most RADIUS servers that implements PEAPv1 + * PEAPv1: added support for terminating PEAP authentication on tunneled + EAP-Success message; this can be configured by adding + peap_outer_success=0 on phase1 parameters in wpa_supplicant.conf + (some RADIUS servers require this whereas others require a tunneled + reply + * PEAPv1: changed phase1 option peaplabel to use default to 0, i.e., to + the old label for key derivation; previously, the default was 1, + but it looks like most existing PEAPv1 implementations use the old + label which is thus more suitable default option + * added support for EAP-PSK (draft-bersani-eap-psk-03.txt) + * fixed parsing of wep_tx_keyidx + * added support for configuring list of allowed Phase 2 EAP types + (for both EAP-PEAP and EAP-TTLS) instead of only one type + * added support for configuring IEEE 802.11 authentication algorithm + (auth_alg; mainly for using Shared Key authentication with static + WEP keys) + * added support for EAP-AKA (with UMTS SIM) + * fixed couple of errors in PCSC handling that could have caused + random-looking errors for EAP-SIM + * added support for EAP-SIM pseudonyms and fast re-authentication + * added support for EAP-TLS/PEAP/TTLS fast re-authentication (TLS + session resumption) + * added support for EAP-SIM with two challenges + (phase1="sim_min_num_chal=3" can be used to require three challenges) + * added support for configuring DH/DSA parameters for an ephemeral DH + key exchange (EAP-TLS/PEAP/TTLS) using new configuration parameters + dh_file and dh_file2 (phase 2); this adds support for using DSA keys + and optional DH key exchange to achieve forward secracy with RSA keys + * added support for matching subject of the authentication server + certificate with a substring when using EAP-TLS/PEAP/TTLS; new + configuration variables subject_match and subject_match2 + * changed SSID configuration in driver_wext.c (used by many driver + interfaces) to use ssid_len+1 as the length for SSID since some Linux + drivers expect this + * fixed couple of unaligned reads in scan result parsing to fix WPA + connection on some platforms (e.g., ARM) + * added driver interface for Intel ipw2100 driver + * added support for LEAP with WPA + * added support for larger scan results report (old limit was 4 kB of + data, i.e., about 35 or so APs) when using Linux wireless extensions + v17 or newer + * fixed a bug in PMKSA cache processing: skip sending of EAPOL-Start + only if there is a PMKSA cache entry for the current AP + * fixed error handling for case where reading of scan results fails: + must schedule a new scan or wpa_supplicant will remain waiting + forever + * changed debug output to remove shared password/key material by + default; all key information can be included with -K command line + argument to match the previous behavior + * added support for timestamping debug log messages (disabled by + default, can be enabled with -t command line argument) + * set pairwise/group cipher suite for non-WPA IEEE 802.1X to WEP-104 + if keys are not configured to be used; this fixes IEEE 802.1X mode + with drivers that use this information to configure whether Privacy + bit can be in Beacon frames (e.g., ndiswrapper) + * avoid clearing driver keys if no keys have been configured since last + key clear request; this seems to improve reliability of group key + handshake for ndiswrapper & NDIS driver which seems to be suffering + of some kind of timing issue when the keys are cleared again after + association + * changed driver interface API: + - WPA_SUPPLICANT_DRIVER_VERSION define can be used to determine which + version is being used (now, this is set to 2; previously, it was + not defined) + - pass pointer to private data structure to all calls + - the new API is not backwards compatible; all in-tree driver + interfaces has been converted to the new API + * added support for controlling multiple interfaces (radios) per + wpa_supplicant process; each interface needs to be listed on the + command line (-c, -i, -D arguments) with -N as a separator + (-cwpa1.conf -iwlan0 -Dhostap -N -cwpa2.conf -iath0 -Dmadwifi) + * added a workaround for EAP servers that incorrectly use same Id for + sequential EAP packets + * changed libpcap/libdnet configuration to use .config variable, + CONFIG_DNET_PCAP, instead of requiring Makefile modification + * improved downgrade attack detection in IE verification of msg 3/4: + verify both WPA and RSN IEs, if present, not only the selected one; + reject the AP if an RSN IE is found in msg 3/4, but not in Beacon or + Probe Response frame, and RSN is enabled in wpa_supplicant + configuration + * fixed WPA msg 3/4 processing to allow Key Data field contain other + IEs than just one WPA IE + * added support for FreeBSD and driver interface for the BSD net80211 + layer (CONFIG_DRIVER_BSD=y in .config); please note that some of the + required kernel mods have not yet been committed + * made EAP workarounds configurable; enabled by default, can be + disabled with network block option eap_workaround=0 + +2004-07-17 - v0.2.4 (beginning of 0.2.x stable releases) + * resolved couple of interoperability issues with EAP-PEAPv1 and + Phase 2 (inner EAP) fragment reassembly + * driver_madwifi: fixed WEP key configuration for IEEE 802.1X when the + AP is using non-zero key index for the unicast key and key index zero + for the broadcast key + * driver_hostap: fixed IEEE 802.1X WEP key updates and + re-authentication by allowing unencrypted EAPOL frames when not using + WPA + * added a new driver interface, 'wext', which uses only standard, + driver independent functionality in Linux wireless extensions; + currently, this can be used only for non-WPA IEEE 802.1X mode, but + eventually, this is to be extended to support full WPA/WPA2 once + Linux wireless extensions get support for this + * added support for mode in which the driver is responsible for AP + scanning and selection; this is disabled by default and can be + enabled with global ap_scan=0 variable in wpa_supplicant.conf; + this mode can be used, e.g., with generic 'wext' driver interface to + use wpa_supplicant as IEEE 802.1X Supplicant with any Linux driver + supporting wireless extensions. + * driver_madwifi: fixed WPA2 configuration and scan_ssid=1 (e.g., + operation with an AP that does not include SSID in the Beacon frames) + * added support for new EAP authentication methods: + EAP-TTLS/EAP-OTP, EAP-PEAPv0/OTP, EAP-PEAPv1/OTP, EAP-OTP + * added support for asking one-time-passwords from frontends (e.g., + wpa_cli); this 'otp' command works otherwise like 'password' command, + but the password is used only once and the frontend will be asked for + a new password whenever a request from authenticator requires a + password; this can be used with both EAP-OTP and EAP-GTC + * changed wpa_cli to automatically re-establish connection so that it + does not need to be re-started when wpa_supplicant is terminated and + started again + * improved user data (identity/password/otp) requests through + frontends: process pending EAPOL packets after getting new + information so that full authentication does not need to be + restarted; in addition, send pending requests again whenever a new + frontend is attached + * changed control frontends to use a new directory for socket files to + make it easier for wpa_cli to automatically select between interfaces + and to provide access control for the control interface; + wpa_supplicant.conf: ctrl_interface is now a path + (/var/run/wpa_supplicant is the recommended path) and + ctrl_interface_group can be used to select which group gets access to + the control interface; + wpa_cli: by default, try to connect to the first interface available + in /var/run/wpa_supplicant; this path can be overridden with -p option + and an interface can be selected with -i option (i.e., in most common + cases, wpa_cli does not need to get any arguments) + * added support for LEAP + * added driver interface for Linux ndiswrapper + * added priority option for network blocks in the configuration file; + this allows networks to be grouped based on priority (the scan + results are searched for matches with network blocks in this order) + +2004-06-20 - v0.2.3 + * sort scan results to improve AP selection + * fixed control interface socket removal for some error cases + * improved scan requesting and authentication timeout + * small improvements/bug fixes for EAP-MSCHAPv2, EAP-PEAP, and + TLS processing + * PEAP version can now be forced with phase1="peapver=<ver>" + (mostly for testing; by default, the highest version supported by + both the Supplicant and Authentication Server is selected + automatically) + * added support for madwifi driver (Atheros ar521x) + * added a workaround for cases where AP sets Install Tx/Rx bit for + WPA Group Key messages when pairwise keys are used (without this, + the Group Key would be used for Tx and the AP would drop frames + from the station) + * added GSM SIM/USIM interface for GSM authentication algorithm for + EAP-SIM; this requires pcsc-lite + * added support for ATMEL AT76C5XXx driver + * fixed IEEE 802.1X WEP key derivation in the case where Authenticator + does not include key data in the EAPOL-Key frame (i.e., part of + EAP keying material is used as data encryption key) + * added support for using plaintext and static WEP networks + (key_mgmt=NONE) + +2004-05-31 - v0.2.2 + * added support for new EAP authentication methods: + EAP-TTLS/EAP-MD5-Challenge + EAP-TTLS/EAP-GTC + EAP-TTLS/EAP-MSCHAPv2 + EAP-TTLS/EAP-TLS + EAP-TTLS/MSCHAPv2 + EAP-TTLS/MSCHAP + EAP-TTLS/PAP + EAP-TTLS/CHAP + EAP-PEAP/TLS + EAP-PEAP/GTC + EAP-PEAP/MD5-Challenge + EAP-GTC + EAP-SIM (not yet complete; needs GSM/SIM authentication interface) + * added support for anonymous identity (to be used when identity is + sent in plaintext; real identity will be used within TLS protected + tunnel (e.g., with EAP-TTLS) + * added event messages from wpa_supplicant to frontends, e.g., wpa_cli + * added support for requesting identity and password information using + control interface; in other words, the password for EAP-PEAP or + EAP-TTLS does not need to be included in the configuration file since + a frontand (e.g., wpa_cli) can ask it from the user + * improved RSN pre-authentication to use a candidate list and process + all candidates from each scan; not only one per scan + * fixed RSN IE and WPA IE capabilities field parsing + * ignore Tx bit in GTK IE when Pairwise keys are used + * avoid making new scan requests during IEEE 802.1X negotiation + * use openssl/libcrypto for MD5 and SHA-1 when compiling wpa_supplicant + with TLS support (this replaces the included implementation with + library code to save about 8 kB since the library code is needed + anyway for TLS) + * fixed WPA-PSK only mode when compiled without IEEE 802.1X support + (i.e., without CONFIG_IEEE8021X_EAPOL=y in .config) + +2004-05-06 - v0.2.1 + * added support for internal IEEE 802.1X (actually, IEEE 802.1aa/D6.1) + Supplicant + - EAPOL state machines for Supplicant [IEEE 802.1aa/D6.1] + - EAP peer state machine [draft-ietf-eap-statemachine-02.pdf] + - EAP-MD5 (cannot be used with WPA-RADIUS) + [draft-ietf-eap-rfc2284bis-09.txt] + - EAP-TLS [RFC 2716] + - EAP-MSCHAPv2 (currently used only with EAP-PEAP) + - EAP-PEAP/MSCHAPv2 [draft-josefsson-pppext-eap-tls-eap-07.txt] + [draft-kamath-pppext-eap-mschapv2-00.txt] + (PEAP version 0, 1, and parts of 2; only 0 and 1 are enabled by + default; tested with FreeRADIUS, Microsoft IAS, and Funk Odyssey) + - new configuration file options: eap, identity, password, ca_cert, + client_cert, privatekey, private_key_passwd + - Xsupplicant is not required anymore, but it can be used by + disabling the internal IEEE 802.1X Supplicant with -e command line + option + - this code is not included in the default build; Makefile need to + be edited for this (uncomment lines for selected functionality) + - EAP-TLS and EAP-PEAP require openssl libraries + * use module prefix in debug messages (WPA, EAP, EAP-TLS, ..) + * added support for non-WPA IEEE 802.1X mode with dynamic WEP keys + (i.e., complete IEEE 802.1X/EAP authentication and use IEEE 802.1X + EAPOL-Key frames instead of WPA key handshakes) + * added support for IEEE 802.11i/RSN (WPA2) + - improved PTK Key Handshake + - PMKSA caching, pre-authentication + * fixed wpa_supplicant to ignore possible extra data after WPA + EAPOL-Key packets (this fixes 'Invalid EAPOL-Key MIC when using + TPTK' error from message 3 of 4-Way Handshake in case the AP + includes extra data after the EAPOL-Key) + * added interface for external programs (frontends) to control + wpa_supplicant + - CLI example (wpa_cli) with interactive mode and command line + mode + - replaced SIGUSR1 status/statistics with the new control interface + * made some feature compile time configurable + - .config file for make + - driver interfaces (hostap, hermes, ..) + - EAPOL/EAP functions + +2004-02-15 - v0.2.0 + * Initial version of wpa_supplicant diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile new file mode 100644 index 000000000000..cb66defac7c8 --- /dev/null +++ b/wpa_supplicant/Makefile @@ -0,0 +1,2074 @@ +BINALL=wpa_supplicant wpa_cli + +ifndef CONFIG_NO_WPA_PASSPHRASE +BINALL += wpa_passphrase +endif + +ALL = $(BINALL) +ALL += systemd/wpa_supplicant.service +ALL += systemd/wpa_supplicant@.service +ALL += systemd/wpa_supplicant-nl80211@.service +ALL += systemd/wpa_supplicant-wired@.service +ALL += dbus/fi.w1.wpa_supplicant1.service +ifdef CONFIG_BUILD_WPA_CLIENT_SO +ALL += libwpa_client.so +endif + +EXTRA_TARGETS=dynamic_eap_methods + +CONFIG_FILE=.config +include ../src/build.rules + +ifdef LIBS +# If LIBS is set with some global build system defaults, clone those for +# LIBS_c and LIBS_p to cover wpa_passphrase and wpa_cli as well. +ifndef LIBS_c +LIBS_c := $(LIBS) +endif +ifndef LIBS_p +LIBS_p := $(LIBS) +endif +endif + +export LIBDIR ?= /usr/local/lib +export INCDIR ?= /usr/local/include +export BINDIR ?= /usr/local/sbin +PKG_CONFIG ?= pkg-config + +CFLAGS += $(EXTRA_CFLAGS) +CFLAGS += -I$(abspath ../src) +CFLAGS += -I$(abspath ../src/utils) + +ifndef CONFIG_NO_GITVER +# Add VERSION_STR postfix for builds from a git repository +ifeq ($(wildcard ../.git),../.git) +GITVER := $(shell git describe --dirty=+) +ifneq ($(GITVER),) +CFLAGS += -DGIT_VERSION_STR_POSTFIX=\"-$(GITVER)\" +endif +endif +endif + +ifdef CONFIG_TESTING_OPTIONS +CFLAGS += -DCONFIG_TESTING_OPTIONS +CONFIG_WPS_TESTING=y +CONFIG_TDLS_TESTING=y +endif + +mkconfig: + @if [ -f .config ]; then \ + echo '.config exists - did not replace it'; \ + exit 1; \ + fi + echo CONFIG_DRIVER_HOSTAP=y >> .config + echo CONFIG_DRIVER_WEXT=y >> .config + +$(DESTDIR)$(BINDIR)/%: % + install -D $(<) $(@) + +install: $(addprefix $(DESTDIR)$(BINDIR)/,$(BINALL)) + $(MAKE) -C ../src install +ifdef CONFIG_BUILD_WPA_CLIENT_SO + install -m 0644 -D libwpa_client.so $(DESTDIR)/$(LIBDIR)/libwpa_client.so + install -m 0644 -D ../src/common/wpa_ctrl.h $(DESTDIR)/$(INCDIR)/wpa_ctrl.h +endif + if ls eap_*.so >/dev/null 2>&1; then \ + install -d $(DESTDIR)$(LIBDIR)/wpa_supplicant && \ + cp *.so $(DESTDIR)$(LIBDIR)/wpa_supplicant \ + ; fi + +ifdef CONFIG_FIPS +CONFIG_NO_RANDOM_POOL= +CONFIG_OPENSSL_CMAC=y +endif + +OBJS = config.o +OBJS += notify.o +OBJS += bss.o +OBJS += eap_register.o +OBJS += ../src/utils/common.o +OBJS += ../src/utils/config.o +OBJS += ../src/utils/wpa_debug.o +OBJS += ../src/utils/wpabuf.o +OBJS += ../src/utils/bitfield.o +OBJS += ../src/utils/ip_addr.o +OBJS += ../src/utils/crc32.o +OBJS += op_classes.o +OBJS += rrm.o +OBJS += twt.o +OBJS += robust_av.o +OBJS_p = wpa_passphrase.o +OBJS_p += ../src/utils/common.o +OBJS_p += ../src/utils/wpa_debug.o +OBJS_p += ../src/utils/wpabuf.o +OBJS_c = wpa_cli.o ../src/common/wpa_ctrl.o +OBJS_c += ../src/utils/wpa_debug.o +OBJS_c += ../src/utils/common.o +OBJS_c += ../src/common/cli.o +OBJS += wmm_ac.o + +ifndef CONFIG_OS +ifdef CONFIG_NATIVE_WINDOWS +CONFIG_OS=win32 +else +CONFIG_OS=unix +endif +endif + +ifeq ($(CONFIG_OS), internal) +CFLAGS += -DOS_NO_C_LIB_DEFINES +endif + +OBJS += ../src/utils/os_$(CONFIG_OS).o +OBJS_p += ../src/utils/os_$(CONFIG_OS).o +OBJS_c += ../src/utils/os_$(CONFIG_OS).o + +ifdef CONFIG_WPA_TRACE +CFLAGS += -DWPA_TRACE +OBJS += ../src/utils/trace.o +OBJS_p += ../src/utils/trace.o +OBJS_c += ../src/utils/trace.o +OBJS_priv += ../src/utils/trace.o +LIBCTRL += ../src/utils/trace.o +LIBCTRLSO += ../src/utils/trace.c +LDFLAGS += -rdynamic +CFLAGS += -funwind-tables +ifdef CONFIG_WPA_TRACE_BFD +CFLAGS += -DPACKAGE="wpa_supplicant" -DWPA_TRACE_BFD +LIBS += -lbfd -ldl -liberty -lz +LIBS_p += -lbfd -ldl -liberty -lz +LIBS_c += -lbfd -ldl -liberty -lz +endif +endif + +ifndef CONFIG_ELOOP +CONFIG_ELOOP=eloop +endif +OBJS += ../src/utils/$(CONFIG_ELOOP).o +OBJS_c += ../src/utils/$(CONFIG_ELOOP).o + +ifndef CONFIG_OSX +ifeq ($(CONFIG_ELOOP), eloop) +# Using glibc < 2.17 requires -lrt for clock_gettime() +# OS X has an alternate implementation +LIBS += -lrt +LIBS_c += -lrt +LIBS_p += -lrt +endif +endif + +ifdef CONFIG_ELOOP_POLL +CFLAGS += -DCONFIG_ELOOP_POLL +endif + +ifdef CONFIG_ELOOP_EPOLL +CFLAGS += -DCONFIG_ELOOP_EPOLL +endif + +ifdef CONFIG_ELOOP_KQUEUE +CFLAGS += -DCONFIG_ELOOP_KQUEUE +endif + +ifdef CONFIG_EAPOL_TEST +CFLAGS += -Werror -DEAPOL_TEST +endif + +ifdef CONFIG_CODE_COVERAGE +CFLAGS += -O0 -fprofile-arcs -ftest-coverage +LIBS += -lgcov +LIBS_c += -lgcov +LIBS_p += -lgcov +endif + +ifdef CONFIG_HT_OVERRIDES +CFLAGS += -DCONFIG_HT_OVERRIDES +endif + +ifdef CONFIG_VHT_OVERRIDES +CFLAGS += -DCONFIG_VHT_OVERRIDES +endif + +ifdef CONFIG_HE_OVERRIDES +CFLAGS += -DCONFIG_HE_OVERRIDES +endif + +ifndef CONFIG_BACKEND +CONFIG_BACKEND=file +endif + +ifeq ($(CONFIG_BACKEND), file) +OBJS += config_file.o +ifndef CONFIG_NO_CONFIG_BLOBS +NEED_BASE64=y +endif +CFLAGS += -DCONFIG_BACKEND_FILE +endif + +ifeq ($(CONFIG_BACKEND), winreg) +OBJS += config_winreg.o +endif + +ifeq ($(CONFIG_BACKEND), none) +OBJS += config_none.o +endif + +ifdef CONFIG_NO_CONFIG_WRITE +CFLAGS += -DCONFIG_NO_CONFIG_WRITE +endif + +ifdef CONFIG_NO_CONFIG_BLOBS +CFLAGS += -DCONFIG_NO_CONFIG_BLOBS +endif + +ifdef CONFIG_NO_SCAN_PROCESSING +CFLAGS += -DCONFIG_NO_SCAN_PROCESSING +endif + +ifdef CONFIG_SUITEB +CFLAGS += -DCONFIG_SUITEB +endif + +ifdef CONFIG_SUITEB192 +CFLAGS += -DCONFIG_SUITEB192 +NEED_SHA384=y +endif + +ifdef CONFIG_OCV +CFLAGS += -DCONFIG_OCV +OBJS += ../src/common/ocv.o +endif + +ifdef CONFIG_IEEE80211R +CFLAGS += -DCONFIG_IEEE80211R +OBJS += ../src/rsn_supp/wpa_ft.o +endif + +ifdef CONFIG_MESH +NEED_80211_COMMON=y +NEED_AES_SIV=y +CONFIG_SAE=y +CONFIG_AP=y +CFLAGS += -DCONFIG_MESH +OBJS += mesh.o +OBJS += mesh_mpm.o +OBJS += mesh_rsn.o +endif + +ifdef CONFIG_SAE +CFLAGS += -DCONFIG_SAE +OBJS += ../src/common/sae.o +ifdef CONFIG_SAE_PK +CFLAGS += -DCONFIG_SAE_PK +OBJS += ../src/common/sae_pk.o +endif +NEED_ECC=y +NEED_DH_GROUPS=y +NEED_HMAC_SHA256_KDF=y +NEED_DRAGONFLY=y +ifdef CONFIG_TESTING_OPTIONS +NEED_DH_GROUPS_ALL=y +endif +endif + +ifdef CONFIG_DPP +CFLAGS += -DCONFIG_DPP +OBJS += ../src/common/dpp.o +OBJS += ../src/common/dpp_auth.o +OBJS += ../src/common/dpp_backup.o +OBJS += ../src/common/dpp_crypto.o +OBJS += ../src/common/dpp_pkex.o +OBJS += ../src/common/dpp_reconfig.o +OBJS += ../src/common/dpp_tcp.o +OBJS += dpp_supplicant.o +NEED_AES_SIV=y +NEED_HMAC_SHA256_KDF=y +NEED_HMAC_SHA384_KDF=y +NEED_HMAC_SHA512_KDF=y +NEED_SHA384=y +NEED_SHA512=y +NEED_ECC=y +NEED_JSON=y +NEED_GAS_SERVER=y +NEED_BASE64=y +NEED_ASN1=y +ifdef CONFIG_DPP2 +CFLAGS += -DCONFIG_DPP2 +endif +ifdef CONFIG_DPP3 +CFLAGS += -DCONFIG_DPP3 +endif +endif + +ifdef CONFIG_OWE +CFLAGS += -DCONFIG_OWE +NEED_ECC=y +NEED_HMAC_SHA256_KDF=y +NEED_HMAC_SHA384_KDF=y +NEED_HMAC_SHA512_KDF=y +NEED_SHA384=y +NEED_SHA512=y +endif + +ifdef CONFIG_FILS +CFLAGS += -DCONFIG_FILS +NEED_SHA384=y +NEED_AES_SIV=y +ifdef CONFIG_FILS_SK_PFS +CFLAGS += -DCONFIG_FILS_SK_PFS +NEED_ECC=y +endif +endif + +ifdef CONFIG_MBO +CONFIG_WNM=y +endif + +ifdef CONFIG_WNM +CFLAGS += -DCONFIG_WNM +OBJS += wnm_sta.o +endif + +ifdef CONFIG_TDLS +CFLAGS += -DCONFIG_TDLS +OBJS += ../src/rsn_supp/tdls.o +endif + +ifdef CONFIG_TDLS_TESTING +CFLAGS += -DCONFIG_TDLS_TESTING +endif + +ifdef CONFIG_PMKSA_CACHE_EXTERNAL +CFLAGS += -DCONFIG_PMKSA_CACHE_EXTERNAL +endif + +ifndef CONFIG_NO_WPA +OBJS += ../src/rsn_supp/wpa.o +OBJS += ../src/rsn_supp/preauth.o +OBJS += ../src/rsn_supp/pmksa_cache.o +OBJS += ../src/rsn_supp/wpa_ie.o +OBJS += ../src/common/wpa_common.o +NEED_AES=y +NEED_SHA1=y +NEED_MD5=y +NEED_RC4=y +else +CFLAGS += -DCONFIG_NO_WPA +ifeq ($(CONFIG_TLS), internal) +NEED_SHA1=y +NEED_MD5=y +endif +endif + +ifdef CONFIG_IBSS_RSN +NEED_RSN_AUTHENTICATOR=y +CFLAGS += -DCONFIG_IBSS_RSN +CFLAGS += -DCONFIG_NO_VLAN +OBJS += ibss_rsn.o +endif + +ifdef CONFIG_MATCH_IFACE +CFLAGS += -DCONFIG_MATCH_IFACE +endif + +ifdef CONFIG_P2P +OBJS += p2p_supplicant.o +OBJS += p2p_supplicant_sd.o +OBJS += ../src/p2p/p2p.o +OBJS += ../src/p2p/p2p_utils.o +OBJS += ../src/p2p/p2p_parse.o +OBJS += ../src/p2p/p2p_build.o +OBJS += ../src/p2p/p2p_go_neg.o +OBJS += ../src/p2p/p2p_sd.o +OBJS += ../src/p2p/p2p_pd.o +OBJS += ../src/p2p/p2p_invitation.o +OBJS += ../src/p2p/p2p_dev_disc.o +OBJS += ../src/p2p/p2p_group.o +OBJS += ../src/ap/p2p_hostapd.o +CFLAGS += -DCONFIG_P2P +NEED_GAS=y +NEED_OFFCHANNEL=y +CONFIG_WPS=y +CONFIG_AP=y +ifdef CONFIG_P2P_STRICT +CFLAGS += -DCONFIG_P2P_STRICT +endif +ifdef CONFIG_WIFI_DISPLAY +CFLAGS += -DCONFIG_WIFI_DISPLAY +OBJS += wifi_display.o +endif +endif + +ifdef CONFIG_PASN +CFLAGS += -DCONFIG_PASN +CFLAGS += -DCONFIG_PTKSA_CACHE +NEED_HMAC_SHA256_KDF=y +NEED_HMAC_SHA384_KDF=y +NEED_SHA256=y +NEED_SHA384=y +OBJS += ../src/common/ptksa_cache.o +OBJS += pasn_supplicant.o +endif + +ifdef CONFIG_HS20 +OBJS += hs20_supplicant.o +CFLAGS += -DCONFIG_HS20 +CONFIG_INTERWORKING=y +endif + +ifdef CONFIG_INTERWORKING +OBJS += interworking.o +CFLAGS += -DCONFIG_INTERWORKING +NEED_GAS=y +endif + +ifdef CONFIG_NO_ROAMING +CFLAGS += -DCONFIG_NO_ROAMING +endif + +include ../src/drivers/drivers.mak +ifdef CONFIG_AP +OBJS_d += $(DRV_BOTH_OBJS) +CFLAGS += $(DRV_BOTH_CFLAGS) +LDFLAGS += $(DRV_BOTH_LDFLAGS) +LIBS += $(DRV_BOTH_LIBS) +else +NEED_AP_MLME= +OBJS_d += $(DRV_WPA_OBJS) +CFLAGS += $(DRV_WPA_CFLAGS) +LDFLAGS += $(DRV_WPA_LDFLAGS) +LIBS += $(DRV_WPA_LIBS) +endif + +ifndef CONFIG_L2_PACKET +CONFIG_L2_PACKET=linux +endif + +OBJS_l2 += ../src/l2_packet/l2_packet_$(CONFIG_L2_PACKET).o + +ifeq ($(CONFIG_L2_PACKET), pcap) +ifdef CONFIG_WINPCAP +CFLAGS += -DCONFIG_WINPCAP +LIBS += -lwpcap -lpacket +LIBS_w += -lwpcap +else +LIBS += -ldnet -lpcap +endif +endif + +ifeq ($(CONFIG_L2_PACKET), winpcap) +LIBS += -lwpcap -lpacket +LIBS_w += -lwpcap +endif + +ifeq ($(CONFIG_L2_PACKET), freebsd) +LIBS += -lpcap +endif + +ifdef CONFIG_ERP +CFLAGS += -DCONFIG_ERP +NEED_HMAC_SHA256_KDF=y +endif + +ifdef CONFIG_EAP_TLS +# EAP-TLS +ifeq ($(CONFIG_EAP_TLS), dyn) +CFLAGS += -DEAP_TLS_DYNAMIC +EAPDYN += eap_tls.so +else +CFLAGS += -DEAP_TLS +OBJS += ../src/eap_peer/eap_tls.o +endif +TLS_FUNCS=y +CONFIG_IEEE8021X_EAPOL=y +endif + +ifdef CONFIG_EAP_UNAUTH_TLS +# EAP-UNAUTH-TLS +CFLAGS += -DEAP_UNAUTH_TLS +ifndef CONFIG_EAP_TLS +OBJS += ../src/eap_peer/eap_tls.o +TLS_FUNCS=y +endif +CONFIG_IEEE8021X_EAPOL=y +endif + +ifdef CONFIG_EAP_PEAP +# EAP-PEAP +SRC_EAP_PEAP = ../src/eap_peer/eap_peap.c ../src/eap_common/eap_peap_common.c +ifeq ($(CONFIG_EAP_PEAP), dyn) +CFLAGS += -DEAP_PEAP_DYNAMIC +EAPDYN += eap_peap.so +else +CFLAGS += -DEAP_PEAP +OBJS += $(patsubst %.c, %.o, $(SRC_EAP_PEAP)) +endif +TLS_FUNCS=y +CONFIG_IEEE8021X_EAPOL=y +endif + +ifdef CONFIG_EAP_TTLS +# EAP-TTLS +ifeq ($(CONFIG_EAP_TTLS), dyn) +CFLAGS += -DEAP_TTLS_DYNAMIC +EAPDYN += eap_ttls.so +else +CFLAGS += -DEAP_TTLS +OBJS += ../src/eap_peer/eap_ttls.o +endif +TLS_FUNCS=y +ifndef CONFIG_FIPS +MS_FUNCS=y +CHAP=y +endif +CONFIG_IEEE8021X_EAPOL=y +endif + +ifdef CONFIG_EAP_MD5 +# EAP-MD5 +ifeq ($(CONFIG_EAP_MD5), dyn) +CFLAGS += -DEAP_MD5_DYNAMIC +EAPDYN += eap_md5.so +else +CFLAGS += -DEAP_MD5 +OBJS += ../src/eap_peer/eap_md5.o +endif +CHAP=y +CONFIG_IEEE8021X_EAPOL=y +endif + +# backwards compatibility for old spelling +ifdef CONFIG_MSCHAPV2 +ifndef CONFIG_EAP_MSCHAPV2 +CONFIG_EAP_MSCHAPV2=y +endif +endif + +ifdef CONFIG_EAP_MSCHAPV2 +# EAP-MSCHAPv2 +SRC_EAP_MSCHAPV2 = ../src/eap_peer/eap_mschapv2.c ../src/eap_peer/mschapv2.c +ifeq ($(CONFIG_EAP_MSCHAPV2), dyn) +CFLAGS += -DEAP_MSCHAPv2_DYNAMIC +EAPDYN += eap_mschapv2.so +else +CFLAGS += -DEAP_MSCHAPv2 +OBJS += $(patsubst %.c, %.o, $(SRC_EAP_MSCHAPV2)) +endif +MS_FUNCS=y +CONFIG_IEEE8021X_EAPOL=y +endif + +ifdef CONFIG_EAP_GTC +# EAP-GTC +ifeq ($(CONFIG_EAP_GTC), dyn) +CFLAGS += -DEAP_GTC_DYNAMIC +EAPDYN += eap_gtc.so +else +CFLAGS += -DEAP_GTC +OBJS += ../src/eap_peer/eap_gtc.o +endif +CONFIG_IEEE8021X_EAPOL=y +endif + +ifdef CONFIG_EAP_OTP +# EAP-OTP +ifeq ($(CONFIG_EAP_OTP), dyn) +CFLAGS += -DEAP_OTP_DYNAMIC +EAPDYN += eap_otp.so +else +CFLAGS += -DEAP_OTP +OBJS += ../src/eap_peer/eap_otp.o +endif +CONFIG_IEEE8021X_EAPOL=y +endif + +ifdef CONFIG_EAP_SIM +# EAP-SIM +ifeq ($(CONFIG_EAP_SIM), dyn) +CFLAGS += -DEAP_SIM_DYNAMIC +EAPDYN += eap_sim.so +else +CFLAGS += -DEAP_SIM +OBJS += ../src/eap_peer/eap_sim.o +endif +CONFIG_IEEE8021X_EAPOL=y +CONFIG_EAP_SIM_COMMON=y +NEED_AES_CBC=y +endif + +ifdef CONFIG_EAP_LEAP +# EAP-LEAP +ifeq ($(CONFIG_EAP_LEAP), dyn) +CFLAGS += -DEAP_LEAP_DYNAMIC +EAPDYN += eap_leap.so +else +CFLAGS += -DEAP_LEAP +OBJS += ../src/eap_peer/eap_leap.o +endif +MS_FUNCS=y +CONFIG_IEEE8021X_EAPOL=y +endif + +ifdef CONFIG_EAP_PSK +# EAP-PSK +SRC_EAP_PSK = ../src/eap_peer/eap_psk.c ../src/eap_common/eap_psk_common.c +ifeq ($(CONFIG_EAP_PSK), dyn) +CFLAGS += -DEAP_PSK_DYNAMIC +EAPDYN += eap_psk.so +else +CFLAGS += -DEAP_PSK +OBJS += $(patsubst %.c, %.o, $(SRC_EAP_PSK)) +endif +CONFIG_IEEE8021X_EAPOL=y +NEED_AES=y +NEED_AES_ENCBLOCK=y +NEED_AES_EAX=y +endif + +ifdef CONFIG_EAP_AKA +# EAP-AKA +ifeq ($(CONFIG_EAP_AKA), dyn) +CFLAGS += -DEAP_AKA_DYNAMIC +EAPDYN += eap_aka.so +else +CFLAGS += -DEAP_AKA +OBJS += ../src/eap_peer/eap_aka.o +endif +CONFIG_IEEE8021X_EAPOL=y +CONFIG_EAP_SIM_COMMON=y +NEED_AES_CBC=y +endif + +ifdef CONFIG_EAP_PROXY +CFLAGS += -DCONFIG_EAP_PROXY +OBJS += ../src/eap_peer/eap_proxy_$(CONFIG_EAP_PROXY).o +include eap_proxy_$(CONFIG_EAP_PROXY).mak +CONFIG_IEEE8021X_EAPOL=y +endif + +ifdef CONFIG_EAP_AKA_PRIME +# EAP-AKA' +ifeq ($(CONFIG_EAP_AKA_PRIME), dyn) +CFLAGS += -DEAP_AKA_PRIME_DYNAMIC +else +CFLAGS += -DEAP_AKA_PRIME +endif +endif + +ifdef CONFIG_EAP_SIM_COMMON +OBJS += ../src/eap_common/eap_sim_common.o +NEED_AES=y +NEED_FIPS186_2_PRF=y +endif + +ifdef CONFIG_EAP_FAST +# EAP-FAST +SRC_EAP_FAST = ../src/eap_peer/eap_fast.c ../src/eap_peer/eap_fast_pac.c +SRC_EAP_FAST += ../src/eap_common/eap_fast_common.c +ifeq ($(CONFIG_EAP_FAST), dyn) +CFLAGS += -DEAP_FAST_DYNAMIC +EAPDYN += eap_fast.so +else +CFLAGS += -DEAP_FAST +OBJS += $(patsubst %.c, %.o, $(SRC_EAP_FAST)) +endif +TLS_FUNCS=y +CONFIG_IEEE8021X_EAPOL=y +NEED_T_PRF=y +endif + +ifdef CONFIG_EAP_TEAP +# EAP-TEAP +SRC_EAP_TEAP = ../src/eap_peer/eap_teap.c ../src/eap_peer/eap_teap_pac.c +SRC_EAP_TEAP += ../src/eap_common/eap_teap_common.c +ifeq ($(CONFIG_EAP_TEAP), dyn) +CFLAGS += -DEAP_TEAP_DYNAMIC +EAPDYN += eap_teap.so +else +CFLAGS += -DEAP_TEAP +OBJS += $(patsubst %.c, %.o, $(SRC_EAP_TEAP)) +endif +TLS_FUNCS=y +CONFIG_IEEE8021X_EAPOL=y +NEED_T_PRF=y +NEED_SHA384=y +NEED_TLS_PRF_SHA256=y +NEED_TLS_PRF_SHA384=y +endif + +ifdef CONFIG_EAP_PAX +# EAP-PAX +SRC_EAP_PAX = ../src/eap_peer/eap_pax.c ../src/eap_common/eap_pax_common.c +ifeq ($(CONFIG_EAP_PAX), dyn) +CFLAGS += -DEAP_PAX_DYNAMIC +EAPDYN += eap_pax.so +else +CFLAGS += -DEAP_PAX +OBJS += $(patsubst %.c, %.o, $(SRC_EAP_PAX)) +endif +CONFIG_IEEE8021X_EAPOL=y +endif + +ifdef CONFIG_EAP_SAKE +# EAP-SAKE +SRC_EAP_SAKE = ../src/eap_peer/eap_sake.c ../src/eap_common/eap_sake_common.c +ifeq ($(CONFIG_EAP_SAKE), dyn) +CFLAGS += -DEAP_SAKE_DYNAMIC +EAPDYN += eap_sake.so +else +CFLAGS += -DEAP_SAKE +OBJS += $(patsubst %.c, %.o, $(SRC_EAP_SAKE)) +endif +CONFIG_IEEE8021X_EAPOL=y +endif + +ifdef CONFIG_EAP_GPSK +# EAP-GPSK +SRC_EAP_GPSK = ../src/eap_peer/eap_gpsk.c ../src/eap_common/eap_gpsk_common.c +ifeq ($(CONFIG_EAP_GPSK), dyn) +CFLAGS += -DEAP_GPSK_DYNAMIC +EAPDYN += eap_gpsk.so +else +CFLAGS += -DEAP_GPSK +OBJS += $(patsubst %.c, %.o, $(SRC_EAP_GPSK)) +endif +CONFIG_IEEE8021X_EAPOL=y +ifdef CONFIG_EAP_GPSK_SHA256 +CFLAGS += -DEAP_GPSK_SHA256 +endif +endif + +ifdef CONFIG_EAP_PWD +CFLAGS += -DEAP_PWD +ifeq ($(CONFIG_TLS), wolfssl) +CFLAGS += -DCONFIG_ECC +endif +OBJS += ../src/eap_peer/eap_pwd.o ../src/eap_common/eap_pwd_common.o +CONFIG_IEEE8021X_EAPOL=y +NEED_ECC=y +NEED_DRAGONFLY=y +endif + +ifdef CONFIG_EAP_EKE +# EAP-EKE +SRC_EAP_EKE = ../src/eap_peer/eap_eke.c ../src/eap_common/eap_eke_common.c +ifeq ($(CONFIG_EAP_EKE), dyn) +CFLAGS += -DEAP_EKE_DYNAMIC +EAPDYN += eap_eke.so +else +CFLAGS += -DEAP_EKE +OBJS += $(patsubst %.c, %.o, $(SRC_EAP_EKE)) +endif +CONFIG_IEEE8021X_EAPOL=y +NEED_DH_GROUPS=y +NEED_DH_GROUPS_ALL=y +NEED_AES_CBC=y +endif + +ifdef CONFIG_WPS +# EAP-WSC +CFLAGS += -DCONFIG_WPS -DEAP_WSC +OBJS += wps_supplicant.o +OBJS += ../src/utils/uuid.o +OBJS += ../src/eap_peer/eap_wsc.o ../src/eap_common/eap_wsc_common.o +OBJS += ../src/wps/wps.o +OBJS += ../src/wps/wps_common.o +OBJS += ../src/wps/wps_attr_parse.o +OBJS += ../src/wps/wps_attr_build.o +OBJS += ../src/wps/wps_attr_process.o +OBJS += ../src/wps/wps_dev_attr.o +OBJS += ../src/wps/wps_enrollee.o +OBJS += ../src/wps/wps_registrar.o +CONFIG_IEEE8021X_EAPOL=y +NEED_DH_GROUPS=y +NEED_BASE64=y +NEED_AES_CBC=y +NEED_MODEXP=y + +ifdef CONFIG_WPS_NFC +CFLAGS += -DCONFIG_WPS_NFC +OBJS += ../src/wps/ndef.o +NEED_WPS_OOB=y +endif + +ifdef NEED_WPS_OOB +CFLAGS += -DCONFIG_WPS_OOB +endif + +ifdef CONFIG_WPS_ER +CONFIG_WPS_UPNP=y +CFLAGS += -DCONFIG_WPS_ER +OBJS += ../src/wps/wps_er.o +OBJS += ../src/wps/wps_er_ssdp.o +endif + +ifdef CONFIG_WPS_UPNP +CFLAGS += -DCONFIG_WPS_UPNP +OBJS += ../src/wps/wps_upnp.o +OBJS += ../src/wps/wps_upnp_ssdp.o +OBJS += ../src/wps/wps_upnp_web.o +OBJS += ../src/wps/wps_upnp_event.o +OBJS += ../src/wps/wps_upnp_ap.o +OBJS += ../src/wps/upnp_xml.o +OBJS += ../src/wps/httpread.o +OBJS += ../src/wps/http_client.o +OBJS += ../src/wps/http_server.o +endif + +ifdef CONFIG_WPS_STRICT +CFLAGS += -DCONFIG_WPS_STRICT +OBJS += ../src/wps/wps_validate.o +endif + +ifdef CONFIG_WPS_TESTING +CFLAGS += -DCONFIG_WPS_TESTING +endif + +ifdef CONFIG_WPS_REG_DISABLE_OPEN +CFLAGS += -DCONFIG_WPS_REG_DISABLE_OPEN +endif + +endif + +ifdef CONFIG_EAP_IKEV2 +# EAP-IKEv2 +SRC_EAP_IKEV2 = ../src/eap_peer/eap_ikev2.c +SRC_EAP_IKEV2 += ../src/eap_peer/ikev2.c +SRC_EAP_IKEV2 += ../src/eap_common/eap_ikev2_common.c +SRC_EAP_IKEV2 += ../src/eap_common/ikev2_common.c +ifeq ($(CONFIG_EAP_IKEV2), dyn) +CFLAGS += -DEAP_IKEV2_DYNAMIC +EAPDYN += eap_ikev2.so +else +CFLAGS += -DEAP_IKEV2 +OBJS += $(patsubst %.c, %.o, $(SRC_EAP_IKEV2)) +endif +CONFIG_IEEE8021X_EAPOL=y +NEED_DH_GROUPS=y +NEED_DH_GROUPS_ALL=y +NEED_MODEXP=y +NEED_CIPHER=y +endif + +ifdef CONFIG_EAP_VENDOR_TEST +ifeq ($(CONFIG_EAP_VENDOR_TEST), dyn) +CFLAGS += -DEAP_VENDOR_TEST_DYNAMIC +EAPDYN += eap_vendor_test.so +else +CFLAGS += -DEAP_VENDOR_TEST +OBJS += ../src/eap_peer/eap_vendor_test.o +endif +CONFIG_IEEE8021X_EAPOL=y +endif + +ifdef CONFIG_EAP_TNC +# EAP-TNC +CFLAGS += -DEAP_TNC +OBJS += ../src/eap_peer/eap_tnc.o +OBJS += ../src/eap_peer/tncc.o +NEED_BASE64=y +ifndef CONFIG_NATIVE_WINDOWS +ifndef CONFIG_DRIVER_BSD +LIBS += -ldl +endif +endif +endif + +ifdef CONFIG_MACSEC +CFLAGS += -DCONFIG_MACSEC +CONFIG_IEEE8021X_EAPOL=y +NEED_AES_ENCBLOCK=y +NEED_AES_UNWRAP=y +NEED_AES_WRAP=y +OBJS += wpas_kay.o +OBJS += ../src/pae/ieee802_1x_cp.o +OBJS += ../src/pae/ieee802_1x_kay.o +OBJS += ../src/pae/ieee802_1x_key.o +OBJS += ../src/pae/ieee802_1x_secy_ops.o +ifdef CONFIG_AP +OBJS += ../src/ap/wpa_auth_kay.o +endif +endif + +ifdef CONFIG_IEEE8021X_EAPOL +# IEEE 802.1X/EAPOL state machines (e.g., for RADIUS authentication) +CFLAGS += -DIEEE8021X_EAPOL +OBJS += ../src/eapol_supp/eapol_supp_sm.o +OBJS += ../src/eap_peer/eap.o ../src/eap_peer/eap_methods.o +NEED_EAP_COMMON=y +ifdef CONFIG_DYNAMIC_EAP_METHODS +CFLAGS += -DCONFIG_DYNAMIC_EAP_METHODS +LIBS += -ldl -rdynamic +endif +endif + +ifdef CONFIG_AP +NEED_EAP_COMMON=y +NEED_RSN_AUTHENTICATOR=y +CFLAGS += -DCONFIG_AP +OBJS += ap.o +CFLAGS += -DCONFIG_NO_RADIUS +CFLAGS += -DCONFIG_NO_ACCOUNTING +CFLAGS += -DCONFIG_NO_VLAN +OBJS += ../src/ap/hostapd.o +OBJS += ../src/ap/wpa_auth_glue.o +OBJS += ../src/ap/utils.o +OBJS += ../src/ap/authsrv.o +OBJS += ../src/ap/ap_config.o +OBJS += ../src/ap/sta_info.o +OBJS += ../src/ap/tkip_countermeasures.o +OBJS += ../src/ap/ap_mlme.o +OBJS += ../src/ap/ieee802_1x.o +OBJS += ../src/eapol_auth/eapol_auth_sm.o +OBJS += ../src/ap/ieee802_11_auth.o +OBJS += ../src/ap/ieee802_11_shared.o +OBJS += ../src/ap/drv_callbacks.o +OBJS += ../src/ap/ap_drv_ops.o +OBJS += ../src/ap/beacon.o +OBJS += ../src/ap/bss_load.o +OBJS += ../src/ap/eap_user_db.o +OBJS += ../src/ap/neighbor_db.o +OBJS += ../src/ap/rrm.o +OBJS += ../src/ap/ieee802_11_ht.o +ifdef CONFIG_IEEE80211AC +OBJS += ../src/ap/ieee802_11_vht.o +endif +ifdef CONFIG_IEEE80211AX +OBJS += ../src/ap/ieee802_11_he.o +endif +ifdef CONFIG_WNM_AP +CFLAGS += -DCONFIG_WNM_AP +OBJS += ../src/ap/wnm_ap.o +endif +ifdef CONFIG_MBO +OBJS += ../src/ap/mbo_ap.o +endif +ifdef CONFIG_FILS +OBJS += ../src/ap/fils_hlp.o +endif +ifdef CONFIG_CTRL_IFACE +OBJS += ../src/ap/ctrl_iface_ap.o +endif + +CFLAGS += -DEAP_SERVER -DEAP_SERVER_IDENTITY +OBJS += ../src/eap_server/eap_server.o +OBJS += ../src/eap_server/eap_server_identity.o +OBJS += ../src/eap_server/eap_server_methods.o + +ifdef CONFIG_IEEE80211AC +CFLAGS += -DCONFIG_IEEE80211AC +endif +ifdef CONFIG_IEEE80211AX +CFLAGS += -DCONFIG_IEEE80211AX +endif + +ifdef NEED_AP_MLME +OBJS += ../src/ap/wmm.o +OBJS += ../src/ap/ap_list.o +OBJS += ../src/ap/ieee802_11.o +OBJS += ../src/ap/hw_features.o +OBJS += ../src/ap/dfs.o +CFLAGS += -DNEED_AP_MLME +endif +ifdef CONFIG_WPS +CFLAGS += -DEAP_SERVER_WSC +OBJS += ../src/ap/wps_hostapd.o +OBJS += ../src/eap_server/eap_server_wsc.o +endif +ifdef CONFIG_DPP +OBJS += ../src/ap/dpp_hostapd.o +OBJS += ../src/ap/gas_query_ap.o +NEED_AP_GAS_SERV=y +endif +ifdef CONFIG_INTERWORKING +NEED_AP_GAS_SERV=y +endif +ifdef NEED_AP_GAS_SERV +OBJS += ../src/ap/gas_serv.o +endif +ifdef CONFIG_HS20 +OBJS += ../src/ap/hs20.o +endif +endif + +ifdef CONFIG_MBO +OBJS += mbo.o +CFLAGS += -DCONFIG_MBO +endif + +ifdef NEED_RSN_AUTHENTICATOR +CFLAGS += -DCONFIG_NO_RADIUS +NEED_AES_WRAP=y +OBJS += ../src/ap/wpa_auth.o +OBJS += ../src/ap/wpa_auth_ie.o +OBJS += ../src/ap/pmksa_cache_auth.o +endif + +ifdef CONFIG_ACS +CFLAGS += -DCONFIG_ACS +OBJS += ../src/ap/acs.o +LIBS += -lm +endif + +ifdef CONFIG_PCSC +# PC/SC interface for smartcards (USIM, GSM SIM) +CFLAGS += -DPCSC_FUNCS -I/usr/include/PCSC +OBJS += ../src/utils/pcsc_funcs.o +ifdef CONFIG_NATIVE_WINDOWS +#Once MinGW gets support for WinScard, -lwinscard could be used instead of the +#dynamic symbol loading that is now used in pcsc_funcs.c +#LIBS += -lwinscard +else +ifdef CONFIG_OSX +LIBS += -framework PCSC +else +LIBS += $(shell $(PKG_CONFIG) --libs libpcsclite) +endif +endif +endif + +ifdef CONFIG_SIM_SIMULATOR +CFLAGS += -DCONFIG_SIM_SIMULATOR +NEED_MILENAGE=y +endif + +ifdef CONFIG_USIM_SIMULATOR +CFLAGS += -DCONFIG_USIM_SIMULATOR +NEED_MILENAGE=y +endif + +ifdef NEED_MILENAGE +OBJS += ../src/crypto/milenage.o +NEED_AES_ENCBLOCK=y +endif + +ifdef CONFIG_PKCS12 +CFLAGS += -DPKCS12_FUNCS +endif + +ifdef CONFIG_SMARTCARD +CFLAGS += -DCONFIG_SMARTCARD +endif + +ifdef NEED_DRAGONFLY +OBJS += ../src/common/dragonfly.o +endif + +ifdef MS_FUNCS +OBJS += ../src/crypto/ms_funcs.o +NEED_DES=y +NEED_MD4=y +endif + +ifdef CHAP +OBJS += ../src/eap_common/chap.o +endif + +ifdef TLS_FUNCS +NEED_DES=y +# Shared TLS functions (needed for EAP_TLS, EAP_PEAP, EAP_TTLS, EAP_FAST, and +# EAP_TEAP) +OBJS += ../src/eap_peer/eap_tls_common.o +ifndef CONFIG_FIPS +NEED_TLS_PRF=y +NEED_SHA1=y +NEED_MD5=y +endif +endif + +ifndef CONFIG_TLS +CONFIG_TLS=openssl +endif + +ifdef CONFIG_TLSV11 +CFLAGS += -DCONFIG_TLSV11 +endif + +ifdef CONFIG_TLSV12 +CFLAGS += -DCONFIG_TLSV12 +endif + +ifeq ($(CONFIG_TLS), wolfssl) +ifdef TLS_FUNCS +CFLAGS += -DWOLFSSL_DER_LOAD +OBJS += ../src/crypto/tls_wolfssl.o +endif +OBJS += ../src/crypto/crypto_wolfssl.o +OBJS_p += ../src/crypto/crypto_wolfssl.o +ifdef NEED_FIPS186_2_PRF +OBJS += ../src/crypto/fips_prf_wolfssl.o +endif +NEED_TLS_PRF_SHA256=y +LIBS += -lwolfssl -lm +LIBS_p += -lwolfssl -lm +endif + +ifeq ($(CONFIG_TLS), openssl) +ifdef TLS_FUNCS +CFLAGS += -DEAP_TLS_OPENSSL +OBJS += ../src/crypto/tls_openssl.o +OBJS += ../src/crypto/tls_openssl_ocsp.o +LIBS += -lssl +endif +OBJS += ../src/crypto/crypto_openssl.o +OBJS_p += ../src/crypto/crypto_openssl.o +OBJS_priv += ../src/crypto/crypto_openssl.o +ifdef NEED_FIPS186_2_PRF +OBJS += ../src/crypto/fips_prf_openssl.o +endif +NEED_TLS_PRF_SHA256=y +LIBS += -lcrypto +LIBS_p += -lcrypto +ifdef CONFIG_TLS_ADD_DL +LIBS += -ldl +LIBS_p += -ldl +endif +ifndef CONFIG_TLS_DEFAULT_CIPHERS +CONFIG_TLS_DEFAULT_CIPHERS = "DEFAULT:!EXP:!LOW" +endif +CFLAGS += -DTLS_DEFAULT_CIPHERS=\"$(CONFIG_TLS_DEFAULT_CIPHERS)\" +endif + +ifeq ($(CONFIG_TLS), gnutls) +ifndef CONFIG_CRYPTO +# default to libgcrypt +CONFIG_CRYPTO=gnutls +endif +ifdef TLS_FUNCS +OBJS += ../src/crypto/tls_gnutls.o +LIBS += -lgnutls -lgpg-error +endif +OBJS += ../src/crypto/crypto_$(CONFIG_CRYPTO).o +OBJS_p += ../src/crypto/crypto_$(CONFIG_CRYPTO).o +OBJS_priv += ../src/crypto/crypto_$(CONFIG_CRYPTO).o +ifdef NEED_FIPS186_2_PRF +OBJS += ../src/crypto/fips_prf_internal.o +SHA1OBJS += ../src/crypto/sha1-internal.o +endif +ifeq ($(CONFIG_CRYPTO), gnutls) +LIBS += -lgcrypt +LIBS_p += -lgcrypt +CONFIG_INTERNAL_RC4=y +CONFIG_INTERNAL_DH_GROUP5=y +endif +ifeq ($(CONFIG_CRYPTO), nettle) +LIBS += -lnettle -lgmp +LIBS_p += -lnettle -lgmp +CONFIG_INTERNAL_RC4=y +CONFIG_INTERNAL_DH_GROUP5=y +endif +endif + +ifeq ($(CONFIG_TLS), internal) +ifndef CONFIG_CRYPTO +CONFIG_CRYPTO=internal +endif +ifdef TLS_FUNCS +OBJS += ../src/crypto/crypto_internal-rsa.o +OBJS += ../src/crypto/tls_internal.o +OBJS += ../src/tls/tlsv1_common.o +OBJS += ../src/tls/tlsv1_record.o +OBJS += ../src/tls/tlsv1_cred.o +OBJS += ../src/tls/tlsv1_client.o +OBJS += ../src/tls/tlsv1_client_write.o +OBJS += ../src/tls/tlsv1_client_read.o +OBJS += ../src/tls/tlsv1_client_ocsp.o +OBJS += ../src/tls/rsa.o +OBJS += ../src/tls/x509v3.o +OBJS += ../src/tls/pkcs1.o +OBJS += ../src/tls/pkcs5.o +OBJS += ../src/tls/pkcs8.o +NEED_ASN1=y +NEED_BASE64=y +NEED_TLS_PRF=y +ifdef CONFIG_TLSV12 +NEED_TLS_PRF_SHA256=y +endif +NEED_MODEXP=y +NEED_CIPHER=y +CFLAGS += -DCONFIG_TLS_INTERNAL_CLIENT +endif +ifdef NEED_CIPHER +NEED_DES=y +OBJS += ../src/crypto/crypto_internal-cipher.o +endif +ifdef NEED_MODEXP +OBJS += ../src/crypto/crypto_internal-modexp.o +OBJS += ../src/tls/bignum.o +endif +ifeq ($(CONFIG_CRYPTO), libtomcrypt) +OBJS += ../src/crypto/crypto_libtomcrypt.o +OBJS_p += ../src/crypto/crypto_libtomcrypt.o +LIBS += -ltomcrypt -ltfm +LIBS_p += -ltomcrypt -ltfm +CONFIG_INTERNAL_SHA256=y +CONFIG_INTERNAL_RC4=y +CONFIG_INTERNAL_DH_GROUP5=y +endif +ifeq ($(CONFIG_CRYPTO), internal) +OBJS += ../src/crypto/crypto_internal.o +OBJS_p += ../src/crypto/crypto_internal.o +NEED_AES_ENC=y +CFLAGS += -DCONFIG_CRYPTO_INTERNAL +ifdef CONFIG_INTERNAL_LIBTOMMATH +CFLAGS += -DCONFIG_INTERNAL_LIBTOMMATH +ifdef CONFIG_INTERNAL_LIBTOMMATH_FAST +CFLAGS += -DLTM_FAST +endif +else +LIBS += -ltommath +LIBS_p += -ltommath +endif +CONFIG_INTERNAL_AES=y +CONFIG_INTERNAL_DES=y +CONFIG_INTERNAL_SHA1=y +CONFIG_INTERNAL_MD4=y +CONFIG_INTERNAL_MD5=y +CONFIG_INTERNAL_SHA256=y +CONFIG_INTERNAL_SHA384=y +CONFIG_INTERNAL_SHA512=y +CONFIG_INTERNAL_RC4=y +CONFIG_INTERNAL_DH_GROUP5=y +endif +ifeq ($(CONFIG_CRYPTO), cryptoapi) +OBJS += ../src/crypto/crypto_cryptoapi.o +OBJS_p += ../src/crypto/crypto_cryptoapi.o +CFLAGS += -DCONFIG_CRYPTO_CRYPTOAPI +CONFIG_INTERNAL_SHA256=y +CONFIG_INTERNAL_RC4=y +endif +endif + +ifeq ($(CONFIG_TLS), linux) +OBJS += ../src/crypto/crypto_linux.o +OBJS_p += ../src/crypto/crypto_linux.o +ifdef TLS_FUNCS +OBJS += ../src/crypto/crypto_internal-rsa.o +OBJS += ../src/crypto/tls_internal.o +OBJS += ../src/tls/tlsv1_common.o +OBJS += ../src/tls/tlsv1_record.o +OBJS += ../src/tls/tlsv1_cred.o +OBJS += ../src/tls/tlsv1_client.o +OBJS += ../src/tls/tlsv1_client_write.o +OBJS += ../src/tls/tlsv1_client_read.o +OBJS += ../src/tls/tlsv1_client_ocsp.o +OBJS += ../src/tls/rsa.o +OBJS += ../src/tls/x509v3.o +OBJS += ../src/tls/pkcs1.o +OBJS += ../src/tls/pkcs5.o +OBJS += ../src/tls/pkcs8.o +NEED_ASN1=y +NEED_BASE64=y +NEED_TLS_PRF=y +ifdef CONFIG_TLSV12 +NEED_TLS_PRF_SHA256=y +endif +NEED_MODEXP=y +NEED_CIPHER=y +CFLAGS += -DCONFIG_TLS_INTERNAL_CLIENT +endif +ifdef NEED_MODEXP +OBJS += ../src/crypto/crypto_internal-modexp.o +OBJS += ../src/tls/bignum.o +CFLAGS += -DCONFIG_INTERNAL_LIBTOMMATH +CFLAGS += -DLTM_FAST +endif +CONFIG_INTERNAL_DH_GROUP5=y +ifdef NEED_FIPS186_2_PRF +OBJS += ../src/crypto/fips_prf_internal.o +OBJS += ../src/crypto/sha1-internal.o +endif +endif + +ifeq ($(CONFIG_TLS), none) +ifdef TLS_FUNCS +OBJS += ../src/crypto/tls_none.o +CFLAGS += -DEAP_TLS_NONE +CONFIG_INTERNAL_AES=y +CONFIG_INTERNAL_SHA1=y +CONFIG_INTERNAL_MD5=y +endif +OBJS += ../src/crypto/crypto_none.o +OBJS_p += ../src/crypto/crypto_none.o +CONFIG_INTERNAL_SHA256=y +CONFIG_INTERNAL_RC4=y +endif + +ifdef TLS_FUNCS +ifdef CONFIG_SMARTCARD +ifndef CONFIG_NATIVE_WINDOWS +ifneq ($(CONFIG_L2_PACKET), freebsd) +LIBS += -ldl +endif +endif +endif +endif + +ifndef TLS_FUNCS +OBJS += ../src/crypto/tls_none.o +ifeq ($(CONFIG_TLS), internal) +CONFIG_INTERNAL_AES=y +CONFIG_INTERNAL_SHA1=y +CONFIG_INTERNAL_MD5=y +CONFIG_INTERNAL_RC4=y +endif +endif + +AESOBJS = # none so far (see below) +ifdef CONFIG_INTERNAL_AES +AESOBJS += ../src/crypto/aes-internal.o ../src/crypto/aes-internal-dec.o +endif + +ifneq ($(CONFIG_TLS), openssl) +ifneq ($(CONFIG_TLS), wolfssl) +NEED_INTERNAL_AES_WRAP=y +endif +endif +ifdef CONFIG_OPENSSL_INTERNAL_AES_WRAP +# Seems to be needed at least with BoringSSL +NEED_INTERNAL_AES_WRAP=y +CFLAGS += -DCONFIG_OPENSSL_INTERNAL_AES_WRAP +endif +ifdef CONFIG_FIPS +# Have to use internal AES key wrap routines to use OpenSSL EVP since the +# OpenSSL AES_wrap_key()/AES_unwrap_key() API is not available in FIPS mode. +NEED_INTERNAL_AES_WRAP=y +endif + +ifdef NEED_INTERNAL_AES_WRAP +ifneq ($(CONFIG_TLS), linux) +AESOBJS += ../src/crypto/aes-unwrap.o +endif +endif +ifdef NEED_AES_EAX +AESOBJS += ../src/crypto/aes-eax.o +NEED_AES_CTR=y +endif +ifdef NEED_AES_SIV +AESOBJS += ../src/crypto/aes-siv.o +NEED_AES_CTR=y +endif +ifdef NEED_AES_CTR +AESOBJS += ../src/crypto/aes-ctr.o +endif +ifdef NEED_AES_ENCBLOCK +AESOBJS += ../src/crypto/aes-encblock.o +endif +NEED_AES_ENC=y +ifdef CONFIG_OPENSSL_CMAC +CFLAGS += -DCONFIG_OPENSSL_CMAC +else +ifneq ($(CONFIG_TLS), linux) +ifneq ($(CONFIG_TLS), wolfssl) +AESOBJS += ../src/crypto/aes-omac1.o +endif +endif +endif +ifdef NEED_AES_WRAP +NEED_AES_ENC=y +ifdef NEED_INTERNAL_AES_WRAP +AESOBJS += ../src/crypto/aes-wrap.o +endif +endif +ifdef NEED_AES_CBC +NEED_AES_ENC=y +ifneq ($(CONFIG_TLS), openssl) +ifneq ($(CONFIG_TLS), linux) +ifneq ($(CONFIG_TLS), wolfssl) +AESOBJS += ../src/crypto/aes-cbc.o +endif +endif +endif +endif +ifdef NEED_AES_ENC +ifdef CONFIG_INTERNAL_AES +AESOBJS += ../src/crypto/aes-internal-enc.o +endif +endif +ifdef NEED_AES +OBJS += $(AESOBJS) +endif + +ifdef NEED_SHA1 +ifneq ($(CONFIG_TLS), openssl) +ifneq ($(CONFIG_TLS), linux) +ifneq ($(CONFIG_TLS), gnutls) +ifneq ($(CONFIG_TLS), wolfssl) +SHA1OBJS += ../src/crypto/sha1.o +endif +endif +endif +endif +SHA1OBJS += ../src/crypto/sha1-prf.o +ifdef CONFIG_INTERNAL_SHA1 +SHA1OBJS += ../src/crypto/sha1-internal.o +ifdef NEED_FIPS186_2_PRF +SHA1OBJS += ../src/crypto/fips_prf_internal.o +endif +endif +ifdef CONFIG_NO_WPA_PASSPHRASE +CFLAGS += -DCONFIG_NO_PBKDF2 +else +ifneq ($(CONFIG_TLS), openssl) +ifneq ($(CONFIG_TLS), wolfssl) +SHA1OBJS += ../src/crypto/sha1-pbkdf2.o +endif +endif +endif +ifdef NEED_T_PRF +SHA1OBJS += ../src/crypto/sha1-tprf.o +endif +ifdef NEED_TLS_PRF +SHA1OBJS += ../src/crypto/sha1-tlsprf.o +endif +endif + +ifndef CONFIG_FIPS +ifneq ($(CONFIG_TLS), openssl) +ifneq ($(CONFIG_TLS), linux) +ifneq ($(CONFIG_TLS), gnutls) +ifneq ($(CONFIG_TLS), wolfssl) +MD5OBJS += ../src/crypto/md5.o +endif +endif +endif +endif +endif +ifdef NEED_MD5 +ifdef CONFIG_INTERNAL_MD5 +MD5OBJS += ../src/crypto/md5-internal.o +endif +OBJS += $(MD5OBJS) +OBJS_p += $(MD5OBJS) +OBJS_priv += $(MD5OBJS) +endif + +ifdef NEED_MD4 +ifdef CONFIG_INTERNAL_MD4 +OBJS += ../src/crypto/md4-internal.o +endif +endif + +DESOBJS = # none needed when not internal +ifdef NEED_DES +ifndef CONFIG_FIPS +CFLAGS += -DCONFIG_DES +endif +ifdef CONFIG_INTERNAL_DES +DESOBJS += ../src/crypto/des-internal.o +endif +endif + +ifdef CONFIG_NO_RC4 +CFLAGS += -DCONFIG_NO_RC4 +endif + +ifdef NEED_RC4 +ifdef CONFIG_INTERNAL_RC4 +ifndef CONFIG_NO_RC4 +OBJS += ../src/crypto/rc4.o +endif +endif +endif + +SHA256OBJS = # none by default +CFLAGS += -DCONFIG_SHA256 +ifneq ($(CONFIG_TLS), openssl) +ifneq ($(CONFIG_TLS), linux) +ifneq ($(CONFIG_TLS), gnutls) +ifneq ($(CONFIG_TLS), wolfssl) +SHA256OBJS += ../src/crypto/sha256.o +endif +endif +endif +endif +SHA256OBJS += ../src/crypto/sha256-prf.o +ifdef CONFIG_INTERNAL_SHA256 +SHA256OBJS += ../src/crypto/sha256-internal.o +endif +ifdef CONFIG_INTERNAL_SHA384 +CFLAGS += -DCONFIG_INTERNAL_SHA384 +SHA256OBJS += ../src/crypto/sha384-internal.o +endif +ifdef CONFIG_INTERNAL_SHA512 +CFLAGS += -DCONFIG_INTERNAL_SHA512 +SHA256OBJS += ../src/crypto/sha512-internal.o +endif +ifdef NEED_TLS_PRF_SHA256 +SHA256OBJS += ../src/crypto/sha256-tlsprf.o +endif +ifdef NEED_TLS_PRF_SHA384 +SHA256OBJS += ../src/crypto/sha384-tlsprf.o +endif +ifdef NEED_HMAC_SHA256_KDF +CFLAGS += -DCONFIG_HMAC_SHA256_KDF +OBJS += ../src/crypto/sha256-kdf.o +endif +ifdef NEED_HMAC_SHA384_KDF +CFLAGS += -DCONFIG_HMAC_SHA384_KDF +OBJS += ../src/crypto/sha384-kdf.o +endif +ifdef NEED_HMAC_SHA512_KDF +CFLAGS += -DCONFIG_HMAC_SHA512_KDF +OBJS += ../src/crypto/sha512-kdf.o +endif +OBJS += $(SHA256OBJS) +ifdef NEED_SHA384 +ifneq ($(CONFIG_TLS), openssl) +ifneq ($(CONFIG_TLS), linux) +ifneq ($(CONFIG_TLS), gnutls) +ifneq ($(CONFIG_TLS), wolfssl) +OBJS += ../src/crypto/sha384.o +endif +endif +endif +endif +CFLAGS += -DCONFIG_SHA384 +OBJS += ../src/crypto/sha384-prf.o +endif +ifdef NEED_SHA512 +ifneq ($(CONFIG_TLS), openssl) +ifneq ($(CONFIG_TLS), linux) +ifneq ($(CONFIG_TLS), gnutls) +ifneq ($(CONFIG_TLS), wolfssl) +OBJS += ../src/crypto/sha512.o +endif +endif +endif +endif +CFLAGS += -DCONFIG_SHA512 +OBJS += ../src/crypto/sha512-prf.o +endif + +ifdef NEED_ASN1 +OBJS += ../src/tls/asn1.o +endif + +ifdef NEED_DH_GROUPS +OBJS += ../src/crypto/dh_groups.o +endif +ifdef NEED_DH_GROUPS_ALL +CFLAGS += -DALL_DH_GROUPS +endif +ifdef CONFIG_INTERNAL_DH_GROUP5 +ifdef NEED_DH_GROUPS +OBJS += ../src/crypto/dh_group5.o +endif +endif + +ifdef NEED_ECC +CFLAGS += -DCONFIG_ECC +endif + +ifdef CONFIG_NO_RANDOM_POOL +CFLAGS += -DCONFIG_NO_RANDOM_POOL +else +ifdef CONFIG_GETRANDOM +CFLAGS += -DCONFIG_GETRANDOM +endif +OBJS += ../src/crypto/random.o +endif + +ifdef CONFIG_CTRL_IFACE +ifeq ($(CONFIG_CTRL_IFACE), y) +ifdef CONFIG_NATIVE_WINDOWS +CONFIG_CTRL_IFACE=named_pipe +else +CONFIG_CTRL_IFACE=unix +endif +endif +CFLAGS += -DCONFIG_CTRL_IFACE +ifeq ($(CONFIG_CTRL_IFACE), unix) +CFLAGS += -DCONFIG_CTRL_IFACE_UNIX +OBJS += ../src/common/ctrl_iface_common.o +endif +ifeq ($(CONFIG_CTRL_IFACE), udp) +CFLAGS += -DCONFIG_CTRL_IFACE_UDP +endif +ifeq ($(CONFIG_CTRL_IFACE), udp6) +CONFIG_CTRL_IFACE=udp +CFLAGS += -DCONFIG_CTRL_IFACE_UDP +CFLAGS += -DCONFIG_CTRL_IFACE_UDP_IPV6 +endif +ifeq ($(CONFIG_CTRL_IFACE), named_pipe) +CFLAGS += -DCONFIG_CTRL_IFACE_NAMED_PIPE +endif +ifeq ($(CONFIG_CTRL_IFACE), udp-remote) +CONFIG_CTRL_IFACE=udp +CFLAGS += -DCONFIG_CTRL_IFACE_UDP +CFLAGS += -DCONFIG_CTRL_IFACE_UDP_REMOTE +endif +ifeq ($(CONFIG_CTRL_IFACE), udp6-remote) +CONFIG_CTRL_IFACE=udp +CFLAGS += -DCONFIG_CTRL_IFACE_UDP +CFLAGS += -DCONFIG_CTRL_IFACE_UDP_REMOTE +CFLAGS += -DCONFIG_CTRL_IFACE_UDP_IPV6 +endif +OBJS += ctrl_iface.o ctrl_iface_$(CONFIG_CTRL_IFACE).o +endif + +ifdef CONFIG_CTRL_IFACE_DBUS_NEW +CFLAGS += -DCONFIG_CTRL_IFACE_DBUS_NEW +OBJS += dbus/dbus_dict_helpers.o +OBJS += dbus/dbus_new_helpers.o +OBJS += dbus/dbus_new.o dbus/dbus_new_handlers.o +OBJS += dbus/dbus_common.o +ifdef CONFIG_WPS +OBJS += dbus/dbus_new_handlers_wps.o +endif +ifdef CONFIG_P2P +OBJS += dbus/dbus_new_handlers_p2p.o +endif +ifndef DBUS_LIBS +DBUS_LIBS := $(shell $(PKG_CONFIG) --libs dbus-1) +endif +ifndef DBUS_INCLUDE +DBUS_INCLUDE := $(shell $(PKG_CONFIG) --cflags dbus-1) +endif +ifdef CONFIG_CTRL_IFACE_DBUS_INTRO +OBJS += dbus/dbus_new_introspect.o +CFLAGS += -DCONFIG_CTRL_IFACE_DBUS_INTRO +endif +CFLAGS += $(DBUS_INCLUDE) +LIBS += $(DBUS_LIBS) +endif + +ifdef CONFIG_READLINE +OBJS_c += ../src/utils/edit_readline.o +LIBS_c += -lreadline -lncurses +else +ifdef CONFIG_WPA_CLI_EDIT +OBJS_c += ../src/utils/edit.o +else +OBJS_c += ../src/utils/edit_simple.o +endif +endif + +ifdef CONFIG_NATIVE_WINDOWS +CFLAGS += -DCONFIG_NATIVE_WINDOWS +LIBS += -lws2_32 -lgdi32 -lcrypt32 +LIBS_c += -lws2_32 +LIBS_p += -lws2_32 -lgdi32 +ifeq ($(CONFIG_CRYPTO), cryptoapi) +LIBS_p += -lcrypt32 +endif +endif + +ifdef CONFIG_NO_STDOUT_DEBUG +CFLAGS += -DCONFIG_NO_STDOUT_DEBUG +ifndef CONFIG_CTRL_IFACE +CFLAGS += -DCONFIG_NO_WPA_MSG +endif +endif + +ifdef CONFIG_IPV6 +# for eapol_test only +CFLAGS += -DCONFIG_IPV6 +endif + +ifdef CONFIG_NO_LINUX_PACKET_SOCKET_WAR +CFLAGS += -DCONFIG_NO_LINUX_PACKET_SOCKET_WAR +endif + +ifdef NEED_BASE64 +OBJS += ../src/utils/base64.o +endif + +ifdef NEED_SME +OBJS += sme.o +CFLAGS += -DCONFIG_SME +endif + +OBJS += ../src/common/ieee802_11_common.o +OBJS += ../src/common/hw_features_common.o + +ifdef NEED_EAP_COMMON +OBJS += ../src/eap_common/eap_common.o +endif + +ifndef CONFIG_MAIN +CONFIG_MAIN=main +endif + +ifdef CONFIG_DEBUG_SYSLOG +CFLAGS += -DCONFIG_DEBUG_SYSLOG +ifdef CONFIG_DEBUG_SYSLOG_FACILITY +CFLAGS += -DLOG_HOSTAPD="$(CONFIG_DEBUG_SYSLOG_FACILITY)" +endif +endif + +ifdef CONFIG_DEBUG_LINUX_TRACING +CFLAGS += -DCONFIG_DEBUG_LINUX_TRACING +endif + +ifdef CONFIG_DEBUG_FILE +CFLAGS += -DCONFIG_DEBUG_FILE +endif + +ifdef CONFIG_DELAYED_MIC_ERROR_REPORT +CFLAGS += -DCONFIG_DELAYED_MIC_ERROR_REPORT +endif + +ifdef CONFIG_FIPS +CFLAGS += -DCONFIG_FIPS +ifneq ($(CONFIG_TLS), openssl) +ifneq ($(CONFIG_TLS), wolfssl) +$(error CONFIG_FIPS=y requires CONFIG_TLS=openssl) +endif +endif +endif + +OBJS += $(SHA1OBJS) $(DESOBJS) + +OBJS_p += $(SHA1OBJS) +OBJS_p += $(SHA256OBJS) +OBJS_priv += $(SHA1OBJS) + +ifdef CONFIG_BGSCAN_SIMPLE +CFLAGS += -DCONFIG_BGSCAN_SIMPLE +OBJS += bgscan_simple.o +NEED_BGSCAN=y +endif + +ifdef CONFIG_BGSCAN_LEARN +CFLAGS += -DCONFIG_BGSCAN_LEARN +OBJS += bgscan_learn.o +NEED_BGSCAN=y +endif + +ifdef NEED_BGSCAN +CFLAGS += -DCONFIG_BGSCAN +OBJS += bgscan.o +endif + +ifdef CONFIG_AUTOSCAN_EXPONENTIAL +CFLAGS += -DCONFIG_AUTOSCAN_EXPONENTIAL +OBJS += autoscan_exponential.o +NEED_AUTOSCAN=y +endif + +ifdef CONFIG_AUTOSCAN_PERIODIC +CFLAGS += -DCONFIG_AUTOSCAN_PERIODIC +OBJS += autoscan_periodic.o +NEED_AUTOSCAN=y +endif + +ifdef NEED_AUTOSCAN +CFLAGS += -DCONFIG_AUTOSCAN +OBJS += autoscan.o +endif + +ifdef CONFIG_EXT_PASSWORD_TEST +OBJS += ../src/utils/ext_password_test.o +CFLAGS += -DCONFIG_EXT_PASSWORD_TEST +NEED_EXT_PASSWORD=y +endif + +ifdef CONFIG_EXT_PASSWORD_FILE +OBJS += ../src/utils/ext_password_file.o +CFLAGS += -DCONFIG_EXT_PASSWORD_FILE +NEED_EXT_PASSWORD=y +endif + +ifdef NEED_EXT_PASSWORD +OBJS += ../src/utils/ext_password.o +CFLAGS += -DCONFIG_EXT_PASSWORD +endif + +ifdef NEED_GAS_SERVER +OBJS += ../src/common/gas_server.o +CFLAGS += -DCONFIG_GAS_SERVER +NEED_GAS=y +endif + +ifdef NEED_GAS +OBJS += ../src/common/gas.o +OBJS += gas_query.o +CFLAGS += -DCONFIG_GAS +NEED_OFFCHANNEL=y +endif + +ifdef NEED_OFFCHANNEL +OBJS += offchannel.o +CFLAGS += -DCONFIG_OFFCHANNEL +endif + +ifdef NEED_JSON +OBJS += ../src/utils/json.o +CFLAGS += -DCONFIG_JSON +endif + +ifdef CONFIG_MODULE_TESTS +CFLAGS += -DCONFIG_MODULE_TESTS +OBJS += wpas_module_tests.o +OBJS += ../src/utils/utils_module_tests.o +OBJS += ../src/common/common_module_tests.o +OBJS += ../src/crypto/crypto_module_tests.o +ifdef CONFIG_WPS +OBJS += ../src/wps/wps_module_tests.o +endif +endif + +OBJS += ../src/drivers/driver_common.o +OBJS_priv += ../src/drivers/driver_common.o + +OBJS += wpa_supplicant.o events.o bssid_ignore.o wpas_glue.o scan.o +OBJS_t := $(OBJS) $(OBJS_l2) eapol_test.o +OBJS_t += ../src/radius/radius_client.o +OBJS_t += ../src/radius/radius.o +OBJS_t2 := $(OBJS) $(OBJS_l2) preauth_test.o + +OBJS_nfc := $(OBJS) $(OBJS_l2) nfc_pw_token.o +OBJS_nfc += $(OBJS_d) ../src/drivers/drivers.o + +OBJS += $(CONFIG_MAIN).o + +ifdef CONFIG_PRIVSEP +OBJS_priv += $(OBJS_d) ../src/drivers/drivers.o +OBJS_priv += $(OBJS_l2) +OBJS_priv += ../src/utils/os_$(CONFIG_OS).o +OBJS_priv += ../src/utils/$(CONFIG_ELOOP).o +OBJS_priv += ../src/utils/common.o +OBJS_priv += ../src/utils/wpa_debug.o +OBJS_priv += ../src/utils/wpabuf.o +OBJS_priv += wpa_priv.o +ifdef CONFIG_DRIVER_NL80211 +OBJS_priv += ../src/common/ieee802_11_common.o +endif +OBJS += ../src/l2_packet/l2_packet_privsep.o +OBJS += ../src/drivers/driver_privsep.o +EXTRA_progs += wpa_priv +else +OBJS += $(OBJS_d) ../src/drivers/drivers.o +OBJS += $(OBJS_l2) +endif + +ifdef CONFIG_NDIS_EVENTS_INTEGRATED +CFLAGS += -DCONFIG_NDIS_EVENTS_INTEGRATED +OBJS += ../src/drivers/ndis_events.o +EXTRALIBS += -loleaut32 -lole32 -luuid +ifdef PLATFORMSDKLIB +EXTRALIBS += $(PLATFORMSDKLIB)/WbemUuid.Lib +else +EXTRALIBS += WbemUuid.Lib +endif +endif + +ifdef CONFIG_FST +CFLAGS += -DCONFIG_FST +ifdef CONFIG_FST_TEST +CFLAGS += -DCONFIG_FST_TEST +endif +FST_OBJS += ../src/fst/fst.o +FST_OBJS += ../src/fst/fst_session.o +FST_OBJS += ../src/fst/fst_iface.o +FST_OBJS += ../src/fst/fst_group.o +FST_OBJS += ../src/fst/fst_ctrl_aux.o +ifdef CONFIG_CTRL_IFACE +FST_OBJS += ../src/fst/fst_ctrl_iface.o +endif +OBJS += $(FST_OBJS) +OBJS_t += $(FST_OBJS) +OBJS_t2 += $(FST_OBJS) +OBJS_nfc += $(FST_OBJS) +endif + +ifdef CONFIG_WEP +CFLAGS += -DCONFIG_WEP +endif + +ifdef CONFIG_NO_TKIP +CFLAGS += -DCONFIG_NO_TKIP +endif + +dynamic_eap_methods: $(EAPDYN) + +_OBJS_VAR := OBJS_priv +include ../src/objs.mk +wpa_priv: $(BCHECK) $(OBJS_priv) + $(Q)$(LDO) $(LDFLAGS) -o wpa_priv $(OBJS_priv) $(LIBS) + @$(E) " LD " $@ + +_OBJS_VAR := OBJS +include ../src/objs.mk +wpa_supplicant: $(BCHECK) $(OBJS) $(EXTRA_progs) + $(Q)$(LDO) $(LDFLAGS) -o wpa_supplicant $(OBJS) $(LIBS) $(EXTRALIBS) + @$(E) " LD " $@ + +_OBJS_VAR := OBJS_t +include ../src/objs.mk +eapol_test: $(OBJS_t) + $(Q)$(LDO) $(LDFLAGS) -o eapol_test $(OBJS_t) $(LIBS) + @$(E) " LD " $@ + +_OBJS_VAR := OBJS_t2 +include ../src/objs.mk +preauth_test: $(OBJS_t2) + $(Q)$(LDO) $(LDFLAGS) -o preauth_test $(OBJS_t2) $(LIBS) + @$(E) " LD " $@ + +_OBJS_VAR := OBJS_p +include ../src/objs.mk +wpa_passphrase: $(OBJS_p) + $(Q)$(LDO) $(LDFLAGS) -o wpa_passphrase $(OBJS_p) $(LIBS_p) $(LIBS) + @$(E) " LD " $@ + +_OBJS_VAR := OBJS_c +include ../src/objs.mk +wpa_cli: $(OBJS_c) + $(Q)$(LDO) $(LDFLAGS) -o wpa_cli $(OBJS_c) $(LIBS_c) + @$(E) " LD " $@ + +LIBCTRL += ../src/common/wpa_ctrl.o +LIBCTRL += ../src/utils/os_$(CONFIG_OS).o +LIBCTRL += ../src/utils/common.o +LIBCTRL += ../src/utils/wpa_debug.o +LIBCTRLSO += ../src/common/wpa_ctrl.c +LIBCTRLSO += ../src/utils/os_$(CONFIG_OS).c +LIBCTRLSO += ../src/utils/common.c +LIBCTRLSO += ../src/utils/wpa_debug.c + +_OBJS_VAR := LIBCTRL +include ../src/objs.mk +libwpa_client.a: $(LIBCTRL) + $(Q)rm -f $@ + $(Q)$(AR) crs $@ $? + @$(E) " AR " $@ + +libwpa_client.so: $(LIBCTRLSO) + @$(E) " CC $@ ($^)" + $(Q)$(CC) $(LDFLAGS) -o $@ $(CFLAGS) -shared -fPIC $^ + +OBJS_wpatest := libwpa_test.o +_OBJS_VAR := OBJS_wpatest +include ../src/objs.mk +libwpa_test1: $(OBJS_wpatest) libwpa_client.a + $(Q)$(LDO) $(LDFLAGS) -o libwpa_test1 $(OBJS_wpatest) libwpa_client.a $(LIBS_c) + @$(E) " LD " $@ + +libwpa_test2: $(OBJS_wpatest) libwpa_client.so + $(Q)$(LDO) $(LDFLAGS) -o libwpa_test2 $(OBJS_wpatest) -L. -lwpa_client $(LIBS_c) + @$(E) " LD " $@ + +_OBJS_VAR := OBJS_nfc +include ../src/objs.mk +nfc_pw_token: $(OBJS_nfc) + $(Q)$(LDO) $(LDFLAGS) -o nfc_pw_token $(OBJS_nfc) $(LIBS) + @$(E) " LD " $@ + +win_if_list: win_if_list.c + $(Q)$(LDO) $(LDFLAGS) -o $@ win_if_list.c $(CFLAGS) $(LIBS_w) + @$(E) " LD " $@ + +eap_psk.so: $(SRC_EAP_PSK) + $(Q)$(CC) $(LDFLAGS) -o $@ $(CFLAGS) -shared -rdynamic -fPIC $^ \ + -Deap_peer_psk_register=eap_peer_method_dynamic_init + @$(E) " CC/LD " $@ + +eap_pax.so: $(SRC_EAP_PAX) + $(Q)$(CC) $(LDFLAGS) -o $@ $(CFLAGS) -shared -rdynamic -fPIC $^ \ + -D$(@F:eap_%.so=eap_peer_%)_register=eap_peer_method_dynamic_init + @$(E) " CC/LD " $@ + +eap_peap.so: $(SRC_EAP_PEAP) + $(Q)$(CC) $(LDFLAGS) -o $@ $(CFLAGS) -shared -rdynamic -fPIC $^ \ + -D$(@F:eap_%.so=eap_peer_%)_register=eap_peer_method_dynamic_init + @$(E) " CC/LD " $@ + +eap_sake.so: $(SRC_EAP_SAKE) + $(Q)$(CC) $(LDFLAGS) -o $@ $(CFLAGS) -shared -rdynamic -fPIC $^ \ + -D$(@F:eap_%.so=eap_peer_%)_register=eap_peer_method_dynamic_init + @$(E) " CC/LD " $@ + +eap_ikev2.so: $(SRC_EAP_IKEV2) + $(Q)$(CC) $(LDFLAGS) -o $@ $(CFLAGS) -shared -rdynamic -fPIC $^ \ + -D$(@F:eap_%.so=eap_peer_%)_register=eap_peer_method_dynamic_init + @$(E) " CC/LD " $@ + +eap_eke.so: $(SRC_EAP_EKE) + $(Q)$(CC) $(LDFLAGS) -o $@ $(CFLAGS) -shared -rdynamic -fPIC $^ \ + -D$(@F:eap_%.so=eap_peer_%)_register=eap_peer_method_dynamic_init + @$(E) " CC/LD " $@ + +eap_mschapv2.so: $(SRC_EAP_MSCHAPV2) + $(Q)$(CC) $(LDFLAGS) -o $@ $(CFLAGS) -shared -rdynamic -fPIC $^ \ + -D$(@F:eap_%.so=eap_peer_%)_register=eap_peer_method_dynamic_init + @$(E) " CC/LD " $@ + +eap_fast.so: $(SRC_EAP_FAST) + $(Q)$(CC) $(LDFLAGS) -o $@ $(CFLAGS) -shared -rdynamic -fPIC $^ \ + -D$(@F:eap_%.so=eap_peer_%)_register=eap_peer_method_dynamic_init + @$(E) " CC/LD " $@ + +eap_teap.so: $(SRC_EAP_TEAP) + $(Q)$(CC) $(LDFLAGS) -o $@ $(CFLAGS) -shared -rdynamic -fPIC $^ \ + -D$(@F:eap_%.so=eap_peer_%)_register=eap_peer_method_dynamic_init + @$(E) " CC/LD " $@ + +eap_gpsk.so: $(SRC_EAP_GPSK) + $(Q)$(CC) $(LDFLAGS) -o $@ $(CFLAGS) -shared -rdynamic -fPIC $^ \ + -D$(@F:eap_%.so=eap_peer_%)_register=eap_peer_method_dynamic_init + @$(E) " CC/LD " $@ + +%.so: ../src/eap_peer/%.c + $(Q)$(CC) $(LDFLAGS) -o $@ $(CFLAGS) -shared -rdynamic -fPIC $< \ + -D$(*F:eap_%=eap_peer_%)_register=eap_peer_method_dynamic_init + @$(E) " CC/LD " $@ + +%.service: %.service.in + $(Q)sed -e 's|\@BINDIR\@|$(BINDIR)|g' $< >$@ + @$(E) " sed" $< + +%@.service: %.service.arg.in + $(Q)sed -e 's|\@BINDIR\@|$(BINDIR)|g' $< >$@ + @$(E) " sed" $< + +wpa_supplicant.exe: wpa_supplicant + mv -f $< $@ +wpa_cli.exe: wpa_cli + mv -f $< $@ +wpa_passphrase.exe: wpa_passphrase + mv -f $< $@ +win_if_list.exe: win_if_list + mv -f $< $@ +eapol_test.exe: eapol_test + mv -f $< $@ + +WINALL=wpa_supplicant.exe wpa_cli.exe wpa_passphrase.exe win_if_list.exe + +windows-bin: $(WINALL) + $(STRIP) $(WINALL) + +wpa_gui: + @echo "wpa_gui has been removed - see wpa_gui-qt4 for replacement" + +wpa_gui-qt4/Makefile: + qmake -o wpa_gui-qt4/Makefile wpa_gui-qt4/wpa_gui.pro + +wpa_gui-qt4/lang/wpa_gui_de.qm: wpa_gui-qt4/lang/wpa_gui_de.ts + lrelease wpa_gui-qt4/wpa_gui.pro + +wpa_gui-qt4: wpa_gui-qt4/Makefile wpa_gui-qt4/lang/wpa_gui_de.qm + $(MAKE) -C wpa_gui-qt4 + +FIPSDIR=/usr/local/ssl/fips-2.0 +FIPSLD=$(FIPSDIR)/bin/fipsld +fips: + $(MAKE) CC=$(FIPSLD) FIPSLD_CC="$(CC)" + +.PHONY: lcov-html +lcov-html: $(call BUILDOBJ,wpa_supplicant.gcda) + lcov -c -d $(BUILDDIR) > lcov.info + genhtml lcov.info --output-directory lcov-html + +clean: common-clean + $(MAKE) -C ../src clean + $(MAKE) -C dbus clean + rm -f core *~ *.o *.d *.gcno *.gcda *.gcov + rm -f eap_*.so $(WINALL) eapol_test preauth_test + rm -f wpa_priv + rm -f nfc_pw_token + rm -f lcov.info + rm -rf lcov-html + rm -f libwpa_client.a + rm -f libwpa_client.so + rm -f libwpa_test1 libwpa_test2 diff --git a/wpa_supplicant/README b/wpa_supplicant/README new file mode 100644 index 000000000000..c643b2684700 --- /dev/null +++ b/wpa_supplicant/README @@ -0,0 +1,1163 @@ +wpa_supplicant +============== + +Copyright (c) 2003-2022, Jouni Malinen <j@w1.fi> and contributors +All Rights Reserved. + +This program is licensed under the BSD license (the one with +advertisement clause removed). + +If you are submitting changes to the project, please see CONTRIBUTIONS +file for more instructions. + + + +License +------- + +This software may be distributed, used, and modified under the terms of +BSD license: + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +3. Neither the name(s) of the above-listed copyright holder(s) nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + +Features +-------- + +Supported WPA/IEEE 802.11i features: +- WPA-PSK ("WPA-Personal") +- WPA with EAP (e.g., with RADIUS authentication server) ("WPA-Enterprise") + Following authentication methods are supported with an integrate IEEE 802.1X + Supplicant: + * EAP-TLS + * EAP-PEAP/MSCHAPv2 (both PEAPv0 and PEAPv1) + * EAP-PEAP/TLS (both PEAPv0 and PEAPv1) + * EAP-PEAP/GTC (both PEAPv0 and PEAPv1) + * EAP-PEAP/OTP (both PEAPv0 and PEAPv1) + * EAP-PEAP/MD5-Challenge (both PEAPv0 and PEAPv1) + * EAP-TTLS/EAP-MD5-Challenge + * EAP-TTLS/EAP-GTC + * EAP-TTLS/EAP-OTP + * EAP-TTLS/EAP-MSCHAPv2 + * EAP-TTLS/EAP-TLS + * EAP-TTLS/MSCHAPv2 + * EAP-TTLS/MSCHAP + * EAP-TTLS/PAP + * EAP-TTLS/CHAP + * EAP-SIM + * EAP-AKA + * EAP-AKA' + * EAP-PSK + * EAP-PAX + * EAP-SAKE + * EAP-IKEv2 + * EAP-GPSK + * EAP-pwd + * LEAP (note: requires special support from the driver for IEEE 802.11 + authentication) + (following methods are supported, but since they do not generate keying + material, they cannot be used with WPA or IEEE 802.1X WEP keying) + * EAP-MD5-Challenge + * EAP-MSCHAPv2 + * EAP-GTC + * EAP-OTP +- key management for CCMP, TKIP, WEP104, WEP40 +- RSN/WPA2 (IEEE 802.11i) + * pre-authentication + * PMKSA caching + +Supported TLS/crypto libraries: +- OpenSSL (default) +- GnuTLS + +Internal TLS/crypto implementation (optional): +- can be used in place of an external TLS/crypto library +- TLSv1 +- X.509 certificate processing +- PKCS #1 +- ASN.1 +- RSA +- bignum +- minimal size (ca. 50 kB binary, parts of which are already needed for WPA; + TLSv1/X.509/ASN.1/RSA/bignum parts are about 25 kB on x86) + + +Requirements +------------ + +Current hardware/software requirements: +- Linux kernel 2.4.x or 2.6.x with Linux Wireless Extensions v15 or newer +- FreeBSD 6-CURRENT +- NetBSD-current +- Microsoft Windows with WinPcap (at least WinXP, may work with other versions) +- drivers: + Linux drivers that support cfg80211/nl80211. Even though there are + number of driver specific interface included in wpa_supplicant, please + note that Linux drivers are moving to use generic wireless configuration + interface driver_nl80211 (-Dnl80211 on wpa_supplicant command line) + should be the default option to start with before falling back to driver + specific interface. + + Linux drivers that support WPA/WPA2 configuration with the generic + Linux wireless extensions (WE-18 or newer). Obsoleted by nl80211. + + In theory, any driver that supports Linux wireless extensions can be + used with IEEE 802.1X (i.e., not WPA) when using ap_scan=0 option in + configuration file. + + Wired Ethernet drivers (with ap_scan=0) + + BSD net80211 layer (e.g., Atheros driver) + At the moment, this is for FreeBSD 6-CURRENT branch and NetBSD-current. + + Windows NDIS + The current Windows port requires WinPcap (http://winpcap.polito.it/). + See README-Windows.txt for more information. + +wpa_supplicant was designed to be portable for different drivers and +operating systems. Hopefully, support for more wlan cards and OSes will be +added in the future. See developer's documentation +(http://hostap.epitest.fi/wpa_supplicant/devel/) for more information about the +design of wpa_supplicant and porting to other drivers. One main goal +is to add full WPA/WPA2 support to Linux wireless extensions to allow +new drivers to be supported without having to implement new +driver-specific interface code in wpa_supplicant. + +Optional libraries for layer2 packet processing: +- libpcap (tested with 0.7.2, most relatively recent versions assumed to work, + this is likely to be available with most distributions, + http://tcpdump.org/) +- libdnet (tested with v1.4, most versions assumed to work, + http://libdnet.sourceforge.net/) + +These libraries are _not_ used in the default Linux build. Instead, +internal Linux specific implementation is used. libpcap/libdnet are +more portable and they can be used by adding CONFIG_L2_PACKET=pcap into +.config. They may also be selected automatically for other operating +systems. In case of Windows builds, WinPcap is used by default +(CONFIG_L2_PACKET=winpcap). + + +Optional libraries for EAP-TLS, EAP-PEAP, and EAP-TTLS: +- OpenSSL (tested with 1.0.1 and 1.0.2 versions; assumed to + work with most relatively recent versions; this is likely to be + available with most distributions, http://www.openssl.org/) +- GnuTLS +- internal TLSv1 implementation + +One of these libraries is needed when EAP-TLS, EAP-PEAP, EAP-TTLS, or +EAP-FAST support is enabled. WPA-PSK mode does not require this or EAPOL/EAP +implementation. A configuration file, .config, for compilation is +needed to enable IEEE 802.1X/EAPOL and EAP methods. Note that EAP-MD5, +EAP-GTC, EAP-OTP, and EAP-MSCHAPV2 cannot be used alone with WPA, so +they should only be enabled if testing the EAPOL/EAP state +machines. However, there can be used as inner authentication +algorithms with EAP-PEAP and EAP-TTLS. + +See Building and installing section below for more detailed +information about the wpa_supplicant build time configuration. + + + +WPA +--- + +The original security mechanism of IEEE 802.11 standard was not +designed to be strong and has proven to be insufficient for most +networks that require some kind of security. Task group I (Security) +of IEEE 802.11 working group (http://www.ieee802.org/11/) has worked +to address the flaws of the base standard and has in practice +completed its work in May 2004. The IEEE 802.11i amendment to the IEEE +802.11 standard was approved in June 2004 and published in July 2004. + +Wi-Fi Alliance (http://www.wi-fi.org/) used a draft version of the +IEEE 802.11i work (draft 3.0) to define a subset of the security +enhancements that can be implemented with existing wlan hardware. This +is called Wi-Fi Protected Access<TM> (WPA). This has now become a +mandatory component of interoperability testing and certification done +by Wi-Fi Alliance. Wi-Fi provides information about WPA at its web +site (http://www.wi-fi.org/OpenSection/protected_access.asp). + +IEEE 802.11 standard defined wired equivalent privacy (WEP) algorithm +for protecting wireless networks. WEP uses RC4 with 40-bit keys, +24-bit initialization vector (IV), and CRC32 to protect against packet +forgery. All these choices have proven to be insufficient: key space is +too small against current attacks, RC4 key scheduling is insufficient +(beginning of the pseudorandom stream should be skipped), IV space is +too small and IV reuse makes attacks easier, there is no replay +protection, and non-keyed authentication does not protect against bit +flipping packet data. + +WPA is an intermediate solution for the security issues. It uses +Temporal Key Integrity Protocol (TKIP) to replace WEP. TKIP is a +compromise on strong security and possibility to use existing +hardware. It still uses RC4 for the encryption like WEP, but with +per-packet RC4 keys. In addition, it implements replay protection, +keyed packet authentication mechanism (Michael MIC). + +Keys can be managed using two different mechanisms. WPA can either use +an external authentication server (e.g., RADIUS) and EAP just like +IEEE 802.1X is using or pre-shared keys without need for additional +servers. Wi-Fi calls these "WPA-Enterprise" and "WPA-Personal", +respectively. Both mechanisms will generate a master session key for +the Authenticator (AP) and Supplicant (client station). + +WPA implements a new key handshake (4-Way Handshake and Group Key +Handshake) for generating and exchanging data encryption keys between +the Authenticator and Supplicant. This handshake is also used to +verify that both Authenticator and Supplicant know the master session +key. These handshakes are identical regardless of the selected key +management mechanism (only the method for generating master session +key changes). + + + +IEEE 802.11i / WPA2 +------------------- + +The design for parts of IEEE 802.11i that were not included in WPA has +finished (May 2004) and this amendment to IEEE 802.11 was approved in +June 2004. Wi-Fi Alliance is using the final IEEE 802.11i as a new +version of WPA called WPA2. This includes, e.g., support for more +robust encryption algorithm (CCMP: AES in Counter mode with CBC-MAC) +to replace TKIP and optimizations for handoff (reduced number of +messages in initial key handshake, pre-authentication, and PMKSA caching). + + + +wpa_supplicant +-------------- + +wpa_supplicant is an implementation of the WPA Supplicant component, +i.e., the part that runs in the client stations. It implements WPA key +negotiation with a WPA Authenticator and EAP authentication with +Authentication Server. In addition, it controls the roaming and IEEE +802.11 authentication/association of the wlan driver. + +wpa_supplicant is designed to be a "daemon" program that runs in the +background and acts as the backend component controlling the wireless +connection. wpa_supplicant supports separate frontend programs and an +example text-based frontend, wpa_cli, is included with wpa_supplicant. + +Following steps are used when associating with an AP using WPA: + +- wpa_supplicant requests the kernel driver to scan neighboring BSSes +- wpa_supplicant selects a BSS based on its configuration +- wpa_supplicant requests the kernel driver to associate with the chosen + BSS +- If WPA-EAP: integrated IEEE 802.1X Supplicant completes EAP + authentication with the authentication server (proxied by the + Authenticator in the AP) +- If WPA-EAP: master key is received from the IEEE 802.1X Supplicant +- If WPA-PSK: wpa_supplicant uses PSK as the master session key +- wpa_supplicant completes WPA 4-Way Handshake and Group Key Handshake + with the Authenticator (AP) +- wpa_supplicant configures encryption keys for unicast and broadcast +- normal data packets can be transmitted and received + + + +Building and installing +----------------------- + +In order to be able to build wpa_supplicant, you will first need to +select which parts of it will be included. This is done by creating a +build time configuration file, .config, in the wpa_supplicant root +directory. Configuration options are text lines using following +format: CONFIG_<option>=y. Lines starting with # are considered +comments and are ignored. See defconfig file for an example configuration +and a list of available options and additional notes. + +The build time configuration can be used to select only the needed +features and limit the binary size and requirements for external +libraries. The main configuration parts are the selection of which +driver interfaces (e.g., nl80211, wext, ..) and which authentication +methods (e.g., EAP-TLS, EAP-PEAP, ..) are included. + +Following build time configuration options are used to control IEEE +802.1X/EAPOL and EAP state machines and all EAP methods. Including +TLS, PEAP, or TTLS will require linking wpa_supplicant with OpenSSL +library for TLS implementation. Alternatively, GnuTLS or the internal +TLSv1 implementation can be used for TLS functionality. + +CONFIG_IEEE8021X_EAPOL=y +CONFIG_EAP_MD5=y +CONFIG_EAP_MSCHAPV2=y +CONFIG_EAP_TLS=y +CONFIG_EAP_PEAP=y +CONFIG_EAP_TTLS=y +CONFIG_EAP_GTC=y +CONFIG_EAP_OTP=y +CONFIG_EAP_SIM=y +CONFIG_EAP_AKA=y +CONFIG_EAP_AKA_PRIME=y +CONFIG_EAP_PSK=y +CONFIG_EAP_SAKE=y +CONFIG_EAP_GPSK=y +CONFIG_EAP_PAX=y +CONFIG_EAP_LEAP=y +CONFIG_EAP_IKEV2=y +CONFIG_EAP_PWD=y + +Following option can be used to include GSM SIM/USIM interface for GSM/UMTS +authentication algorithm (for EAP-SIM/EAP-AKA/EAP-AKA'). This requires pcsc-lite +(http://www.linuxnet.com/) for smart card access. + +CONFIG_PCSC=y + +Following options can be added to .config to select which driver +interfaces are included. + +CONFIG_DRIVER_NL80211=y +CONFIG_DRIVER_WEXT=y +CONFIG_DRIVER_BSD=y +CONFIG_DRIVER_NDIS=y + +Following example includes some more features and driver interfaces that +are included in the wpa_supplicant package: + +CONFIG_DRIVER_NL80211=y +CONFIG_DRIVER_WEXT=y +CONFIG_DRIVER_BSD=y +CONFIG_DRIVER_NDIS=y +CONFIG_IEEE8021X_EAPOL=y +CONFIG_EAP_MD5=y +CONFIG_EAP_MSCHAPV2=y +CONFIG_EAP_TLS=y +CONFIG_EAP_PEAP=y +CONFIG_EAP_TTLS=y +CONFIG_EAP_GTC=y +CONFIG_EAP_OTP=y +CONFIG_EAP_SIM=y +CONFIG_EAP_AKA=y +CONFIG_EAP_PSK=y +CONFIG_EAP_SAKE=y +CONFIG_EAP_GPSK=y +CONFIG_EAP_PAX=y +CONFIG_EAP_LEAP=y +CONFIG_EAP_IKEV2=y +CONFIG_PCSC=y + +EAP-PEAP and EAP-TTLS will automatically include configured EAP +methods (MD5, OTP, GTC, MSCHAPV2) for inner authentication selection. + + +After you have created a configuration file, you can build +wpa_supplicant and wpa_cli with 'make' command. You may then install +the binaries to a suitable system directory, e.g., /usr/local/bin. + +Example commands: + +# build wpa_supplicant and wpa_cli +make +# install binaries (this may need root privileges) +cp wpa_cli wpa_supplicant /usr/local/bin + + +You will need to make a configuration file, e.g., +/etc/wpa_supplicant.conf, with network configuration for the networks +you are going to use. Configuration file section below includes +explanation of the configuration file format and includes various +examples. Once the configuration is ready, you can test whether the +configuration work by first running wpa_supplicant with following +command to start it on foreground with debugging enabled: + +wpa_supplicant -iwlan0 -c/etc/wpa_supplicant.conf -d + +Assuming everything goes fine, you can start using following command +to start wpa_supplicant on background without debugging: + +wpa_supplicant -iwlan0 -c/etc/wpa_supplicant.conf -B + +Please note that if you included more than one driver interface in the +build time configuration (.config), you may need to specify which +interface to use by including -D<driver name> option on the command +line. See following section for more details on command line options +for wpa_supplicant. + + + +Command line options +-------------------- + +usage: + wpa_supplicant [-BddfhKLqqtuvW] [-P<pid file>] [-g<global ctrl>] \ + [-G<group>] \ + -i<ifname> -c<config file> [-C<ctrl>] [-D<driver>] [-p<driver_param>] \ + [-b<br_ifname> [-MN -i<ifname> -c<conf> [-C<ctrl>] [-D<driver>] \ + [-p<driver_param>] [-b<br_ifname>] [-m<P2P Device config file>] ... + +options: + -b = optional bridge interface name + -B = run daemon in the background + -c = Configuration file + -C = ctrl_interface parameter (only used if -c is not) + -i = interface name + -d = increase debugging verbosity (-dd even more) + -D = driver name (can be multiple drivers: nl80211,wext) + -f = Log output to default log location (normally /tmp) + -g = global ctrl_interface + -G = global ctrl_interface group + -K = include keys (passwords, etc.) in debug output + -t = include timestamp in debug messages + -h = show this help text + -L = show license (BSD) + -p = driver parameters + -P = PID file + -q = decrease debugging verbosity (-qq even less) + -u = enable DBus control interface + -v = show version + -W = wait for a control interface monitor before starting + -M = start describing matching interface + -N = start describing new interface + -m = Configuration file for the P2P Device + +drivers: + nl80211 = Linux nl80211/cfg80211 + wext = Linux wireless extensions (generic) + wired = wpa_supplicant wired Ethernet driver + roboswitch = wpa_supplicant Broadcom switch driver + bsd = BSD 802.11 support (Atheros, etc.) + ndis = Windows NDIS driver + +In most common cases, wpa_supplicant is started with + +wpa_supplicant -B -c/etc/wpa_supplicant.conf -iwlan0 + +This makes the process fork into background. + +The easiest way to debug problems, and to get debug log for bug +reports, is to start wpa_supplicant on foreground with debugging +enabled: + +wpa_supplicant -c/etc/wpa_supplicant.conf -iwlan0 -d + +If the specific driver wrapper is not known beforehand, it is possible +to specify multiple comma separated driver wrappers on the command +line. wpa_supplicant will use the first driver wrapper that is able to +initialize the interface. + +wpa_supplicant -Dnl80211,wext -c/etc/wpa_supplicant.conf -iwlan0 + + +wpa_supplicant can control multiple interfaces (radios) either by +running one process for each interface separately or by running just +one process and list of options at command line. Each interface is +separated with -N argument. As an example, following command would +start wpa_supplicant for two interfaces: + +wpa_supplicant \ + -c wpa1.conf -i wlan0 -D nl80211 -N \ + -c wpa2.conf -i wlan1 -D wext + + +If the interfaces on which wpa_supplicant is to run are not known or do +not exist, wpa_supplicant can match an interface when it arrives. Each +matched interface is separated with -M argument and the -i argument now +allows for pattern matching. + +As an example, the following command would start wpa_supplicant for a +specific wired interface called lan0, any interface starting with wlan +and lastly any other interface. Each match has its own configuration +file, and for the wired interface a specific driver has also been given. + +wpa_supplicant \ + -M -c wpa_wired.conf -ilan0 -D wired \ + -M -c wpa1.conf -iwlan* \ + -M -c wpa2.conf + + +If the interface is added in a Linux bridge (e.g., br0), the bridge +interface needs to be configured to wpa_supplicant in addition to the +main interface: + +wpa_supplicant -cw.conf -Dnl80211 -iwlan0 -bbr0 + + +Configuration file +------------------ + +wpa_supplicant is configured using a text file that lists all accepted +networks and security policies, including pre-shared keys. See +example configuration file, wpa_supplicant.conf, for detailed +information about the configuration format and supported fields. + +Changes to configuration file can be reloaded be sending SIGHUP signal +to wpa_supplicant ('killall -HUP wpa_supplicant'). Similarly, +reloading can be triggered with 'wpa_cli reconfigure' command. + +Configuration file can include one or more network blocks, e.g., one +for each used SSID. wpa_supplicant will automatically select the best +network based on the order of network blocks in the configuration +file, network security level (WPA/WPA2 is preferred), and signal +strength. + +Example configuration files for some common configurations: + +1) WPA-Personal (PSK) as home network and WPA-Enterprise with EAP-TLS as work + network + +# allow frontend (e.g., wpa_cli) to be used by all users in 'wheel' group +ctrl_interface=/var/run/wpa_supplicant +ctrl_interface_group=wheel +# +# home network; allow all valid ciphers +network={ + ssid="home" + scan_ssid=1 + key_mgmt=WPA-PSK + psk="very secret passphrase" +} +# +# work network; use EAP-TLS with WPA; allow only CCMP and TKIP ciphers +network={ + ssid="work" + scan_ssid=1 + key_mgmt=WPA-EAP + pairwise=CCMP TKIP + group=CCMP TKIP + eap=TLS + identity="user@example.com" + ca_cert="/etc/cert/ca.pem" + client_cert="/etc/cert/user.pem" + private_key="/etc/cert/user.prv" + private_key_passwd="password" +} + + +2) WPA-RADIUS/EAP-PEAP/MSCHAPv2 with RADIUS servers that use old peaplabel + (e.g., Funk Odyssey and SBR, Meetinghouse Aegis, Interlink RAD-Series) + +ctrl_interface=/var/run/wpa_supplicant +ctrl_interface_group=wheel +network={ + ssid="example" + scan_ssid=1 + key_mgmt=WPA-EAP + eap=PEAP + identity="user@example.com" + password="foobar" + ca_cert="/etc/cert/ca.pem" + phase1="peaplabel=0" + phase2="auth=MSCHAPV2" +} + + +3) EAP-TTLS/EAP-MD5-Challenge configuration with anonymous identity for the + unencrypted use. Real identity is sent only within an encrypted TLS tunnel. + +ctrl_interface=/var/run/wpa_supplicant +ctrl_interface_group=wheel +network={ + ssid="example" + scan_ssid=1 + key_mgmt=WPA-EAP + eap=TTLS + identity="user@example.com" + anonymous_identity="anonymous@example.com" + password="foobar" + ca_cert="/etc/cert/ca.pem" + phase2="auth=MD5" +} + + +4) IEEE 802.1X (i.e., no WPA) with dynamic WEP keys (require both unicast and + broadcast); use EAP-TLS for authentication + +ctrl_interface=/var/run/wpa_supplicant +ctrl_interface_group=wheel +network={ + ssid="1x-test" + scan_ssid=1 + key_mgmt=IEEE8021X + eap=TLS + identity="user@example.com" + ca_cert="/etc/cert/ca.pem" + client_cert="/etc/cert/user.pem" + private_key="/etc/cert/user.prv" + private_key_passwd="password" + eapol_flags=3 +} + + +5) Catch all example that allows more or less all configuration modes. The + configuration options are used based on what security policy is used in the + selected SSID. This is mostly for testing and is not recommended for normal + use. + +ctrl_interface=/var/run/wpa_supplicant +ctrl_interface_group=wheel +network={ + ssid="example" + scan_ssid=1 + key_mgmt=WPA-EAP WPA-PSK IEEE8021X NONE + pairwise=CCMP TKIP + group=CCMP TKIP WEP104 WEP40 + psk="very secret passphrase" + eap=TTLS PEAP TLS + identity="user@example.com" + password="foobar" + ca_cert="/etc/cert/ca.pem" + client_cert="/etc/cert/user.pem" + private_key="/etc/cert/user.prv" + private_key_passwd="password" + phase1="peaplabel=0" + ca_cert2="/etc/cert/ca2.pem" + client_cert2="/etc/cer/user.pem" + private_key2="/etc/cer/user.prv" + private_key2_passwd="password" +} + + +6) Authentication for wired Ethernet. This can be used with 'wired' or + 'roboswitch' interface (-Dwired or -Droboswitch on command line). + +ctrl_interface=/var/run/wpa_supplicant +ctrl_interface_group=wheel +ap_scan=0 +network={ + key_mgmt=IEEE8021X + eap=MD5 + identity="user" + password="password" + eapol_flags=0 +} + + + +Certificates +------------ + +Some EAP authentication methods require use of certificates. EAP-TLS +uses both server side and client certificates whereas EAP-PEAP and +EAP-TTLS only require the server side certificate. When client +certificate is used, a matching private key file has to also be +included in configuration. If the private key uses a passphrase, this +has to be configured in wpa_supplicant.conf ("private_key_passwd"). + +wpa_supplicant supports X.509 certificates in PEM and DER +formats. User certificate and private key can be included in the same +file. + +If the user certificate and private key is received in PKCS#12/PFX +format, they need to be converted to suitable PEM/DER format for +wpa_supplicant. This can be done, e.g., with following commands: + +# convert client certificate and private key to PEM format +openssl pkcs12 -in example.pfx -out user.pem -clcerts +# convert CA certificate (if included in PFX file) to PEM format +openssl pkcs12 -in example.pfx -out ca.pem -cacerts -nokeys + + + +wpa_cli +------- + +wpa_cli is a text-based frontend program for interacting with +wpa_supplicant. It is used to query current status, change +configuration, trigger events, and request interactive user input. + +wpa_cli can show the current authentication status, selected security +mode, dot11 and dot1x MIBs, etc. In addition, it can configure some +variables like EAPOL state machine parameters and trigger events like +reassociation and IEEE 802.1X logoff/logon. wpa_cli provides a user +interface to request authentication information, like username and +password, if these are not included in the configuration. This can be +used to implement, e.g., one-time-passwords or generic token card +authentication where the authentication is based on a +challenge-response that uses an external device for generating the +response. + +The control interface of wpa_supplicant can be configured to allow +non-root user access (ctrl_interface_group in the configuration +file). This makes it possible to run wpa_cli with a normal user +account. + +wpa_cli supports two modes: interactive and command line. Both modes +share the same command set and the main difference is in interactive +mode providing access to unsolicited messages (event messages, +username/password requests). + +Interactive mode is started when wpa_cli is executed without including +the command as a command line parameter. Commands are then entered on +the wpa_cli prompt. In command line mode, the same commands are +entered as command line arguments for wpa_cli. + + +Interactive authentication parameters request + +When wpa_supplicant need authentication parameters, like username and +password, which are not present in the configuration file, it sends a +request message to all attached frontend programs, e.g., wpa_cli in +interactive mode. wpa_cli shows these requests with +"CTRL-REQ-<type>-<id>:<text>" prefix. <type> is IDENTITY, PASSWORD, or +OTP (one-time-password). <id> is a unique identifier for the current +network. <text> is description of the request. In case of OTP request, +it includes the challenge from the authentication server. + +The reply to these requests can be given with 'identity', 'password', +and 'otp' commands. <id> needs to be copied from the the matching +request. 'password' and 'otp' commands can be used regardless of +whether the request was for PASSWORD or OTP. The main difference +between these two commands is that values given with 'password' are +remembered as long as wpa_supplicant is running whereas values given +with 'otp' are used only once and then forgotten, i.e., wpa_supplicant +will ask frontend for a new value for every use. This can be used to +implement one-time-password lists and generic token card -based +authentication. + +Example request for password and a matching reply: + +CTRL-REQ-PASSWORD-1:Password needed for SSID foobar +> password 1 mysecretpassword + +Example request for generic token card challenge-response: + +CTRL-REQ-OTP-2:Challenge 1235663 needed for SSID foobar +> otp 2 9876 + + +wpa_cli commands + + status = get current WPA/EAPOL/EAP status + mib = get MIB variables (dot1x, dot11) + help = show this usage help + interface [ifname] = show interfaces/select interface + level <debug level> = change debug level + license = show full wpa_cli license + logoff = IEEE 802.1X EAPOL state machine logoff + logon = IEEE 802.1X EAPOL state machine logon + set = set variables (shows list of variables when run without arguments) + pmksa = show PMKSA cache + reassociate = force reassociation + reconfigure = force wpa_supplicant to re-read its configuration file + preauthenticate <BSSID> = force preauthentication + identity <network id> <identity> = configure identity for an SSID + password <network id> <password> = configure password for an SSID + pin <network id> <pin> = configure pin for an SSID + otp <network id> <password> = configure one-time-password for an SSID + passphrase <network id> <passphrase> = configure private key passphrase + for an SSID + bssid <network id> <BSSID> = set preferred BSSID for an SSID + list_networks = list configured networks + select_network <network id> = select a network (disable others) + enable_network <network id> = enable a network + disable_network <network id> = disable a network + add_network = add a network + remove_network <network id> = remove a network + set_network <network id> <variable> <value> = set network variables (shows + list of variables when run without arguments) + get_network <network id> <variable> = get network variables + save_config = save the current configuration + disconnect = disconnect and wait for reassociate command before connecting + scan = request new BSS scan + scan_results = get latest scan results + get_capability <eap/pairwise/group/key_mgmt/proto/auth_alg> = get capabilities + terminate = terminate wpa_supplicant + quit = exit wpa_cli + + +wpa_cli command line options + +wpa_cli [-p<path to ctrl sockets>] [-i<ifname>] [-hvB] [-a<action file>] \ + [-P<pid file>] [-g<global ctrl>] [command..] + -h = help (show this usage text) + -v = shown version information + -a = run in daemon mode executing the action file based on events from + wpa_supplicant + -B = run a daemon in the background + default path: /var/run/wpa_supplicant + default interface: first interface found in socket path + + +Using wpa_cli to run external program on connect/disconnect +----------------------------------------------------------- + +wpa_cli can used to run external programs whenever wpa_supplicant +connects or disconnects from a network. This can be used, e.g., to +update network configuration and/or trigget DHCP client to update IP +addresses, etc. + +One wpa_cli process in "action" mode needs to be started for each +interface. For example, the following command starts wpa_cli for the +default interface (-i can be used to select the interface in case of +more than one interface being used at the same time): + +wpa_cli -a/sbin/wpa_action.sh -B + +The action file (-a option, /sbin/wpa_action.sh in this example) will +be executed whenever wpa_supplicant completes authentication (connect +event) or detects disconnection). The action script will be called +with two command line arguments: interface name and event (CONNECTED +or DISCONNECTED). If the action script needs to get more information +about the current network, it can use 'wpa_cli status' to query +wpa_supplicant for more information. + +Following example can be used as a simple template for an action +script: + +#!/bin/sh + +IFNAME=$1 +CMD=$2 + +if [ "$CMD" = "CONNECTED" ]; then + SSID=`wpa_cli -i$IFNAME status | grep ^ssid= | cut -f2- -d=` + # configure network, signal DHCP client, etc. +fi + +if [ "$CMD" = "DISCONNECTED" ]; then + # remove network configuration, if needed + SSID= +fi + + + +Integrating with pcmcia-cs/cardmgr scripts +------------------------------------------ + +wpa_supplicant needs to be running when using a wireless network with +WPA. It can be started either from system startup scripts or from +pcmcia-cs/cardmgr scripts (when using PC Cards). WPA handshake must be +completed before data frames can be exchanged, so wpa_supplicant +should be started before DHCP client. + +For example, following small changes to pcmcia-cs scripts can be used +to enable WPA support: + +Add MODE="Managed" and WPA="y" to the network scheme in +/etc/pcmcia/wireless.opts. + +Add the following block to the end of 'start' action handler in +/etc/pcmcia/wireless: + + if [ "$WPA" = "y" -a -x /usr/local/bin/wpa_supplicant ]; then + /usr/local/bin/wpa_supplicant -B -c/etc/wpa_supplicant.conf \ + -i$DEVICE + fi + +Add the following block to the end of 'stop' action handler (may need +to be separated from other actions) in /etc/pcmcia/wireless: + + if [ "$WPA" = "y" -a -x /usr/local/bin/wpa_supplicant ]; then + killall wpa_supplicant + fi + +This will make cardmgr start wpa_supplicant when the card is plugged +in. + + + +Dynamic interface add and operation without configuration files +--------------------------------------------------------------- + +wpa_supplicant can be started without any configuration files or +network interfaces. When used in this way, a global (i.e., per +wpa_supplicant process) control interface is used to add and remove +network interfaces. Each network interface can then be configured +through a per-network interface control interface. For example, +following commands show how to start wpa_supplicant without any +network interfaces and then add a network interface and configure a +network (SSID): + +# Start wpa_supplicant in the background +wpa_supplicant -g/var/run/wpa_supplicant-global -B + +# Add a new interface (wlan0, no configuration file, driver=nl80211, and +# enable control interface) +wpa_cli -g/var/run/wpa_supplicant-global interface_add wlan0 \ + "" nl80211 /var/run/wpa_supplicant + +# Configure a network using the newly added network interface: +wpa_cli -iwlan0 add_network +wpa_cli -iwlan0 set_network 0 ssid '"test"' +wpa_cli -iwlan0 set_network 0 key_mgmt WPA-PSK +wpa_cli -iwlan0 set_network 0 psk '"12345678"' +wpa_cli -iwlan0 set_network 0 pairwise TKIP +wpa_cli -iwlan0 set_network 0 group TKIP +wpa_cli -iwlan0 set_network 0 proto WPA +wpa_cli -iwlan0 enable_network 0 + +# At this point, the new network interface should start trying to associate +# with the WPA-PSK network using SSID test. + +# Remove network interface +wpa_cli -g/var/run/wpa_supplicant-global interface_remove wlan0 + + +Privilege separation +-------------------- + +To minimize the size of code that needs to be run with root privileges +(e.g., to control wireless interface operation), wpa_supplicant +supports optional privilege separation. If enabled, this separates the +privileged operations into a separate process (wpa_priv) while leaving +rest of the code (e.g., EAP authentication and WPA handshakes) into an +unprivileged process (wpa_supplicant) that can be run as non-root +user. Privilege separation restricts the effects of potential software +errors by containing the majority of the code in an unprivileged +process to avoid full system compromise. + +Privilege separation is not enabled by default and it can be enabled +by adding CONFIG_PRIVSEP=y to the build configuration (.config). When +enabled, the privileged operations (driver wrapper and l2_packet) are +linked into a separate daemon program, wpa_priv. The unprivileged +program, wpa_supplicant, will be built with a special driver/l2_packet +wrappers that communicate with the privileged wpa_priv process to +perform the needed operations. wpa_priv can control what privileged +are allowed. + +wpa_priv needs to be run with network admin privileges (usually, root +user). It opens a UNIX domain socket for each interface that is +included on the command line; any other interface will be off limits +for wpa_supplicant in this kind of configuration. After this, +wpa_supplicant can be run as a non-root user (e.g., all standard users +on a laptop or as a special non-privileged user account created just +for this purpose to limit access to user files even further). + + +Example configuration: +- create user group for users that are allowed to use wpa_supplicant + ('wpapriv' in this example) and assign users that should be able to + use wpa_supplicant into that group +- create /var/run/wpa_priv directory for UNIX domain sockets and control + user access by setting it accessible only for the wpapriv group: + mkdir /var/run/wpa_priv + chown root:wpapriv /var/run/wpa_priv + chmod 0750 /var/run/wpa_priv +- start wpa_priv as root (e.g., from system startup scripts) with the + enabled interfaces configured on the command line: + wpa_priv -B -P /var/run/wpa_priv.pid nl80211:wlan0 +- run wpa_supplicant as non-root with a user that is in wpapriv group: + wpa_supplicant -i ath0 -c wpa_supplicant.conf + +wpa_priv does not use the network interface before wpa_supplicant is +started, so it is fine to include network interfaces that are not +available at the time wpa_priv is started. As an alternative, wpa_priv +can be started when an interface is added (hotplug/udev/etc. scripts). +wpa_priv can control multiple interface with one process, but it is +also possible to run multiple wpa_priv processes at the same time, if +desired. + +It should be noted that the interface used between wpa_supplicant and +wpa_priv does not include all the capabilities of the wpa_supplicant +driver interface and at times, this interface lacks update especially +for recent addition. Consequently, use of wpa_priv does come with the +price of somewhat reduced available functionality. The next section +describing how wpa_supplicant can be used with reduced privileges +without having to handle the complexity of separate wpa_priv. While that +approve does not provide separation for network admin capabilities, it +does allow other root privileges to be dropped without the drawbacks of +the wpa_priv process. + + +Linux capabilities instead of privileged process +------------------------------------------------ + +wpa_supplicant performs operations that need special permissions, e.g., +to control the network connection. Traditionally this has been achieved +by running wpa_supplicant as a privileged process with effective user id +0 (root). Linux capabilities can be used to provide restricted set of +capabilities to match the functions needed by wpa_supplicant. The +minimum set of capabilities needed for the operations is CAP_NET_ADMIN +and CAP_NET_RAW. + +setcap(8) can be used to set file capabilities. For example: + +sudo setcap cap_net_raw,cap_net_admin+ep wpa_supplicant + +Please note that this would give anyone being able to run that +wpa_supplicant binary access to the additional capabilities. This can +further be limited by file owner/group and mode bits. For example: + +sudo chown wpas wpa_supplicant +sudo chmod 0100 wpa_supplicant + +This combination of setcap, chown, and chmod commands would allow wpas +user to execute wpa_supplicant with additional network admin/raw +capabilities. + +Common way style of creating a control interface socket in +/var/run/wpa_supplicant could not be done by this user, but this +directory could be created before starting the wpa_supplicant and set to +suitable mode to allow wpa_supplicant to create sockets +there. Alternatively, other directory or abstract socket namespace could +be used for the control interface. + + +External requests for radio control +----------------------------------- + +External programs can request wpa_supplicant to not start offchannel +operations during other tasks that may need exclusive control of the +radio. The RADIO_WORK control interface command can be used for this. + +"RADIO_WORK add <name> [freq=<MHz>] [timeout=<seconds>]" command can be +used to reserve a slot for radio access. If freq is specified, other +radio work items on the same channel may be completed in +parallel. Otherwise, all other radio work items are blocked during +execution. Timeout is set to 10 seconds by default to avoid blocking +wpa_supplicant operations for excessive time. If a longer (or shorter) +safety timeout is needed, that can be specified with the optional +timeout parameter. This command returns an identifier for the radio work +item. + +Once the radio work item has been started, "EXT-RADIO-WORK-START <id>" +event message is indicated that the external processing can start. Once +the operation has been completed, "RADIO_WORK done <id>" is used to +indicate that to wpa_supplicant. This allows other radio works to be +performed. If this command is forgotten (e.g., due to the external +program terminating), wpa_supplicant will time out the radio work item +and send "EXT-RADIO-WORK-TIMEOUT <id>" event to indicate that this has +happened. "RADIO_WORK done <id>" can also be used to cancel items that +have not yet been started. + +For example, in wpa_cli interactive mode: + +> radio_work add test +1 +<3>EXT-RADIO-WORK-START 1 +> radio_work show +ext:test@wlan0:0:1:2.487797 +> radio_work done 1 +OK +> radio_work show + + +> radio_work done 3 +OK +> radio_work show +ext:test freq=2412 timeout=30@wlan0:2412:1:28.583483 +<3>EXT-RADIO-WORK-TIMEOUT 2 + + +> radio_work add test2 freq=2412 timeout=60 +5 +<3>EXT-RADIO-WORK-START 5 +> radio_work add test3 +6 +> radio_work add test4 +7 +> radio_work show +ext:test2 freq=2412 timeout=60@wlan0:2412:1:9.751844 +ext:test3@wlan0:0:0:5.071812 +ext:test4@wlan0:0:0:3.143870 +> radio_work done 6 +OK +> radio_work show +ext:test2 freq=2412 timeout=60@wlan0:2412:1:16.287869 +ext:test4@wlan0:0:0:9.679895 +> radio_work done 5 +OK +<3>EXT-RADIO-WORK-START 7 +<3>EXT-RADIO-WORK-TIMEOUT 7 + + +DSCP policy procedures +---------------------- + +DSCP policy procedures defined in WFA QoS Management-R2 program +facilitates AP devices to configure DSCP settings for specific uplink +data streams. + +An AP may transmit a DSCP Policy Request frame containing zero or more +QoS Management IEs to an associated STA which supports DSCP policy +procedures. Each QoS Management element in a DSCP Policy Request frame +represents one DSCP policy, and shall include one DSCP Policy attribute +including a DSCP Policy ID, Request type, and a DSCP value. + +wpa_supplicant sends control interface event messages consisting details +of DSCP policies requested by the AP through a DSCP Policy Request frame +to external programs. The format of the control interface event messages +is as shown below: + +- Control interface event message format to indicate DSCP request start + + <3>CTRL-EVENT-DSCP-POLICY request_start [clear_all] [more] + + clear_all - AP requested to clear all DSCP policies configured earlier + more - AP may request to configure more DSCP policies with new DSCP + request + +- Control interface event message format to add new policy + + <3>CTRL-EVENT-DSCP-POLICY add <policy_id> <dscp_value> <ip_version=0|4|6> + [protocol] [source ip] [destination_ip]/[domain name] [source port] + [[<start_port> <end_port>]/destination port] + + ip_version = 0: Both IPv4 and IPv6 + = 4: IPv4 + = 6: IPv6 + protocol: Internet Protocol Numbers as per IETF RFCs + = 6: TCP + = 17: UDP + = 50: ESP + +- Control interface event message format to remove a particular policy, + identified by the policy_id attribute. + + <3>CTRL-EVENT-DSCP-POLICY remove <policy_id> + +- DSCP policy may get rejected due to invalid policy parameters. Ccontrol + interface event message format for rejected policy. + + <3>CTRL-EVENT-DSCP-POLICY reject <policy_id> + +- Control interface event message format to indicate end of DSCP request. + + <3>CTRL-EVENT-DSCP-POLICY request_end + +- External applications shall clear active DSCP policies upon receiving + "CTRL-EVENT-DISCONNECTED" or "CTRL-EVENT-DSCP-POLICY clear_all" events. + +- Control interface event message format to indicate wpa_supplicant started + a timer to wait until the unsolicited DSCP request from the AP. + + <3>CTRL-EVENT-DSCP-POLICY request_wait start + +- Control interface event message format to indicate timeout to receive the + unsolicited DSCP request. This event is expected only when an unsolicited + DSCP request is not received from the AP before timeout. + + <3>CTRL-EVENT-DSCP-POLICY request_wait end + +DSCP Response: +A QoS Management STA that enables DSCP Policy capability shall respond +with DSCP response on receipt of a successful DSCP request from its +associated AP. wpa_supplicant sends DSCP policy response based on the +control interface command received from the user is as below: + +DSCP_RESP <[reset]>/<[solicited] [policy_id=1 status=0...]> [more] + +DSCP Query: +DSCP Policy Query enables a STA to query its associated AP for DSCP +policies applicable to the STA. Currently, this includes support to send +a wildcard DSCP query or a DSCP query with a single domain name +attribute. The command format for the DSCP query command is as follows: +DSCP_QUERY <wildcard>/<domain_name=<string>> diff --git a/wpa_supplicant/README-DPP b/wpa_supplicant/README-DPP new file mode 100644 index 000000000000..d378245cd6de --- /dev/null +++ b/wpa_supplicant/README-DPP @@ -0,0 +1,204 @@ +Device Provisioning Protocol (DPP) +================================== + +This document describes how the Device Provisioning Protocol (DPP) +implementation in wpa_supplicant and hostapd can be configured and how +the STA device and AP can be configured to connect each other using DPP +Connector mechanism. + +Introduction to DPP +------------------- + +Device Provisioning Protocol (also known as Wi-Fi Easy Connect) allows +enrolling of interface-less devices in a secure Wi-Fi network using many +methods like QR code based authentication (detailed below), PKEX based +authentication (password with in-band provisioning), etc. In DPP a +Configurator is used to provide network credentials to the devices. The +three phases of DPP connection are authentication, configuration and +network introduction. + +More information about Wi-Fi Easy Connect is available from this Wi-Fi +Alliance web page: +https://www.wi-fi.org/discover-wi-fi/wi-fi-easy-connect + +Build config setup +------------------ + +The following parameters must be included in the config file used to +compile hostapd and wpa_supplicant. + +wpa_supplicant build config +--------------------------- + +Enable DPP in wpa_supplicant build config file + +CONFIG_DPP=y + +hostapd build config +-------------------- + +Enable DPP in hostapd build config file + +CONFIG_DPP=y + +Configurator build config +------------------------- + +Any STA or AP device can act as a Configurator. Enable DPP in build +config. For an AP to act as a Configurator, Interworking needs to be +enabled for GAS. For wpa_supplicant it is not required. + +CONFIG_INTERWORKING=y + + +Sample supplicant config file before provisioning +------------------------------------------------- + +ctrl_interface=DIR=/var/run/wpa_supplicant +ctrl_interface_group=0 +update_config=1 +pmf=2 +dpp_config_processing=2 + +Sample hostapd config file before provisioning +---------------------------------------------- + +interface=wlan0 +driver=nl80211 +ctrl_interface=/var/run/hostapd +ssid=test +channel=1 +wpa=2 +wpa_key_mgmt=DPP +ieee80211w=1 +wpa_pairwise=CCMP +rsn_pairwise=CCMP + + +Pre-requisites +-------------- + +It is assumed that an AP and client station are up by running hostapd +and wpa_supplicant using respective config files. + + +Creating Configurator +--------------------- + +Add a Configurator over the control interface (wpa_cli/hostapd_cli) + +> dpp_configurator_add +(returns id) + +To get key of Configurator +> dpp_configurator_get_key <id> + + +How to configure an Enrollee using Configurator +----------------------------------------------- + +On Enrollee side: + +Generate QR code for the device. Store the QR code id returned by the +command. + +> dpp_bootstrap_gen type=qrcode mac=<mac-address-of-device> chan=<operating-class/channel> key=<key of the device> +(Returns bootstrapping info id. If the key parameter is not included, a new key +is generated automatically. The MAC address is specified without octet +separating colons. The channel list includes the possible channels on which the +device is waiting. This uses global operating classes; e.g., 81/1 is the 2.4 +GHz channel 1 on 2412 MHz.) + +Get URI for the QR Code of device using the bootstrap info id. +> dpp_bootstrap_get_uri <bootstrap-id> + +Make device listen to DPP request. The central frequency of the 2.4 GHz +band channel 1 is 2412 MHz) in case the Enrollee is a client device. An +AP as an Enrollee is listening on its operating channel. + +> dpp_listen <frequency> + +On Configurator side: + +Enter the QR Code in the Configurator. +> dpp_qr_code "<URI-from-QR-Code-read-from-enrollee>" + +On successfully adding QR Code, a bootstrapping info id is returned. + +Send provisioning request to Enrollee. (conf is ap-dpp if Enrollee is an +AP. conf is sta-dpp if Enrollee is a client) +> dpp_auth_init peer=<qr-code-id> conf=<ap-dpp|sta-dpp> ssid=<SSID hexdump> configurator=<configurator-id> +or for legacy (PSK/SAE) provisioning for a station Enrollee: +> dpp_auth_init peer=<qr-code-id> conf=sta-psk ssid=<SSID hexdump> pass=<passphrase hexdump> + +The DPP values will be printed in the console. Save these values into the +config file. If the Enrollee is an AP, we need to manually write these +values to the hostapd config file. If the Enrollee is a client device, +these details can be automatically saved to config file using the +following command. + +> save_config + +To set values in runtime for AP enrollees + +> set dpp_connector <Connector-value-printed-on-console> +> set dpp_csign <csign-value-on-console> +> set dpp_netaccesskey <netaccess-value-on-console> + +To set values in runtime for client enrollees, set dpp_config_processing +to 2 in wpa_supplicant conf file. + +Once the values are set in run-time (if not set in run-time, but saved +in config files, they are taken up in next restart), the client device +will automatically connect to the already provisioned AP and connection +will be established. + + +Self-configuring a device +------------------------- + +It is possible for a device to configure itself if it is the +Configurator for the network. + +Create a Configurator in the device and use the dpp_configurator_sign +command to get DPP credentials. + +> dpp_configurator_add +(returns configurator id) +> dpp_configurator_sign conf=<ap-dpp|sta-dpp> configurator=<configurator-id> ssid=<SSID hexdump> + + +Sample AP configuration files after provisioning +------------------------------------------------ + +interface=wlan0 +driver=nl80211 +ctrl_interface=/var/run/hostapd +ssid=test +channel=1 +wpa=2 +wpa_key_mgmt=DPP +ieee80211w=1 +wpa_pairwise=CCMP +rsn_pairwise=CCMP +dpp_connector=<Connector value provided by Configurator> +dpp_csign=<C-Sign-Key value provided by Configurator> +dpp_netaccesskey=<Net access key provided by Configurator> + + +Sample station configuration file after provisioning +---------------------------------------------------- + +ctrl_interface=DIR=/var/run/wpa_supplicant +ctrl_interface_group=0 +update_config=1 +pmf=2 +dpp_config_processing=2 +network={ + ssid="test" + key_mgmt=DPP + ieee80211w=2 + dpp_connector="<Connector value provided by Configurator>" + dpp_netaccesskey=<Net access key provided by Configurator> + dpp_csign=<C-sign-key value provided by Configurator> +} diff --git a/wpa_supplicant/README-HS20 b/wpa_supplicant/README-HS20 new file mode 100644 index 000000000000..b076621db527 --- /dev/null +++ b/wpa_supplicant/README-HS20 @@ -0,0 +1,654 @@ +wpa_supplicant and Hotspot 2.0 +============================== + +This document describe how the IEEE 802.11u Interworking and Wi-Fi +Hotspot 2.0 (Release 1) implementation in wpa_supplicant can be +configured and how an external component on the client e.g., management +GUI or Wi-Fi framework) is used to manage this functionality. + + +Introduction to Wi-Fi Hotspot 2.0 +--------------------------------- + +Hotspot 2.0 is the name of the Wi-Fi Alliance specification that is used +in the Wi-Fi CERTIFIED Passpoint<TM> program. More information about +this is available in this white paper: + +http://www.wi-fi.org/knowledge-center/white-papers/wi-fi-certified-passpoint%E2%84%A2-new-program-wi-fi-alliance%C2%AE-enable-seamless + +The Hotspot 2.0 specification is also available from WFA: +https://www.wi-fi.org/knowledge-center/published-specifications + +The core Interworking functionality (network selection, GAS/ANQP) were +standardized in IEEE Std 802.11u-2011 which is now part of the IEEE Std +802.11-2012. + + +wpa_supplicant network selection +-------------------------------- + +Interworking support added option for configuring credentials that can +work with multiple networks as an alternative to configuration of +network blocks (e.g., per-SSID parameters). When requested to perform +network selection, wpa_supplicant picks the highest priority enabled +network block or credential. If a credential is picked (based on ANQP +information from APs), a temporary network block is created +automatically for the matching network. This temporary network block is +used similarly to the network blocks that can be configured by the user, +but it is not stored into the configuration file and is meant to be used +only for temporary period of time since a new one can be created +whenever needed based on ANQP information and the credential. + +By default, wpa_supplicant is not using automatic network selection +unless requested explicitly with the interworking_select command. This +can be changed with the auto_interworking=1 parameter to perform network +selection automatically whenever trying to find a network for connection +and none of the enabled network blocks match with the scan results. This +case works similarly to "interworking_select auto", i.e., wpa_supplicant +will internally determine which network or credential is going to be +used based on configured priorities, scan results, and ANQP information. + + +wpa_supplicant configuration +---------------------------- + +Interworking and Hotspot 2.0 functionality are optional components that +need to be enabled in the wpa_supplicant build configuration +(.config). This is done by adding following parameters into that file: + +CONFIG_INTERWORKING=y +CONFIG_HS20=y + +It should be noted that this functionality requires a driver that +supports GAS/ANQP operations. This uses the same design as P2P, i.e., +Action frame processing and building in user space within +wpa_supplicant. The Linux nl80211 driver interface provides the needed +functionality for this. + + +There are number of run-time configuration parameters (e.g., in +wpa_supplicant.conf when using the configuration file) that can be used +to control Hotspot 2.0 operations. + +# Enable Interworking +interworking=1 + +# Enable Hotspot 2.0 +hs20=1 + +# Parameters for controlling scanning + +# Homogeneous ESS identifier +# If this is set, scans will be used to request response only from BSSes +# belonging to the specified Homogeneous ESS. This is used only if interworking +# is enabled. +#hessid=00:11:22:33:44:55 + +# Access Network Type +# When Interworking is enabled, scans can be limited to APs that advertise the +# specified Access Network Type (0..15; with 15 indicating wildcard match). +# This value controls the Access Network Type value in Probe Request frames. +#access_network_type=15 + +# Automatic network selection behavior +# 0 = do not automatically go through Interworking network selection +# (i.e., require explicit interworking_select command for this; default) +# 1 = perform Interworking network selection if one or more +# credentials have been configured and scan did not find a +# matching network block +#auto_interworking=0 + + +Credentials can be pre-configured for automatic network selection: + +# credential block +# +# Each credential used for automatic network selection is configured as a set +# of parameters that are compared to the information advertised by the APs when +# interworking_select and interworking_connect commands are used. +# +# credential fields: +# +# temporary: Whether this credential is temporary and not to be saved +# +# priority: Priority group +# By default, all networks and credentials get the same priority group +# (0). This field can be used to give higher priority for credentials +# (and similarly in struct wpa_ssid for network blocks) to change the +# Interworking automatic networking selection behavior. The matching +# network (based on either an enabled network block or a credential) +# with the highest priority value will be selected. +# +# pcsc: Use PC/SC and SIM/USIM card +# +# realm: Home Realm for Interworking +# +# username: Username for Interworking network selection +# +# password: Password for Interworking network selection +# +# ca_cert: CA certificate for Interworking network selection +# +# client_cert: File path to client certificate file (PEM/DER) +# This field is used with Interworking networking selection for a case +# where client certificate/private key is used for authentication +# (EAP-TLS). Full path to the file should be used since working +# directory may change when wpa_supplicant is run in the background. +# +# Alternatively, a named configuration blob can be used by setting +# this to blob://blob_name. +# +# private_key: File path to client private key file (PEM/DER/PFX) +# When PKCS#12/PFX file (.p12/.pfx) is used, client_cert should be +# commented out. Both the private key and certificate will be read +# from the PKCS#12 file in this case. Full path to the file should be +# used since working directory may change when wpa_supplicant is run +# in the background. +# +# Windows certificate store can be used by leaving client_cert out and +# configuring private_key in one of the following formats: +# +# cert://substring_to_match +# +# hash://certificate_thumbprint_in_hex +# +# For example: private_key="hash://63093aa9c47f56ae88334c7b65a4" +# +# Note that when running wpa_supplicant as an application, the user +# certificate store (My user account) is used, whereas computer store +# (Computer account) is used when running wpasvc as a service. +# +# Alternatively, a named configuration blob can be used by setting +# this to blob://blob_name. +# +# private_key_passwd: Password for private key file +# +# imsi: IMSI in <MCC> | <MNC> | '-' | <MSIN> format +# +# milenage: Milenage parameters for SIM/USIM simulator in <Ki>:<OPc>:<SQN> +# format +# +# domain_suffix_match: Constraint for server domain name +# If set, this FQDN is used as a suffix match requirement for the AAA +# server certificate in SubjectAltName dNSName element(s). If a +# matching dNSName is found, this constraint is met. If no dNSName +# values are present, this constraint is matched against SubjectName CN +# using same suffix match comparison. Suffix match here means that the +# host/domain name is compared one label at a time starting from the +# top-level domain and all the labels in @domain_suffix_match shall be +# included in the certificate. The certificate may include additional +# sub-level labels in addition to the required labels. +# +# For example, domain_suffix_match=example.com would match +# test.example.com but would not match test-example.com. +# +# domain: Home service provider FQDN(s) +# This is used to compare against the Domain Name List to figure out +# whether the AP is operated by the Home SP. Multiple domain entries can +# be used to configure alternative FQDNs that will be considered home +# networks. +# +# roaming_consortium: Roaming Consortium OI +# If roaming_consortium_len is non-zero, this field contains the +# Roaming Consortium OI that can be used to determine which access +# points support authentication with this credential. This is an +# alternative to the use of the realm parameter. When using Roaming +# Consortium to match the network, the EAP parameters need to be +# pre-configured with the credential since the NAI Realm information +# may not be available or fetched. +# +# required_roaming_consortium: Required Roaming Consortium OI +# If required_roaming_consortium_len is non-zero, this field contains the +# Roaming Consortium OI that is required to be advertised by the AP for +# the credential to be considered matching. +# +# roaming_consortiums: Roaming Consortium OI(s) memberships +# This string field contains one or more comma delimited OIs (hexdump) +# identifying the roaming consortiums of which the provider is a member. +# The list is sorted from the most preferred one to the least preferred +# one. A match between the Roaming Consortium OIs advertised by an AP and +# the OIs in this list indicates that successful authentication is +# possible. +# (Hotspot 2.0 PerProviderSubscription/<X+>/HomeSP/RoamingConsortiumOI) +# +# eap: Pre-configured EAP method +# This optional field can be used to specify which EAP method will be +# used with this credential. If not set, the EAP method is selected +# automatically based on ANQP information (e.g., NAI Realm). +# +# phase1: Pre-configure Phase 1 (outer authentication) parameters +# This optional field is used with like the 'eap' parameter. +# +# phase2: Pre-configure Phase 2 (inner authentication) parameters +# This optional field is used with like the 'eap' parameter. +# +# excluded_ssid: Excluded SSID +# This optional field can be used to excluded specific SSID(s) from +# matching with the network. Multiple entries can be used to specify more +# than one SSID. +# +# roaming_partner: Roaming partner information +# This optional field can be used to configure preferences between roaming +# partners. The field is a string in following format: +# <FQDN>,<0/1 exact match>,<priority>,<* or country code> +# (non-exact match means any subdomain matches the entry; priority is in +# 0..255 range with 0 being the highest priority) +# +# update_identifier: PPS MO ID +# (Hotspot 2.0 PerProviderSubscription/UpdateIdentifier) +# +# provisioning_sp: FQDN of the SP that provisioned the credential +# This optional field can be used to keep track of the SP that provisioned +# the credential to find the PPS MO (./Wi-Fi/<provisioning_sp>). +# +# sp_priority: Credential priority within a provisioning SP +# This is the priority of the credential among all credentials +# provisioned by the same SP (i.e., for entries that have identical +# provisioning_sp value). The range of this priority is 0-255 with 0 +# being the highest and 255 the lower priority. +# +# Minimum backhaul threshold (PPS/<X+>/Policy/MinBackhauldThreshold/*) +# These fields can be used to specify minimum download/upload backhaul +# bandwidth that is preferred for the credential. This constraint is +# ignored if the AP does not advertise WAN Metrics information or if the +# limit would prevent any connection. Values are in kilobits per second. +# min_dl_bandwidth_home +# min_ul_bandwidth_home +# min_dl_bandwidth_roaming +# min_ul_bandwidth_roaming +# +# max_bss_load: Maximum BSS Load Channel Utilization (1..255) +# (PPS/<X+>/Policy/MaximumBSSLoadValue) +# This value is used as the maximum channel utilization for network +# selection purposes for home networks. If the AP does not advertise +# BSS Load or if the limit would prevent any connection, this constraint +# will be ignored. +# +# req_conn_capab: Required connection capability +# (PPS/<X+>/Policy/RequiredProtoPortTuple) +# This value is used to configure set of required protocol/port pairs that +# a roaming network shall support (include explicitly in Connection +# Capability ANQP element). This constraint is ignored if the AP does not +# advertise Connection Capability or if this constraint would prevent any +# network connection. This policy is not used in home networks. +# Format: <protocol>[:<comma-separated list of ports] +# Multiple entries can be used to list multiple requirements. +# For example, number of common TCP protocols: +# req_conn_capab=6:22,80,443 +# For example, IPSec/IKE: +# req_conn_capab=17:500 +# req_conn_capab=50 +# +# ocsp: Whether to use/require OCSP to check server certificate +# 0 = do not use OCSP stapling (TLS certificate status extension) +# 1 = try to use OCSP stapling, but not require response +# 2 = require valid OCSP stapling response +# +# sim_num: Identifier for which SIM to use in multi-SIM devices +# +# engine: Whether to use an engine for private key operations (0/1) +# engine_id: String identifying the engine to use +# ca_cert_id: The CA certificate identifier when using an engine +# cert_id: The certificate identifier when using an engine +# key_id: The private key identifier when using an engine +# +# for example: +# +#cred={ +# realm="example.com" +# username="user@example.com" +# password="password" +# ca_cert="/etc/wpa_supplicant/ca.pem" +# domain="example.com" +# domain_suffix_match="example.com" +#} +# +#cred={ +# imsi="310026-000000000" +# milenage="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82" +#} +# +#cred={ +# realm="example.com" +# username="user" +# password="password" +# ca_cert="/etc/wpa_supplicant/ca.pem" +# domain="example.com" +# roaming_consortium=223344 +# roaming_consortiums="112233,4455667788,aabbcc" +# eap=TTLS +# phase2="auth=MSCHAPV2" +#} + + +Control interface +----------------- + +wpa_supplicant provides a control interface that can be used from +external programs to manage various operations. The included command +line tool, wpa_cli, can be used for manual testing with this interface. + +Following wpa_cli interactive mode commands show some examples of manual +operations related to Hotspot 2.0: + +Remove configured networks and credentials: + +> remove_network all +OK +> remove_cred all +OK + + +Add a username/password credential: + +> add_cred +0 +> set_cred 0 realm "mail.example.com" +OK +> set_cred 0 username "username" +OK +> set_cred 0 password "password" +OK +> set_cred 0 priority 1 +OK +> set_cred 0 temporary 1 +OK + +Add a SIM credential using a simulated SIM/USIM card for testing: + +> add_cred +1 +> set_cred 1 imsi "23456-0000000000" +OK +> set_cred 1 milenage "90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581:000000000123" +OK +> set_cred 1 priority 1 +OK + +Note: the return value of add_cred is used as the first argument to +the following set_cred commands. + +Add a SIM credential using a external SIM/USIM processing: + +> set external_sim 1 +OK +> add_cred +1 +> set_cred 1 imsi "23456-0000000000" +OK +> set_cred 1 eap SIM +OK + + +Add a WPA2-Enterprise network: + +> add_network +0 +> set_network 0 key_mgmt WPA-EAP +OK +> set_network 0 ssid "enterprise" +OK +> set_network 0 eap TTLS +OK +> set_network 0 anonymous_identity "anonymous" +OK +> set_network 0 identity "user" +OK +> set_network 0 password "password" +OK +> set_network 0 priority 0 +OK +> enable_network 0 no-connect +OK + + +Add an open network: + +> add_network +3 +> set_network 3 key_mgmt NONE +OK +> set_network 3 ssid "coffee-shop" +OK +> select_network 3 +OK + +Note: the return value of add_network is used as the first argument to +the following set_network commands. + +The preferred credentials/networks can be indicated with the priority +parameter (1 is higher priority than 0). + + +Interworking network selection can be started with interworking_select +command. This instructs wpa_supplicant to run a network scan and iterate +through the discovered APs to request ANQP information from the APs that +advertise support for Interworking/Hotspot 2.0: + +> interworking_select +OK +<3>Starting ANQP fetch for 02:00:00:00:01:00 +<3>RX-ANQP 02:00:00:00:01:00 ANQP Capability list +<3>RX-ANQP 02:00:00:00:01:00 Roaming Consortium list +<3>RX-HS20-ANQP 02:00:00:00:01:00 HS Capability List +<3>ANQP fetch completed +<3>INTERWORKING-AP 02:00:00:00:01:00 type=unknown + + +INTERWORKING-AP event messages indicate the APs that support network +selection and for which there is a matching +credential. interworking_connect command can be used to select a network +to connect with: + + +> interworking_connect 02:00:00:00:01:00 +OK +<3>CTRL-EVENT-SCAN-RESULTS +<3>SME: Trying to authenticate with 02:00:00:00:01:00 (SSID='Example Network' freq=2412 MHz) +<3>Trying to associate with 02:00:00:00:01:00 (SSID='Example Network' freq=2412 MHz) +<3>Associated with 02:00:00:00:01:00 +<3>CTRL-EVENT-EAP-STARTED EAP authentication started +<3>CTRL-EVENT-EAP-PROPOSED-METHOD vendor=0 method=21 +<3>CTRL-EVENT-EAP-METHOD EAP vendor 0 method 21 (TTLS) selected +<3>CTRL-EVENT-EAP-SUCCESS EAP authentication completed successfully +<3>WPA: Key negotiation completed with 02:00:00:00:01:00 [PTK=CCMP GTK=CCMP] +<3>CTRL-EVENT-CONNECTED - Connection to 02:00:00:00:01:00 completed (auth) [id=0 id_str=] + + +wpa_supplicant creates a temporary network block for the selected +network based on the configured credential and ANQP information from the +AP: + +> list_networks +network id / ssid / bssid / flags +0 Example Network any [CURRENT] +> get_network 0 key_mgmt +WPA-EAP +> get_network 0 eap +TTLS + + +Alternatively to using an external program to select the network, +"interworking_select auto" command can be used to request wpa_supplicant +to select which network to use based on configured priorities: + + +> remove_network all +OK +<3>CTRL-EVENT-DISCONNECTED bssid=02:00:00:00:01:00 reason=1 locally_generated=1 +> interworking_select auto +OK +<3>Starting ANQP fetch for 02:00:00:00:01:00 +<3>RX-ANQP 02:00:00:00:01:00 ANQP Capability list +<3>RX-ANQP 02:00:00:00:01:00 Roaming Consortium list +<3>RX-HS20-ANQP 02:00:00:00:01:00 HS Capability List +<3>ANQP fetch completed +<3>INTERWORKING-AP 02:00:00:00:01:00 type=unknown +<3>CTRL-EVENT-SCAN-RESULTS +<3>SME: Trying to authenticate with 02:00:00:00:01:00 (SSID='Example Network' freq=2412 MHz) +<3>Trying to associate with 02:00:00:00:01:00 (SSID='Example Network' freq=2412 MHz) +<3>Associated with 02:00:00:00:01:00 +<3>CTRL-EVENT-EAP-STARTED EAP authentication started +<3>CTRL-EVENT-EAP-PROPOSED-METHOD vendor=0 method=21 +<3>CTRL-EVENT-EAP-METHOD EAP vendor 0 method 21 (TTLS) selected +<3>CTRL-EVENT-EAP-SUCCESS EAP authentication completed successfully +<3>WPA: Key negotiation completed with 02:00:00:00:01:00 [PTK=CCMP GTK=CCMP] +<3>CTRL-EVENT-CONNECTED - Connection to 02:00:00:00:01:00 completed (reauth) [id=0 id_str=] + + +The connection status can be shown with the status command: + +> status +bssid=02:00:00:00:01:00 +ssid=Example Network +id=0 +mode=station +pairwise_cipher=CCMP <--- link layer security indication +group_cipher=CCMP +key_mgmt=WPA2/IEEE 802.1X/EAP +wpa_state=COMPLETED +p2p_device_address=02:00:00:00:00:00 +address=02:00:00:00:00:00 +hs20=1 <--- HS 2.0 indication +Supplicant PAE state=AUTHENTICATED +suppPortStatus=Authorized +EAP state=SUCCESS +selectedMethod=21 (EAP-TTLS) +EAP TLS cipher=AES-128-SHA +EAP-TTLSv0 Phase2 method=PAP + + +> status +bssid=02:00:00:00:02:00 +ssid=coffee-shop +id=3 +mode=station +pairwise_cipher=NONE +group_cipher=NONE +key_mgmt=NONE +wpa_state=COMPLETED +p2p_device_address=02:00:00:00:00:00 +address=02:00:00:00:00:00 + + +Note: The Hotspot 2.0 indication is shown as "hs20=1" in the status +command output. Link layer security is indicated with the +pairwise_cipher (CCMP = secure, NONE = no encryption used). + + +Also the scan results include the Hotspot 2.0 indication: + +> scan_results +bssid / frequency / signal level / flags / ssid +02:00:00:00:01:00 2412 -30 [WPA2-EAP-CCMP][ESS][HS20] Example Network + + +ANQP information for the BSS can be fetched using the BSS command: + +> bss 02:00:00:00:01:00 +id=1 +bssid=02:00:00:00:01:00 +freq=2412 +beacon_int=100 +capabilities=0x0411 +qual=0 +noise=-92 +level=-30 +tsf=1345573286517276 +age=105 +ie=000f4578616d706c65204e6574776f726b010882848b960c1218240301012a010432043048606c30140100000fac040100000fac040100000fac0100007f04000000806b091e07010203040506076c027f006f1001531122331020304050010203040506dd05506f9a1000 +flags=[WPA2-EAP-CCMP][ESS][HS20] +ssid=Example Network +anqp_roaming_consortium=031122330510203040500601020304050603fedcba + + +ANQP queries can also be requested with the anqp_get and hs20_anqp_get +commands: + +> anqp_get 02:00:00:00:01:00 261 +OK +<3>RX-ANQP 02:00:00:00:01:00 Roaming Consortium list +> hs20_anqp_get 02:00:00:00:01:00 2 +OK +<3>RX-HS20-ANQP 02:00:00:00:01:00 HS Capability List + +In addition, fetch_anqp command can be used to request similar set of +ANQP queries to be done as is run as part of interworking_select: + +> scan +OK +<3>CTRL-EVENT-SCAN-RESULTS +> fetch_anqp +OK +<3>Starting ANQP fetch for 02:00:00:00:01:00 +<3>RX-ANQP 02:00:00:00:01:00 ANQP Capability list +<3>RX-ANQP 02:00:00:00:01:00 Roaming Consortium list +<3>RX-HS20-ANQP 02:00:00:00:01:00 HS Capability List +<3>ANQP fetch completed + + +Hotspot 2.0 Rel 2 online signup and OSEN +---------------------------------------- + +Following parameters can be used to create a network profile for +link-layer protected Hotspot 2.0 online signup connection with +OSEN. Note that ssid and identify (NAI) values need to be set based on +the information for the selected provider in the OSU Providers list +ANQP-element. + +network={ + ssid="HS 2.0 OSU" + proto=OSEN + key_mgmt=OSEN + pairwise=CCMP + group=GTK_NOT_USED + eap=WFA-UNAUTH-TLS + identity="anonymous@example.com" + ca_cert="osu-ca.pem" + ocsp=2 +} + + +Hotspot 2.0 connection with external network selection +------------------------------------------------------ + +When a component controlling wpa_supplicant takes care of Interworking +network selection, following configuration and network profile +parameters can be used to configure a temporary network profile for a +Hotspot 2.0 connection (e.g., with SET, ADD_NETWORK, SET_NETWORK, and +SELECT_NETWORK control interface commands): + +interworking=1 +hs20=1 +auto_interworking=0 + +network={ + ssid="test-hs20" + proto=RSN + key_mgmt=WPA-EAP + pairwise=CCMP + anonymous_identity="anonymous@example.com" + identity="hs20-test@example.com" + password="password" + ca_cert="ca.pem" + eap=TTLS + phase2="auth=MSCHAPV2" + update_identifier=54321 + roaming_consortium_selection=112233 + #ocsp=2 +} + + +These parameters are set based on the PPS MO credential and/or NAI Realm +list ANQP-element: + +anonymous_identity: Credential/UsernamePassword/Username with username part + replaced with "anonymous" +identity: Credential/UsernamePassword/Username +password: Credential/UsernamePassword/Password +update_identifier: PPS/UpdateIdentifier +ca_cert: from the downloaded trust root based on PPS information +eap: Credential/UsernamePassword/EAPMethod or NAI Realm list +phase2: Credential/UsernamePassword/EAPMethod or NAI Realm list +roaming_consortium_selection: Matching OI from HomeSP/RoamingConsortiumOI +ocsp: Credential/CheckAAAServerCertStatus diff --git a/wpa_supplicant/README-P2P b/wpa_supplicant/README-P2P new file mode 100644 index 000000000000..55a60a296ad7 --- /dev/null +++ b/wpa_supplicant/README-P2P @@ -0,0 +1,856 @@ +wpa_supplicant and Wi-Fi P2P +============================ + +This document describes how the Wi-Fi P2P implementation in +wpa_supplicant can be configured and how an external component on the +client (e.g., management GUI) is used to enable WPS enrollment and +registrar registration. + + +Introduction to Wi-Fi P2P +------------------------- + +TODO + +More information about Wi-Fi P2P is available from Wi-Fi Alliance: +http://www.wi-fi.org/Wi-Fi_Direct.php + + +wpa_supplicant implementation +----------------------------- + +TODO + + +wpa_supplicant configuration +---------------------------- + +Wi-Fi P2P is an optional component that needs to be enabled in the +wpa_supplicant build configuration (.config). Here is an example +configuration that includes Wi-Fi P2P support and Linux nl80211 +-based driver interface: + +CONFIG_DRIVER_NL80211=y +CONFIG_CTRL_IFACE=y +CONFIG_P2P=y +CONFIG_AP=y +CONFIG_WPS=y + + +In run-time configuration file (wpa_supplicant.conf), some parameters +for P2P may be set. In order to make the devices easier to recognize, +device_name and device_type should be specified. For example, +something like this should be included: + +ctrl_interface=/var/run/wpa_supplicant +device_name=My P2P Device +device_type=1-0050F204-1 + + +wpa_cli +------- + +Actual Wi-Fi P2P operations are requested during runtime. These can be +done for example using wpa_cli (which is described below) or a GUI +like wpa_gui-qt4. + + +wpa_cli starts in interactive mode if no command string is included on +the command line. By default, it will select the first network interface +that it can find (and that wpa_supplicant controls). If more than one +interface is in use, it may be necessary to select one of the explicitly +by adding -i argument on the command line (e.g., 'wpa_cli -i wlan1'). + +Most of the P2P operations are done on the main interface (e.g., the +interface that is automatically added when the driver is loaded, e.g., +wlan0). When using a separate virtual interface for group operations +(e.g., wlan1), the control interface for that group interface may need +to be used for some operations (mainly WPS activation in GO). This may +change in the future so that all the needed operations could be done +over the main control interface. + +Device Discovery + +p2p_find [timeout in seconds] [type=<social|progressive>] \ + [dev_id=<addr>] [dev_type=<device type>] \ + [delay=<search delay in ms>] [seek=<service name>] [freq=<MHz>] + +The default behavior is to run a single full scan in the beginning and +then scan only social channels. type=social will scan only social +channels, i.e., it skips the initial full scan. type=progressive is +like the default behavior, but it will scan through all the channels +progressively one channel at the time in the Search state rounds. This +will help in finding new groups or groups missed during the initial +full scan. When the type parameter is not included (i.e., full scan), the +optional freq parameter can be used to override the first scan to use only +the specified channel after which only social channels are scanned. + +The optional dev_id option can be used to specify a single P2P peer to +search for. The optional delay parameter can be used to request an extra +delay to be used between search iterations (e.g., to free up radio +resources for concurrent operations). + +The optional dev_type option can be used to specify a single device type +(primary or secondary) to search for, e.g., +"p2p_find dev_type=1-0050F204-1". + + +With one or more seek arguments, the command sends Probe Request frames +for a P2PS service. For example, +p2p_find 5 dev_id=11:22:33:44:55:66 seek=alt.example.chat seek=alt.example.video + +Parameters description: + Timeout - Optional ASCII base-10-encoded u16. If missing, request will not + time out and must be canceled manually + dev_id - Optional to request responses from a single known remote device + Service Name - Mandatory UTF-8 string for ASP seeks + Service name must match the remote service being advertised exactly + (no prefix matching). + Service name may be empty, in which case all ASP services will be + returned, and may be filtered with p2p_serv_disc_req settings, and + p2p_serv_asp_resp results. + Multiple service names may be requested, but if it exceeds internal + limit, it will automatically revert to requesting all ASP services. + +p2p_listen [timeout in seconds] + +Start Listen-only state (become discoverable without searching for +other devices). Optional parameter can be used to specify the duration +for the Listen operation in seconds. This command may not be of that +much use during normal operations and is mainly designed for +testing. It can also be used to keep the device discoverable without +having to maintain a group. + +p2p_stop_find + +Stop ongoing P2P device discovery or other operation (connect, listen +mode). + +p2p_flush + +Flush P2P peer table and state. + +Group Formation + +p2p_prov_disc <peer device address> <display|keypad|pbc> [join|auto] + +Send P2P provision discovery request to the specified peer. The +parameters for this command are the P2P device address of the peer and +the desired configuration method. For example, "p2p_prov_disc +02:01:02:03:04:05 display" would request the peer to display a PIN for +us and "p2p_prov_disc 02:01:02:03:04:05 keypad" would request the peer +to enter a PIN that we display. + +The optional "join" parameter can be used to indicate that this command +is requesting an already running GO to prepare for a new client. This is +mainly used with "display" to request it to display a PIN. The "auto" +parameter can be used to request wpa_supplicant to automatically figure +out whether the peer device is operating as a GO and if so, use +join-a-group style PD instead of GO Negotiation style PD. + +p2p_connect <peer device address> <pbc|pin|PIN#|p2ps> [display|keypad|p2ps] + [persistent|persistent=<network id>] [join|auth] + [go_intent=<0..15>] [freq=<in MHz>] [ht40] [vht] [he] [provdisc] [auto] + [ssid=<hexdump>] + +Start P2P group formation with a discovered P2P peer. This includes +optional group owner negotiation, group interface setup, provisioning, +and establishing data connection. + +The <pbc|pin|PIN#> parameter specifies the WPS provisioning +method. "pbc" string starts pushbutton method, "pin" string start PIN +method using an automatically generated PIN (which will be returned as +the command return code), PIN# means that a pre-selected PIN can be +used (e.g., 12345670). [display|keypad] is used with PIN method +to specify which PIN is used (display=dynamically generated random PIN +from local display, keypad=PIN entered from peer display). "persistent" +parameter can be used to request a persistent group to be formed. The +"persistent=<network id>" alternative can be used to pre-populate +SSID/passphrase configuration based on a previously used persistent +group where this device was the GO. The previously used parameters will +then be used if the local end becomes the GO in GO Negotiation (which +can be forced with go_intent=15). + +"join" indicates that this is a command to join an existing group as a +client. It skips the GO Negotiation part. This will send a Provision +Discovery Request message to the target GO before associating for WPS +provisioning. + +"auth" indicates that the WPS parameters are authorized for the peer +device without actually starting GO Negotiation (i.e., the peer is +expected to initiate GO Negotiation). This is mainly for testing +purposes. + +"go_intent" can be used to override the default GO Intent for this GO +Negotiation. + +"freq" can be used to set a forced operating channel (e.g., freq=2412 +to select 2.4 GHz channel 1). + +"provdisc" can be used to request a Provision Discovery exchange to be +used prior to starting GO Negotiation as a workaround with some deployed +P2P implementations that require this to allow the user to accept the +connection. + +"auto" can be used to request wpa_supplicant to automatically figure +out whether the peer device is operating as a GO and if so, use +join-a-group operation rather than GO Negotiation. + +"ssid=<hexdump>" can be used to specify the Group SSID for join +operations. This allows the P2P Client interface to filter scan results +based on SSID to avoid selecting an incorrect BSS entry in case the same +P2P Device or Interface address have been used in multiple groups +recently. + +P2PS attribute changes to p2p_connect command: + +P2PS supports two WPS provisioning methods namely PIN method and P2PS default. +The remaining parameters hold same role as in legacy P2P. In case of P2PS +default config method "p2ps" keyword is added in p2p_connect command. + +For example: +p2p_connect 02:0a:f5:85:11:00 12345670 p2ps persistent join + (WPS Method = P2PS default) + +p2p_connect 02:0a:f5:85:11:00 45629034 keypad persistent + (WPS Method = PIN) + +p2p_asp_provision <peer MAC address> <adv_id=peer adv id> + <adv_mac=peer MAC address> [role=2|4|1] <session=session id> + <session_mac=initiator mac address> + [info='service info'] <method=Default|keypad|Display> + +This command starts provision discovery with the P2PS enabled peer device. + +For example, +p2p_asp_provision 00:11:22:33:44:55 adv_id=4d6fc7 adv_mac=00:55:44:33:22:11 role=1 session=12ab34 session_mac=00:11:22:33:44:55 info='name=john' method=1000 + +Parameter description: + MAC address - Mandatory + adv_id - Mandatory remote Advertising ID of service connection is being + established for + adv_mac - Mandatory MAC address that owns/registered the service + role - Optional + 2 (group client only) or 4 (group owner only) + if not present (or 1) role is negotiated by the two peers. + session - Mandatory Session ID of the first session to be established + session_mac - Mandatory MAC address that owns/initiated the session + method - Optional method to request for provisioning (1000 - P2PS Default, + 100 - Keypad(PIN), 8 - Display(PIN)) + info - Optional UTF-8 string. Hint for service to indicate possible usage + parameters - Escape single quote & backslash: + with a backslash 0x27 == ' == \', and 0x5c == \ == \\ + +p2p_asp_provision_resp <peer mac address> <adv_id= local adv id> + <adv_mac=local MAC address> <role=1|2|4> <status=0> + <session=session id> <session_mac=peer MAC address> + +This command sends a provision discovery response from responder side. + +For example, +p2p_asp_provision_resp 00:55:44:33:22:11 adv_id=4d6fc7 adv_mac=00:55:44:33:22:11 role=1 status=0 session=12ab34 session_mac=00:11:22:33:44:55 + +Parameters definition: + MAC address - Mandatory + adv_id - Mandatory local Advertising ID of service connection is being + established for + adv_mac - Mandatory MAC address that owns/registered the service + role - Optional 2 (group client only) or 4 (group owner only) + if not present (or 1) role is negotiated by the two peers. + status - Mandatory Acceptance/Rejection code of Provisioning + session - Mandatory Session ID of the first session to be established + session_mac - Mandatory MAC address that owns/initiated the session + +p2p_group_add [persistent|persistent=<network id>] [freq=<freq in MHz>] + [ht40] [vht] [he] + +Set up a P2P group owner manually (i.e., without group owner +negotiation with a specific peer). This is also known as autonomous +GO. Optional persistent=<network id> can be used to specify restart of +a persistent group. Optional freq=<freq in MHz> can be used to force +the GO to be started on a specific frequency. Special freq=2 or freq=5 +options can be used to request the best 2.4 GHz or 5 GHz band channel +to be selected automatically. + +p2p_reject <peer device address> + +Reject connection attempt from a peer (specified with a device +address). This is a mechanism to reject a pending GO Negotiation with +a peer and request to automatically block any further connection or +discovery of the peer. + +p2p_group_remove <group interface> + +Terminate a P2P group. If a new virtual network interface was used for +the group, it will also be removed. The network interface name of the +group interface is used as a parameter for this command. + +p2p_cancel + +Cancel an ongoing P2P group formation and joining-a-group related +operation. This operation unauthorizes the specific peer device (if any +had been authorized to start group formation), stops P2P find (if in +progress), stops pending operations for join-a-group, and removes the +P2P group interface (if one was used) that is in the WPS provisioning +step. If the WPS provisioning step has been completed, the group is not +terminated. + +p2p_remove_client <peer's P2P Device Address|iface=<interface address>> + +This command can be used to remove the specified client from all groups +(operating and persistent) from the local GO. Note that the peer device +can rejoin the group if it is in possession of a valid key. See p2p_set +per_sta_psk command below for more details on how the peer can be +removed securely. + +Service Discovery + +p2p_service_add asp <auto accept> <adv id> <status 0/1> <Config Methods> + <Service name> [Service Information] [Response Info] + +This command can be used to search for a P2PS service which includes +Play, Send, Display, and Print service. The parameters for this command +are "asp" to identify the command as P2PS one, auto accept value, +advertisement id which uniquely identifies the service requests, state +of the service whether the service is available or not, config methods +which can be either P2PS method or PIN method, service name followed by +two optional parameters service information, and response info. + +For example, +p2p_service_add asp 1 4d6fc7 0 1108 alt.example.chat svc_info='name=john' rsp_info='enter PIN 1234' + +Parameters definition: + asp - Mandatory for ASP service registration + auto accept - Mandatory ASCII hex-encoded boolean (0 == no auto-accept, + 1 == auto-accept ANY role, 2 == auto-accept CLIENT role, + 4 == auto-accept GO role) + Advertisement ID - Mandatory non-zero ASCII hex-encoded u32 + (Must be unique/not yet exist in svc db) + State - Mandatory ASCII hex-encoded u8 (0 -- Svc not available, + 1 -- Svc available, 2-0xff Application defined) + Config Methods - Mandatory ASCII hex-encoded u16 (bitmask of WSC config + methods) + Service Name - Mandatory UTF-8 string + Service Information - Optional UTF-8 string + Escape single quote & backslash with a backslash: + 0x27 == ' == \', and 0x5c == \ == \\ + Session response information - Optional (used only if auto accept is TRUE) + UTF-8 string + Escape single quote & backslash with a backslash: + 0x27 == ' == \', and 0x5c == \ == \\ + +p2p_service_rep asp <auto accept> <adv id> <status 0/1> <Config Methods> + <Service name> [Service Information] [Response Info] + +This command can be used to replace the existing service request +attributes from the initiator side. The replacement is only allowed if +the advertisement id issued in the command matches with any one entry in +the list of existing SD queries. If advertisement id doesn't match the +command returns a failure. + +For example, +p2p_service_rep asp 1 4d6fc7 1 1108 alt.example.chat svc_info='name=john' rsp_info='enter PIN 1234' + +Parameters definition: + asp - Mandatory for ASP service registration + auto accept - Mandatory ASCII hex-encoded boolean (1 == true, 0 == false) + Advertisement ID - Mandatory non-zero ASCII hex-encoded u32 + (Must already exist in svc db) + State - Mandatory ASCII hex-encoded u8 (can be used to indicate svc + available or not available for instance) + Config Methods - Mandatory ASCII hex-encoded u16 (bitmask of WSC config + methods) + Service Name - Mandatory UTF-8 string (Must match existing string in svc db) + Service Information - Optional UTF-8 string + Escape single quote & backslash with a backslash: + 0x27 == ' == \', and 0x5c == \ == \\ + Session response information - Optional (used only if auto accept is TRUE) + UTF-8 string + Escape single quote & backslash with a backslash: + 0x27 == ' == \', and 0x5c == \ == \\ + +p2p_serv_disc_req + +Schedule a P2P service discovery request. The parameters for this +command are the device address of the peer device (or 00:00:00:00:00:00 +for wildcard query that is sent to every discovered P2P peer that +supports service discovery) and P2P Service Query TLV(s) as hexdump. For +example, + +p2p_serv_disc_req 00:00:00:00:00:00 02000001 + +schedules a request for listing all available services of all service +discovery protocols and requests this to be sent to all discovered +peers (note: this can result in long response frames). The pending +requests are sent during device discovery (see p2p_find). + +There can be multiple pending peer device specific queries (each will be +sent in sequence whenever the peer is found). + +This command returns an identifier for the pending query (e.g., +"1f77628") that can be used to cancel the request. Directed requests +will be automatically removed when the specified peer has replied to +it. + +Service Query TLV has following format: +Length (2 octets, little endian) - length of following data +Service Protocol Type (1 octet) - see the table below +Service Transaction ID (1 octet) - nonzero identifier for the TLV +Query Data (Length - 2 octets of data) - service protocol specific data + +Service Protocol Types: +0 = All service protocols +1 = Bonjour +2 = UPnP +3 = WS-Discovery +4 = Wi-Fi Display + +For UPnP, an alternative command format can be used to specify a +single query TLV (i.e., a service discovery for a specific UPnP +service): + +p2p_serv_disc_req 00:00:00:00:00:00 upnp <version hex> <ST: from M-SEARCH> + +For example: + +p2p_serv_disc_req 00:00:00:00:00:00 upnp 10 urn:schemas-upnp-org:device:InternetGatewayDevice:1 + +Additional examples for queries: + +# list of all Bonjour services +p2p_serv_disc_req 00:00:00:00:00:00 02000101 + +# list of all UPnP services +p2p_serv_disc_req 00:00:00:00:00:00 02000201 + +# list of all WS-Discovery services +p2p_serv_disc_req 00:00:00:00:00:00 02000301 + +# list of all Bonjour and UPnP services +p2p_serv_disc_req 00:00:00:00:00:00 0200010102000202 + +# Apple File Sharing over TCP +p2p_serv_disc_req 00:00:00:00:00:00 130001010b5f6166706f766572746370c00c000c01 + +# Bonjour SSTH (supported service type hash) +p2p_serv_disc_req 00:00:00:00:00:00 05000101000000 + +# UPnP examples +p2p_serv_disc_req 00:00:00:00:00:00 upnp 10 ssdp:all +p2p_serv_disc_req 00:00:00:00:00:00 upnp 10 upnp:rootdevice +p2p_serv_disc_req 00:00:00:00:00:00 upnp 10 urn:schemas-upnp-org:service:ContentDirectory:2 +p2p_serv_disc_req 00:00:00:00:00:00 upnp 10 uuid:6859dede-8574-59ab-9332-123456789012 +p2p_serv_disc_req 00:00:00:00:00:00 upnp 10 urn:schemas-upnp-org:device:InternetGatewayDevice:1 + +# Wi-Fi Display examples +# format: wifi-display <list of roles> <list of subelements> +p2p_serv_disc_req 00:00:00:00:00:00 wifi-display [source] 2,3,4,5 +p2p_serv_disc_req 02:01:02:03:04:05 wifi-display [pri-sink] 3 +p2p_serv_disc_req 00:00:00:00:00:00 wifi-display [sec-source] 2 +p2p_serv_disc_req 00:00:00:00:00:00 wifi-display [source+sink] 2,3,4,5 +p2p_serv_disc_req 00:00:00:00:00:00 wifi-display [source][pri-sink] 2,3,4,5 + +p2p_serv_disc_req <Unicast|Broadcast mac address> asp <Transaction ID> + <Service Name> [Service Information] + +The command can be used for service discovery for P2PS enabled devices. + +For example: p2p_serv_disc_req 00:00:00:00:00:00 asp a1 alt.example 'john' + +Parameters definition: + MAC address - Mandatory Existing + asp - Mandatory for ASP queries + Transaction ID - Mandatory non-zero ASCII hex-encoded u8 for GAS + Service Name Prefix - Mandatory UTF-8 string. + Will match from beginning of remote Service Name + Service Information Substring - Optional UTF-8 string + If Service Information Substring is not included, all services matching + Service Name Prefix will be returned. + If Service Information Substring is included, both the Substring and the + Service Name Prefix must match for service to be returned. + If remote service has no Service Information, all Substring searches + will fail. + +p2p_serv_disc_cancel_req <query identifier> + +Cancel a pending P2P service discovery request. This command takes a +single parameter: identifier for the pending query (the value returned +by p2p_serv_disc_req, e.g., "p2p_serv_disc_cancel_req 1f77628". + +p2p_serv_disc_resp + +Reply to a service discovery query. This command takes following +parameters: frequency in MHz, destination address, dialog token, +response TLV(s). The first three parameters are copied from the +request event. For example, "p2p_serv_disc_resp 2437 02:40:61:c2:f3:b7 +1 0300000101". This command is used only if external program is used +to process the request (see p2p_serv_disc_external). + +p2p_service_update + +Indicate that local services have changed. This is used to increment +the P2P service indicator value so that peers know when previously +cached information may have changed. This is only needed when external +service discovery processing is enabled since the commands to +pre-configure services for internal processing will increment the +indicator automatically. + +p2p_serv_disc_external <0|1> + +Configure external processing of P2P service requests: 0 (default) = +no external processing of requests (i.e., internal code will process +each request based on pre-configured services), 1 = external +processing of requests (external program is responsible for replying +to service discovery requests with p2p_serv_disc_resp). Please note +that there is quite strict limit on how quickly the response needs to +be transmitted, so use of the internal processing is strongly +recommended. + +p2p_service_add bonjour <query hexdump> <RDATA hexdump> + +Add a local Bonjour service for internal SD query processing. + +Examples: + +# AFP Over TCP (PTR) +p2p_service_add bonjour 0b5f6166706f766572746370c00c000c01 074578616d706c65c027 +# AFP Over TCP (TXT) (RDATA=null) +p2p_service_add bonjour 076578616d706c650b5f6166706f766572746370c00c001001 00 + +# IP Printing over TCP (PTR) (RDATA=MyPrinter._ipp._tcp.local.) +p2p_service_add bonjour 045f697070c00c000c01 094d795072696e746572c027 +# IP Printing over TCP (TXT) (RDATA=txtvers=1,pdl=application/postscript) +p2p_service_add bonjour 096d797072696e746572045f697070c00c001001 09747874766572733d311a70646c3d6170706c69636174696f6e2f706f7374736372797074 + +# Supported Service Type Hash (SSTH) +p2p_service_add bonjour 000000 <32-byte bitfield as hexdump> +(note: see P2P spec Annex E.4 for information on how to construct the bitfield) + +p2p_service_del bonjour <query hexdump> + +Remove a local Bonjour service from internal SD query processing. + +p2p_service_add upnp <version hex> <service> + +Add a local UPnP service for internal SD query processing. + +Examples: + +p2p_service_add upnp 10 uuid:6859dede-8574-59ab-9332-123456789012::upnp:rootdevice +p2p_service_add upnp 10 uuid:5566d33e-9774-09ab-4822-333456785632::upnp:rootdevice +p2p_service_add upnp 10 uuid:1122de4e-8574-59ab-9322-333456789044::urn:schemas-upnp-org:service:ContentDirectory:2 +p2p_service_add upnp 10 uuid:5566d33e-9774-09ab-4822-333456785632::urn:schemas-upnp-org:service:ContentDirectory:2 +p2p_service_add upnp 10 uuid:6859dede-8574-59ab-9332-123456789012::urn:schemas-upnp-org:device:InternetGatewayDevice:1 + +p2p_service_del upnp <version hex> <service> + +Remove a local UPnP service from internal SD query processing. + +p2p_service_del asp <adv id> + +Removes the local asp service from internal SD query list. +For example: p2p_service_del asp 4d6fc7 + +p2p_service_flush + +Remove all local services from internal SD query processing. + +Invitation + +p2p_invite [persistent=<network id>|group=<group ifname>] [peer=address] + [go_dev_addr=address] [freq=<freq in MHz>] [ht40] [vht] [he] + [pref=<MHz>] + +Invite a peer to join a group (e.g., group=wlan1) or to reinvoke a +persistent group (e.g., persistent=4). If the peer device is the GO of +the persistent group, the peer parameter is not needed. Otherwise it is +used to specify which device to invite. go_dev_addr parameter can be +used to override the GO device address for Invitation Request should +it be not known for some reason (this should not be needed in most +cases). When reinvoking a persistent group, the GO device can specify +the frequency for the group with the freq parameter. When reinvoking a +persistent group, the P2P client device can use freq parameter to force +a specific operating channel (or invitation failure if GO rejects that) +or pref parameter to request a specific channel (while allowing GO to +select to use another channel, if needed). + +Group Operations + +(These are used on the group interface.) + +wps_pin <any|address> <PIN> + +Start WPS PIN method. This allows a single WPS Enrollee to connect to +the AP/GO. This is used on the GO when a P2P client joins an existing +group. The second parameter is the address of the Enrollee or a string +"any" to allow any station to use the entered PIN (which will restrict +the PIN for one-time-use). PIN is the Enrollee PIN read either from a +label or display on the P2P Client/WPS Enrollee. + +wps_pbc + +Start WPS PBC method (i.e., push the button). This allows a single WPS +Enrollee to connect to the AP/GO. This is used on the GO when a P2P +client joins an existing group. + +p2p_get_passphrase + +Get the passphrase for a group (only available when acting as a GO). + +p2p_presence_req [<duration> <interval>] [<duration> <interval>] + +Send a P2P Presence Request to the GO (this is only available when +acting as a P2P client). If no duration/interval pairs are given, the +request indicates that this client has no special needs for GO +presence. The first parameter pair gives the preferred duration and +interval values in microseconds. If the second pair is included, that +indicates which value would be acceptable. This command returns OK +immediately and the response from the GO is indicated in a +P2P-PRESENCE-RESPONSE event message. + +Parameters + +p2p_ext_listen [<period> <interval>] + +Configure Extended Listen Timing. If the parameters are omitted, this +feature is disabled. If the parameters are included, Listen State will +be entered every interval msec for at least period msec. Both values +have acceptable range of 1-65535 (with interval obviously having to be +larger than or equal to duration). If the P2P module is not idle at +the time the Extended Listen Timing timeout occurs, the Listen State +operation will be skipped. + +The configured values will also be advertised to other P2P Devices. The +received values are available in the p2p_peer command output: + +ext_listen_period=100 ext_listen_interval=5000 + +p2p_set <field> <value> + +Change dynamic P2P parameters + +p2p_set discoverability <0/1> + +Disable/enable advertisement of client discoverability. This is +enabled by default and this parameter is mainly used to allow testing +of device discoverability. + +p2p_set managed <0/1> + +Disable/enable managed P2P Device operations. This is disabled by +default. + +p2p_set listen_channel <channel> [<op_class>] + +Set P2P Listen channel. This is mainly meant for testing purposes and +changing the Listen channel during normal operations can result in +protocol failures. + +When specifying a social channel on the 2.4 GHz band (1/6/11) there is +no need to specify the operating class since it defaults to 81. When +specifying a social channel on the 60 GHz band (2), specify the 60 GHz +operating class (180). + +p2p_set ssid_postfix <postfix> + +Set postfix string to be added to the automatically generated P2P SSID +(DIRECT-<two random characters>). For example, postfix of "-testing" +could result in the SSID becoming DIRECT-ab-testing. + +p2p_set per_sta_psk <0/1> + +Disabled(default)/enables use of per-client PSK in the P2P groups. This +can be used to request GO to assign a unique PSK for each client during +WPS provisioning. When enabled, this allow clients to be removed from +the group securely with p2p_remove_client command since that client's +PSK is removed at the same time to prevent it from connecting back using +the old PSK. When per-client PSK is not used, the client can still be +disconnected, but it will be able to re-join the group since the PSK it +learned previously is still valid. It should be noted that the default +passphrase on the GO that is normally used to allow legacy stations to +connect through manual configuration does not change here, so if that is +shared, devices with knowledge of that passphrase can still connect. + +set <field> <value> + +Set global configuration parameters which may also affect P2P +operations. The format on these parameters is same as is used in +wpa_supplicant.conf. Only the parameters listen here should be +changed. Modifying other parameters may result in incorrect behavior +since not all existing users of the parameters are updated. + +set uuid <UUID> + +Set WPS UUID (by default, this is generated based on the MAC address). + +set device_name <device name> + +Set WPS Device Name (also included in some P2P messages). + +set manufacturer <manufacturer> + +Set WPS Manufacturer. + +set model_name <model name> + +Set WPS Model Name. + +set model_number <model number> + +Set WPS Model Number. + +set serial_number <serial number> + +Set WPS Serial Number. + +set device_type <device type> + +Set WPS Device Type. + +set os_version <OS version> + +Set WPS OS Version. + +set config_methods <config methods> + +Set WPS Configuration Methods. + +set sec_device_type <device type> + +Add a new Secondary Device Type. + +set p2p_go_intent <GO intent> + +Set the default P2P GO Intent. Note: This value can be overridden in +p2p_connect command and as such, there should be no need to change the +default value here during normal operations. + +set p2p_ssid_postfix <P2P SSID postfix> + +Set P2P SSID postfix. + +set persistent_reconnect <0/1> + +Disable/enabled persistent reconnect for reinvocation of persistent +groups. If enabled, invitations to reinvoke a persistent group will be +accepted without separate authorization (e.g., user interaction). + +set country <two character country code> + +Set country code (this is included in some P2P messages). + +set p2p_search_delay <delay> + +Set p2p_search_delay which adds extra delay in milliseconds between +concurrent search iterations to make p2p_find friendlier to concurrent +operations by avoiding it from taking 100% of radio resources. The +default value is 500 ms. + +Status + +p2p_peers [discovered] + +List P2P Device Addresses of all the P2P peers we know. The optional +"discovered" parameter filters out the peers that we have not fully +discovered, i.e., which we have only seen in a received Probe Request +frame. + +p2p_peer <P2P Device Address> + +Fetch information about a known P2P peer. + +Group Status + +(These are used on the group interface.) + +status + +Show status information (connection state, role, use encryption +parameters, IP address, etc.). + +sta + +Show information about an associated station (when acting in AP/GO role). + +all_sta + +Lists the currently associated stations. + +Configuration data + +list_networks + +Lists the configured networks, including stored information for +persistent groups. The identifier in this list is used with +p2p_group_add and p2p_invite to indicate which persistent group is to +be reinvoked. + +remove_network <network id> + +Remove a network entry from configuration. + + +P2PS Events/Responses: + +P2PS-PROV-START: This events gets triggered when provisioning is issued for +either seeker or advertiser. + +For example, +P2PS-PROV-START 00:55:44:33:22:11 adv_id=111 adv_mac=00:55:44:33:22:11 conncap=1 session=1234567 session_mac=00:11:22:33:44:55 info='xxxx' + +Parameters definition: + MAC address - always + adv_id - always ASCII hex-encoded u32 + adv_mac - always MAC address that owns/registered the service + conncap - always mask of 0x01 (new), 0x02 (group client), 0x04 (group owner) + bits + session - always Session ID of the first session to be established + session_mac - always MAC address that owns/initiated the session + info - if available, UTF-8 string + Escaped single quote & backslash with a backslash: + \' == 0x27 == ', and \\ == 0x5c == \ + +P2PS-PROV-DONE: When provisioning is completed then this event gets triggered. + +For example, +P2PS-PROV-DONE 00:11:22:33:44:55 status=0 adv_id=111 adv_mac=00:55:44:33:22:11 conncap=1 session=1234567 session_mac=00:11:22:33:44:55 [dev_passwd_id=8 | go=p2p-wlan0-0 | join=11:22:33:44:55:66 | persist=0] + +Parameters definition: + MAC address - always main device address of peer. May be different from MAC + ultimately connected to. + status - always ascii hex-encoded u8 (0 == success, 12 == deferred success) + adv_id - always ascii hex-encoded u32 + adv_mac - always MAC address that owns/registered the service + conncap - always One of: 1 (new), 2 (group client), 4 (group owner) bits + session - always Session ID of the first session to be established + session_mac - always MAC address that owns/initiated the session + dev_passwd_id - only if conncap value == 1 (New GO negotiation) + 8 - "p2ps" password must be passed in p2p_connect command + 1 - "display" password must be passed in p2p_connect command + 5 - "keypad" password must be passed in p2p_connect command + join only - if conncap value == 2 (Client Only). Display password and "join" + must be passed in p2p_connect and address must be the MAC specified + go only - if conncap value == 4 (GO Only). Interface name must be set with a + password + persist - only if previous persistent group existed between peers and shall + be re-used. Group is restarted by sending "p2p_group_add persistent=0" + where value is taken from P2P-PROV-DONE + +Extended Events/Response + +P2P-DEVICE-FOUND 00:11:22:33:44:55 p2p_dev_addr=00:11:22:33:44:55 pri_dev_type=0-00000000-0 name='' config_methods=0x108 dev_capab=0x21 group_capab=0x0 adv_id=111 asp_svc=alt.example.chat + +Parameters definition: + adv_id - if ASP ASCII hex-encoded u32. If it is reporting the + "wildcard service", this value will be 0 + asp_svc - if ASP this is the service string. If it is reporting the + "wildcard service", this value will be org.wi-fi.wfds + + +wpa_cli action script +--------------------- + +See examples/p2p-action.sh + +TODO: describe DHCP/DNS setup +TODO: cross-connection diff --git a/wpa_supplicant/README-WPS b/wpa_supplicant/README-WPS new file mode 100644 index 000000000000..b884f67a2435 --- /dev/null +++ b/wpa_supplicant/README-WPS @@ -0,0 +1,399 @@ +wpa_supplicant and Wi-Fi Protected Setup (WPS) +============================================== + +This document describes how the WPS implementation in wpa_supplicant +can be configured and how an external component on the client (e.g., +management GUI) is used to enable WPS enrollment and registrar +registration. + + +Introduction to WPS +------------------- + +Wi-Fi Protected Setup (WPS) is a mechanism for easy configuration of a +wireless network. It allows automated generation of random keys (WPA +passphrase/PSK) and configuration of an access point and client +devices. WPS includes number of methods for setting up connections +with PIN method and push-button configuration (PBC) being the most +commonly deployed options. + +While WPS can enable more home networks to use encryption in the +wireless network, it should be noted that the use of the PIN and +especially PBC mechanisms for authenticating the initial key setup is +not very secure. As such, use of WPS may not be suitable for +environments that require secure network access without chance for +allowing outsiders to gain access during the setup phase. + +WPS uses following terms to describe the entities participating in the +network setup: +- access point: the WLAN access point +- Registrar: a device that control a network and can authorize + addition of new devices); this may be either in the AP ("internal + Registrar") or in an external device, e.g., a laptop, ("external + Registrar") +- Enrollee: a device that is being authorized to use the network + +It should also be noted that the AP and a client device may change +roles (i.e., AP acts as an Enrollee and client device as a Registrar) +when WPS is used to configure the access point. + + +More information about WPS is available from Wi-Fi Alliance: +http://www.wi-fi.org/wifi-protected-setup + + +wpa_supplicant implementation +----------------------------- + +wpa_supplicant includes an optional WPS component that can be used as +an Enrollee to enroll new network credential or as a Registrar to +configure an AP. + + +wpa_supplicant configuration +---------------------------- + +WPS is an optional component that needs to be enabled in +wpa_supplicant build configuration (.config). Here is an example +configuration that includes WPS support and Linux nl80211 -based +driver interface: + +CONFIG_DRIVER_NL80211=y +CONFIG_WPS=y + +If you want to enable WPS external registrar (ER) functionality, you +will also need to add following line: + +CONFIG_WPS_ER=y + +Following parameter can be used to enable support for NFC config method: + +CONFIG_WPS_NFC=y + + +WPS needs the Universally Unique IDentifier (UUID; see RFC 4122) for +the device. This is configured in the runtime configuration for +wpa_supplicant (if not set, UUID will be generated based on local MAC +address): + +# example UUID for WPS +uuid=12345678-9abc-def0-1234-56789abcdef0 + +The network configuration blocks needed for WPS are added +automatically based on control interface commands, so they do not need +to be added explicitly in the configuration file. + +WPS registration will generate new network blocks for the acquired +credentials. If these are to be stored for future use (after +restarting wpa_supplicant), wpa_supplicant will need to be configured +to allow configuration file updates: + +update_config=1 + + + +External operations +------------------- + +WPS requires either a device PIN code (usually, 8-digit number) or a +pushbutton event (for PBC) to allow a new WPS Enrollee to join the +network. wpa_supplicant uses the control interface as an input channel +for these events. + +The PIN value used in the commands must be processed by an UI to +remove non-digit characters and potentially, to verify the checksum +digit. "wpa_cli wps_check_pin <PIN>" can be used to do such processing. +It returns FAIL if the PIN is invalid, or FAIL-CHECKSUM if the checksum +digit is incorrect, or the processed PIN (non-digit characters removed) +if the PIN is valid. + +If the client device has a display, a random PIN has to be generated +for each WPS registration session. wpa_supplicant can do this with a +control interface request, e.g., by calling wpa_cli: + +wpa_cli wps_pin any + +This will return the generated 8-digit PIN which will then need to be +entered at the Registrar to complete WPS registration. At that point, +the client will be enrolled with credentials needed to connect to the +AP to access the network. + + +If the client device does not have a display that could show the +random PIN, a hardcoded PIN that is printed on a label can be +used. wpa_supplicant is notified this with a control interface +request, e.g., by calling wpa_cli: + +wpa_cli wps_pin any 12345670 + +This starts the WPS negotiation in the same way as above with the +generated PIN. + +When the wps_pin command is issued for an AP (including P2P GO) mode +interface, an optional timeout parameter can be used to specify +expiration timeout for the PIN in seconds. For example: + +wpa_cli wps_pin any 12345670 300 + + +If a random PIN is needed for a user interface, "wpa_cli wps_pin get" +can be used to generate a new PIN without starting WPS negotiation. +This random PIN can then be passed as an argument to another wps_pin +call when the actual operation should be started. + +If the client design wants to support optional WPS PBC mode, this can +be enabled by either a physical button in the client device or a +virtual button in the user interface. The PBC operation requires that +a button is also pressed at the AP/Registrar at about the same time (2 +minute window). wpa_supplicant is notified of the local button event +over the control interface, e.g., by calling wpa_cli: + +wpa_cli wps_pbc + +At this point, the AP/Registrar has two minutes to complete WPS +negotiation which will generate a new WPA PSK in the same way as the +PIN method described above. + + +If the client wants to operate in the Registrar role to learn the +current AP configuration and optionally, to configure an AP, +wpa_supplicant is notified over the control interface, e.g., with +wpa_cli: + +wpa_cli wps_reg <AP BSSID> <AP PIN> +(example: wpa_cli wps_reg 02:34:56:78:9a:bc 12345670) + +This is used to fetch the current AP settings instead of actually +changing them. The main difference with the wps_pin command is that +wps_reg uses the AP PIN (e.g., from a label on the AP) instead of a +PIN generated at the client. + +In order to change the AP configuration, the new configuration +parameters are given to the wps_reg command: + +wpa_cli wps_reg <AP BSSID> <AP PIN> <new SSID> <auth> <encr> <new key> +examples: + wpa_cli wps_reg 02:34:56:78:9a:bc 12345670 testing WPA2PSK CCMP 12345678 + wpa_cli wps_reg 02:34:56:78:9a:bc 12345670 clear OPEN NONE "" + +<auth> must be one of the following: OPEN WPAPSK WPA2PSK +<encr> must be one of the following: NONE WEP TKIP CCMP + + +Scanning +-------- + +Scan results ('wpa_cli scan_results' or 'wpa_cli bss <idx>') include a +flags field that is used to indicate whether the BSS support WPS. If +the AP support WPS, but has not recently activated a Registrar, [WPS] +flag will be included. If PIN method has been recently selected, +[WPS-PIN] is shown instead. Similarly, [WPS-PBC] is shown if PBC mode +is in progress. GUI programs can use these as triggers for suggesting +a guided WPS configuration to the user. In addition, control interface +monitor events WPS-AP-AVAILABLE{,-PBC,-PIN} can be used to find out if +there are WPS enabled APs in scan results without having to go through +all the details in the GUI. These notification could be used, e.g., to +suggest possible WPS connection to the user. + + +wpa_gui +------- + +wpa_gui-qt4 directory contains a sample GUI that shows an example of +how WPS support can be integrated into the GUI. Its main window has a +WPS tab that guides user through WPS registration with automatic AP +selection. In addition, it shows how WPS can be started manually by +selecting an AP from scan results. + + +Credential processing +--------------------- + +By default, wpa_supplicant processes received credentials and updates +its configuration internally. However, it is possible to +control these operations from external programs, if desired. + +This internal processing can be disabled with wps_cred_processing=1 +option. When this is used, an external program is responsible for +processing the credential attributes and updating wpa_supplicant +configuration based on them. + +Following control interface messages are sent out for external programs: + +WPS-CRED-RECEIVED <hexdump of Credential attribute(s)> +For example: +<2>WPS-CRED-RECEIVED 100e006f10260001011045000c6a6b6d2d7770732d74657374100300020020100f000200081027004030653462303435366332363666653064333961643135353461316634626637313234333761636664623766333939653534663166316230323061643434386235102000060266a0ee1727 + + +wpa_supplicant as WPS External Registrar (ER) +--------------------------------------------- + +wpa_supplicant can be used as a WPS ER to configure an AP or enroll +new Enrollee to join the network. This functionality uses UPnP and +requires that a working IP connectivity is available with the AP (this +can be either over a wired or wireless connection). + +Separate wpa_supplicant process can be started for WPS ER +operations. A special "none" driver can be used in such a case to +indicate that no local network interface is actually controlled. For +example, following command could be used to start the ER: + +wpa_supplicant -Dnone -c er.conf -ieth0 + +Sample er.conf: + +ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=admin +device_name=WPS External Registrar + + +wpa_cli commands for ER functionality: + +wps_er_start [IP address] +- start WPS ER functionality +- the optional IP address parameter can be used to filter operations only + to include a single AP +- if run again while ER is active, the stored information (discovered APs + and Enrollees) are shown again + +wps_er_stop +- stop WPS ER functionality + +wps_er_learn <UUID|BSSID> <AP PIN> +- learn AP configuration + +wps_er_set_config <UUID|BSSID> <network id> +- use AP configuration from a locally configured network (e.g., from + wps_reg command); this does not change the AP's configuration, but + only prepares a configuration to be used when enrolling a new device + to the AP + +wps_er_config <UUID|BSSID> <AP PIN> <new SSID> <auth> <encr> <new key> +- examples: + wps_er_config 87654321-9abc-def0-1234-56789abc0002 12345670 testing WPA2PSK CCMP 12345678 + wpa_er_config 87654321-9abc-def0-1234-56789abc0002 12345670 clear OPEN NONE "" + +<auth> must be one of the following: OPEN WPAPSK WPA2PSK +<encr> must be one of the following: NONE WEP TKIP CCMP + + +wps_er_pbc <Enrollee UUID|MAC address> +- accept an Enrollee PBC using External Registrar + +wps_er_pin <Enrollee UUID|"any"|MAC address> <PIN> [Enrollee MAC address] +- add an Enrollee PIN to External Registrar +- if Enrollee UUID is not known, "any" can be used to add a wildcard PIN +- if the MAC address of the enrollee is known, it should be configured + to allow the AP to advertise list of authorized enrollees + + +WPS ER events: + +WPS_EVENT_ER_AP_ADD +- WPS ER discovered an AP + +WPS-ER-AP-ADD 87654321-9abc-def0-1234-56789abc0002 02:11:22:33:44:55 pri_dev_type=6-0050F204-1 wps_state=1 |Very friendly name|Company|Long description of the model|WAP|http://w1.fi/|http://w1.fi/hostapd/ + +WPS_EVENT_ER_AP_REMOVE +- WPS ER removed an AP entry + +WPS-ER-AP-REMOVE 87654321-9abc-def0-1234-56789abc0002 + +WPS_EVENT_ER_ENROLLEE_ADD +- WPS ER discovered a new Enrollee + +WPS-ER-ENROLLEE-ADD 2b7093f1-d6fb-5108-adbb-bea66bb87333 02:66:a0:ee:17:27 M1=1 config_methods=0x14d dev_passwd_id=0 pri_dev_type=1-0050F204-1 |Wireless Client|Company|cmodel|123|12345| + +WPS_EVENT_ER_ENROLLEE_REMOVE +- WPS ER removed an Enrollee entry + +WPS-ER-ENROLLEE-REMOVE 2b7093f1-d6fb-5108-adbb-bea66bb87333 02:66:a0:ee:17:27 + +WPS-ER-AP-SETTINGS +- WPS ER learned AP settings + +WPS-ER-AP-SETTINGS uuid=fd91b4ec-e3fa-5891-a57d-8c59efeed1d2 ssid=test-wps auth_type=0x0020 encr_type=0x0008 key=12345678 + + +WPS with NFC +------------ + +WPS can be used with NFC-based configuration method. An NFC tag +containing a password token from the Enrollee can be used to +authenticate the connection instead of the PIN. In addition, an NFC tag +with a configuration token can be used to transfer AP settings without +going through the WPS protocol. + +When the station acts as an Enrollee, a local NFC tag with a password +token can be used by touching the NFC interface of a Registrar. + +"wps_nfc [BSSID]" command starts WPS protocol run with the local end as +the Enrollee using the NFC password token that is either pre-configured +in the configuration file (wps_nfc_dev_pw_id, wps_nfc_dh_pubkey, +wps_nfc_dh_privkey, wps_nfc_dev_pw) or generated dynamically with +"wps_nfc_token <WPS|NDEF>" command. The included nfc_pw_token tool +(build with "make nfc_pw_token") can be used to generate NFC password +tokens during manufacturing (each station needs to have its own random +keys). + +The "wps_nfc_config_token <WPS/NDEF>" command can be used to build an +NFC configuration token when wpa_supplicant is controlling an AP +interface (AP or P2P GO). The output value from this command is a +hexdump of the current AP configuration (WPS parameter requests this to +include only the WPS attributes; NDEF parameter requests additional NDEF +encapsulation to be included). This data needs to be written to an NFC +tag with an external program. Once written, the NFC configuration token +can be used to touch an NFC interface on a station to provision the +credentials needed to access the network. + +The "wps_nfc_config_token <WPS/NDEF> <network id>" command can be used +to build an NFC configuration token based on a locally configured +network. + +If the station includes NFC interface and reads an NFC tag with a MIME +media type "application/vnd.wfa.wsc", the NDEF message payload (with or +without NDEF encapsulation) can be delivered to wpa_supplicant using the +following wpa_cli command: + +wps_nfc_tag_read <hexdump of payload> + +If the NFC tag contains a configuration token, the network is added to +wpa_supplicant configuration. If the NFC tag contains a password token, +the token is added to the WPS Registrar component. This information can +then be used with wps_reg command (when the NFC password token was from +an AP) using a special value "nfc-pw" in place of the PIN parameter. If +the ER functionality has been started (wps_er_start), the NFC password +token is used to enable enrollment of a new station (that was the source +of the NFC password token). + +"nfc_get_handover_req <NDEF> <WPS-CR>" command can be used to build the +WPS carrier record for a Handover Request Message for connection +handover. The first argument selects the format of the output data and +the second argument selects which type of connection handover is +requested (WPS-CR = Wi-Fi handover as specified in WSC 2.0). + +"nfc_get_handover_sel <NDEF> <WPS> [UUID|BSSID]" command can be used to +build the contents of a Handover Select Message for connection handover +when this does not depend on the contents of the Handover Request +Message. The first argument selects the format of the output data and +the second argument selects which type of connection handover is +requested (WPS = Wi-Fi handover as specified in WSC 2.0). If the options +UUID|BSSID argument is included, this is a request to build the handover +message for the specified AP when wpa_supplicant is operating as a WPS +ER. + +"nfc_report_handover <INIT/RESP> WPS <carrier from handover request> +<carrier from handover select>" can be used as an alternative way for +reporting completed NFC connection handover. The first parameter +indicates whether the local device initiated or responded to the +connection handover and the carrier records are the selected carrier +from the handover request and select messages as a hexdump. + +The "wps_er_nfc_config_token <WPS/NDEF> <UUID|BSSID>" command can be +used to build an NFC configuration token for the specified AP when +wpa_supplicant is operating as a WPS ER. The output value from this +command is a hexdump of the selected AP configuration (WPS parameter +requests this to include only the WPS attributes; NDEF parameter +requests additional NDEF encapsulation to be included). This data needs +to be written to an NFC tag with an external program. Once written, the +NFC configuration token can be used to touch an NFC interface on a +station to provision the credentials needed to access the network. diff --git a/wpa_supplicant/README-Windows.txt b/wpa_supplicant/README-Windows.txt new file mode 100644 index 000000000000..7288abd9a161 --- /dev/null +++ b/wpa_supplicant/README-Windows.txt @@ -0,0 +1,299 @@ +wpa_supplicant for Windows +========================== + +Copyright (c) 2003-2009, Jouni Malinen <j@w1.fi> and contributors +All Rights Reserved. + +This program is licensed under the BSD license (the one with +advertisement clause removed). + + +wpa_supplicant has support for being used as a WPA/WPA2/IEEE 802.1X +Supplicant on Windows. The current port requires that WinPcap +(http://winpcap.polito.it/) is installed for accessing packets and the +driver interface. Both release versions 3.0 and 3.1 are supported. + +The current port is still somewhat experimental. It has been tested +mainly on Windows XP (SP2) with limited set of NDIS drivers. In +addition, the current version has been reported to work with Windows +2000. + +All security modes have been verified to work (at least complete +authentication and successfully ping a wired host): +- plaintext +- static WEP / open system authentication +- static WEP / shared key authentication +- IEEE 802.1X with dynamic WEP keys +- WPA-PSK, TKIP, CCMP, TKIP+CCMP +- WPA-EAP, TKIP, CCMP, TKIP+CCMP +- WPA2-PSK, TKIP, CCMP, TKIP+CCMP +- WPA2-EAP, TKIP, CCMP, TKIP+CCMP + + +Building wpa_supplicant with mingw +---------------------------------- + +The default build setup for wpa_supplicant is to use MinGW and +cross-compiling from Linux to MinGW/Windows. It should also be +possible to build this under Windows using the MinGW tools, but that +is not tested nor supported and is likely to require some changes to +the Makefile unless cygwin is used. + + +Building wpa_supplicant with MSVC +--------------------------------- + +wpa_supplicant can be built with Microsoft Visual C++ compiler. This +has been tested with Microsoft Visual C++ Toolkit 2003 and Visual +Studio 2005 using the included nmake.mak as a Makefile for nmake. IDE +can also be used by creating a project that includes the files and +defines mentioned in nmake.mak. Example VS2005 solution and project +files are included in vs2005 subdirectory. This can be used as a +starting point for building the programs with VS2005 IDE. Visual Studio +2008 Express Edition is also able to use these project files. + +WinPcap development package is needed for the build and this can be +downloaded from http://www.winpcap.org/install/bin/WpdPack_4_0_2.zip. The +default nmake.mak expects this to be unpacked into C:\dev\WpdPack so +that Include and Lib directories are in this directory. The files can be +stored elsewhere as long as the WINPCAPDIR in nmake.mak is updated to +match with the selected directory. In case a project file in the IDE is +used, these Include and Lib directories need to be added to project +properties as additional include/library directories. + +OpenSSL source package can be downloaded from +http://www.openssl.org/source/openssl-0.9.8i.tar.gz and built and +installed following instructions in INSTALL.W32. Note that if EAP-FAST +support will be included in the wpa_supplicant, OpenSSL needs to be +patched to# support it openssl-0.9.8i-tls-extensions.patch. The example +nmake.mak file expects OpenSSL to be installed into C:\dev\openssl, but +this directory can be modified by changing OPENSSLDIR variable in +nmake.mak. + +If you do not need EAP-FAST support, you may also be able to use Win32 +binary installation package of OpenSSL from +http://www.slproweb.com/products/Win32OpenSSL.html instead of building +the library yourself. In this case, you will need to copy Include and +Lib directories in suitable directory, e.g., C:\dev\openssl for the +default nmake.mak. Copy {Win32OpenSSLRoot}\include into +C:\dev\openssl\include and make C:\dev\openssl\lib subdirectory with +files from {Win32OpenSSLRoot}\VC (i.e., libeay*.lib and ssleay*.lib). +This will end up using dynamically linked OpenSSL (i.e., .dll files are +needed) for it. Alternative, you can copy files from +{Win32OpenSSLRoot}\VC\static to create a static build (no OpenSSL .dll +files needed). + + +Building wpa_supplicant for cygwin +---------------------------------- + +wpa_supplicant can be built for cygwin by installing the needed +development packages for cygwin. This includes things like compiler, +make, openssl development package, etc. In addition, developer's pack +for WinPcap (WPdpack.zip) from +http://winpcap.polito.it/install/default.htm is needed. + +.config file should enable only one driver interface, +CONFIG_DRIVER_NDIS. In addition, include directories may need to be +added to match the system. An example configuration is available in +defconfig. The library and include files for WinPcap will either need +to be installed in compiler/linker default directories or their +location will need to be adding to .config when building +wpa_supplicant. + +Othen than this, the build should be more or less identical to Linux +version, i.e., just run make after having created .config file. An +additional tool, win_if_list.exe, can be built by running "make +win_if_list". + + +Building wpa_gui +---------------- + +wpa_gui uses Qt application framework from Trolltech. It can be built +with the open source version of Qt4 and MinGW. Following commands can +be used to build the binary in the Qt 4 Command Prompt: + +# go to the root directory of wpa_supplicant source code +cd wpa_gui-qt4 +qmake -o Makefile wpa_gui.pro +make +# the wpa_gui.exe binary is created into 'release' subdirectory + + +Using wpa_supplicant for Windows +-------------------------------- + +wpa_supplicant, wpa_cli, and wpa_gui behave more or less identically to +Linux version, so instructions in README and example wpa_supplicant.conf +should be applicable for most parts. In addition, there is another +version of wpa_supplicant, wpasvc.exe, which can be used as a Windows +service and which reads its configuration from registry instead of +text file. + +When using access points in "hidden SSID" mode, ap_scan=2 mode need to +be used (see wpa_supplicant.conf for more information). + +Windows NDIS/WinPcap uses quite long interface names, so some care +will be needed when starting wpa_supplicant. Alternatively, the +adapter description can be used as the interface name which may be +easier since it is usually in more human-readable +format. win_if_list.exe can be used to find out the proper interface +name. + +Example steps in starting up wpa_supplicant: + +# win_if_list.exe +ifname: \Device\NPF_GenericNdisWanAdapter +description: Generic NdisWan adapter + +ifname: \Device\NPF_{769E012B-FD17-4935-A5E3-8090C38E25D2} +description: Atheros Wireless Network Adapter (Microsoft's Packet Scheduler) + +ifname: \Device\NPF_{732546E7-E26C-48E3-9871-7537B020A211} +description: Intel 8255x-based Integrated Fast Ethernet (Microsoft's Packet Scheduler) + + +Since the example configuration used Atheros WLAN card, the middle one +is the correct interface in this case. The interface name for -i +command line option is the full string following "ifname:" (the +"\Device\NPF_" prefix can be removed). In other words, wpa_supplicant +would be started with the following command: + +# wpa_supplicant.exe -i'{769E012B-FD17-4935-A5E3-8090C38E25D2}' -c wpa_supplicant.conf -d + +-d optional enables some more debugging (use -dd for even more, if +needed). It can be left out if debugging information is not needed. + +With the alternative mechanism for selecting the interface, this +command has identical results in this case: + +# wpa_supplicant.exe -iAtheros -c wpa_supplicant.conf -d + + +Simple configuration example for WPA-PSK: + +#ap_scan=2 +ctrl_interface= +network={ + ssid="test" + key_mgmt=WPA-PSK + proto=WPA + pairwise=TKIP + psk="secret passphrase" +} + +(remove '#' from the comment out ap_scan line to enable mode in which +wpa_supplicant tries to associate with the SSID without doing +scanning; this allows APs with hidden SSIDs to be used) + + +wpa_cli.exe and wpa_gui.exe can be used to interact with the +wpa_supplicant.exe program in the same way as with Linux. Note that +ctrl_interface is using UNIX domain sockets when built for cygwin, but +the native build for Windows uses named pipes and the contents of the +ctrl_interface configuration item is used to control access to the +interface. Anyway, this variable has to be included in the configuration +to enable the control interface. + + +Example SDDL string formats: + +(local admins group has permission, but nobody else): + +ctrl_interface=SDDL=D:(A;;GA;;;BA) + +("A" == "access allowed", "GA" == GENERIC_ALL == all permissions, and +"BA" == "builtin administrators" == the local admins. The empty fields +are for flags and object GUIDs, none of which should be required in this +case.) + +(local admins and the local "power users" group have permissions, +but nobody else): + +ctrl_interface=SDDL=D:(A;;GA;;;BA)(A;;GA;;;PU) + +(One ACCESS_ALLOWED ACE for GENERIC_ALL for builtin administrators, and +one ACCESS_ALLOWED ACE for GENERIC_ALL for power users.) + +(close to wide open, but you have to be a valid user on +the machine): + +ctrl_interface=SDDL=D:(A;;GA;;;AU) + +(One ACCESS_ALLOWED ACE for GENERIC_ALL for the "authenticated users" +group.) + +This one would allow absolutely everyone (including anonymous +users) -- this is *not* recommended, since named pipes can be attached +to from anywhere on the network (i.e. there's no "this machine only" +like there is with 127.0.0.1 sockets): + +ctrl_interface=SDDL=D:(A;;GA;;;BU)(A;;GA;;;AN) + +(BU == "builtin users", "AN" == "anonymous") + +See also [1] for the format of ACEs, and [2] for the possible strings +that can be used for principal names. + +[1] +http://msdn.microsoft.com/library/default.asp?url=/library/en-us/secauthz/security/ace_strings.asp +[2] +http://msdn.microsoft.com/library/default.asp?url=/library/en-us/secauthz/security/sid_strings.asp + + +Starting wpa_supplicant as a Windows service (wpasvc.exe) +--------------------------------------------------------- + +wpa_supplicant can be started as a Windows service by using wpasvc.exe +program that is alternative build of wpa_supplicant.exe. Most of the +core functionality of wpasvc.exe is identical to wpa_supplicant.exe, |