diff options
71 files changed, 1526 insertions, 432 deletions
diff --git a/hostapd/Android.mk b/hostapd/Android.mk index 85ac8c5a..10f50d85 100644 --- a/hostapd/Android.mk +++ b/hostapd/Android.mk @@ -687,8 +687,10 @@ endif endif ifdef NEED_AES_CBC NEED_AES_DEC=y +ifneq ($(CONFIG_TLS), openssl) AESOBJS += src/crypto/aes-cbc.c endif +endif ifdef NEED_AES_DEC ifdef CONFIG_INTERNAL_AES AESOBJS += src/crypto/aes-internal-dec.c diff --git a/hostapd/Makefile b/hostapd/Makefile index d718c15e..3c7bd6f9 100644 --- a/hostapd/Makefile +++ b/hostapd/Makefile @@ -227,6 +227,7 @@ CFLAGS += -DCONFIG_SAE OBJS += ../src/common/sae.o NEED_ECC=y NEED_DH_GROUPS=y +NEED_AP_MLME=y endif ifdef CONFIG_WNM @@ -683,8 +684,10 @@ endif endif ifdef NEED_AES_CBC NEED_AES_DEC=y +ifneq ($(CONFIG_TLS), openssl) AESOBJS += ../src/crypto/aes-cbc.o endif +endif ifdef NEED_AES_DEC ifdef CONFIG_INTERNAL_AES AESOBJS += ../src/crypto/aes-internal-dec.o diff --git a/hostapd/config_file.c b/hostapd/config_file.c index cae9fd30..82b08f92 100644 --- a/hostapd/config_file.c +++ b/hostapd/config_file.c @@ -222,9 +222,15 @@ static int hostapd_config_read_eap_user(const char *fname, return 0; if (os_strncmp(fname, "sqlite:", 7) == 0) { +#ifdef CONFIG_SQLITE os_free(conf->eap_user_sqlite); conf->eap_user_sqlite = os_strdup(fname + 7); return 0; +#else /* CONFIG_SQLITE */ + wpa_printf(MSG_ERROR, + "EAP user file in SQLite DB, but CONFIG_SQLITE was not enabled in the build."); + return -1; +#endif /* CONFIG_SQLITE */ } f = fopen(fname, "r"); diff --git a/hostapd/hlr_auc_gw.c b/hostapd/hlr_auc_gw.c index 42d59dba..8afe4570 100644 --- a/hostapd/hlr_auc_gw.c +++ b/hostapd/hlr_auc_gw.c @@ -87,6 +87,7 @@ struct milenage_parameters { u8 amf[2]; u8 sqn[6]; int set; + size_t res_len; }; static struct milenage_parameters *milenage_db = NULL; @@ -96,6 +97,7 @@ static struct milenage_parameters *milenage_db = NULL; #define EAP_AKA_RAND_LEN 16 #define EAP_AKA_AUTN_LEN 16 #define EAP_AKA_AUTS_LEN 14 +#define EAP_AKA_RES_MIN_LEN 4 #define EAP_AKA_RES_MAX_LEN 16 #define EAP_AKA_IK_LEN 16 #define EAP_AKA_CK_LEN 16 @@ -124,7 +126,8 @@ static int db_table_create_milenage(sqlite3 *db) " ki CHAR(32) NOT NULL," " opc CHAR(32) NOT NULL," " amf CHAR(4) NOT NULL," - " sqn CHAR(12) NOT NULL" + " sqn CHAR(12) NOT NULL," + " res_len INTEGER" ");"; printf("Adding database table for milenage information\n"); @@ -190,6 +193,10 @@ static int get_milenage_cb(void *ctx, int argc, char *argv[], char *col[]) printf("Invalid sqn value in database\n"); return -1; } + + if (os_strcmp(col[i], "res_len") == 0 && argv[i]) { + m->res_len = atoi(argv[i]); + } } return 0; @@ -206,8 +213,7 @@ static struct milenage_parameters * db_get_milenage(const char *imsi_txt) os_snprintf(db_tmp_milenage.imsi, sizeof(db_tmp_milenage.imsi), "%llu", imsi); os_snprintf(cmd, sizeof(cmd), - "SELECT ki,opc,amf,sqn FROM milenage WHERE imsi=%llu;", - imsi); + "SELECT * FROM milenage WHERE imsi=%llu;", imsi); if (sqlite3_exec(sqlite_db, cmd, get_milenage_cb, &db_tmp_milenage, NULL) != SQLITE_OK) return NULL; @@ -424,7 +430,7 @@ static int read_milenage(const char *fname) while (fgets(buf, sizeof(buf), f)) { line++; - /* Parse IMSI Ki OPc AMF SQN */ + /* Parse IMSI Ki OPc AMF SQN [RES_len] */ buf[sizeof(buf) - 1] = '\0'; if (buf[0] == '#') continue; @@ -515,7 +521,19 @@ static int read_milenage(const char *fname) ret = -1; break; } - pos = pos2 + 1; + + if (pos2) { + pos = pos2 + 1; + m->res_len = atoi(pos); + if (m->res_len && + (m->res_len < EAP_AKA_RES_MIN_LEN || + m->res_len > EAP_AKA_RES_MAX_LEN)) { + printf("%s:%d - Invalid RES_len (%s)\n", + fname, line, pos); + ret = -1; + break; + } + } m->next = milenage_db; milenage_db = m; @@ -798,6 +816,10 @@ static int aka_req_auth(char *imsi, char *resp, size_t resp_len) } milenage_generate(m->opc, m->amf, m->ki, m->sqn, _rand, autn, ik, ck, res, &res_len); + if (m->res_len >= EAP_AKA_RES_MIN_LEN && + m->res_len <= EAP_AKA_RES_MAX_LEN && + m->res_len < res_len) + res_len = m->res_len; } else { printf("Unknown IMSI: %s\n", imsi); #ifdef AKA_USE_FIXED_TEST_VALUES diff --git a/hostapd/hlr_auc_gw.milenage_db b/hostapd/hlr_auc_gw.milenage_db index ecd06d72..c156a29a 100644 --- a/hostapd/hlr_auc_gw.milenage_db +++ b/hostapd/hlr_auc_gw.milenage_db @@ -5,8 +5,10 @@ # authentication. In case of GSM/EAP-SIM, AMF and SQN values are not used, but # dummy values will need to be included in this file. -# IMSI Ki OPc AMF SQN +# IMSI Ki OPc AMF SQN [RES_len] 232010000000000 90dca4eda45b53cf0f12d7c9c3bc6a89 cb9cccc4b9258e6dca4760379fb82581 61df 000000000000 +# Example using truncated 32-bit RES instead of 64-bit default +232010000000001 90dca4eda45b53cf0f12d7c9c3bc6a89 cb9cccc4b9258e6dca4760379fb82581 61df 000000000000 4 # These values are from Test Set 19 which has the AMF separation bit set to 1 # and as such, is suitable for EAP-AKA' test. diff --git a/hs20/client/Makefile b/hs20/client/Makefile index ca67b54d..94cd5f14 100644 --- a/hs20/client/Makefile +++ b/hs20/client/Makefile @@ -67,7 +67,13 @@ 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 LIBS += -lssl -lcrypto diff --git a/hs20/client/osu_client.c b/hs20/client/osu_client.c index de7f351d..5cd823ee 100644 --- a/hs20/client/osu_client.c +++ b/hs20/client/osu_client.c @@ -25,6 +25,8 @@ #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, ...) { @@ -547,8 +549,9 @@ int hs20_add_pps_mo(struct hs20_osu_client *ctx, const char *uri, 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", - 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); @@ -2094,10 +2097,14 @@ static int osu_connect(struct hs20_osu_client *ctx, const char *bssid, } ctx->no_reconnect = 1; - if (methods & 0x02) + if (methods & 0x02) { + wpa_printf(MSG_DEBUG, "Calling cmd_prov from osu_connect"); res = cmd_prov(ctx, url); - else if (methods & 0x01) + } 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"); @@ -2139,7 +2146,7 @@ static int cmd_osu_select(struct hs20_osu_client *ctx, const char *dir, 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 any OSU providers from %s", + wpa_printf(MSG_INFO, "Could not find any OSU providers from %s", fname); write_result(ctx, "No OSU providers available"); return -1; @@ -2290,12 +2297,19 @@ selected: } if (connect == 2) { - if (last->methods & 0x02) + 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) + } 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 + } 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->url, last->methods, @@ -2810,17 +2824,21 @@ static int osu_cert_cb(void *_ctx, struct http_cert *cert) char *name = ctx->icon_filename[j]; size_t name_len = os_strlen(name); - wpa_printf(MSG_INFO, "Looking for icon file name '%s' match", - name); + wpa_printf(MSG_INFO, + "[%i] 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, "Comparing to '%s' uri_len=%d name_len=%d", - logo->uri, (int) uri_len, (int) name_len); - if (uri_len < 1 + name_len) + wpa_printf(MSG_INFO, + "[%i] 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; @@ -2847,17 +2865,30 @@ static int osu_cert_cb(void *_ctx, struct http_cert *cert) for (i = 0; i < cert->num_logo; i++) { struct http_logo *logo = &cert->logo[i]; - if (logo->hash_len != 32) + if (logo->hash_len != 32) { + wpa_printf(MSG_INFO, + "[%i][%i] 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, + "[%u][%u] 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 found"); - write_result(ctx, "No icon hash match found"); + wpa_printf(MSG_INFO, + "No icon hash match (by hash) found"); + write_result(ctx, + "No icon hash match (by hash) found"); return -1; } } @@ -2955,6 +2986,7 @@ static void usage(void) " [-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" @@ -2996,7 +3028,7 @@ int main(int argc, char *argv[]) return -1; for (;;) { - c = getopt(argc, argv, "df:hi:KNO:qr:s:S:tw:"); + c = getopt(argc, argv, "df:hKNO:qr:s:S:tw:x:"); if (c < 0) break; switch (c) { @@ -3034,6 +3066,9 @@ int main(int argc, char *argv[]) case 'w': wpas_ctrl_path = optarg; break; + case 'x': + spp_xsd_fname = optarg; + break; case 'h': default: usage(); @@ -3108,6 +3143,7 @@ int main(int argc, char *argv[]) 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) { diff --git a/hs20/client/spp_client.c b/hs20/client/spp_client.c index 302a0504..cc1a0bfa 100644 --- a/hs20/client/spp_client.c +++ b/hs20/client/spp_client.c @@ -21,6 +21,8 @@ #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, @@ -59,7 +61,7 @@ static int hs20_spp_validate(struct hs20_osu_client *ctx, xml_node_t *node, return -1; } - ret = xml_validate(xctx, node, "spp.xsd", &err); + 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"); @@ -952,7 +954,9 @@ int cmd_prov(struct hs20_osu_client *ctx, const char *url) return -1; } - wpa_printf(MSG_INFO, "Credential provisioning requested"); + 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); diff --git a/hs20/server/ca/clean.sh b/hs20/server/ca/clean.sh index c69a1f54..c72dcbda 100644..100755 --- a/hs20/server/ca/clean.sh +++ b/hs20/server/ca/clean.sh @@ -5,6 +5,9 @@ for i in server-client server server-revoked user ocsp; do done rm -f openssl.cnf.tmp -rm -r demoCA +if [ -d demoCA ]; then + rm -r demoCA +fi rm -f ca.pem logo.asn1 logo.der server.der ocsp-server-cache.der +rm -f my-openssl.cnf my-openssl-root.cnf #rm -r rootCA diff --git a/hs20/server/ca/openssl-root.cnf b/hs20/server/ca/openssl-root.cnf index 5b220fe8..5bc50be1 100644 --- a/hs20/server/ca/openssl-root.cnf +++ b/hs20/server/ca/openssl-root.cnf @@ -69,8 +69,8 @@ distinguished_name = req_distinguished_name attributes = req_attributes x509_extensions = v3_ca # The extentions to add to the self signed cert -input_password = whatever -output_password = whatever +input_password = @PASSWORD@ +output_password = @PASSWORD@ string_mask = utf8only diff --git a/hs20/server/ca/openssl.cnf b/hs20/server/ca/openssl.cnf index a939f081..61410138 100644 --- a/hs20/server/ca/openssl.cnf +++ b/hs20/server/ca/openssl.cnf @@ -80,8 +80,8 @@ distinguished_name = req_distinguished_name attributes = req_attributes x509_extensions = v3_ca # The extentions to add to the self signed cert -input_password = whatever -output_password = whatever +input_password = @PASSWORD@ +output_password = @PASSWORD@ string_mask = utf8only @@ -95,7 +95,7 @@ localityName = Locality Name (eg, city) localityName_default = Tuusula 0.organizationName = Organization Name (eg, company) -0.organizationName_default = w1.fi +0.organizationName_default = @DOMAIN@ ##organizationalUnitName = Organizational Unit Name (eg, section) #organizationalUnitName_default = @@ -117,10 +117,10 @@ subjectKeyIdentifier=hash authorityKeyIdentifier=keyid:always,issuer basicConstraints = critical, CA:true, pathlen:0 keyUsage = critical, cRLSign, keyCertSign -authorityInfoAccess = OCSP;URI:http://osu.w1.fi:8888/ +authorityInfoAccess = OCSP;URI:@OCSP_URI@ # For SP intermediate CA #subjectAltName=critical,otherName:1.3.6.1.4.1.40808.1.1.1;UTF8String:engExample OSU -#nameConstraints=permitted;DNS:.w1.fi +#nameConstraints=permitted;DNS:.@DOMAIN@ #1.3.6.1.5.5.7.1.12=ASN1:SEQUENCE:LogotypeExtn [ v3_osu_server ] @@ -150,16 +150,16 @@ value1=SEQUENCE:HashAlgAndValueSHA256 #value2=SEQUENCE:HashAlgAndValueSHA1 [HashAlgAndValueSHA256] hashAlg=SEQUENCE:sha256_alg -hashValue=FORMAT:HEX,OCTETSTRING:4532f7ec36424381617c03c6ce87b55a51d6e7177ffafda243cebf280a68954d +hashValue=FORMAT:HEX,OCTETSTRING:@LOGO_HASH256@ [HashAlgAndValueSHA1] hashAlg=SEQUENCE:sha1_alg -hashValue=FORMAT:HEX,OCTETSTRING:5e1d5085676eede6b02da14d31c523ec20ffba0b +hashValue=FORMAT:HEX,OCTETSTRING:@LOGO_HASH1@ [sha256_alg] algorithm=OID:sha256 [sha1_alg] algorithm=OID:sha1 [URI] -uri=IA5STRING:http://osu.w1.fi/w1fi_logo.png +uri=IA5STRING:@LOGO_URI@ [LogotypeImageInfo] # default value color(1), component optional #type=IMP:0,INTEGER:1 @@ -184,7 +184,7 @@ extendedKeyUsage = OCSPSigning basicConstraints=CA:FALSE subjectKeyIdentifier=hash authorityKeyIdentifier=keyid,issuer -authorityInfoAccess = OCSP;URI:http://osu.w1.fi:8888/ +authorityInfoAccess = OCSP;URI:@OCSP_URI@ #@ALTNAME@ extendedKeyUsage = clientAuth @@ -194,7 +194,7 @@ extendedKeyUsage = clientAuth basicConstraints=critical, CA:FALSE subjectKeyIdentifier=hash authorityKeyIdentifier=keyid,issuer -authorityInfoAccess = OCSP;URI:http://osu.w1.fi:8888/ +authorityInfoAccess = OCSP;URI:@OCSP_URI@ #@ALTNAME@ extendedKeyUsage = critical, serverAuth keyUsage = critical, keyEncipherment diff --git a/hs20/server/ca/setup.sh b/hs20/server/ca/setup.sh index f61bf73b..78abcccf 100644..100755 --- a/hs20/server/ca/setup.sh +++ b/hs20/server/ca/setup.sh @@ -5,6 +5,67 @@ if [ -z "$OPENSSL" ]; then fi export OPENSSL_CONF=$PWD/openssl.cnf PASS=whatever +if [ -z "$DOMAIN" ]; then + DOMAIN=w1.fi +fi +COMPANY=w1.fi +OPER_ENG="engw1.fi TESTING USE" +OPER_FI="finw1.fi TESTIKÄYTTÖ" +CNR="Hotspot 2.0 Trust Root CA - 99" +CNO="ocsp.$DOMAIN" +CNV="osu-revoked.$DOMAIN" +CNOC="osu-client.$DOMAIN" +OSU_SERVER_HOSTNAME="osu.$DOMAIN" +DEBUG=0 +OCSP_URI="http://$CNO:8888/" +LOGO_URI="http://osu.w1.fi/w1fi_logo.png" +LOGO_HASH256="4532f7ec36424381617c03c6ce87b55a51d6e7177ffafda243cebf280a68954d" +LOGO_HASH1="5e1d5085676eede6b02da14d31c523ec20ffba0b" + +# Command line overrides +USAGE=$( cat <<EOF +Usage:\n +# -c: Company name, used to generate Subject name CN for Intermediate CA\n +# -C: Subject name CN of the Root CA ($CNR)\n +# -D: Enable debugging (set -x, etc)\n +# -g: Logo sha1 hash ($LOGO_HASH1)\n +# -G: Logo sha256 hash ($LOGO_HASH256)\n +# -h: Show this help message\n +# -l: Logo URI ($LOGO_URI)\n +# -m: Domain ($DOMAIN)\n +# -o: Subject name CN for OSU-Client Server ($CNOC)\n +# -O: Subject name CN for OCSP Server ($CNO)\n +# -p: passphrase for private keys ($PASS)\n +# -r: Operator-english ($OPER_ENG)\n +# -R: Operator-finish ($OPER_FI)\n +# -S: OSU Server name ($OSU_SERVER_HOSTNAME)\n +# -u: OCSP-URI ($OCSP_URI)\n +# -V: Subject name CN for OSU-Revoked Server ($CNV)\n +EOF +) + +while getopts "c:C:Dg:G:l:m:o:O:p:r:R:S:u:V:h" flag + do + case $flag in + c) COMPANY=$OPTARG;; + C) CNR=$OPTARG;; + D) DEBUG=1;; + g) LOGO_HASH1=$OPTARG;; + G) LOGO_HASH256=$OPTARG;; + h) echo -e $USAGE; exit 0;; + l) LOGO_URI=$OPTARG;; + m) DOMAIN=$OPTARG;; + o) CNOC=$OPTARG;; + O) CNO=$OPTARG;; + p) PASS=$OPTARG;; + r) OPER_ENG=$OPTARG;; + R) OPER_FI=$OPTARG;; + S) OSU_SERVER_HOSTNAME=$OPTARG;; + u) OCSP_URI=$OPTARG;; + V) CNV=$OPTARG;; + *) echo "Unknown flag: $flag"; echo -e $USAGE; exit 1;; + esac +done fail() { @@ -16,7 +77,25 @@ echo echo "---[ Root CA ]----------------------------------------------------------" echo -cat openssl-root.cnf | sed "s/#@CN@/commonName_default = Hotspot 2.0 Trust Root CA - 99/" > openssl.cnf.tmp +if [ $DEBUG = 1 ] +then + set -x +fi + +# Set the passphrase and some other common config accordingly. +cat openssl-root.cnf | sed "s/@PASSWORD@/$PASS/" \ + > my-openssl-root.cnf + +cat openssl.cnf | sed "s/@PASSWORD@/$PASS/" | +sed "s,@OCSP_URI@,$OCSP_URI," | +sed "s,@LOGO_URI@,$LOGO_URI," | +sed "s,@LOGO_HASH1@,$LOGO_HASH1," | +sed "s,@LOGO_HASH256@,$LOGO_HASH256," | +sed "s/@DOMAIN@/$DOMAIN/" \ + > my-openssl.cnf + + +cat my-openssl-root.cnf | sed "s/#@CN@/commonName_default = $CNR/" > openssl.cnf.tmp mkdir -p rootCA/certs rootCA/crl rootCA/newcerts rootCA/private touch rootCA/index.txt if [ -e rootCA/private/cakey.pem ]; then @@ -26,6 +105,8 @@ else $OPENSSL req -config openssl.cnf.tmp -batch -new -newkey rsa:4096 -keyout rootCA/private/cakey.pem -out rootCA/careq.pem || fail "Failed to generate Root CA private key" echo " * Sign Root CA certificate" $OPENSSL ca -config openssl.cnf.tmp -md sha256 -create_serial -out rootCA/cacert.pem -days 10957 -batch -keyfile rootCA/private/cakey.pem -passin pass:$PASS -selfsign -extensions v3_ca -outdir rootCA/newcerts -infiles rootCA/careq.pem || fail "Failed to sign Root CA certificate" + $OPENSSL x509 -in rootCA/cacert.pem -out rootCA/cacert.der -outform DER || fail "Failed to create rootCA DER" + sha256sum rootCA/cacert.der > rootCA/cacert.fingerprint || fail "Failed to create rootCA fingerprint" fi if [ ! -e rootCA/crlnumber ]; then echo 00 > rootCA/crlnumber @@ -35,7 +116,7 @@ echo echo "---[ Intermediate CA ]--------------------------------------------------" echo -cat openssl.cnf | sed "s/#@CN@/commonName_default = w1.fi Hotspot 2.0 Intermediate CA/" > openssl.cnf.tmp +cat my-openssl.cnf | sed "s/#@CN@/commonName_default = $COMPANY Hotspot 2.0 Intermediate CA/" > openssl.cnf.tmp mkdir -p demoCA/certs demoCA/crl demoCA/newcerts demoCA/private touch demoCA/index.txt if [ -e demoCA/private/cakey.pem ]; then @@ -47,6 +128,8 @@ else $OPENSSL ca -config openssl.cnf.tmp -md sha256 -create_serial -out demoCA/cacert.pem -days 3652 -batch -keyfile rootCA/private/cakey.pem -cert rootCA/cacert.pem -passin pass:$PASS -extensions v3_ca -infiles demoCA/careq.pem || fail "Failed to sign Intermediate CA certificate" # horrible from security view point, but for testing purposes since OCSP responder does not seem to support -passin openssl rsa -in demoCA/private/cakey.pem -out demoCA/private/cakey-plain.pem -passin pass:$PASS + $OPENSSL x509 -in demoCA/cacert.pem -out demoCA/cacert.der -outform DER || fail "Failed to create demoCA DER." + sha256sum demoCA/cacert.der > demoCA/cacert.fingerprint || fail "Failed to create demoCA fingerprint" fi if [ ! -e demoCA/crlnumber ]; then echo 00 > demoCA/crlnumber @@ -56,45 +139,46 @@ echo echo "OCSP responder" echo -cat openssl.cnf | sed "s/#@CN@/commonName_default = ocsp.w1.fi/" > openssl.cnf.tmp +cat my-openssl.cnf | sed "s/#@CN@/commonName_default = $CNO/" > openssl.cnf.tmp $OPENSSL req -config $PWD/openssl.cnf.tmp -batch -new -newkey rsa:2048 -nodes -out ocsp.csr -keyout ocsp.key -extensions v3_OCSP -$OPENSSL ca -config $PWD/openssl.cnf.tmp -batch -md sha256 -keyfile demoCA/private/cakey.pem -passin pass:$PASS -in ocsp.csr -out ocsp.pem -days 730 -extensions v3_OCSP +$OPENSSL ca -config $PWD/openssl.cnf.tmp -batch -md sha256 -keyfile demoCA/private/cakey.pem -passin pass:$PASS -in ocsp.csr -out ocsp.pem -days 730 -extensions v3_OCSP || fail "Could not generate ocsp.pem" echo echo "---[ Server - to be revoked ] ------------------------------------------" echo -cat openssl.cnf | sed "s/#@CN@/commonName_default = osu-revoked.w1.fi/" > openssl.cnf.tmp +cat my-openssl.cnf | sed "s/#@CN@/commonName_default = $CNV/" > openssl.cnf.tmp $OPENSSL req -config $PWD/openssl.cnf.tmp -batch -new -newkey rsa:2048 -nodes -out server-revoked.csr -keyout server-revoked.key $OPENSSL ca -config $PWD/openssl.cnf.tmp -batch -md sha256 -in server-revoked.csr -out server-revoked.pem -key $PASS -days 730 -extensions ext_server $OPENSSL ca -revoke server-revoked.pem -key $PASS echo echo "---[ Server - with client ext key use ] ---------------------------------" +echo "---[ Only used for negative-testing for OSU-client implementation ] -----" echo -cat openssl.cnf | sed "s/#@CN@/commonName_default = osu-client.w1.fi/" > openssl.cnf.tmp -$OPENSSL req -config $PWD/openssl.cnf.tmp -batch -new -newkey rsa:2048 -nodes -out server-client.csr -keyout server-client.key -$OPENSSL ca -config $PWD/openssl.cnf.tmp -batch -md sha256 -in server-client.csr -out server-client.pem -key $PASS -days 730 -extensions ext_client +cat my-openssl.cnf | sed "s/#@CN@/commonName_default = $CNOC/" > openssl.cnf.tmp +$OPENSSL req -config $PWD/openssl.cnf.tmp -batch -new -newkey rsa:2048 -nodes -out server-client.csr -keyout server-client.key || fail "Could not create server-client.key" +$OPENSSL ca -config $PWD/openssl.cnf.tmp -batch -md sha256 -in server-client.csr -out server-client.pem -key $PASS -days 730 -extensions ext_client || fail "Could not create server-client.pem" echo echo "---[ User ]-------------------------------------------------------------" echo -cat openssl.cnf | sed "s/#@CN@/commonName_default = User/" > openssl.cnf.tmp -$OPENSSL req -config $PWD/openssl.cnf.tmp -batch -new -newkey rsa:2048 -nodes -out user.csr -keyout user.key -$OPENSSL ca -config $PWD/openssl.cnf.tmp -batch -md sha256 -in user.csr -out user.pem -key $PASS -days 730 -extensions ext_client +cat my-openssl.cnf | sed "s/#@CN@/commonName_default = User/" > openssl.cnf.tmp +$OPENSSL req -config $PWD/openssl.cnf.tmp -batch -new -newkey rsa:2048 -nodes -out user.csr -keyout user.key || fail "Could not create user.key" +$OPENSSL ca -config $PWD/openssl.cnf.tmp -batch -md sha256 -in user.csr -out user.pem -key $PASS -days 730 -extensions ext_client || fail "Could not create user.pem" echo echo "---[ Server ]-----------------------------------------------------------" echo -ALT="DNS:osu.w1.fi" -ALT="$ALT,otherName:1.3.6.1.4.1.40808.1.1.1;UTF8String:engw1.fi TESTING USE" -ALT="$ALT,otherName:1.3.6.1.4.1.40808.1.1.1;UTF8String:finw1.fi TESTIKÄYTTÖ" +ALT="DNS:$OSU_SERVER_HOSTNAME" +ALT="$ALT,otherName:1.3.6.1.4.1.40808.1.1.1;UTF8String:$OPER_ENG" +ALT="$ALT,otherName:1.3.6.1.4.1.40808.1.1.1;UTF8String:$OPER_FI" -cat openssl.cnf | - sed "s/#@CN@/commonName_default = osu.w1.fi/" | +cat my-openssl.cnf | + sed "s/#@CN@/commonName_default = $OSU_SERVER_HOSTNAME/" | sed "s/^##organizationalUnitName/organizationalUnitName/" | sed "s/#@OU@/organizationalUnitName_default = Hotspot 2.0 Online Sign Up Server/" | sed "s/#@ALTNAME@/subjectAltName=critical,$ALT/" \ @@ -113,7 +197,7 @@ echo echo "---[ CRL ]---------------------------------------------------------------" echo -$OPENSSL ca -config $PWD/openssl.cnf -gencrl -md sha256 -out demoCA/crl/crl.pem -passin pass:$PASS +$OPENSSL ca -config $PWD/my-openssl.cnf -gencrl -md sha256 -out demoCA/crl/crl.pem -passin pass:$PASS echo echo "---[ Verify ]------------------------------------------------------------" diff --git a/hs20/server/hs20-osu-server.txt b/hs20/server/hs20-osu-server.txt index 80985f73..001d6f25 100644 --- a/hs20/server/hs20-osu-server.txt +++ b/hs20/server/hs20-osu-server.txt @@ -100,6 +100,21 @@ sqlite3 /home/user/hs20-server/AS/DB/eap_user.db < sql-example.txt # the examples as-is for initial testing). cp -r www /home/user/hs20-server +# Build local keys and certs +cd ca +# Display help options. +./setup.sh -h + +# Remove old keys, fill in appropriate values, and generate your keys. +# For instance: +./clean.sh +rm -fr rootCA" +old_hostname=myserver.local +./setup.sh -C "Hotspot 2.0 Trust Root CA - CT" -d $old_hostname \ + -I "Hotspot 2.0 Intermediate CA - CT" -o $old_hostname-osu-client \ + -O $old_hostname-oscp -p lanforge -S $old_hostname \ + -V $old_hostname-osu-revoked \ + -m local -u http://$old_hostname:8888/ # Configure subscription policies mkdir -p /home/user/hs20-server/spp/policy @@ -156,6 +171,50 @@ cd /home/user/hs20-server/AS ./hostapd -B as-sql.conf +OSEN RADIUS server configuration notes + +The OSEN RADIUS server config file should have the 'ocsp_stapling_response' +configuration in it. For example: + +# hostapd-radius config for the radius used by the OSEN AP +interface=eth0#0 +driver=none +logger_syslog=-1 +logger_syslog_level=2 +logger_stdout=-1 +logger_stdout_level=2 +ctrl_interface=/var/run/hostapd +ctrl_interface_group=0 +eap_server=1 +eap_user_file=/home/user/hs20-server/AS/hostapd-osen.eap_user +server_id=ben-ota-2-osen +radius_server_auth_port=1811 +radius_server_clients=/home/user/hs20-server/AS/hostap.radius_clients + +ca_cert=/home/user/hs20-server/ca/ca.pem +server_cert=/home/user/hs20-server/ca/server.pem +private_key=/home/user/hs20-server/ca/server.key +private_key_passwd=whatever + +ocsp_stapling_response=/home/user/hs20-server/ca/ocsp-server-cache.der + +The /home/user/hs20-server/AS/hostapd-osen.eap_user file should look +similar to this, and should coorelate with the osu_nai entry in +the non-OSEN VAP config file. For instance: + +# cat hostapd-osen.eap_user +# For OSEN authentication (Hotspot 2.0 Release 2) +"osen@w1.fi" WFA-UNAUTH-TLS + + +# Run OCSP server: +cd /home/user/hs20-server/ca +./ocsp-responder.sh& + +# Update cache (This should be run periodically) +./ocsp-update-cache.sh + + Configure web server -------------------- @@ -172,6 +231,8 @@ Add following block just before "SSL Engine Switch" line": </Directory> Update SSL configuration to use the OSU server certificate/key. +They keys and certs are called 'server.key' and 'server.pem' from +ca/setup.sh. Enable default-ssl site and restart Apache2: sudo a2ensite default-ssl diff --git a/hs20/server/spp_server.c b/hs20/server/spp_server.c index 8a2abf1f..33e3fa10 100644 --- a/hs20/server/spp_server.c +++ b/hs20/server/spp_server.c @@ -2196,7 +2196,9 @@ xml_node_t * hs20_spp_server_process(struct hs20_svc *ctx, xml_node_t *node, session_id = xml_node_get_attr_value_ns(ctx->xml, node, SPP_NS_URI, "sessionID"); - debug_print(ctx, 1, "SPP message failed validation"); + debug_print(ctx, 1, + "SPP message failed validation, xsd file: %s xml-error: %s", + fname, xml_err); hs20_eventlog_node(ctx, auth_user, auth_realm, session_id, "SPP message failed validation", node); hs20_eventlog(ctx, auth_user, auth_realm, session_id, diff --git a/hs20/server/www/signup.php b/hs20/server/www/signup.php index a6267047..aeb2f683 100644 --- a/hs20/server/www/signup.php +++ b/hs20/server/www/signup.php @@ -17,7 +17,7 @@ if (!$db) { $row = $db->query("SELECT realm FROM sessions WHERE id='$id'")->fetch(); if ($row == false) { - die("Session not found"); + die("Session not found for id: $id"); } $realm = $row['realm']; diff --git a/src/ap/authsrv.c b/src/ap/authsrv.c index bd1778e4..f10e1b72 100644 --- a/src/ap/authsrv.c +++ b/src/ap/authsrv.c @@ -55,10 +55,11 @@ static int hostapd_radius_get_eap_user(void *ctx, const u8 *identity, { const struct hostapd_eap_user *eap_user; int i; + int rv = -1; eap_user = hostapd_get_eap_user(ctx, identity, identity_len, phase2); if (eap_user == NULL) - return -1; + goto out; if (user == NULL) return 0; @@ -72,7 +73,7 @@ static int hostapd_radius_get_eap_user(void *ctx, const u8 *identity, if (eap_user->password) { user->password = os_malloc(eap_user->password_len); if (user->password == NULL) - return -1; + goto out; os_memcpy(user->password, eap_user->password, eap_user->password_len); user->password_len = eap_user->password_len; @@ -83,8 +84,13 @@ static int hostapd_radius_get_eap_user(void *ctx, const u8 *identity, user->ttls_auth = eap_user->ttls_auth; user->remediation = eap_user->remediation; user->accept_attr = eap_user->accept_attr; + rv = 0; - return 0; +out: + if (rv) + wpa_printf(MSG_DEBUG, "%s: Failed to find user", __func__); + + return rv; } diff --git a/src/ap/eap_user_db.c b/src/ap/eap_user_db.c index 559d77f9..082d0f53 100644 --- a/src/ap/eap_user_db.c +++ b/src/ap/eap_user_db.c @@ -138,8 +138,12 @@ eap_user_sqlite_get(struct hostapd_data *hapd, const u8 *identity, char id_str[256], cmd[300]; size_t i; - if (identity_len >= sizeof(id_str)) + if (identity_len >= sizeof(id_str)) { + wpa_printf(MSG_DEBUG, "%s: identity len too big: %d >= %d", + __func__, (int) identity_len, + (int) (sizeof(id_str))); return NULL; + } os_memcpy(id_str, identity, identity_len); id_str[identity_len] = '\0'; for (i = 0; i < identity_len; i++) { @@ -182,7 +186,9 @@ eap_user_sqlite_get(struct hostapd_data *hapd, const u8 *identity, wpa_printf(MSG_DEBUG, "DB: %s", cmd); if (sqlite3_exec(db, cmd, get_user_cb, &hapd->tmp_eap_user, NULL) != SQLITE_OK) { - wpa_printf(MSG_DEBUG, "DB: Failed to complete SQL operation"); + wpa_printf(MSG_DEBUG, + "DB: Failed to complete SQL operation: %s db: %s", + sqlite3_errmsg(db), hapd->conf->eap_user_sqlite); } else if (hapd->tmp_eap_user.next) user = &hapd->tmp_eap_user; @@ -192,8 +198,10 @@ eap_user_sqlite_get(struct hostapd_data *hapd, const u8 *identity, wpa_printf(MSG_DEBUG, "DB: %s", cmd); if (sqlite3_exec(db, cmd, get_wildcard_cb, &hapd->tmp_eap_user, NULL) != SQLITE_OK) { - wpa_printf(MSG_DEBUG, "DB: Failed to complete SQL " - "operation"); + wpa_printf(MSG_DEBUG, + "DB: Failed to complete SQL operation: %s db: %s", + sqlite3_errmsg(db), + hapd->conf->eap_user_sqlite); } else if (hapd->tmp_eap_user.next) { user = &hapd->tmp_eap_user; os_free(user->identity); diff --git a/src/ap/hw_features.h b/src/ap/hw_features.h index 0f67ab8e..ca7f22ba 100644 --- a/src/ap/hw_features.h +++ b/src/ap/hw_features.h @@ -36,6 +36,11 @@ static inline int hostapd_get_hw_features(struct hostapd_iface *iface) return -1; } +static inline int hostapd_acs_completed(struct hostapd_iface *iface, int err) +{ + return -1; +} + static inline int hostapd_select_hw_mode(struct hostapd_iface *iface) { return -100; diff --git a/src/ap/ieee802_11_ht.c b/src/ap/ieee802_11_ht.c index 4b0653de..9dad8e34 100644 --- a/src/ap/ieee802_11_ht.c +++ b/src/ap/ieee802_11_ht.c @@ -209,7 +209,7 @@ void hostapd_2040_coex_action(struct hostapd_data *hapd, struct hostapd_iface *iface = hapd->iface; struct ieee80211_2040_bss_coex_ie *bc_ie; struct ieee80211_2040_intol_chan_report *ic_report; - int is_ht_allowed = 1; + int is_ht40_allowed = 1; int i; const u8 *start = (const u8 *) mgmt; const u8 *data = start + IEEE80211_HDRLEN + 2; @@ -242,7 +242,7 @@ void hostapd_2040_coex_action(struct hostapd_data *hapd, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_DEBUG, "20 MHz BSS width request bit is set in BSS coexistence information field"); - is_ht_allowed = 0; + is_ht40_allowed = 0; } if (bc_ie->coex_param & WLAN_20_40_BSS_COEX_40MHZ_INTOL) { @@ -250,7 +250,7 @@ void hostapd_2040_coex_action(struct hostapd_data *hapd, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_DEBUG, "40 MHz intolerant bit is set in BSS coexistence information field"); - is_ht_allowed = 0; + is_ht40_allowed = 0; } if (start + len - data >= 3 && @@ -276,13 +276,13 @@ void hostapd_2040_coex_action(struct hostapd_data *hapd, HOSTAPD_LEVEL_DEBUG, "20_40_INTOLERANT channel %d reported", chan); - is_ht_allowed = 0; + is_ht40_allowed = 0; } } - wpa_printf(MSG_DEBUG, "is_ht_allowed=%d num_sta_ht40_intolerant=%d", - is_ht_allowed, iface->num_sta_ht40_intolerant); + wpa_printf(MSG_DEBUG, "is_ht40_allowed=%d num_sta_ht40_intolerant=%d", + is_ht40_allowed, iface->num_sta_ht40_intolerant); - if (!is_ht_allowed && + if (!is_ht40_allowed && (iface->drv_flags & WPA_DRIVER_FLAGS_HT_2040_COEX)) { if (iface->conf->secondary_channel) { hostapd_logger(hapd, mgmt->sa, @@ -312,10 +312,14 @@ void hostapd_2040_coex_action(struct hostapd_data *hapd, u16 copy_sta_ht_capab(struct hostapd_data *hapd, struct sta_info *sta, const u8 *ht_capab, size_t ht_capab_len) { - /* Disable HT caps for STAs associated to no-HT BSSes. */ + /* + * Disable HT caps for STAs associated to no-HT BSSes, or for stations + * that did not specify a valid WMM IE in the (Re)Association Request + * frame. + */ if (!ht_capab || ht_capab_len < sizeof(struct ieee80211_ht_capabilities) || - hapd->conf->disable_11n) { + !(sta->flags & WLAN_STA_WMM) || hapd->conf->disable_11n) { sta->flags &= ~WLAN_STA_HT; os_free(sta->ht_capabilities); sta->ht_capabilities = NULL; diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c index 79dc0f95..7e17ef4f 100644 --- a/src/ap/ieee802_1x.c +++ b/src/ap/ieee802_1x.c @@ -1926,10 +1926,11 @@ static int ieee802_1x_get_eap_user(void *ctx, const u8 *identity, struct hostapd_data *hapd = ctx; const struct hostapd_eap_user *eap_user; int i; + int rv = -1; eap_user = hostapd_get_eap_user(hapd, identity, identity_len, phase2); if (eap_user == NULL) - return -1; + goto out; os_memset(user, 0, sizeof(*user)); user->phase2 = phase2; @@ -1941,7 +1942,7 @@ static int ieee802_1x_get_eap_user(void *ctx, const u8 *identity, if (eap_user->password) { user->password = os_malloc(eap_user->password_len); if (user->password == NULL) - return -1; + goto out; os_memcpy(user->password, eap_user->password, eap_user->password_len); user->password_len = eap_user->password_len; @@ -1951,8 +1952,13 @@ static int ieee802_1x_get_eap_user(void *ctx, const u8 *identity, user->macacl = eap_user->macacl; user->ttls_auth = eap_user->ttls_auth; user->remediation = eap_user->remediation; + rv = 0; - return 0; +out: + if (rv) + wpa_printf(MSG_DEBUG, "%s: Failed to find user", __func__); + + return rv; } diff --git a/src/common/defs.h b/src/common/defs.h index b5f4f801..24f80ad4 100644 --- a/src/common/defs.h +++ b/src/common/defs.h @@ -310,6 +310,7 @@ enum wpa_ctrl_req_type { WPA_CTRL_REQ_EAP_OTP, WPA_CTRL_REQ_EAP_PASSPHRASE, WPA_CTRL_REQ_SIM, + WPA_CTRL_REQ_PSK_PASSPHRASE, NUM_WPA_CTRL_REQS }; diff --git a/src/common/wpa_common.c b/src/common/wpa_common.c index 5534eab4..03689048 100644 --- a/src/common/wpa_common.c +++ b/src/common/wpa_common.c @@ -486,6 +486,8 @@ static int rsn_key_mgmt_to_bitfield(const u8 *s) return WPA_KEY_MGMT_IEEE8021X_SUITE_B; if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192) return WPA_KEY_MGMT_IEEE8021X_SUITE_B_192; + if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_OSEN) + return WPA_KEY_MGMT_OSEN; return 0; } @@ -520,7 +522,6 @@ int wpa_cipher_valid_mgmt_group(int cipher) int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len, struct wpa_ie_data *data) { - const struct rsn_ie_hdr *hdr; const u8 *pos; int left; int i, count; @@ -550,18 +551,29 @@ int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len, return -1; } - hdr = (const struct rsn_ie_hdr *) rsn_ie; + if (rsn_ie_len >= 6 && rsn_ie[1] >= 4 && + rsn_ie[1] == rsn_ie_len - 2 && + WPA_GET_BE32(&rsn_ie[2]) == OSEN_IE_VENDOR_TYPE) { + pos = rsn_ie + 6; + left = rsn_ie_len - 6; - if (hdr->elem_id != WLAN_EID_RSN || - hdr->len != rsn_ie_len - 2 || - WPA_GET_LE16(hdr->version) != RSN_VERSION) { - wpa_printf(MSG_DEBUG, "%s: malformed ie or unknown version", - __func__); - return -2; - } + data->proto = WPA_PROTO_OSEN; + } else { + const struct rsn_ie_hdr *hdr; - pos = (const u8 *) (hdr + 1); - left = rsn_ie_len - sizeof(*hdr); + hdr = (const struct rsn_ie_hdr *) rsn_ie; + + if (hdr->elem_id != WLAN_EID_RSN || + hdr->len != rsn_ie_len - 2 || + WPA_GET_LE16(hdr->version) != RSN_VERSION) { + wpa_printf(MSG_DEBUG, "%s: malformed ie or unknown version", + __func__); + return -2; + } + + pos = (const u8 *) (hdr + 1); + left = rsn_ie_len - sizeof(*hdr); + } if (left >= RSN_SELECTOR_LEN) { data->group_cipher = rsn_selector_to_bitfield(pos); diff --git a/src/crypto/crypto_openssl.c b/src/crypto/crypto_openssl.c index f158ef43..9834b25c 100644 --- a/src/crypto/crypto_openssl.c +++ b/src/crypto/crypto_openssl.c @@ -324,6 +324,56 @@ int aes_unwrap(const u8 *kek, size_t kek_len, int n, const u8 *cipher, } +int aes_128_cbc_encrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len) +{ + EVP_CIPHER_CTX ctx; + int clen, len; + u8 buf[16]; + + EVP_CIPHER_CTX_init(&ctx); + if (EVP_EncryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL, key, iv) != 1) + return -1; + EVP_CIPHER_CTX_set_padding(&ctx, 0); + + clen = data_len; + if (EVP_EncryptUpdate(&ctx, data, &clen, data, data_len) != 1 || + clen != (int) data_len) + return -1; + + len = sizeof(buf); + if (EVP_EncryptFinal_ex(&ctx, buf, &len) != 1 || len != 0) + return -1; + EVP_CIPHER_CTX_cleanup(&ctx); + + return 0; +} + + +int aes_128_cbc_decrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len) +{ + EVP_CIPHER_CTX ctx; + int plen, len; + u8 buf[16]; + + EVP_CIPHER_CTX_init(&ctx); + if (EVP_DecryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL, key, iv) != 1) + return -1; + EVP_CIPHER_CTX_set_padding(&ctx, 0); + + plen = data_len; + if (EVP_DecryptUpdate(&ctx, data, &plen, data, data_len) != 1 || + plen != (int) data_len) + return -1; + + len = sizeof(buf); + if (EVP_DecryptFinal_ex(&ctx, buf, &len) != 1 || len != 0) + return -1; + EVP_CIPHER_CTX_cleanup(&ctx); + + return 0; +} + + int crypto_mod_exp(const u8 *base, size_t base_len, const u8 *power, size_t power_len, const u8 *modulus, size_t modulus_len, diff --git a/src/crypto/ms_funcs.c b/src/crypto/ms_funcs.c index 49a5c1c2..5f576560 100644 --- a/src/crypto/ms_funcs.c +++ b/src/crypto/ms_funcs.c @@ -78,9 +78,8 @@ static int utf8_to_ucs2(const u8 *utf8_string, size_t utf8_string_len, * @challenge: 8-octet Challenge (OUT) * Returns: 0 on success, -1 on failure */ -static int challenge_hash(const u8 *peer_challenge, const u8 *auth_challenge, - const u8 *username, size_t username_len, - u8 *challenge) +int challenge_hash(const u8 *peer_challenge, const u8 *auth_challenge, + const u8 *username, size_t username_len, u8 *challenge) { u8 hash[SHA1_MAC_LEN]; const unsigned char *addr[3]; diff --git a/src/crypto/ms_funcs.h b/src/crypto/ms_funcs.h index bd9bfee9..b5b5918e 100644 --- a/src/crypto/ms_funcs.h +++ b/src/crypto/ms_funcs.h @@ -33,6 +33,8 @@ int nt_challenge_response(const u8 *challenge, const u8 *password, void challenge_response(const u8 *challenge, const u8 *password_hash, u8 *response); +int challenge_hash(const u8 *peer_challenge, const u8 *auth_challenge, + const u8 *username, size_t username_len, u8 *challenge); int nt_password_hash(const u8 *password, size_t password_len, u8 *password_hash); int hash_nt_password_hash(const u8 *password_hash, u8 *password_hash_hash); diff --git a/src/crypto/sha1-tlsprf.c b/src/crypto/sha1-tlsprf.c index 0effd9b7..f9bc0ebf 100644 --- a/src/crypto/sha1-tlsprf.c +++ b/src/crypto/sha1-tlsprf.c @@ -95,5 +95,10 @@ int tls_prf_sha1_md5(const u8 *secret, size_t secret_len, const char *label, SHA1_pos++; } + os_memset(A_MD5, 0, MD5_MAC_LEN); + os_memset(P_MD5, 0, MD5_MAC_LEN); + os_memset(A_SHA1, 0, SHA1_MAC_LEN); + os_memset(P_SHA1, 0, SHA1_MAC_LEN); + return 0; } diff --git a/src/crypto/sha1-tprf.c b/src/crypto/sha1-tprf.c index a5294946..562510f8 100644 --- a/src/crypto/sha1-tprf.c +++ b/src/crypto/sha1-tprf.c @@ -66,5 +66,7 @@ int sha1_t_prf(const u8 *key, size_t key_len, const char *label, len[0] = SHA1_MAC_LEN; } + os_memset(hash, 0, SHA1_MAC_LEN); + return 0; } diff --git a/src/crypto/sha256-kdf.c b/src/crypto/sha256-kdf.c index d8a1beb3..e7509ce4 100644 --- a/src/crypto/sha256-kdf.c +++ b/src/crypto/sha256-kdf.c @@ -61,6 +61,7 @@ int hmac_sha256_kdf(const u8 *secret, size_t secret_len, if (iter == 255) { os_memset(out, 0, outlen); + os_memset(T, 0, SHA256_MAC_LEN); return -1; } iter++; @@ -68,9 +69,11 @@ int hmac_sha256_kdf(const u8 *secret, size_t secret_len, if (hmac_sha256_vector(secret, secret_len, 4, addr, len, T) < 0) { os_memset(out, 0, outlen); + os_memset(T, 0, SHA256_MAC_LEN); return -1; } } + os_memset(T, 0, SHA256_MAC_LEN); return 0; } diff --git a/src/crypto/tls.h b/src/crypto/tls.h index 9ae95a66..f9e2e10e 100644 --- a/src/crypto/tls.h +++ b/src/crypto/tls.h @@ -12,8 +12,6 @@ struct tls_connection; struct tls_keys { - const u8 *master_key; /* TLS master secret */ - size_t master_key_len; const u8 *client_random; size_t client_random_len; const u8 *server_random; @@ -308,10 +306,10 @@ int __must_check tls_connection_set_verify(void *tls_ctx, int verify_peer); /** - * tls_connection_get_keys - Get master key and random data from TLS connection + * tls_connection_get_keys - Get random data from TLS connection * @tls_ctx: TLS context data from tls_init() * @conn: Connection context data from tls_connection_init() - * @keys: Structure of key/random data (filled on success) + * @keys: Structure of client/server random data (filled on success) * Returns: 0 on success, -1 on failure */ int __must_check tls_connection_get_keys(void *tls_ctx, @@ -325,6 +323,7 @@ int __must_check tls_connection_get_keys(void *tls_ctx, * @label: Label (e.g., description of the key) for PRF * @server_random_first: seed is 0 = client_random|server_random, * 1 = server_random|client_random + * @skip_keyblock: Skip TLS key block from the beginning of PRF output * @out: Buffer for output data from TLS-PRF * @out_len: Length of the output buffer * Returns: 0 on success, -1 on failure @@ -342,6 +341,7 @@ int __must_check tls_connection_prf(void *tls_ctx, struct tls_connection *conn, const char *label, int server_random_first, + int skip_keyblock, u8 *out, size_t out_len); /** @@ -528,16 +528,6 @@ int tls_connection_get_write_alerts(void *tls_ctx, struct tls_connection *conn); /** - * tls_connection_get_keyblock_size - Get TLS key_block size - * @tls_ctx: TLS context data from tls_init() - * @conn: Connection context data from tls_connection_init() - * Returns: Size of the key_block for the negotiated cipher suite or -1 on - * failure - */ -int tls_connection_get_keyblock_size(void *tls_ctx, - struct tls_connection *conn); - -/** * tls_capabilities - Get supported TLS capabilities * @tls_ctx: TLS context data from tls_init() * Returns: Bit field of supported TLS capabilities (TLS_CAPABILITY_*) diff --git a/src/crypto/tls_gnutls.c b/src/crypto/tls_gnutls.c index 65db6fcc..c7f6464b 100644 --- a/src/crypto/tls_gnutls.c +++ b/src/crypto/tls_gnutls.c @@ -747,9 +747,9 @@ int tls_connection_get_keys(void *ssl_ctx, struct tls_connection *conn, int tls_connection_prf(void *tls_ctx, struct tls_connection *conn, const char *label, int server_random_first, - u8 *out, size_t out_len) + int skip_keyblock, u8 *out, size_t out_len) { - if (conn == NULL || conn->session == NULL) + if (conn == NULL || conn->session == NULL || skip_keyblock) return -1; return gnutls_prf(conn->session, os_strlen(label), label, @@ -1476,14 +1476,6 @@ int tls_connection_get_write_alerts(void *ssl_ctx, struct tls_connection *conn) } -int tls_connection_get_keyblock_size(void *tls_ctx, - struct tls_connection *conn) -{ - /* TODO */ - return -1; -} - - unsigned int tls_capabilities(void *tls_ctx) { return 0; diff --git a/src/crypto/tls_internal.c b/src/crypto/tls_internal.c index 0c955da2..afd46953 100644 --- a/src/crypto/tls_internal.c +++ b/src/crypto/tls_internal.c @@ -192,26 +192,31 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn, if (params->subject_match) { wpa_printf(MSG_INFO, "TLS: subject_match not supported"); + tlsv1_cred_free(cred); return -1; } if (params->altsubject_match) { wpa_printf(MSG_INFO, "TLS: altsubject_match not supported"); + tlsv1_cred_free(cred); return -1; } if (params->suffix_match) { wpa_printf(MSG_INFO, "TLS: suffix_match not supported"); + tlsv1_cred_free(cred); return -1; } if (params->domain_match) { wpa_printf(MSG_INFO, "TLS: domain_match not supported"); + tlsv1_cred_free(cred); return -1; } if (params->openssl_ciphers) { - wpa_printf(MSG_INFO, "GnuTLS: openssl_ciphers not supported"); + wpa_printf(MSG_INFO, "TLS: openssl_ciphers not supported"); + tlsv1_cred_free(cred); return -1; } @@ -348,25 +353,57 @@ int tls_connection_get_keys(void *tls_ctx, struct tls_connection *conn, } +static int tls_get_keyblock_size(struct tls_connection *conn) +{ +#ifdef CONFIG_TLS_INTERNAL_CLIENT + if (conn->client) + return tlsv1_client_get_keyblock_size(conn->client); +#endif /* CONFIG_TLS_INTERNAL_CLIENT */ +#ifdef CONFIG_TLS_INTERNAL_SERVER + if (conn->server) + return tlsv1_server_get_keyblock_size(conn->server); +#endif /* CONFIG_TLS_INTERNAL_SERVER */ + return -1; +} + + int tls_connection_prf(void *tls_ctx, struct tls_connection *conn, const char *label, int server_random_first, - u8 *out, size_t out_len) -{ + int skip_keyblock, u8 *out, size_t out_len) +{ + int ret = -1, skip = 0; + u8 *tmp_out = NULL; + u8 *_out = out; + + if (skip_keyblock) { + skip = tls_get_keyblock_size(conn); + if (skip < 0) + return -1; + tmp_out = os_malloc(skip + out_len); + if (!tmp_out) + return -1; + _out = tmp_out; + } + #ifdef CONFIG_TLS_INTERNAL_CLIENT if (conn->client) { - return tlsv1_client_prf(conn->client, label, - server_random_first, - out, out_len); + ret = tlsv1_client_prf(conn->client, label, + server_random_first, + _out, out_len); } #endif /* CONFIG_TLS_INTERNAL_CLIENT */ #ifdef CONFIG_TLS_INTERNAL_SERVER if (conn->server) { - return tlsv1_server_prf(conn->server, label, - server_random_first, - out, out_len); + ret = tlsv1_server_prf(conn->server, label, + server_random_first, + _out, out_len); } #endif /* CONFIG_TLS_INTERNAL_SERVER */ - return -1; + if (ret == 0 && skip_keyblock) + os_memcpy(out, _out + skip, out_len); + bin_clear_free(tmp_out, skip); + + return ret; } @@ -637,21 +674,6 @@ int tls_connection_get_write_alerts(void *tls_ctx, } -int tls_connection_get_keyblock_size(void *tls_ctx, - struct tls_connection *conn) -{ -#ifdef CONFIG_TLS_INTERNAL_CLIENT - if (conn->client) - return tlsv1_client_get_keyblock_size(conn->client); -#endif /* CONFIG_TLS_INTERNAL_CLIENT */ -#ifdef CONFIG_TLS_INTERNAL_SERVER - if (conn->server) - return tlsv1_server_get_keyblock_size(conn->server); -#endif /* CONFIG_TLS_INTERNAL_SERVER */ - return -1; -} - - unsigned int tls_capabilities(void *tls_ctx) { return 0; diff --git a/src/crypto/tls_none.c b/src/crypto/tls_none.c index a6d210af..1b1ba569 100644 --- a/src/crypto/tls_none.c +++ b/src/crypto/tls_none.c @@ -87,7 +87,7 @@ int tls_connection_get_keys(void *tls_ctx, struct tls_connection *conn, int tls_connection_prf(void *tls_ctx, struct tls_connection *conn, const char *label, int server_random_first, - u8 *out, size_t out_len) + int skip_keyblock, u8 *out, size_t out_len) { return -1; } @@ -181,13 +181,6 @@ int tls_connection_get_write_alerts(void *tls_ctx, } -int tls_connection_get_keyblock_size(void *tls_ctx, - struct tls_connection *conn) -{ - return -1; -} - - unsigned int tls_capabilities(void *tls_ctx) { return 0; diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c index 52db8fc0..935add5a 100644 --- a/src/crypto/tls_openssl.c +++ b/src/crypto/tls_openssl.c @@ -26,6 +26,7 @@ #include "common.h" #include "crypto.h" +#include "sha1.h" #include "tls.h" #if defined(SSL_CTX_get_app_data) && defined(SSL_CTX_set_app_data) @@ -2632,8 +2633,6 @@ int tls_connection_get_keys(void *ssl_ctx, struct tls_connection *conn, return -1; os_memset(keys, 0, sizeof(*keys)); - keys->master_key = ssl->session->master_key; - keys->master_key_len = ssl->session->master_key_length; keys->client_random = ssl->s3->client_random; keys->client_random_len = SSL3_RANDOM_SIZE; keys->server_random = ssl->s3->server_random; @@ -2644,16 +2643,122 @@ int tls_connection_get_keys(void *ssl_ctx, struct tls_connection *conn, } +static int openssl_get_keyblock_size(SSL *ssl) +{ + const EVP_CIPHER *c; + const EVP_MD *h; + int md_size; + + if (ssl->enc_read_ctx == NULL || ssl->enc_read_ctx->cipher == NULL || + ssl->read_hash == NULL) + return -1; + + c = ssl->enc_read_ctx->cipher; +#if OPENSSL_VERSION_NUMBER >= 0x00909000L + h = EVP_MD_CTX_md(ssl->read_hash); +#else + h = conn->ssl->read_hash; +#endif + if (h) + md_size = EVP_MD_size(h); +#if OPENSSL_VERSION_NUMBER >= 0x10000000L + else if (ssl->s3) + md_size = ssl->s3->tmp.new_mac_secret_size; +#endif + else + return -1; + + wpa_printf(MSG_DEBUG, "OpenSSL: keyblock size: key_len=%d MD_size=%d " + "IV_len=%d", EVP_CIPHER_key_length(c), md_size, + EVP_CIPHER_iv_length(c)); + return 2 * (EVP_CIPHER_key_length(c) + + md_size + + EVP_CIPHER_iv_length(c)); +} + + +static int openssl_tls_prf(void *tls_ctx, struct tls_connection *conn, + const char *label, int server_random_first, + int skip_keyblock, u8 *out, size_t out_len) +{ +#ifdef CONFIG_FIPS + wpa_printf(MSG_ERROR, "OpenSSL: TLS keys cannot be exported in FIPS " + "mode"); + return -1; +#else /* CONFIG_FIPS */ + SSL *ssl; + u8 *rnd; + int ret = -1; + int skip = 0; + u8 *tmp_out = NULL; + u8 *_out = out; + + /* + * TLS library did not support key generation, so get the needed TLS + * session parameters and use an internal implementation of TLS PRF to + * derive the key. + */ + + if (conn == NULL) + return -1; + ssl = conn->ssl; + if (ssl == NULL || ssl->s3 == NULL || ssl->session == NULL || + ssl->s3->client_random == NULL || ssl->s3->server_random == NULL || + ssl->session->master_key == NULL) + return -1; + + if (skip_keyblock) { + skip = openssl_get_keyblock_size(ssl); + if (skip < 0) + return -1; + tmp_out = os_malloc(skip + out_len); + if (!tmp_out) + return -1; + _out = tmp_out; + } + + rnd = os_malloc(2 * SSL3_RANDOM_SIZE); + if (rnd == NULL) + return -1; + if (server_random_first) { + os_memcpy(rnd, ssl->s3->server_random, SSL3_RANDOM_SIZE); + os_memcpy(rnd + SSL3_RANDOM_SIZE, ssl->s3->client_random, + SSL3_RANDOM_SIZE); + } else { + os_memcpy(rnd, ssl->s3->client_random, SSL3_RANDOM_SIZE); + os_memcpy(rnd + SSL3_RANDOM_SIZE, ssl->s3->server_random, + SSL3_RANDOM_SIZE); + } + + /* TODO: TLSv1.2 may need another PRF. This could use something closer + * to SSL_export_keying_material() design. */ + if (tls_prf_sha1_md5(ssl->session->master_key, + ssl->session->master_key_length, + label, rnd, 2 * SSL3_RANDOM_SIZE, + _out, skip + out_len) == 0) + ret = 0; + os_free(rnd); + if (ret == 0 && skip_keyblock) + os_memcpy(out, _out + skip, out_len); + bin_clear_free(tmp_out, skip); + + return ret; +#endif /* CONFIG_FIPS */ +} + + int tls_connection_prf(void *tls_ctx, struct tls_connection *conn, const char *label, int server_random_first, - u8 *out, size_t out_len) + int skip_keyblock, u8 *out, size_t out_len) { #if OPENSSL_VERSION_NUMBER >= 0x10001000L SSL *ssl; if (conn == NULL) return -1; - if (server_random_first) - return -1; + if (server_random_first || skip_keyblock) + return openssl_tls_prf(tls_ctx, conn, label, + server_random_first, skip_keyblock, + out, out_len); ssl = conn->ssl; if (SSL_export_keying_material(ssl, out, out_len, label, os_strlen(label), NULL, 0, 0) == 1) { @@ -2661,7 +2766,8 @@ int tls_connection_prf(void *tls_ctx, struct tls_connection *conn, return 0; } #endif - return -1; + return openssl_tls_prf(tls_ctx, conn, label, server_random_first, + skip_keyblock, out, out_len); } @@ -3514,43 +3620,6 @@ int tls_global_set_params(void *tls_ctx, } -int tls_connection_get_keyblock_size(void *tls_ctx, - struct tls_connection *conn) -{ - const EVP_CIPHER *c; - const EVP_MD *h; - int md_size; - - if (conn == NULL || conn->ssl == NULL || - conn->ssl->enc_read_ctx == NULL || - conn->ssl->enc_read_ctx->cipher == NULL || - conn->ssl->read_hash == NULL) - return -1; - - c = conn->ssl->enc_read_ctx->cipher; -#if OPENSSL_VERSION_NUMBER >= 0x00909000L - h = EVP_MD_CTX_md(conn->ssl->read_hash); -#else - h = conn->ssl->read_hash; -#endif - if (h) - md_size = EVP_MD_size(h); -#if OPENSSL_VERSION_NUMBER >= 0x10000000L - else if (conn->ssl->s3) - md_size = conn->ssl->s3->tmp.new_mac_secret_size; -#endif - else - return -1; - - wpa_printf(MSG_DEBUG, "OpenSSL: keyblock size: key_len=%d MD_size=%d " - "IV_len=%d", EVP_CIPHER_key_length(c), md_size, - EVP_CIPHER_iv_length(c)); - return 2 * (EVP_CIPHER_key_length(c) + - md_size + - EVP_CIPHER_iv_length(c)); -} - - unsigned int tls_capabilities(void *tls_ctx) { return 0; diff --git a/src/drivers/driver_wext.c b/src/drivers/driver_wext.c index a1581b8c..22e11840 100644 --- a/src/drivers/driver_wext.c +++ b/src/drivers/driver_wext.c @@ -1,6 +1,6 @@ /* * Driver interaction with generic Linux Wireless Extensions - * Copyright (c) 2003-2010, Jouni Malinen <j@w1.fi> + * Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -18,6 +18,7 @@ #include <sys/stat.h> #include <fcntl.h> #include <net/if_arp.h> +#include <dirent.h> #include "linux_wext.h" #include "common.h" @@ -874,6 +875,105 @@ static void wpa_driver_wext_send_rfkill(void *eloop_ctx, void *timeout_ctx) } +static int wext_hostap_ifname(struct wpa_driver_wext_data *drv, + const char *ifname) +{ + char buf[200], *res; + int type; + FILE *f; + + if (strcmp(ifname, ".") == 0 || strcmp(ifname, "..") == 0) + return -1; + + snprintf(buf, sizeof(buf), "/sys/class/net/%s/device/net/%s/type", + drv->ifname, ifname); + + f = fopen(buf, "r"); + if (!f) + return -1; + res = fgets(buf, sizeof(buf), f); + fclose(f); + + type = res ? atoi(res) : -1; + wpa_printf(MSG_DEBUG, "WEXT: hostap ifname %s type %d", ifname, type); + + if (type == ARPHRD_IEEE80211) { + wpa_printf(MSG_DEBUG, + "WEXT: Found hostap driver wifi# interface (%s)", + ifname); + wpa_driver_wext_alternative_ifindex(drv, ifname); + return 0; + } + return -1; +} + + +static int wext_add_hostap(struct wpa_driver_wext_data *drv) +{ + char buf[200]; + int n; + struct dirent **names; + int ret = -1; + + snprintf(buf, sizeof(buf), "/sys/class/net/%s/device/net", drv->ifname); + n = scandir(buf, &names, NULL, alphasort); + if (n < 0) + return -1; + + while (n--) { + if (ret < 0 && wext_hostap_ifname(drv, names[n]->d_name) == 0) + ret = 0; + free(names[n]); + } + free(names); + + return ret; +} + + +static void wext_check_hostap(struct wpa_driver_wext_data *drv) +{ + char buf[200], *pos; + ssize_t res; + + /* + * Host AP driver may use both wlan# and wifi# interface in wireless + * events. Since some of the versions included WE-18 support, let's add + * the alternative ifindex also from driver_wext.c for the time being. + * This may be removed at some point once it is believed that old + * versions of the driver are not in use anymore. However, it looks like + * the wifi# interface is still used in the current kernel tree, so it + * may not really be possible to remove this before the Host AP driver + * gets removed from the kernel. + */ + + /* First, try to see if driver information is available from sysfs */ + snprintf(buf, sizeof(buf), "/sys/class/net/%s/device/driver", + drv->ifname); + res = readlink(buf, buf, sizeof(buf) - 1); + if (res > 0) { + buf[res] = '\0'; + pos = strrchr(buf, '/'); + if (pos) + pos++; + else + pos = buf; + wpa_printf(MSG_DEBUG, "WEXT: Driver: %s", pos); + if (os_strncmp(pos, "hostap", 6) == 0 && + wext_add_hostap(drv) == 0) + return; + } + + /* Second, use the old design with hardcoded ifname */ + if (os_strncmp(drv->ifname, "wlan", 4) == 0) { + char ifname2[IFNAMSIZ + 1]; + os_strlcpy(ifname2, drv->ifname, sizeof(ifname2)); + os_memcpy(ifname2, "wifi", 4); + wpa_driver_wext_alternative_ifindex(drv, ifname2); + } +} + + static int wpa_driver_wext_finish_drv_init(struct wpa_driver_wext_data *drv) { int send_rfkill_event = 0; @@ -914,20 +1014,7 @@ static int wpa_driver_wext_finish_drv_init(struct wpa_driver_wext_data *drv) drv->ifindex = if_nametoindex(drv->ifname); - if (os_strncmp(drv->ifname, "wlan", 4) == 0) { - /* - * Host AP driver may use both wlan# and wifi# interface in - * wireless events. Since some of the versions included WE-18 - * support, let's add the alternative ifindex also from - * driver_wext.c for the time being. This may be removed at - * some point once it is believed that old versions of the - * driver are not in use anymore. - */ - char ifname2[IFNAMSIZ + 1]; - os_strlcpy(ifname2, drv->ifname, sizeof(ifname2)); - os_memcpy(ifname2, "wifi", 4); - wpa_driver_wext_alternative_ifindex(drv, ifname2); - } + wext_check_hostap(drv); netlink_send_oper_ifla(drv->netlink, drv->ifindex, 1, IF_OPER_DORMANT); diff --git a/src/eap_common/eap_fast_common.c b/src/eap_common/eap_fast_common.c index fceb1b0a..151cc785 100644 --- a/src/eap_common/eap_fast_common.c +++ b/src/eap_common/eap_fast_common.c @@ -96,49 +96,18 @@ void eap_fast_derive_master_secret(const u8 *pac_key, const u8 *server_random, u8 * eap_fast_derive_key(void *ssl_ctx, struct tls_connection *conn, const char *label, size_t len) { - struct tls_keys keys; - u8 *rnd = NULL, *out; - int block_size; + u8 *out; - block_size = tls_connection_get_keyblock_size(ssl_ctx, conn); - if (block_size < 0) - return NULL; - - out = os_malloc(block_size + len); + out = os_malloc(len); if (out == NULL) return NULL; - if (tls_connection_prf(ssl_ctx, conn, label, 1, out, block_size + len) - == 0) { - os_memmove(out, out + block_size, len); - return out; + if (tls_connection_prf(ssl_ctx, conn, label, 1, 1, out, len)) { + os_free(out); + return NULL; } - if (tls_connection_get_keys(ssl_ctx, conn, &keys)) - goto fail; - - rnd = os_malloc(keys.client_random_len + keys.server_random_len); - if (rnd == NULL) - goto fail; - - os_memcpy(rnd, keys.server_random, keys.server_random_len); - os_memcpy(rnd + keys.server_random_len, keys.client_random, - keys.client_random_len); - - wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: master_secret for key " - "expansion", keys.master_key, keys.master_key_len); - if (tls_prf_sha1_md5(keys.master_key, keys.master_key_len, - label, rnd, keys.client_random_len + - keys.server_random_len, out, block_size + len)) - goto fail; - os_free(rnd); - os_memmove(out, out + block_size, len); return out; - -fail: - os_free(rnd); - os_free(out); - return NULL; } diff --git a/src/eap_common/eap_pwd_common.c b/src/eap_common/eap_pwd_common.c index 631c363f..4d27623f 100644 --- a/src/eap_common/eap_pwd_common.c +++ b/src/eap_common/eap_pwd_common.c @@ -86,9 +86,10 @@ static int eap_pwd_kdf(const u8 *key, size_t keylen, const u8 *label, * on the password and identities. */ int compute_password_element(EAP_PWD_group *grp, u16 num, - u8 *password, int password_len, - u8 *id_server, int id_server_len, - u8 *id_peer, int id_peer_len, u8 *token) + const u8 *password, size_t password_len, + const u8 *id_server, size_t id_server_len, + const u8 *id_peer, size_t id_peer_len, + const u8 *token) { BIGNUM *x_candidate = NULL, *rnd = NULL, *cofactor = NULL; struct crypto_hash *hash; @@ -283,10 +284,10 @@ int compute_password_element(EAP_PWD_group *grp, u16 num, } -int compute_keys(EAP_PWD_group *grp, BN_CTX *bnctx, BIGNUM *k, - BIGNUM *peer_scalar, BIGNUM *server_scalar, - u8 *confirm_peer, u8 *confirm_server, - u32 *ciphersuite, u8 *msk, u8 *emsk, u8 *session_id) +int compute_keys(EAP_PWD_group *grp, BN_CTX *bnctx, const BIGNUM *k, + const BIGNUM *peer_scalar, const BIGNUM *server_scalar, + const u8 *confirm_peer, const u8 *confirm_server, + const u32 *ciphersuite, u8 *msk, u8 *emsk, u8 *session_id) { struct crypto_hash *hash; u8 mk[SHA256_MAC_LEN], *cruft; @@ -306,7 +307,7 @@ int compute_keys(EAP_PWD_group *grp, BN_CTX *bnctx, BIGNUM *k, os_free(cruft); return -1; } - eap_pwd_h_update(hash, (u8 *) ciphersuite, sizeof(u32)); + eap_pwd_h_update(hash, (const u8 *) ciphersuite, sizeof(u32)); offset = BN_num_bytes(grp->order) - BN_num_bytes(peer_scalar); os_memset(cruft, 0, BN_num_bytes(grp->prime)); BN_bn2bin(peer_scalar, cruft + offset); diff --git a/src/eap_common/eap_pwd_common.h b/src/eap_common/eap_pwd_common.h index c54c4414..a0d717ed 100644 --- a/src/eap_common/eap_pwd_common.h +++ b/src/eap_common/eap_pwd_common.h @@ -56,10 +56,15 @@ struct eap_pwd_id { } STRUCT_PACKED; /* common routines */ -int compute_password_element(EAP_PWD_group *, u16, u8 *, int, u8 *, int, u8 *, - int, u8 *); -int compute_keys(EAP_PWD_group *, BN_CTX *, BIGNUM *, BIGNUM *, BIGNUM *, - u8 *, u8 *, u32 *, u8 *, u8 *, u8 *); +int compute_password_element(EAP_PWD_group *grp, u16 num, + const u8 *password, size_t password_len, + const u8 *id_server, size_t id_server_len, + const u8 *id_peer, size_t id_peer_len, + const u8 *token); +int compute_keys(EAP_PWD_group *grp, BN_CTX *bnctx, const BIGNUM *k, + const BIGNUM *peer_scalar, const BIGNUM *server_scalar, + const u8 *confirm_peer, const u8 *confirm_server, + const u32 *ciphersuite, u8 *msk, u8 *emsk, u8 *session_id); struct crypto_hash * eap_pwd_h_init(void); void eap_pwd_h_update(struct crypto_hash *hash, const u8 *data, size_t len); void eap_pwd_h_final(struct crypto_hash *hash, u8 *digest); diff --git a/src/eap_peer/eap.c b/src/eap_peer/eap.c index 35433f3b..fc4af953 100644 --- a/src/eap_peer/eap.c +++ b/src/eap_peer/eap.c @@ -2400,7 +2400,7 @@ static int eap_allowed_phase2_type(int vendor, int type) u32 eap_get_phase2_type(const char *name, int *vendor) { int v; - u8 type = eap_peer_get_type(name, &v); + u32 type = eap_peer_get_type(name, &v); if (eap_allowed_phase2_type(v, type)) { *vendor = v; return type; diff --git a/src/eap_peer/eap_pwd.c b/src/eap_peer/eap_pwd.c index 059bbeec..f2b09266 100644 --- a/src/eap_peer/eap_pwd.c +++ b/src/eap_peer/eap_pwd.c @@ -10,6 +10,7 @@ #include "common.h" #include "crypto/sha256.h" +#include "crypto/ms_funcs.h" #include "eap_peer/eap_i.h" #include "eap_common/eap_pwd_common.h" @@ -25,6 +26,7 @@ struct eap_pwd_data { size_t id_server_len; u8 *password; size_t password_len; + int password_hash; u16 group_num; EAP_PWD_group *grp; @@ -86,8 +88,9 @@ static void * eap_pwd_init(struct eap_sm *sm) const u8 *identity, *password; size_t identity_len, password_len; int fragment_size; + int pwhash; - password = eap_get_config_password(sm, &password_len); + password = eap_get_config_password2(sm, &password_len, &pwhash); if (password == NULL) { wpa_printf(MSG_INFO, "EAP-PWD: No password configured!"); return NULL; @@ -129,6 +132,7 @@ static void * eap_pwd_init(struct eap_sm *sm) } os_memcpy(data->password, password, password_len); data->password_len = password_len; + data->password_hash = pwhash; data->out_frag_pos = data->in_frag_pos = 0; data->inbuf = data->outbuf = NULL; @@ -216,6 +220,10 @@ eap_pwd_perform_id_exchange(struct eap_sm *sm, struct eap_pwd_data *data, const u8 *payload, size_t payload_len) { struct eap_pwd_id *id; + const u8 *password; + size_t password_len; + u8 pwhashhash[16]; + int res; if (data->state != PWD_ID_Req) { ret->ignore = TRUE; @@ -231,6 +239,9 @@ eap_pwd_perform_id_exchange(struct eap_sm *sm, struct eap_pwd_data *data, id = (struct eap_pwd_id *) payload; data->group_num = be_to_host16(id->group_num); + wpa_printf(MSG_DEBUG, + "EAP-PWD: Server EAP-pwd-ID proposal: group=%u random=%u prf=%u prep=%u", + data->group_num, id->random_function, id->prf, id->prep); if ((id->random_function != EAP_PWD_DEFAULT_RAND_FUNC) || (id->prf != EAP_PWD_DEFAULT_PRF)) { ret->ignore = TRUE; @@ -238,6 +249,22 @@ eap_pwd_perform_id_exchange(struct eap_sm *sm, struct eap_pwd_data *data, return; } + if (id->prep != EAP_PWD_PREP_NONE && + id->prep != EAP_PWD_PREP_MS) { + wpa_printf(MSG_DEBUG, + "EAP-PWD: Unsupported password pre-processing technique (Prep=%u)", + id->prep); + eap_pwd_state(data, FAILURE); + return; + } + + if (id->prep == EAP_PWD_PREP_NONE && data->password_hash) { + wpa_printf(MSG_DEBUG, + "EAP-PWD: Unhashed password not available"); + eap_pwd_state(data, FAILURE); + return; + } + wpa_printf(MSG_DEBUG, "EAP-PWD (peer): using group %d", data->group_num); @@ -260,12 +287,39 @@ eap_pwd_perform_id_exchange(struct eap_sm *sm, struct eap_pwd_data *data, return; } + if (id->prep == EAP_PWD_PREP_MS) { + if (data->password_hash) { + res = hash_nt_password_hash(data->password, pwhashhash); + } else { + u8 pwhash[16]; + + res = nt_password_hash(data->password, + data->password_len, pwhash); + if (res == 0) + res = hash_nt_password_hash(pwhash, pwhashhash); + os_memset(pwhash, 0, sizeof(pwhash)); + } + + if (res) { + eap_pwd_state(data, FAILURE); + return; + } + + password = pwhashhash; + password_len = sizeof(pwhashhash); + } else { + password = data->password; + password_len = data->password_len; + } + /* compute PWE */ - if (compute_password_element(data->grp, data->group_num, - data->password, data->password_len, - data->id_server, data->id_server_len, - data->id_peer, data->id_peer_len, - id->token)) { + res = compute_password_element(data->grp, data->group_num, + password, password_len, + data->id_server, data->id_server_len, + data->id_peer, data->id_peer_len, + id->token); + os_memset(pwhashhash, 0, sizeof(pwhashhash)); + if (res) { wpa_printf(MSG_INFO, "EAP-PWD (peer): unable to compute PWE"); eap_pwd_state(data, FAILURE); return; diff --git a/src/eap_peer/eap_tls_common.c b/src/eap_peer/eap_tls_common.c index 87107816..15c1bac5 100644 --- a/src/eap_peer/eap_tls_common.c +++ b/src/eap_peer/eap_tls_common.c @@ -313,53 +313,19 @@ void eap_peer_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data) u8 * eap_peer_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data, const char *label, size_t len) { -#ifndef CONFIG_FIPS - struct tls_keys keys; -#endif /* CONFIG_FIPS */ - u8 *rnd = NULL, *out; + u8 *out; out = os_malloc(len); if (out == NULL) return NULL; - /* First, try to use TLS library function for PRF, if available. */ - if (tls_connection_prf(data->ssl_ctx, data->conn, label, 0, out, len) - == 0) - return out; - -#ifndef CONFIG_FIPS - /* - * TLS library did not support key generation, so get the needed TLS - * session parameters and use an internal implementation of TLS PRF to - * derive the key. - */ - if (tls_connection_get_keys(data->ssl_ctx, data->conn, &keys)) - goto fail; - - if (keys.client_random == NULL || keys.server_random == NULL || - keys.master_key == NULL) - goto fail; - - rnd = os_malloc(keys.client_random_len + keys.server_random_len); - if (rnd == NULL) - goto fail; - os_memcpy(rnd, keys.client_random, keys.client_random_len); - os_memcpy(rnd + keys.client_random_len, keys.server_random, - keys.server_random_len); - - if (tls_prf_sha1_md5(keys.master_key, keys.master_key_len, - label, rnd, keys.client_random_len + - keys.server_random_len, out, len)) - goto fail; + if (tls_connection_prf(data->ssl_ctx, data->conn, label, 0, 0, + out, len)) { + os_free(out); + return NULL; + } - os_free(rnd); return out; - -fail: -#endif /* CONFIG_FIPS */ - os_free(out); - os_free(rnd); - return NULL; } @@ -1032,7 +998,7 @@ int eap_peer_select_phase2_methods(struct eap_peer_config *config, { char *start, *pos, *buf; struct eap_method_type *methods = NULL, *_methods; - u8 method; + u32 method; size_t num_methods = 0, prefix_len; if (config == NULL || config->phase2 == NULL) diff --git a/src/eap_server/eap.h b/src/eap_server/eap.h index 9de6cb62..b825e18f 100644 --- a/src/eap_server/eap.h +++ b/src/eap_server/eap.h @@ -149,5 +149,8 @@ int eap_sm_method_pending(struct eap_sm *sm); const u8 * eap_get_identity(struct eap_sm *sm, size_t *len); struct eap_eapol_interface * eap_get_interface(struct eap_sm *sm); void eap_server_clear_identity(struct eap_sm *sm); +void eap_server_mschap_rx_callback(struct eap_sm *sm, const char *source, + const u8 *username, size_t username_len, + const u8 *challenge, const u8 *response); #endif /* EAP_H */ diff --git a/src/eap_server/eap_server.c b/src/eap_server/eap_server.c index bd919e57..693debe8 100644 --- a/src/eap_server/eap_server.c +++ b/src/eap_server/eap_server.c @@ -1979,3 +1979,25 @@ void eap_server_clear_identity(struct eap_sm *sm) os_free(sm->identity); sm->identity = NULL; } + + +#ifdef CONFIG_TESTING_OPTIONS +void eap_server_mschap_rx_callback(struct eap_sm *sm, const char *source, + const u8 *username, size_t username_len, + const u8 *challenge, const u8 *response) +{ + char hex_challenge[30], hex_response[90], user[100]; + + /* Print out Challenge and Response in format supported by asleap. */ + if (username) + printf_encode(user, sizeof(user), username, username_len); + else + user[0] = '\0'; + wpa_snprintf_hex_sep(hex_challenge, sizeof(hex_challenge), + challenge, sizeof(challenge), ':'); + wpa_snprintf_hex_sep(hex_response, sizeof(hex_response), response, 24, + ':'); + wpa_printf(MSG_DEBUG, "[%s/user=%s] asleap -C %s -R %s", + source, user, hex_challenge, hex_response); +} +#endif /* CONFIG_TESTING_OPTIONS */ diff --git a/src/eap_server/eap_server_mschapv2.c b/src/eap_server/eap_server_mschapv2.c index 05848d2e..98d74e0d 100644 --- a/src/eap_server/eap_server_mschapv2.c +++ b/src/eap_server/eap_server_mschapv2.c @@ -360,6 +360,19 @@ static void eap_mschapv2_process_response(struct eap_sm *sm, } } +#ifdef CONFIG_TESTING_OPTIONS + { + u8 challenge[8]; + + if (challenge_hash(peer_challenge, data->auth_challenge, + username, username_len, challenge) == 0) { + eap_server_mschap_rx_callback(sm, "EAP-MSCHAPV2", + username, username_len, + challenge, nt_response); + } + } +#endif /* CONFIG_TESTING_OPTIONS */ + if (username_len != user_len || os_memcmp(username, user, username_len) != 0) { wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Mismatch in user names"); diff --git a/src/eap_server/eap_server_peap.c b/src/eap_server/eap_server_peap.c index faa0fd2f..3848f308 100644 --- a/src/eap_server/eap_server_peap.c +++ b/src/eap_server/eap_server_peap.c @@ -539,15 +539,14 @@ static Boolean eap_peap_check(struct eap_sm *sm, void *priv, static int eap_peap_phase2_init(struct eap_sm *sm, struct eap_peap_data *data, - EapType eap_type) + int vendor, EapType eap_type) { if (data->phase2_priv && data->phase2_method) { data->phase2_method->reset(sm, data->phase2_priv); data->phase2_method = NULL; data->phase2_priv = NULL; } - data->phase2_method = eap_server_get_eap_method(EAP_VENDOR_IETF, - eap_type); + data->phase2_method = eap_server_get_eap_method(vendor, eap_type); if (!data->phase2_method) return -1; @@ -737,7 +736,7 @@ static void eap_peap_process_phase2_soh(struct eap_sm *sm, const u8 *soh_tlv = NULL; size_t soh_tlv_len = 0; int tlv_type, mandatory, tlv_len, vtlv_len; - u8 next_type; + u32 next_type; u32 vendor_id; pos = eap_hdr_validate(EAP_VENDOR_MICROSOFT, 0x21, in_data, &left); @@ -852,8 +851,9 @@ auth_method: eap_peap_state(data, PHASE2_METHOD); next_type = sm->user->methods[0].method; sm->user_eap_method_index = 1; - wpa_printf(MSG_DEBUG, "EAP-PEAP: try EAP type %d", next_type); - eap_peap_phase2_init(sm, data, next_type); + wpa_printf(MSG_DEBUG, "EAP-PEAP: try EAP vendor %d type %d", + sm->user->methods[0].vendor, next_type); + eap_peap_phase2_init(sm, data, sm->user->methods[0].vendor, next_type); } #endif /* EAP_SERVER_TNC */ @@ -862,7 +862,8 @@ static void eap_peap_process_phase2_response(struct eap_sm *sm, struct eap_peap_data *data, struct wpabuf *in_data) { - u8 next_type = EAP_TYPE_NONE; + int next_vendor = EAP_VENDOR_IETF; + u32 next_type = EAP_TYPE_NONE; const struct eap_hdr *hdr; const u8 *pos; size_t left; @@ -894,17 +895,23 @@ static void eap_peap_process_phase2_response(struct eap_sm *sm, "allowed types", pos + 1, left - 1); eap_sm_process_nak(sm, pos + 1, left - 1); if (sm->user && sm->user_eap_method_index < EAP_MAX_METHODS && - sm->user->methods[sm->user_eap_method_index].method != - EAP_TYPE_NONE) { + (sm->user->methods[sm->user_eap_method_index].vendor != + EAP_VENDOR_IETF || + sm->user->methods[sm->user_eap_method_index].method != + EAP_TYPE_NONE)) { + next_vendor = sm->user->methods[ + sm->user_eap_method_index].vendor; next_type = sm->user->methods[ sm->user_eap_method_index++].method; - wpa_printf(MSG_DEBUG, "EAP-PEAP: try EAP type %d", - next_type); + wpa_printf(MSG_DEBUG, + "EAP-PEAP: try EAP vendor %d type 0x%x", + next_vendor, next_type); } else { eap_peap_req_failure(sm, data); + next_vendor = EAP_VENDOR_IETF; next_type = EAP_TYPE_NONE; } - eap_peap_phase2_init(sm, data, next_type); + eap_peap_phase2_init(sm, data, next_vendor, next_type); return; } @@ -929,8 +936,9 @@ static void eap_peap_process_phase2_response(struct eap_sm *sm, if (!data->phase2_method->isSuccess(sm, data->phase2_priv)) { wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase2 method failed"); eap_peap_req_failure(sm, data); + next_vendor = EAP_VENDOR_IETF; next_type = EAP_TYPE_NONE; - eap_peap_phase2_init(sm, data, next_type); + eap_peap_phase2_init(sm, data, next_vendor, next_type); return; } @@ -942,7 +950,8 @@ static void eap_peap_process_phase2_response(struct eap_sm *sm, wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase2 getKey " "failed"); eap_peap_req_failure(sm, data); - eap_peap_phase2_init(sm, data, EAP_TYPE_NONE); + eap_peap_phase2_init(sm, data, EAP_VENDOR_IETF, + EAP_TYPE_NONE); return; } } @@ -957,6 +966,7 @@ static void eap_peap_process_phase2_response(struct eap_sm *sm, "database", sm->identity, sm->identity_len); eap_peap_req_failure(sm, data); + next_vendor = EAP_VENDOR_IETF; next_type = EAP_TYPE_NONE; break; } @@ -967,18 +977,22 @@ static void eap_peap_process_phase2_response(struct eap_sm *sm, eap_peap_state(data, PHASE2_SOH); wpa_printf(MSG_DEBUG, "EAP-PEAP: Try to initialize " "TNC (NAP SOH)"); + next_vendor = EAP_VENDOR_IETF; next_type = EAP_TYPE_NONE; break; } #endif /* EAP_SERVER_TNC */ eap_peap_state(data, PHASE2_METHOD); + next_vendor = sm->user->methods[0].vendor; next_type = sm->user->methods[0].method; sm->user_eap_method_index = 1; - wpa_printf(MSG_DEBUG, "EAP-PEAP: try EAP type %d", next_type); + wpa_printf(MSG_DEBUG, "EAP-PEAP: try EAP vendor %d type 0x%x", + next_vendor, next_type); break; case PHASE2_METHOD: eap_peap_req_success(sm, data); + next_vendor = EAP_VENDOR_IETF; next_type = EAP_TYPE_NONE; break; case FAILURE: @@ -989,7 +1003,7 @@ static void eap_peap_process_phase2_response(struct eap_sm *sm, break; } - eap_peap_phase2_init(sm, data, next_type); + eap_peap_phase2_init(sm, data, next_vendor, next_type); } @@ -1133,7 +1147,8 @@ static void eap_peap_process_msg(struct eap_sm *sm, void *priv, break; case PHASE2_START: eap_peap_state(data, PHASE2_ID); - eap_peap_phase2_init(sm, data, EAP_TYPE_IDENTITY); + eap_peap_phase2_init(sm, data, EAP_VENDOR_IETF, + EAP_TYPE_IDENTITY); break; case PHASE1_ID2: case PHASE2_ID: diff --git a/src/eap_server/eap_server_pwd.c b/src/eap_server/eap_server_pwd.c index 943af0d1..66bd5d2e 100644 --- a/src/eap_server/eap_server_pwd.c +++ b/src/eap_server/eap_server_pwd.c @@ -10,6 +10,7 @@ #include "common.h" #include "crypto/sha256.h" +#include "crypto/ms_funcs.h" #include "eap_server/eap_i.h" #include "eap_common/eap_pwd_common.h" @@ -24,6 +25,7 @@ struct eap_pwd_data { size_t id_server_len; u8 *password; size_t password_len; + int password_hash; u32 token; u16 group_num; EAP_PWD_group *grp; @@ -112,6 +114,7 @@ static void * eap_pwd_init(struct eap_sm *sm) } data->password_len = sm->user->password_len; os_memcpy(data->password, sm->user->password, data->password_len); + data->password_hash = sm->user->password_hash; data->bnctx = BN_CTX_new(); if (data->bnctx == NULL) { @@ -181,7 +184,8 @@ static void eap_pwd_build_id_req(struct eap_sm *sm, struct eap_pwd_data *data, wpabuf_put_u8(data->outbuf, EAP_PWD_DEFAULT_RAND_FUNC); wpabuf_put_u8(data->outbuf, EAP_PWD_DEFAULT_PRF); wpabuf_put_data(data->outbuf, &data->token, sizeof(data->token)); - wpabuf_put_u8(data->outbuf, EAP_PWD_PREP_NONE); + wpabuf_put_u8(data->outbuf, data->password_hash ? EAP_PWD_PREP_MS : + EAP_PWD_PREP_NONE); wpabuf_put_data(data->outbuf, data->id_server, data->id_server_len); } @@ -579,6 +583,10 @@ static void eap_pwd_process_id_resp(struct eap_sm *sm, const u8 *payload, size_t payload_len) { struct eap_pwd_id *id; + const u8 *password; + size_t password_len; + u8 pwhashhash[16]; + int res; if (payload_len < sizeof(struct eap_pwd_id)) { wpa_printf(MSG_INFO, "EAP-pwd: Invalid ID response"); @@ -610,11 +618,25 @@ static void eap_pwd_process_id_resp(struct eap_sm *sm, "group"); return; } - if (compute_password_element(data->grp, data->group_num, - data->password, data->password_len, - data->id_server, data->id_server_len, - data->id_peer, data->id_peer_len, - (u8 *) &data->token)) { + + if (data->password_hash) { + res = hash_nt_password_hash(data->password, pwhashhash); + if (res) + return; + password = pwhashhash; + password_len = sizeof(pwhashhash); + } else { + password = data->password; + password_len = data->password_len; + } + + res = compute_password_element(data->grp, data->group_num, + password, password_len, + data->id_server, data->id_server_len, + data->id_peer, data->id_peer_len, + (u8 *) &data->token); + os_memset(pwhashhash, 0, sizeof(pwhashhash)); + if (res) { wpa_printf(MSG_INFO, "EAP-PWD (server): unable to compute " "PWE"); return; diff --git a/src/eap_server/eap_server_tls_common.c b/src/eap_server/eap_server_tls_common.c index 56916c45..23498c99 100644 --- a/src/eap_server/eap_server_tls_common.c +++ b/src/eap_server/eap_server_tls_common.c @@ -100,43 +100,19 @@ void eap_server_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data) u8 * eap_server_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data, char *label, size_t len) { - struct tls_keys keys; - u8 *rnd = NULL, *out; + u8 *out; out = os_malloc(len); if (out == NULL) return NULL; - if (tls_connection_prf(sm->ssl_ctx, data->conn, label, 0, out, len) == - 0) - return out; - - if (tls_connection_get_keys(sm->ssl_ctx, data->conn, &keys)) - goto fail; - - if (keys.client_random == NULL || keys.server_random == NULL || - keys.master_key == NULL) - goto fail; - - rnd = os_malloc(keys.client_random_len + keys.server_random_len); - if (rnd == NULL) - goto fail; - os_memcpy(rnd, keys.client_random, keys.client_random_len); - os_memcpy(rnd + keys.client_random_len, keys.server_random, - keys.server_random_len); - - if (tls_prf_sha1_md5(keys.master_key, keys.master_key_len, - label, rnd, keys.client_random_len + - keys.server_random_len, out, len)) - goto fail; + if (tls_connection_prf(sm->ssl_ctx, data->conn, label, 0, 0, + out, len)) { + os_free(out); + return NULL; + } - os_free(rnd); return out; - -fail: - os_free(out); - os_free(rnd); - return NULL; } diff --git a/src/eap_server/eap_server_ttls.c b/src/eap_server/eap_server_ttls.c index 12a31b07..31c67e8f 100644 --- a/src/eap_server/eap_server_ttls.c +++ b/src/eap_server/eap_server_ttls.c @@ -618,6 +618,12 @@ static void eap_ttls_process_phase2_mschap(struct eap_sm *sm, return; } +#ifdef CONFIG_TESTING_OPTIONS + eap_server_mschap_rx_callback(sm, "TTLS-MSCHAP", + sm->identity, sm->identity_len, + challenge, response + 2 + 24); +#endif /* CONFIG_TESTING_OPTIONS */ + if (os_memcmp_const(challenge, chal, EAP_TTLS_MSCHAP_CHALLENGE_LEN) != 0 || response[0] != chal[EAP_TTLS_MSCHAP_CHALLENGE_LEN]) { @@ -740,6 +746,18 @@ static void eap_ttls_process_phase2_mschapv2(struct eap_sm *sm, } rx_resp = response + 2 + EAP_TTLS_MSCHAPV2_CHALLENGE_LEN + 8; +#ifdef CONFIG_TESTING_OPTIONS + { + u8 challenge2[8]; + + if (challenge_hash(peer_challenge, auth_challenge, + username, username_len, challenge2) == 0) { + eap_server_mschap_rx_callback(sm, "TTLS-MSCHAPV2", + username, username_len, + challenge2, rx_resp); + } + } +#endif /* CONFIG_TESTING_OPTIONS */ if (os_memcmp_const(nt_response, rx_resp, 24) == 0) { wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Correct " "NT-Response"); diff --git a/src/radius/radius_server.c b/src/radius/radius_server.c index 85a485e9..3f881cf3 100644 --- a/src/radius/radius_server.c +++ b/src/radius/radius_server.c @@ -2035,6 +2035,12 @@ static int radius_server_get_eap_user(void *ctx, const u8 *identity, sess->remediation = user->remediation; sess->macacl = user->macacl; } + + if (ret) { + RADIUS_DEBUG("%s: User-Name not found from user database", + __func__); + } + return ret; } diff --git a/src/rsn_supp/wpa_ie.c b/src/rsn_supp/wpa_ie.c index cb334df6..0d96216d 100644 --- a/src/rsn_supp/wpa_ie.c +++ b/src/rsn_supp/wpa_ie.c @@ -30,6 +30,9 @@ int wpa_parse_wpa_ie(const u8 *wpa_ie, size_t wpa_ie_len, { if (wpa_ie_len >= 1 && wpa_ie[0] == WLAN_EID_RSN) return wpa_parse_wpa_ie_rsn(wpa_ie, wpa_ie_len, data); + if (wpa_ie_len >= 6 && wpa_ie[0] == WLAN_EID_VENDOR_SPECIFIC && + wpa_ie[1] >= 4 && WPA_GET_BE32(&wpa_ie[2]) == OSEN_IE_VENDOR_TYPE) + return wpa_parse_wpa_ie_rsn(wpa_ie, wpa_ie_len, data); else return wpa_parse_wpa_ie_wpa(wpa_ie, wpa_ie_len, data); } diff --git a/src/tls/tlsv1_client.c b/src/tls/tlsv1_client.c index facdd659..533286c1 100644 --- a/src/tls/tlsv1_client.c +++ b/src/tls/tlsv1_client.c @@ -731,8 +731,6 @@ int tlsv1_client_get_keys(struct tlsv1_client *conn, struct tls_keys *keys) if (conn->state != SERVER_HELLO) { keys->server_random = conn->server_random; keys->server_random_len = TLS_RANDOM_LEN; - keys->master_key = conn->master_secret; - keys->master_key_len = TLS_MASTER_SECRET_LEN; } return 0; diff --git a/src/tls/tlsv1_server.c b/src/tls/tlsv1_server.c index 93ae4888..4df756f7 100644 --- a/src/tls/tlsv1_server.c +++ b/src/tls/tlsv1_server.c @@ -627,8 +627,6 @@ int tlsv1_server_get_keys(struct tlsv1_server *conn, struct tls_keys *keys) if (conn->state != SERVER_HELLO) { keys->server_random = conn->server_random; keys->server_random_len = TLS_RANDOM_LEN; - keys->master_key = conn->master_secret; - keys->master_key_len = TLS_MASTER_SECRET_LEN; } return 0; diff --git a/src/utils/common.c b/src/utils/common.c index 5fd795f3..0bdc38db 100644 --- a/src/utils/common.c +++ b/src/utils/common.c @@ -277,6 +277,31 @@ int wpa_scnprintf(char *buf, size_t size, const char *fmt, ...) return ret; } + +int wpa_snprintf_hex_sep(char *buf, size_t buf_size, const u8 *data, size_t len, + char sep) +{ + size_t i; + char *pos = buf, *end = buf + buf_size; + int ret; + + if (buf_size == 0) + return 0; + + for (i = 0; i < len; i++) { + ret = os_snprintf(pos, end - pos, "%02x%c", + data[i], sep); + if (os_snprintf_error(end - pos, ret)) { + end[-1] = '\0'; + return pos - buf; + } + pos += ret; + } + pos[-1] = '\0'; + return pos - buf; +} + + static inline int _wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data, size_t len, int uppercase) { diff --git a/src/utils/common.h b/src/utils/common.h index 576e8e7e..a0eda4a2 100644 --- a/src/utils/common.h +++ b/src/utils/common.h @@ -480,6 +480,8 @@ int hexstr2bin(const char *hex, u8 *buf, size_t len); void inc_byte_array(u8 *counter, size_t len); void wpa_get_ntp_timestamp(u8 *buf); int wpa_scnprintf(char *buf, size_t size, const char *fmt, ...); +int wpa_snprintf_hex_sep(char *buf, size_t buf_size, const u8 *data, size_t len, + char sep); int wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data, size_t len); int wpa_snprintf_hex_uppercase(char *buf, size_t buf_size, const u8 *data, size_t len); diff --git a/src/utils/http_curl.c b/src/utils/http_curl.c index b38cf796..653eb541 100644 --- a/src/utils/http_curl.c +++ b/src/utils/http_curl.c @@ -855,8 +855,10 @@ static int validate_server_cert(struct http_ctx *ctx, X509 *cert) struct http_cert hcert; int ret; - if (ctx->cert_cb == NULL) + if (ctx->cert_cb == NULL) { + wpa_printf(MSG_DEBUG, "%s: no cert_cb configured", __func__); return 0; + } if (0) { BIO *out; @@ -950,7 +952,8 @@ static int curl_cb_ssl_verify(int preverify_ok, X509_STORE_CTX *x509_ctx) ssl_ctx = ssl->ctx; ctx = SSL_CTX_get_app_data(ssl_ctx); - wpa_printf(MSG_DEBUG, "curl_cb_ssl_verify"); + wpa_printf(MSG_DEBUG, "curl_cb_ssl_verify, preverify_ok: %d", + preverify_ok); err = X509_STORE_CTX_get_error(x509_ctx); err_str = X509_verify_cert_error_string(err); @@ -1249,9 +1252,14 @@ static CURL * setup_curl_post(struct http_ctx *ctx, const char *address, const char *client_key) { CURL *curl; +#ifdef EAP_TLS_OPENSSL + const char *extra = " tls=openssl"; +#else /* EAP_TLS_OPENSSL */ + const char *extra = ""; +#endif /* EAP_TLS_OPENSSL */ wpa_printf(MSG_DEBUG, "Start HTTP client: address=%s ca_fname=%s " - "username=%s", address, ca_fname, username); + "username=%s%s", address, ca_fname, username, extra); curl = curl_easy_init(); if (curl == NULL) diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk index ee40d307..621851b6 100644 --- a/wpa_supplicant/Android.mk +++ b/wpa_supplicant/Android.mk @@ -40,6 +40,9 @@ endif L_CFLAGS += -DCONFIG_CTRL_IFACE_CLIENT_DIR=\"/data/misc/wifi/sockets\" L_CFLAGS += -DCONFIG_CTRL_IFACE_DIR=\"/data/system/wpa_supplicant\" +# 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 @@ -1141,8 +1144,10 @@ 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 diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile index d086eeb6..af2d9242 100644 --- a/wpa_supplicant/Makefile +++ b/wpa_supplicant/Makefile @@ -317,6 +317,10 @@ 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) @@ -1162,8 +1166,10 @@ endif endif ifdef NEED_AES_CBC NEED_AES_ENC=y +ifneq ($(CONFIG_TLS), openssl) AESOBJS += ../src/crypto/aes-cbc.o endif +endif ifdef NEED_AES_ENC ifdef CONFIG_INTERNAL_AES AESOBJS += ../src/crypto/aes-internal-enc.o diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c index a01a9109..c6905422 100644 --- a/wpa_supplicant/config.c +++ b/wpa_supplicant/config.c @@ -1816,6 +1816,7 @@ static const struct parse_data ssid_fields[] = { { FUNC(bssid_blacklist) }, { FUNC(bssid_whitelist) }, { FUNC_KEY(psk) }, + { INT(mem_only_psk) }, { FUNC(proto) }, { FUNC(key_mgmt) }, { INT(bg_scan_period) }, diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c index 3d3a6e40..781f5e5a 100644 --- a/wpa_supplicant/config_file.c +++ b/wpa_supplicant/config_file.c @@ -501,7 +501,12 @@ static void write_bssid(FILE *f, struct wpa_ssid *ssid) static void write_psk(FILE *f, struct wpa_ssid *ssid) { - char *value = wpa_config_get(ssid, "psk"); + char *value; + + if (ssid->mem_only_psk) + return; + + value = wpa_config_get(ssid, "psk"); if (value == NULL) return; fprintf(f, "\tpsk=%s\n", value); @@ -673,6 +678,7 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid) write_str(f, "bssid_blacklist", ssid); write_str(f, "bssid_whitelist", ssid); write_psk(f, ssid); + INT(mem_only_psk); write_proto(f, ssid); write_key_mgmt(f, ssid); INT_DEF(bg_scan_period, DEFAULT_BG_SCAN_PERIOD); diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h index 7c826cfd..23a37cc3 100644 --- a/wpa_supplicant/config_ssid.h +++ b/wpa_supplicant/config_ssid.h @@ -181,6 +181,14 @@ struct wpa_ssid { char *ext_psk; /** + * mem_only_psk - Whether to keep PSK/passphrase only in memory + * + * 0 = allow psk/passphrase to be stored to the configuration file + * 1 = do not store psk/passphrase to the configuration file + */ + int mem_only_psk; + + /** * pairwise_cipher - Bitfield of allowed pairwise ciphers, WPA_CIPHER_* */ int pairwise_cipher; diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index 53d2d015..377b9ed1 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -2366,6 +2366,14 @@ static char * wpa_supplicant_ie_txt(char *pos, char *end, const char *proto, } #endif /* CONFIG_SUITEB192 */ + if (data.key_mgmt & WPA_KEY_MGMT_OSEN) { + ret = os_snprintf(pos, end - pos, "%sOSEN", + pos == start ? "" : "+"); + if (os_snprintf_error(end - pos, ret)) + return pos; + pos += ret; + } + pos = wpa_supplicant_cipher_txt(pos, end, data.pairwise_cipher); if (data.capabilities & WPA_CAPABILITY_PREAUTH) { @@ -2433,7 +2441,7 @@ static int wpa_supplicant_ctrl_iface_scan_result( { char *pos, *end; int ret; - const u8 *ie, *ie2, *p2p, *mesh; + const u8 *ie, *ie2, *osen_ie, *p2p, *mesh; mesh = wpa_bss_get_ie(bss, WLAN_EID_MESH_ID); p2p = wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE); @@ -2460,8 +2468,12 @@ static int wpa_supplicant_ctrl_iface_scan_result( pos = wpa_supplicant_ie_txt(pos, end, mesh ? "RSN" : "WPA2", ie2, 2 + ie2[1]); } + osen_ie = wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE); + if (osen_ie) + pos = wpa_supplicant_ie_txt(pos, end, "OSEN", + osen_ie, 2 + osen_ie[1]); pos = wpa_supplicant_wps_ie_txt(wpa_s, pos, end, bss); - if (!ie && !ie2 && bss->caps & IEEE80211_CAP_PRIVACY) { + if (!ie && !ie2 && !osen_ie && (bss->caps & IEEE80211_CAP_PRIVACY)) { ret = os_snprintf(pos, end - pos, "[WEP]"); if (os_snprintf_error(end - pos, ret)) return -1; @@ -3937,7 +3949,7 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, size_t i; int ret; char *pos, *end; - const u8 *ie, *ie2; + const u8 *ie, *ie2, *osen_ie; pos = buf; end = buf + buflen; @@ -4054,8 +4066,13 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, if (ie2) pos = wpa_supplicant_ie_txt(pos, end, "WPA2", ie2, 2 + ie2[1]); + osen_ie = wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE); + if (osen_ie) + pos = wpa_supplicant_ie_txt(pos, end, "OSEN", + osen_ie, 2 + osen_ie[1]); pos = wpa_supplicant_wps_ie_txt(wpa_s, pos, end, bss); - if (!ie && !ie2 && bss->caps & IEEE80211_CAP_PRIVACY) { + if (!ie && !ie2 && !osen_ie && + (bss->caps & IEEE80211_CAP_PRIVACY)) { ret = os_snprintf(pos, end - pos, "[WEP]"); if (os_snprintf_error(end - pos, ret)) return 0; @@ -8504,11 +8521,14 @@ static int wpa_supplicant_global_iface_add(struct wpa_global *global, char *cmd) { struct wpa_interface iface; - char *pos; + char *pos, *extra; + struct wpa_supplicant *wpa_s; + unsigned int create_iface = 0; + u8 mac_addr[ETH_ALEN]; /* * <ifname>TAB<confname>TAB<driver>TAB<ctrl_interface>TAB<driver_param> - * TAB<bridge_ifname> + * TAB<bridge_ifname>[TAB<create>] */ wpa_printf(MSG_DEBUG, "CTRL_IFACE GLOBAL INTERFACE_ADD '%s'", cmd); @@ -8568,12 +8588,47 @@ static int wpa_supplicant_global_iface_add(struct wpa_global *global, iface.bridge_ifname = NULL; if (pos == NULL) break; + + extra = pos; + pos = os_strchr(pos, '\t'); + if (pos) + *pos++ = '\0'; + if (os_strcmp(extra, "create") == 0) + create_iface = 1; + else + return -1; } while (0); + if (create_iface) { + wpa_printf(MSG_DEBUG, "CTRL_IFACE creating interface '%s'", + iface.ifname); + if (!global->ifaces) + return -1; + if (wpa_drv_if_add(global->ifaces, WPA_IF_STATION, iface.ifname, + NULL, NULL, NULL, mac_addr, NULL) < 0) { + wpa_printf(MSG_ERROR, + "CTRL_IFACE interface creation failed"); + return -1; + } + + wpa_printf(MSG_DEBUG, + "CTRL_IFACE interface '%s' created with MAC addr: " + MACSTR, iface.ifname, MAC2STR(mac_addr)); + } + if (wpa_supplicant_get_iface(global, iface.ifname)) - return -1; + goto fail; + + wpa_s = wpa_supplicant_add_iface(global, &iface, NULL); + if (!wpa_s) + goto fail; + wpa_s->added_vif = create_iface; + return 0; - return wpa_supplicant_add_iface(global, &iface, NULL) ? 0 : -1; +fail: + if (create_iface) + wpa_drv_if_remove(global->ifaces, WPA_IF_STATION, iface.ifname); + return -1; } @@ -8581,13 +8636,22 @@ static int wpa_supplicant_global_iface_remove(struct wpa_global *global, char *cmd) { struct wpa_supplicant *wpa_s; + int ret; + unsigned int delete_iface; wpa_printf(MSG_DEBUG, "CTRL_IFACE GLOBAL INTERFACE_REMOVE '%s'", cmd); wpa_s = wpa_supplicant_get_iface(global, cmd); if (wpa_s == NULL) return -1; - return wpa_supplicant_remove_iface(global, wpa_s, 0); + delete_iface = wpa_s->added_vif; + ret = wpa_supplicant_remove_iface(global, wpa_s, 0); + if (!ret && delete_iface) { + wpa_printf(MSG_DEBUG, "CTRL_IFACE deleting the interface '%s'", + cmd); + ret = wpa_drv_if_remove(global->ifaces, WPA_IF_STATION, cmd); + } + return ret; } diff --git a/wpa_supplicant/doc/docbook/wpa_gui.sgml b/wpa_supplicant/doc/docbook/wpa_gui.sgml index fe912362..5f7b49da 100644 --- a/wpa_supplicant/doc/docbook/wpa_gui.sgml +++ b/wpa_supplicant/doc/docbook/wpa_gui.sgml @@ -16,6 +16,7 @@ <command>wpa_gui</command> <arg>-p <replaceable>path to ctrl sockets</replaceable></arg> <arg>-i <replaceable>ifname</replaceable></arg> + <arg>-m <replaceable>seconds</replaceable></arg> <arg>-t</arg> <arg>-q</arg> </cmdsynopsis> @@ -52,6 +53,14 @@ </varlistentry> <varlistentry> + <term>-m seconds</term> + + <listitem><para>Set the update interval in seconds for the signal + strength meter. This value must be a positive integer, otherwise + meter is not enabled (default behavior).</para></listitem> + </varlistentry> + + <varlistentry> <term>-t</term> <listitem><para>Start program in the system tray only (if the window diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c index 6ed2549a..fc70035a 100644 --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c @@ -1085,14 +1085,13 @@ struct wpa_bss * wpa_supplicant_pick_network(struct wpa_supplicant *wpa_s, struct wpa_bss *selected = NULL; int prio; struct wpa_ssid *next_ssid = NULL; + struct wpa_ssid *ssid; if (wpa_s->last_scan_res == NULL || wpa_s->last_scan_res_used == 0) return NULL; /* no scan results from last update */ if (wpa_s->next_ssid) { - struct wpa_ssid *ssid; - /* check that next_ssid is still valid */ for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) { if (ssid == wpa_s->next_ssid) @@ -1128,6 +1127,27 @@ struct wpa_bss * wpa_supplicant_pick_network(struct wpa_supplicant *wpa_s, break; } + ssid = *selected_ssid; + if (selected && ssid && ssid->mem_only_psk && !ssid->psk_set && + !ssid->passphrase && !ssid->ext_psk) { + const char *field_name, *txt = NULL; + + wpa_dbg(wpa_s, MSG_DEBUG, + "PSK/passphrase not yet available for the selected network"); + + wpas_notify_network_request(wpa_s, ssid, + WPA_CTRL_REQ_PSK_PASSPHRASE, NULL); + + field_name = wpa_supplicant_ctrl_req_to_string( + WPA_CTRL_REQ_PSK_PASSPHRASE, NULL, &txt); + if (field_name == NULL) + return NULL; + + wpas_send_ctrl_req(wpa_s, ssid, field_name, txt); + + selected = NULL; + } + return selected; } @@ -1266,7 +1286,9 @@ static int wpa_supplicant_need_to_roam(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) { struct wpa_bss *current_bss = NULL; +#ifndef CONFIG_NO_ROAMING int min_diff; +#endif /* CONFIG_NO_ROAMING */ if (wpa_s->reassociate) return 1; /* explicit request to reassociate */ @@ -3146,6 +3168,7 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, union wpa_event_data *data) { struct wpa_supplicant *wpa_s = ctx; + int resched; if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED && event != EVENT_INTERFACE_ENABLED && @@ -3712,6 +3735,7 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, case EVENT_SCHED_SCAN_STOPPED: wpa_s->pno = 0; wpa_s->sched_scanning = 0; + resched = wpa_s->scanning; wpa_supplicant_notify_scanning(wpa_s, 0); if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) @@ -3726,6 +3750,8 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, } else if (wpa_s->pno_sched_pending) { wpa_s->pno_sched_pending = 0; wpas_start_pno(wpa_s); + } else if (resched) { + wpa_supplicant_req_scan(wpa_s, 0, 0); } break; diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c index bb618082..4c71ef4c 100644 --- a/wpa_supplicant/p2p_supplicant.c +++ b/wpa_supplicant/p2p_supplicant.c @@ -5504,18 +5504,26 @@ int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s, (freq > 0 && !freq_included(channels, freq))) freq = 0; } - } else { + } else if (ssid->mode == WPAS_MODE_INFRA) { freq = neg_freq; - if (freq < 0 || - (freq > 0 && !freq_included(channels, freq))) - freq = 0; - } + if (freq <= 0 || !freq_included(channels, freq)) { + struct os_reltime now; + struct wpa_bss *bss = + wpa_bss_get_p2p_dev_addr(wpa_s, ssid->bssid); + + os_get_reltime(&now); + if (bss && + !os_reltime_expired(&now, &bss->last_update, 5) && + freq_included(channels, bss->freq)) + freq = bss->freq; + else + freq = 0; + } - if (ssid->mode == WPAS_MODE_INFRA) return wpas_start_p2p_client(wpa_s, ssid, addr_allocated, freq); - - if (ssid->mode != WPAS_MODE_P2P_GO) + } else { return -1; + } if (wpas_p2p_init_go_params(wpa_s, ¶ms, freq, ht40, vht, channels)) return -1; diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c index 2b40bbf8..5fe46186 100644 --- a/wpa_supplicant/wpa_cli.c +++ b/wpa_supplicant/wpa_cli.c @@ -92,6 +92,7 @@ static DEFINE_DL_LIST(bsses); /* struct cli_txt_entry */ static DEFINE_DL_LIST(p2p_peers); /* struct cli_txt_entry */ static DEFINE_DL_LIST(p2p_groups); /* struct cli_txt_entry */ static DEFINE_DL_LIST(ifnames); /* struct cli_txt_entry */ +static DEFINE_DL_LIST(networks); /* struct cli_txt_entry */ static void print_help(const char *cmd); @@ -99,6 +100,7 @@ static void wpa_cli_mon_receive(int sock, void *eloop_ctx, void *sock_ctx); static void wpa_cli_close_connection(void); static char * wpa_cli_get_default_ifname(void); static char ** wpa_list_cmd_list(void); +static void update_networks(struct wpa_ctrl *ctrl); static void usage(void) @@ -168,11 +170,12 @@ static void cli_txt_list_del_addr(struct dl_list *txt_list, const char *txt) #ifdef CONFIG_P2P -static void cli_txt_list_del_word(struct dl_list *txt_list, const char *txt) +static void cli_txt_list_del_word(struct dl_list *txt_list, const char *txt, + int separator) { const char *end; char *buf; - end = os_strchr(txt, ' '); + end = os_strchr(txt, separator); if (end == NULL) end = txt + os_strlen(txt); buf = dup_binstr(txt, end - txt); @@ -213,14 +216,16 @@ static int cli_txt_list_add_addr(struct dl_list *txt_list, const char *txt) os_snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr)); return cli_txt_list_add(txt_list, buf); } +#endif /* CONFIG_P2P */ -static int cli_txt_list_add_word(struct dl_list *txt_list, const char *txt) +static int cli_txt_list_add_word(struct dl_list *txt_list, const char *txt, + int separator) { const char *end; char *buf; int ret; - end = os_strchr(txt, ' '); + end = os_strchr(txt, separator); if (end == NULL) end = txt + os_strlen(txt); buf = dup_binstr(txt, end - txt); @@ -230,7 +235,6 @@ static int cli_txt_list_add_word(struct dl_list *txt_list, const char *txt) os_free(buf); return ret; } -#endif /* CONFIG_P2P */ static char ** cli_txt_list_array(struct dl_list *txt_list) @@ -1451,14 +1455,18 @@ static int wpa_cli_cmd_disable_network(struct wpa_ctrl *ctrl, int argc, static int wpa_cli_cmd_add_network(struct wpa_ctrl *ctrl, int argc, char *argv[]) { - return wpa_ctrl_command(ctrl, "ADD_NETWORK"); + int res = wpa_ctrl_command(ctrl, "ADD_NETWORK"); + update_networks(ctrl); + return res; } static int wpa_cli_cmd_remove_network(struct wpa_ctrl *ctrl, int argc, char *argv[]) { - return wpa_cli_cmd(ctrl, "REMOVE_NETWORK", 1, argc, argv); + int res = wpa_cli_cmd(ctrl, "REMOVE_NETWORK", 1, argc, argv); + update_networks(ctrl); + return res; } @@ -1519,6 +1527,105 @@ static int wpa_cli_cmd_get_network(struct wpa_ctrl *ctrl, int argc, } +static const char *network_fields[] = { + "ssid", "scan_ssid", "bssid", "bssid_blacklist", + "bssid_whitelist", "psk", "proto", "key_mgmt", + "bg_scan_period", "pairwise", "group", "auth_alg", "scan_freq", + "freq_list", +#ifdef IEEE8021X_EAPOL + "eap", "identity", "anonymous_identity", "password", "ca_cert", + "ca_path", "client_cert", "private_key", "private_key_passwd", + "dh_file", "subject_match", "altsubject_match", + "domain_suffix_match", "domain_match", "ca_cert2", "ca_path2", + "client_cert2", "private_key2", "private_key2_passwd", + "dh_file2", "subject_match2", "altsubject_match2", + "domain_suffix_match2", "domain_match2", "phase1", "phase2", + "pcsc", "pin", "engine_id", "key_id", "cert_id", "ca_cert_id", + "pin2", "engine2_id", "key2_id", "cert2_id", "ca_cert2_id", + "engine", "engine2", "eapol_flags", "sim_num", + "openssl_ciphers", "erp", +#endif /* IEEE8021X_EAPOL */ + "wep_key0", "wep_key1", "wep_key2", "wep_key3", + "wep_tx_keyidx", "priority", +#ifdef IEEE8021X_EAPOL + "eap_workaround", "pac_file", "fragment_size", "ocsp", +#endif /* IEEE8021X_EAPOL */ +#ifdef CONFIG_MESH + "mode", "no_auto_peer", +#else /* CONFIG_MESH */ + "mode", +#endif /* CONFIG_MESH */ + "proactive_key_caching", "disabled", "id_str", +#ifdef CONFIG_IEEE80211W + "ieee80211w", +#endif /* CONFIG_IEEE80211W */ + "peerkey", "mixed_cell", "frequency", "fixed_freq", +#ifdef CONFIG_MESH + "mesh_basic_rates", "dot11MeshMaxRetries", + "dot11MeshRetryTimeout", "dot11MeshConfirmTimeout", + "dot11MeshHoldingTimeout", +#endif /* CONFIG_MESH */ + "wpa_ptk_rekey", "bgscan", "ignore_broadcast_ssid", +#ifdef CONFIG_P2P + "go_p2p_dev_addr", "p2p_client_list", "psk_list", +#endif /* CONFIG_P2P */ +#ifdef CONFIG_HT_OVERRIDES + "disable_ht", "disable_ht40", "disable_sgi", "disable_ldpc", + "ht40_intolerant", "disable_max_amsdu", "ampdu_factor", + "ampdu_density", "ht_mcs", +#endif /* CONFIG_HT_OVERRIDES */ +#ifdef CONFIG_VHT_OVERRIDES + "disable_vht", "vht_capa", "vht_capa_mask", "vht_rx_mcs_nss_1", + "vht_rx_mcs_nss_2", "vht_rx_mcs_nss_3", "vht_rx_mcs_nss_4", + "vht_rx_mcs_nss_5", "vht_rx_mcs_nss_6", "vht_rx_mcs_nss_7", + "vht_rx_mcs_nss_8", "vht_tx_mcs_nss_1", "vht_tx_mcs_nss_2", + "vht_tx_mcs_nss_3", "vht_tx_mcs_nss_4", "vht_tx_mcs_nss_5", + "vht_tx_mcs_nss_6", "vht_tx_mcs_nss_7", "vht_tx_mcs_nss_8", +#endif /* CONFIG_VHT_OVERRIDES */ + "ap_max_inactivity", "dtim_period", "beacon_int", +#ifdef CONFIG_MACSEC + "macsec_policy", +#endif /* CONFIG_MACSEC */ +#ifdef CONFIG_HS20 + "update_identifier", +#endif /* CONFIG_HS20 */ + "mac_addr" +}; + + +static char ** wpa_cli_complete_network(const char *str, int pos) +{ + int arg = get_cmd_arg_num(str, pos); + int i, num_fields = ARRAY_SIZE(network_fields); + char **res = NULL; + + switch (arg) { + case 1: + res = cli_txt_list_array(&networks); + break; + case 2: + res = os_calloc(num_fields + 1, sizeof(char *)); + if (res == NULL) + return NULL; + for (i = 0; i < num_fields; i++) { + res[i] = os_strdup(network_fields[i]); + if (res[i] == NULL) + break; + } + } + return res; +} + + +static char ** wpa_cli_complete_network_id(const char *str, int pos) +{ + int arg = get_cmd_arg_num(str, pos); + if (arg == 1) + return cli_txt_list_array(&networks); + return NULL; +} + + static int wpa_cli_cmd_dup_network(struct wpa_ctrl *ctrl, int argc, char *argv[]) { @@ -1537,6 +1644,31 @@ static int wpa_cli_cmd_dup_network(struct wpa_ctrl *ctrl, int argc, } +static char ** wpa_cli_complete_dup_network(const char *str, int pos) +{ + int arg = get_cmd_arg_num(str, pos); + int i, num_fields = ARRAY_SIZE(network_fields); + char **res = NULL; + + switch (arg) { + case 1: + case 2: + res = cli_txt_list_array(&networks); + break; + case 3: + res = os_calloc(num_fields + 1, sizeof(char *)); + if (res == NULL) + return NULL; + for (i = 0; i < num_fields; i++) { + res[i] = os_strdup(network_fields[i]); + if (res[i] == NULL) + break; + } + } + return res; +} + + static int wpa_cli_cmd_list_creds(struct wpa_ctrl *ctrl, int argc, char *argv[]) { @@ -1711,20 +1843,20 @@ static int wpa_cli_cmd_interface_add(struct wpa_ctrl *ctrl, int argc, printf("Invalid INTERFACE_ADD command: needs at least one " "argument (interface name)\n" "All arguments: ifname confname driver ctrl_interface " - "driver_param bridge_name\n"); + "driver_param bridge_name [create]\n"); return -1; } /* * INTERFACE_ADD <ifname>TAB<confname>TAB<driver>TAB<ctrl_interface>TAB - * <driver_param>TAB<bridge_name> + * <driver_param>TAB<bridge_name>[TAB<create>] */ res = os_snprintf(cmd, sizeof(cmd), - "INTERFACE_ADD %s\t%s\t%s\t%s\t%s\t%s", + "INTERFACE_ADD %s\t%s\t%s\t%s\t%s\t%s\t%s", argv[0], argc > 1 ? argv[1] : "", argc > 2 ? argv[2] : "", argc > 3 ? argv[3] : "", argc > 4 ? argv[4] : "", - argc > 5 ? argv[5] : ""); + argc > 5 ? argv[5] : "", argc > 6 ? argv[6] : ""); if (os_snprintf_error(sizeof(cmd), res)) return -1; cmd[sizeof(cmd) - 1] = '\0'; @@ -2776,29 +2908,33 @@ static struct wpa_cli_cmd wpa_cli_commands[] = { { "list_networks", wpa_cli_cmd_list_networks, NULL, cli_cmd_flag_none, "= list configured networks" }, - { "select_network", wpa_cli_cmd_select_network, NULL, + { "select_network", wpa_cli_cmd_select_network, + wpa_cli_complete_network_id, cli_cmd_flag_none, "<network id> = select a network (disable others)" }, - { "enable_network", wpa_cli_cmd_enable_network, NULL, + { "enable_network", wpa_cli_cmd_enable_network, + wpa_cli_complete_network_id, cli_cmd_flag_none, "<network id> = enable a network" }, - { "disable_network", wpa_cli_cmd_disable_network, NULL, + { "disable_network", wpa_cli_cmd_disable_network, + wpa_cli_complete_network_id, cli_cmd_flag_none, "<network id> = disable a network" }, { "add_network", wpa_cli_cmd_add_network, NULL, cli_cmd_flag_none, "= add a network" }, - { "remove_network", wpa_cli_cmd_remove_network, NULL, + { "remove_network", wpa_cli_cmd_remove_network, + wpa_cli_complete_network_id, cli_cmd_flag_none, "<network id> = remove a network" }, - { "set_network", wpa_cli_cmd_set_network, NULL, + { "set_network", wpa_cli_cmd_set_network, wpa_cli_complete_network, cli_cmd_flag_sensitive, "<network id> <variable> <value> = set network variables (shows\n" " list of variables when run without arguments)" }, - { "get_network", wpa_cli_cmd_get_network, NULL, + { "get_network", wpa_cli_cmd_get_network, wpa_cli_complete_network, cli_cmd_flag_none, "<network id> <variable> = get network variables" }, - { "dup_network", wpa_cli_cmd_dup_network, NULL, + { "dup_network", wpa_cli_cmd_dup_network, wpa_cli_complete_dup_network, cli_cmd_flag_none, "<src network id> <dst network id> <variable> = duplicate network variables" }, @@ -2840,7 +2976,7 @@ static struct wpa_cli_cmd wpa_cli_commands[] = { { "get_capability", wpa_cli_cmd_get_capability, NULL, cli_cmd_flag_none, "<eap/pairwise/group/key_mgmt/proto/auth_alg/channels/freq/modes> " - "= get capabilies" }, + "= get capabilities" }, { "reconfigure", wpa_cli_cmd_reconfigure, NULL, cli_cmd_flag_none, "= force wpa_supplicant to re-read its configuration file" }, @@ -3614,7 +3750,7 @@ static void cli_event(const char *str) s = os_strchr(start, ' '); if (s == NULL) return; - cli_txt_list_add_word(&p2p_groups, s + 1); + cli_txt_list_add_word(&p2p_groups, s + 1, ' '); return; } @@ -3622,7 +3758,7 @@ static void cli_event(const char *str) s = os_strchr(start, ' '); if (s == NULL) return; - cli_txt_list_del_word(&p2p_groups, s + 1); + cli_txt_list_del_word(&p2p_groups, s + 1, ' '); return; } #endif /* CONFIG_P2P */ @@ -3781,7 +3917,11 @@ static void start_edit(void) ps = wpa_ctrl_get_remote_ifname(ctrl_conn); #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */ +#ifdef CONFIG_WPA_CLI_HISTORY_DIR + home = CONFIG_WPA_CLI_HISTORY_DIR; +#else /* CONFIG_WPA_CLI_HISTORY_DIR */ home = getenv("HOME"); +#endif /* CONFIG_WPA_CLI_HISTORY_DIR */ if (home) { const char *fname = ".wpa_cli_history"; int hfile_len = os_strlen(home) + 1 + os_strlen(fname) + 1; @@ -3864,6 +4004,38 @@ static void update_ifnames(struct wpa_ctrl *ctrl) } +static void update_networks(struct wpa_ctrl *ctrl) +{ + char buf[4096]; + size_t len = sizeof(buf); + int ret; + char *cmd = "LIST_NETWORKS"; + char *pos, *end; + int header = 1; + + cli_txt_list_flush(&networks); + + if (ctrl == NULL) + return; + ret = wpa_ctrl_request(ctrl, cmd, os_strlen(cmd), buf, &len, NULL); + if (ret < 0) + return; + buf[len] = '\0'; + + pos = buf; + while (pos) { + end = os_strchr(pos, '\n'); + if (end == NULL) + break; + *end = '\0'; + if (!header) + cli_txt_list_add_word(&networks, pos, '\t'); + header = 0; + pos = end + 1; + } +} + + static void try_connection(void *eloop_ctx, void *timeout_ctx) { if (ctrl_conn) @@ -3884,6 +4056,7 @@ static void try_connection(void *eloop_ctx, void *timeout_ctx) } update_bssid_list(ctrl_conn); + update_networks(ctrl_conn); if (warning_displayed) printf("Connection established.\n"); @@ -3905,6 +4078,7 @@ static void wpa_cli_interactive(void) cli_txt_list_flush(&p2p_groups); cli_txt_list_flush(&bsses); cli_txt_list_flush(&ifnames); + cli_txt_list_flush(&networks); if (edit_started) edit_deinit(hfile, wpa_cli_edit_filter_history_cb); os_free(hfile); diff --git a/wpa_supplicant/wpa_gui-qt4/wpagui.cpp b/wpa_supplicant/wpa_gui-qt4/wpagui.cpp index bc6fa7f4..408e3876 100644 --- a/wpa_supplicant/wpa_gui-qt4/wpagui.cpp +++ b/wpa_supplicant/wpa_gui-qt4/wpagui.cpp @@ -135,6 +135,7 @@ WpaGui::WpaGui(QApplication *_app, QWidget *parent, const char *, Qt::WFlags) monitor_conn = NULL; msgNotifier = NULL; ctrl_iface_dir = strdup("/var/run/wpa_supplicant"); + signalMeterInterval = 0; parse_argv(); @@ -161,6 +162,10 @@ WpaGui::WpaGui(QApplication *_app, QWidget *parent, const char *, Qt::WFlags) timer->setSingleShot(FALSE); timer->start(1000); + signalMeterTimer = new QTimer(this); + signalMeterTimer->setInterval(signalMeterInterval); + connect(signalMeterTimer, SIGNAL(timeout()), SLOT(signalMeterUpdate())); + if (openCtrlConnection(ctrl_iface) < 0) { debug("Failed to open control connection to " "wpa_supplicant."); @@ -234,7 +239,7 @@ void WpaGui::parse_argv() { int c; for (;;) { - c = getopt(qApp->argc(), qApp->argv(), "i:p:tq"); + c = getopt(qApp->argc(), qApp->argv(), "i:m:p:tq"); if (c < 0) break; switch (c) { @@ -242,6 +247,9 @@ void WpaGui::parse_argv() free(ctrl_iface); ctrl_iface = strdup(optarg); break; + case 'm': + signalMeterInterval = atoi(optarg) * 1000; + break; case 'p': free(ctrl_iface_dir); ctrl_iface_dir = strdup(optarg); @@ -496,6 +504,8 @@ void WpaGui::updateStatus() textBssid->clear(); textIpAddress->clear(); updateTrayToolTip(tr("no status information")); + updateTrayIcon(TrayIconOffline); + signalMeterTimer->stop(); #ifdef CONFIG_NATIVE_WINDOWS static bool first = true; @@ -544,6 +554,11 @@ void WpaGui::updateStatus() ssid_updated = true; textSsid->setText(pos); updateTrayToolTip(pos + tr(" (associated)")); + if (!signalMeterInterval) { + /* if signal meter is not enabled show + * full signal strength */ + updateTrayIcon(TrayIconSignalExcellent); + } } else if (strcmp(start, "ip_address") == 0) { ipaddr_updated = true; textIpAddress->setText(pos); @@ -587,6 +602,23 @@ void WpaGui::updateStatus() } else textEncryption->clear(); + if (signalMeterInterval) { + /* + * Handle signal meter service. When network is not associated, + * deactivate timer, otherwise keep it going. Tray icon has to + * be initialized here, because of the initial delay of the + * timer. + */ + if (ssid_updated) { + if (!signalMeterTimer->isActive()) { + updateTrayIcon(TrayIconConnected); + signalMeterTimer->start(); + } + } else { + signalMeterTimer->stop(); + } + } + if (!status_updated) textStatus->clear(); if (!auth_updated) @@ -594,6 +626,7 @@ void WpaGui::updateStatus() if (!ssid_updated) { textSsid->clear(); updateTrayToolTip(tr("(not-associated)")); + updateTrayIcon(TrayIconOffline); } if (!bssid_updated) textBssid->clear(); @@ -828,6 +861,53 @@ void WpaGui::ping() } +void WpaGui::signalMeterUpdate() +{ + char reply[128]; + size_t reply_len = sizeof(reply); + char *rssi; + int rssi_value; + + ctrlRequest("SIGNAL_POLL", reply, &reply_len); + + /* In order to eliminate signal strength fluctuations, try + * to obtain averaged RSSI value in the first place. */ + if ((rssi = strstr(reply, "AVG_RSSI=")) != NULL) + rssi_value = atoi(&rssi[sizeof("AVG_RSSI")]); + else if ((rssi = strstr(reply, "RSSI=")) != NULL) + rssi_value = atoi(&rssi[sizeof("RSSI")]); + else { + debug("Failed to get RSSI value"); + updateTrayIcon(TrayIconSignalNone); + return; + } + + debug("RSSI value: %d", rssi_value); + + /* + * NOTE: The code below assumes, that the unit of the value returned + * by the SIGNAL POLL request is dBm. It might not be true for all + * wpa_supplicant drivers. + */ + + /* + * Calibration is based on "various Internet sources". Nonetheless, + * it seems to be compatible with the Windows 8.1 strength meter - + * tested on Intel Centrino Advanced-N 6235. + */ + if (rssi_value >= -60) + updateTrayIcon(TrayIconSignalExcellent); + else if (rssi_value >= -68) + updateTrayIcon(TrayIconSignalGood); + else if (rssi_value >= -76) + updateTrayIcon(TrayIconSignalOk); + else if (rssi_value >= -84) + updateTrayIcon(TrayIconSignalWeak); + else + updateTrayIcon(TrayIconSignalNone); +} + + static int str_match(const char *a, const char *b) { return strncmp(a, b, strlen(b)) == 0; @@ -1278,10 +1358,7 @@ void WpaGui::createTrayIcon(bool trayOnly) QApplication::setQuitOnLastWindowClosed(false); tray_icon = new QSystemTrayIcon(this); - if (QImageReader::supportedImageFormats().contains(QByteArray("svg"))) - tray_icon->setIcon(QIcon(":/icons/wpa_gui.svg")); - else - tray_icon->setIcon(QIcon(":/icons/wpa_gui.png")); + updateTrayIcon(TrayIconOffline); connect(tray_icon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), @@ -1421,6 +1498,59 @@ void WpaGui::updateTrayToolTip(const QString &msg) } +void WpaGui::updateTrayIcon(TrayIconType type) +{ + if (!tray_icon || currentIconType == type) + return; + + QIcon icon; + QIcon fallback_icon; + + if (QImageReader::supportedImageFormats().contains(QByteArray("svg"))) + fallback_icon = QIcon(":/icons/wpa_gui.svg"); + else + fallback_icon = QIcon(":/icons/wpa_gui.png"); + + switch (type) { + case TrayIconOffline: + icon = QIcon::fromTheme("network-wireless-offline", + fallback_icon); + break; + case TrayIconAcquiring: + icon = QIcon::fromTheme("network-wireless-acquiring", + fallback_icon); + break; + case TrayIconConnected: + icon = QIcon::fromTheme("network-wireless-connected", + fallback_icon); + break; + case TrayIconSignalNone: + icon = QIcon::fromTheme("network-wireless-signal-none", + fallback_icon); + break; + case TrayIconSignalWeak: + icon = QIcon::fromTheme("network-wireless-signal-weak", + fallback_icon); + break; + case TrayIconSignalOk: + icon = QIcon::fromTheme("network-wireless-signal-ok", + fallback_icon); + break; + case TrayIconSignalGood: + icon = QIcon::fromTheme("network-wireless-signal-good", + fallback_icon); + break; + case TrayIconSignalExcellent: + icon = QIcon::fromTheme("network-wireless-signal-excellent", + fallback_icon); + break; + } + + currentIconType = type; + tray_icon->setIcon(icon); +} + + void WpaGui::closeEvent(QCloseEvent *event) { if (eh) { diff --git a/wpa_supplicant/wpa_gui-qt4/wpagui.h b/wpa_supplicant/wpa_gui-qt4/wpagui.h index 026eacb9..c0de67b0 100644 --- a/wpa_supplicant/wpa_gui-qt4/wpagui.h +++ b/wpa_supplicant/wpa_gui-qt4/wpagui.h @@ -22,6 +22,18 @@ class WpaGui : public QMainWindow, public Ui::WpaGui Q_OBJECT public: + + enum TrayIconType { + TrayIconOffline = 0, + TrayIconAcquiring, + TrayIconConnected, + TrayIconSignalNone, + TrayIconSignalWeak, + TrayIconSignalOk, + TrayIconSignalGood, + TrayIconSignalExcellent, + }; + WpaGui(QApplication *app, QWidget *parent = 0, const char *name = 0, Qt::WFlags fl = 0); ~WpaGui(); @@ -49,6 +61,7 @@ public slots: virtual void scan(); virtual void eventHistory(); virtual void ping(); + virtual void signalMeterUpdate(); virtual void processMsg(char *msg); virtual void processCtrlReq(const char *req); virtual void receiveMsgs(); @@ -70,6 +83,7 @@ public slots: virtual void showTrayMessage(QSystemTrayIcon::MessageIcon type, int sec, const QString &msg); virtual void showTrayStatus(); + virtual void updateTrayIcon(TrayIconType type); virtual void updateTrayToolTip(const QString &msg); virtual void wpsDialog(); virtual void peersDialog(); @@ -113,6 +127,7 @@ private: QAction *quitAction; QMenu *tray_menu; QSystemTrayIcon *tray_icon; + TrayIconType currentIconType; QString wpaStateTranslate(char *state); void createTrayIcon(bool); bool ackTrayIcon; @@ -127,6 +142,9 @@ private: void stopWpsRun(bool success); + QTimer *signalMeterTimer; + int signalMeterInterval; + #ifdef CONFIG_NATIVE_WINDOWS QAction *fileStartServiceAction; QAction *fileStopServiceAction; diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index 6f5fbada..2ba9c384 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -731,6 +731,7 @@ void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s, ssid && ssid->id_str ? ssid->id_str : ""); #endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */ wpas_clear_temp_disabled(wpa_s, ssid, 1); + wpa_blacklist_clear(wpa_s); wpa_s->extra_blacklist_count = 0; wpa_s->new_connection = 0; wpa_drv_set_operstate(wpa_s, 1); @@ -1239,7 +1240,12 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s, } if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt)) { - wpa_sm_set_pmk(wpa_s->wpa, ssid->psk, PMK_LEN, NULL); + int psk_set = 0; + + if (ssid->psk_set) { + wpa_sm_set_pmk(wpa_s->wpa, ssid->psk, PMK_LEN, NULL); + psk_set = 1; + } #ifndef CONFIG_NO_PBKDF2 if (bss && ssid->bssid_set && ssid->ssid_len == 0 && ssid->passphrase) { @@ -1249,6 +1255,7 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s, wpa_hexdump_key(MSG_MSGDUMP, "PSK (from passphrase)", psk, PMK_LEN); wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN, NULL); + psk_set = 1; os_memset(psk, 0, sizeof(psk)); } #endif /* CONFIG_NO_PBKDF2 */ @@ -1286,6 +1293,7 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s, "external passphrase)", psk, PMK_LEN); wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN, NULL); + psk_set = 1; os_memset(psk, 0, sizeof(psk)); } else #endif /* CONFIG_NO_PBKDF2 */ @@ -1298,6 +1306,7 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s, return -1; } wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN, NULL); + psk_set = 1; os_memset(psk, 0, sizeof(psk)); } else { wpa_msg(wpa_s, MSG_INFO, "EXT PW: No suitable " @@ -1311,6 +1320,12 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s, ext_password_free(pw); } #endif /* CONFIG_EXT_PASSWORD */ + + if (!psk_set) { + wpa_msg(wpa_s, MSG_INFO, + "No PSK available for association"); + return -1; + } } else wpa_sm_set_pmk_from_pmksa(wpa_s->wpa); @@ -4967,6 +4982,15 @@ int wpa_supplicant_ctrl_iface_ctrl_rsp_handle(struct wpa_supplicant *wpa_s, str_clear_free(eap->external_sim_resp); eap->external_sim_resp = os_strdup(value); break; + case WPA_CTRL_REQ_PSK_PASSPHRASE: + if (wpa_config_set(ssid, "psk", value, 0) < 0) + return -1; + ssid->mem_only_psk = 1; + if (ssid->passphrase) + wpa_config_update_psk(ssid); + if (wpa_s->wpa_state == WPA_SCANNING && !wpa_s->scanning) + wpa_supplicant_req_scan(wpa_s, 0, 0); + break; default: wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown field '%s'", field); return -1; @@ -5014,7 +5038,8 @@ int wpas_network_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) } if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt) && !ssid->psk_set && - (!ssid->passphrase || ssid->ssid_len != 0) && !ssid->ext_psk) + (!ssid->passphrase || ssid->ssid_len != 0) && !ssid->ext_psk && + !ssid->mem_only_psk) return 1; return 0; diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf index 8964b3f7..eb7434a8 100644 --- a/wpa_supplicant/wpa_supplicant.conf +++ b/wpa_supplicant/wpa_supplicant.conf @@ -740,6 +740,11 @@ fast_reauth=1 # startup and reconfiguration time can be optimized by generating the PSK only # only when the passphrase or SSID has actually changed. # +# mem_only_psk: Whether to keep PSK/passphrase only in memory +# 0 = allow psk/passphrase to be stored to the configuration file +# 1 = do not store psk/passphrase to the configuration file +#mem_only_psk=0 +# # eapol_flags: IEEE 802.1X/EAPOL options (bit field) # Dynamic WEP key required for non-WPA mode # bit0 (1): require dynamically generated unicast WEP key @@ -969,7 +974,7 @@ fast_reauth=1 # tls_disable_session_ticket=0 - allow TLS Session Ticket extension to be used # Note: If not set, this is automatically set to 1 for EAP-TLS/PEAP/TTLS # as a workaround for broken authentication server implementations unless -# EAP workarounds are disabled with eap_workarounds=0. +# EAP workarounds are disabled with eap_workaround=0. # For EAP-FAST, this must be set to 0 (or left unconfigured for the # default value to be used automatically). # tls_disable_tlsv1_1=1 - disable use of TLSv1.1 (a workaround for AAA servers diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index 0ec102f1..2d517f1a 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -648,6 +648,7 @@ struct wpa_supplicant { unsigned int eap_expected_failure:1; unsigned int reattach:1; /* reassociation to the same BSS requested */ unsigned int mac_addr_changed:1; + unsigned int added_vif:1; struct os_reltime last_mac_addr_change; int last_mac_addr_style; diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c index 1bb82ba7..48a5d698 100644 --- a/wpa_supplicant/wpas_glue.c +++ b/wpa_supplicant/wpas_glue.c @@ -737,6 +737,8 @@ enum wpa_ctrl_req_type wpa_supplicant_ctrl_req_from_string(const char *field) return WPA_CTRL_REQ_EAP_PASSPHRASE; else if (os_strcmp(field, "SIM") == 0) return WPA_CTRL_REQ_SIM; + else if (os_strcmp(field, "PSK_PASSPHRASE") == 0) + return WPA_CTRL_REQ_PSK_PASSPHRASE; return WPA_CTRL_REQ_UNKNOWN; } @@ -776,6 +778,10 @@ const char * wpa_supplicant_ctrl_req_to_string(enum wpa_ctrl_req_type field, case WPA_CTRL_REQ_SIM: ret = "SIM"; break; + case WPA_CTRL_REQ_PSK_PASSPHRASE: + *txt = "PSK or passphrase"; + ret = "PSK_PASSPHRASE"; + break; default: break; } @@ -789,6 +795,35 @@ const char * wpa_supplicant_ctrl_req_to_string(enum wpa_ctrl_req_type field, return ret; } + +void wpas_send_ctrl_req(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, + const char *field_name, const char *txt) +{ + char *buf; + size_t buflen; + int len; + + buflen = 100 + os_strlen(txt) + ssid->ssid_len; + buf = os_malloc(buflen); + if (buf == NULL) + return; + len = os_snprintf(buf, buflen, "%s-%d:%s needed for SSID ", + field_name, ssid->id, txt); + if (os_snprintf_error(buflen, len)) { + os_free(buf); + return; + } + if (ssid->ssid && buflen > len + ssid->ssid_len) { + os_memcpy(buf + len, ssid->ssid, ssid->ssid_len); + len += ssid->ssid_len; + buf[len] = '\0'; + } + buf[buflen - 1] = '\0'; + wpa_msg(wpa_s, MSG_INFO, WPA_CTRL_REQ "%s", buf); + os_free(buf); +} + + #ifdef IEEE8021X_EAPOL #if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG) static void wpa_supplicant_eap_param_needed(void *ctx, @@ -798,9 +833,6 @@ static void wpa_supplicant_eap_param_needed(void *ctx, struct wpa_supplicant *wpa_s = ctx; struct wpa_ssid *ssid = wpa_s->current_ssid; const char *field_name, *txt = NULL; - char *buf; - size_t buflen; - int len; if (ssid == NULL) return; @@ -817,25 +849,7 @@ static void wpa_supplicant_eap_param_needed(void *ctx, wpas_notify_eap_status(wpa_s, "eap parameter needed", field_name); - buflen = 100 + os_strlen(txt) + ssid->ssid_len; - buf = os_malloc(buflen); - if (buf == NULL) - return; - len = os_snprintf(buf, buflen, - WPA_CTRL_REQ "%s-%d:%s needed for SSID ", - field_name, ssid->id, txt); - if (os_snprintf_error(buflen, len)) { - os_free(buf); - return; - } - if (ssid->ssid && buflen > len + ssid->ssid_len) { - os_memcpy(buf + len, ssid->ssid, ssid->ssid_len); - len += ssid->ssid_len; - buf[len] = '\0'; - } - buf[buflen - 1] = '\0'; - wpa_msg(wpa_s, MSG_INFO, "%s", buf); - os_free(buf); + wpas_send_ctrl_req(wpa_s, ssid, field_name, txt); } #else /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */ #define wpa_supplicant_eap_param_needed NULL diff --git a/wpa_supplicant/wpas_glue.h b/wpa_supplicant/wpas_glue.h index 9808c226..5585e561 100644 --- a/wpa_supplicant/wpas_glue.h +++ b/wpa_supplicant/wpas_glue.h @@ -22,4 +22,7 @@ const char * wpa_supplicant_ctrl_req_to_string(enum wpa_ctrl_req_type field, enum wpa_ctrl_req_type wpa_supplicant_ctrl_req_from_string(const char *field); +void wpas_send_ctrl_req(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, + const char *field_name, const char *txt); + #endif /* WPAS_GLUE_H */ |
