Cumulative patch from commit c41d0840a1ae4d755c525b091a4bf9d740efdb5f
c41d084 nl80211: Allow driver-based roam to change ESS
6ba7eba Add OpenSSL 0.9.8zf patch for EAP-FAST support
1de0710 atheros: Clear WPS appie during deinit
857d942 Extend offloaded ACS QCA vendor command to support VHT
0fd52a6 Remove duplicated wpa_s->conf->interworking check
ad44309 Add Extended Capabilities element to all Probe Request frames
9bd566a Delay AP selection if all networks are temporarily disabled
701f396 Don't optimize scan frequencies if selected network has changed
e9d2805 P2PS: Extend p2p_service_del asp to support 'all' parameter
6dd51ec P2PS: Add P2PS advertisements on ALL_SERVICES ANQP query
c40a891 P2PS: Delete ASP advertisements on wpas_p2p_service_flush
2dc422e P2PS: Update SD indicator value on ASP add/del/update
030a3e1 DFS: Fix range availability check
56ef992 DFS: Consider non-contiguous channels
6ceea4c Restart sched_scan on channel list change
e7a296b Remove unused shared_freq driver op
58e115b Fix hlr_auc_gw build with OpenSSL
5f9c92f nl80211: Fix vendor command handling
55e8f0e Fix CONFIG_EAP_UNAUTH_TLS without CONFIG_EAP_TLS build
9772af6 Interworking: Prevent scan during ANQP fetch and Interworking select
2c50246 Add a AP mode event message for possible PSK/passphrase mismatch
6784168 Remove SChannel support
Change-Id: I21078309f83821d4b685de77c517c0886b3366bd
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/src/ap/acs.c b/src/ap/acs.c
index ae7f6c3..652d020 100644
--- a/src/ap/acs.c
+++ b/src/ap/acs.c
@@ -479,16 +479,10 @@
static int is_in_chanlist(struct hostapd_iface *iface,
struct hostapd_channel_data *chan)
{
- int *entry;
-
- if (!iface->conf->chanlist)
+ if (!iface->conf->acs_ch_list.num)
return 1;
- for (entry = iface->conf->chanlist; *entry != -1; entry++) {
- if (*entry == chan->chan)
- return 1;
- }
- return 0;
+ return freq_range_list_includes(&iface->conf->acs_ch_list, chan->chan);
}
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index 76011dc..cccbfab 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -181,6 +181,8 @@
conf->corrupt_gtk_rekey_mic_probability = 0.0;
#endif /* CONFIG_TESTING_OPTIONS */
+ conf->acs = 0;
+ conf->acs_ch_list.num = 0;
#ifdef CONFIG_ACS
conf->acs_num_scans = 5;
#endif /* CONFIG_ACS */
@@ -579,7 +581,7 @@
os_free(conf->bss);
os_free(conf->supported_rates);
os_free(conf->basic_rates);
- os_free(conf->chanlist);
+ os_free(conf->acs_ch_list.range);
os_free(conf->driver_params);
#ifdef CONFIG_ACS
os_free(conf->acs_chan_bias);
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index 961d2dd..b9d6832 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -568,7 +568,8 @@
int fragm_threshold;
u8 send_probe_response;
u8 channel;
- int *chanlist;
+ u8 acs;
+ struct wpa_freq_range_list acs_ch_list;
enum hostapd_hw_mode hw_mode; /* HOSTAPD_MODE_IEEE80211A, .. */
enum {
LONG_PREAMBLE = 0,
diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
index e16306c..9ee88b4 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -217,6 +217,15 @@
}
+int hostapd_reset_ap_wps_ie(struct hostapd_data *hapd)
+{
+ if (hapd->driver == NULL || hapd->driver->set_ap_wps_ie == NULL)
+ return 0;
+
+ return hapd->driver->set_ap_wps_ie(hapd->drv_priv, NULL, NULL, NULL);
+}
+
+
int hostapd_set_ap_wps_ie(struct hostapd_data *hapd)
{
struct wpabuf *beacon, *proberesp, *assocresp;
@@ -715,13 +724,66 @@
int hostapd_drv_do_acs(struct hostapd_data *hapd)
{
struct drv_acs_params params;
+ int ret, i, acs_ch_list_all = 0;
+ u8 *channels = NULL;
+ unsigned int num_channels = 0;
+ struct hostapd_hw_modes *mode;
if (hapd->driver == NULL || hapd->driver->do_acs == NULL)
return 0;
+
os_memset(¶ms, 0, sizeof(params));
params.hw_mode = hapd->iface->conf->hw_mode;
+
+ /*
+ * If no chanlist config parameter is provided, include all enabled
+ * channels of the selected hw_mode.
+ */
+ if (!hapd->iface->conf->acs_ch_list.num)
+ acs_ch_list_all = 1;
+
+ mode = hapd->iface->current_mode;
+ if (mode == NULL)
+ return -1;
+ channels = os_malloc(mode->num_channels);
+ if (channels == NULL)
+ return -1;
+
+ for (i = 0; i < mode->num_channels; i++) {
+ struct hostapd_channel_data *chan = &mode->channels[i];
+ if (!acs_ch_list_all &&
+ !freq_range_list_includes(&hapd->iface->conf->acs_ch_list,
+ chan->chan))
+ continue;
+ if (!(chan->flag & HOSTAPD_CHAN_DISABLED))
+ channels[num_channels++] = chan->chan;
+ }
+
+ params.ch_list = channels;
+ params.ch_list_len = num_channels;
+
params.ht_enabled = !!(hapd->iface->conf->ieee80211n);
params.ht40_enabled = !!(hapd->iface->conf->ht_capab &
HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET);
- return hapd->driver->do_acs(hapd->drv_priv, ¶ms);
+ params.vht_enabled = !!(hapd->iface->conf->ieee80211ac);
+ params.ch_width = 20;
+ if (hapd->iface->conf->ieee80211n && params.ht40_enabled)
+ params.ch_width = 40;
+
+ /* Note: VHT20 is defined by combination of ht_capab & vht_oper_chwidth
+ */
+ if (hapd->iface->conf->ieee80211ac && params.ht40_enabled) {
+ if (hapd->iface->conf->vht_oper_chwidth == VHT_CHANWIDTH_80MHZ)
+ params.ch_width = 80;
+ else if (hapd->iface->conf->vht_oper_chwidth ==
+ VHT_CHANWIDTH_160MHZ ||
+ hapd->iface->conf->vht_oper_chwidth ==
+ VHT_CHANWIDTH_80P80MHZ)
+ params.ch_width = 160;
+ }
+
+ ret = hapd->driver->do_acs(hapd->drv_priv, ¶ms);
+ os_free(channels);
+
+ return ret;
}
diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
index 5d07e71..82eaf3f 100644
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -24,6 +24,7 @@
void hostapd_free_ap_extra_ies(struct hostapd_data *hapd, struct wpabuf *beacon,
struct wpabuf *proberesp,
struct wpabuf *assocresp);
+int hostapd_reset_ap_wps_ie(struct hostapd_data *hapd);
int hostapd_set_ap_wps_ie(struct hostapd_data *hapd);
int hostapd_set_authorized(struct hostapd_data *hapd,
struct sta_info *sta, int authorized);
diff --git a/src/ap/dfs.c b/src/ap/dfs.c
index da6fd46..715f19b 100644
--- a/src/ap/dfs.c
+++ b/src/ap/dfs.c
@@ -122,6 +122,20 @@
}
+static struct hostapd_channel_data *
+dfs_get_chan_data(struct hostapd_hw_modes *mode, int freq, int first_chan_idx)
+{
+ int i;
+
+ for (i = first_chan_idx; i < mode->num_channels; i++) {
+ if (mode->channels[i].freq == freq)
+ return &mode->channels[i];
+ }
+
+ return NULL;
+}
+
+
static int dfs_chan_range_available(struct hostapd_hw_modes *mode,
int first_chan_idx, int num_chans,
int skip_radar)
@@ -129,15 +143,15 @@
struct hostapd_channel_data *first_chan, *chan;
int i;
- if (first_chan_idx + num_chans >= mode->num_channels)
+ if (first_chan_idx + num_chans > mode->num_channels)
return 0;
first_chan = &mode->channels[first_chan_idx];
for (i = 0; i < num_chans; i++) {
- chan = &mode->channels[first_chan_idx + i];
-
- if (first_chan->freq + i * 20 != chan->freq)
+ chan = dfs_get_chan_data(mode, first_chan->freq + i * 20,
+ first_chan_idx);
+ if (!chan)
return 0;
if (!dfs_channel_available(chan, skip_radar))
@@ -151,16 +165,10 @@
static int is_in_chanlist(struct hostapd_iface *iface,
struct hostapd_channel_data *chan)
{
- int *entry;
-
- if (!iface->conf->chanlist)
+ if (!iface->conf->acs_ch_list.num)
return 1;
- for (entry = iface->conf->chanlist; *entry != -1; entry++) {
- if (*entry == chan->chan)
- return 1;
- }
- return 0;
+ return freq_range_list_includes(&iface->conf->acs_ch_list, chan->chan);
}
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index a0adc67..507053e 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -532,9 +532,8 @@
#ifdef CONFIG_ACS
static void hostapd_acs_channel_selected(struct hostapd_data *hapd,
- u8 pri_channel, u8 sec_channel)
+ struct acs_selected_channels *acs_res)
{
- int channel;
int ret;
if (hapd->iconf->channel) {
@@ -543,29 +542,55 @@
return;
}
- hapd->iface->freq = hostapd_hw_get_freq(hapd, pri_channel);
+ hapd->iface->freq = hostapd_hw_get_freq(hapd, acs_res->pri_channel);
- channel = pri_channel;
- if (!channel) {
+ if (!acs_res->pri_channel) {
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_WARNING,
"driver switched to bad channel");
return;
}
- hapd->iconf->channel = channel;
+ hapd->iconf->channel = acs_res->pri_channel;
+ hapd->iconf->acs = 1;
- if (sec_channel == 0)
+ if (acs_res->sec_channel == 0)
hapd->iconf->secondary_channel = 0;
- else if (sec_channel < pri_channel)
+ else if (acs_res->sec_channel < acs_res->pri_channel)
hapd->iconf->secondary_channel = -1;
- else if (sec_channel > pri_channel)
+ else if (acs_res->sec_channel > acs_res->pri_channel)
hapd->iconf->secondary_channel = 1;
else {
wpa_printf(MSG_ERROR, "Invalid secondary channel!");
return;
}
+ if (hapd->iface->conf->ieee80211ac) {
+ /* set defaults for backwards compatibility */
+ hapd->iconf->vht_oper_centr_freq_seg1_idx = 0;
+ hapd->iconf->vht_oper_centr_freq_seg0_idx = 0;
+ hapd->iconf->vht_oper_chwidth = VHT_CHANWIDTH_USE_HT;
+ if (acs_res->ch_width == 80) {
+ hapd->iconf->vht_oper_centr_freq_seg0_idx =
+ acs_res->vht_seg0_center_ch;
+ hapd->iconf->vht_oper_chwidth = VHT_CHANWIDTH_80MHZ;
+ } else if (acs_res->ch_width == 160) {
+ if (acs_res->vht_seg1_center_ch == 0) {
+ hapd->iconf->vht_oper_centr_freq_seg0_idx =
+ acs_res->vht_seg0_center_ch;
+ hapd->iconf->vht_oper_chwidth =
+ VHT_CHANWIDTH_160MHZ;
+ } else {
+ hapd->iconf->vht_oper_centr_freq_seg0_idx =
+ acs_res->vht_seg0_center_ch;
+ hapd->iconf->vht_oper_centr_freq_seg1_idx =
+ acs_res->vht_seg1_center_ch;
+ hapd->iconf->vht_oper_chwidth =
+ VHT_CHANWIDTH_80P80MHZ;
+ }
+ }
+ }
+
ret = hostapd_acs_completed(hapd->iface, 0);
if (ret) {
wpa_printf(MSG_ERROR,
@@ -1248,9 +1273,8 @@
break;
#ifdef CONFIG_ACS
case EVENT_ACS_CHANNEL_SELECTED:
- hostapd_acs_channel_selected(
- hapd, data->acs_selected_channels.pri_channel,
- data->acs_selected_channels.sec_channel);
+ hostapd_acs_channel_selected(hapd,
+ &data->acs_selected_channels);
break;
#endif /* CONFIG_ACS */
default:
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index 3e4e16b..6cdb6d3 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -179,6 +179,7 @@
hapd = iface->bss[j];
hapd->iconf = newconf;
hapd->iconf->channel = oldconf->channel;
+ hapd->iconf->acs = oldconf->acs;
hapd->iconf->secondary_channel = oldconf->secondary_channel;
hapd->iconf->ieee80211n = oldconf->ieee80211n;
hapd->iconf->ieee80211ac = oldconf->ieee80211ac;
diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c
index 05431d3..96744c4 100644
--- a/src/ap/hw_features.c
+++ b/src/ap/hw_features.c
@@ -510,7 +510,11 @@
return 0;
}
- if ((conf & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET) &&
+ /*
+ * Driver ACS chosen channel may not be HT40 due to internal driver
+ * restrictions.
+ */
+ if (!iface->conf->acs && (conf & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET) &&
!(hw & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)) {
wpa_printf(MSG_ERROR, "Driver does not support configured "
"HT capability [HT40*]");
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index 9c5f609..b83b460 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -67,6 +67,14 @@
}
+static inline void wpa_auth_psk_failure_report(
+ struct wpa_authenticator *wpa_auth, const u8 *addr)
+{
+ if (wpa_auth->cb.psk_failure_report)
+ wpa_auth->cb.psk_failure_report(wpa_auth->cb.ctx, addr);
+}
+
+
static inline void wpa_auth_set_eapol(struct wpa_authenticator *wpa_auth,
const u8 *addr, wpa_eapol_variable var,
int value)
@@ -1985,7 +1993,7 @@
SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
{
struct wpa_ptk PTK;
- int ok = 0;
+ int ok = 0, psk_found = 0;
const u8 *pmk = NULL;
SM_ENTRY_MA(WPA_PTK, PTKCALCNEGOTIATING, wpa_ptk);
@@ -2001,6 +2009,7 @@
sm->p2p_dev_addr, pmk);
if (pmk == NULL)
break;
+ psk_found = 1;
} else
pmk = sm->PMK;
@@ -2020,6 +2029,8 @@
if (!ok) {
wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
"invalid MIC in msg 2/4 of 4-Way Handshake");
+ if (psk_found)
+ wpa_auth_psk_failure_report(sm->wpa_auth, sm->addr);
return;
}
diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h
index 2788e65..11e745e 100644
--- a/src/ap/wpa_auth.h
+++ b/src/ap/wpa_auth.h
@@ -189,6 +189,7 @@
const char *txt);
void (*disconnect)(void *ctx, const u8 *addr, u16 reason);
int (*mic_failure_report)(void *ctx, const u8 *addr);
+ void (*psk_failure_report)(void *ctx, const u8 *addr);
void (*set_eapol)(void *ctx, const u8 *addr, wpa_eapol_variable var,
int value);
int (*get_eapol)(void *ctx, const u8 *addr, wpa_eapol_variable var);
diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c
index 7f83207..d417a72 100644
--- a/src/ap/wpa_auth_glue.c
+++ b/src/ap/wpa_auth_glue.c
@@ -11,6 +11,7 @@
#include "utils/common.h"
#include "common/ieee802_11_defs.h"
#include "common/sae.h"
+#include "common/wpa_ctrl.h"
#include "eapol_auth/eapol_auth_sm.h"
#include "eapol_auth/eapol_auth_sm_i.h"
#include "eap_server/eap.h"
@@ -144,6 +145,14 @@
}
+static void hostapd_wpa_auth_psk_failure_report(void *ctx, const u8 *addr)
+{
+ struct hostapd_data *hapd = ctx;
+ wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_POSSIBLE_PSK_MISMATCH MACSTR,
+ MAC2STR(addr));
+}
+
+
static void hostapd_wpa_auth_set_eapol(void *ctx, const u8 *addr,
wpa_eapol_variable var, int value)
{
@@ -579,6 +588,7 @@
cb.logger = hostapd_wpa_auth_logger;
cb.disconnect = hostapd_wpa_auth_disconnect;
cb.mic_failure_report = hostapd_wpa_auth_mic_failure_report;
+ cb.psk_failure_report = hostapd_wpa_auth_psk_failure_report;
cb.set_eapol = hostapd_wpa_auth_set_eapol;
cb.get_eapol = hostapd_wpa_auth_get_eapol;
cb.get_psk = hostapd_wpa_auth_get_psk;
diff --git a/src/ap/wps_hostapd.c b/src/ap/wps_hostapd.c
index b0e8b0b..7e74829 100644
--- a/src/ap/wps_hostapd.c
+++ b/src/ap/wps_hostapd.c
@@ -856,8 +856,10 @@
wpabuf_free(hapd->wps_probe_resp_ie);
hapd->wps_probe_resp_ie = NULL;
- if (deinit_only)
+ if (deinit_only) {
+ hostapd_reset_ap_wps_ie(hapd);
return;
+ }
hostapd_set_ap_wps_ie(hapd);
}
diff --git a/src/common/hw_features_common.c b/src/common/hw_features_common.c
index 309215e..8d83de6 100644
--- a/src/common/hw_features_common.c
+++ b/src/common/hw_features_common.c
@@ -363,8 +363,6 @@
int vht_oper_chwidth, int center_segment0,
int center_segment1, u32 vht_caps)
{
- int tmp;
-
os_memset(data, 0, sizeof(*data));
data->mode = mode;
data->freq = freq;
@@ -404,13 +402,34 @@
return -1;
if (!sec_channel_offset)
return -1;
- /* primary 40 part must match the HT configuration */
- tmp = (30 + freq - 5000 - center_segment0 * 5) / 20;
- tmp /= 2;
- if (data->center_freq1 != 5000 +
- center_segment0 * 5 - 20 + 40 * tmp)
- return -1;
- data->center_freq1 = 5000 + center_segment0 * 5;
+ if (!center_segment0) {
+ if (channel <= 48)
+ center_segment0 = 42;
+ else if (channel <= 64)
+ center_segment0 = 58;
+ else if (channel <= 112)
+ center_segment0 = 106;
+ else if (channel <= 128)
+ center_segment0 = 122;
+ else if (channel <= 144)
+ center_segment0 = 138;
+ else if (channel <= 161)
+ center_segment0 = 155;
+ data->center_freq1 = 5000 + center_segment0 * 5;
+ } else {
+ /*
+ * Note: HT/VHT config and params are coupled. Check if
+ * HT40 channel band is in VHT80 Pri channel band
+ * configuration.
+ */
+ if (center_segment0 == channel + 6 ||
+ center_segment0 == channel + 2 ||
+ center_segment0 == channel - 2 ||
+ center_segment0 == channel - 6)
+ data->center_freq1 = 5000 + center_segment0 * 5;
+ else
+ return -1;
+ }
break;
case VHT_CHANWIDTH_160MHZ:
data->bandwidth = 160;
@@ -424,13 +443,21 @@
return -1;
if (!sec_channel_offset)
return -1;
- /* primary 40 part must match the HT configuration */
- tmp = (70 + freq - 5000 - center_segment0 * 5) / 20;
- tmp /= 2;
- if (data->center_freq1 != 5000 +
- center_segment0 * 5 - 60 + 40 * tmp)
+ /*
+ * Note: HT/VHT config and params are coupled. Check if
+ * HT40 channel band is in VHT160 channel band configuration.
+ */
+ if (center_segment0 == channel + 14 ||
+ center_segment0 == channel + 10 ||
+ center_segment0 == channel + 6 ||
+ center_segment0 == channel + 2 ||
+ center_segment0 == channel - 2 ||
+ center_segment0 == channel - 6 ||
+ center_segment0 == channel - 10 ||
+ center_segment0 == channel - 14)
+ data->center_freq1 = 5000 + center_segment0 * 5;
+ else
return -1;
- data->center_freq1 = 5000 + center_segment0 * 5;
break;
}
diff --git a/src/common/qca-vendor.h b/src/common/qca-vendor.h
index 2117ee7..5ff6817 100644
--- a/src/common/qca-vendor.h
+++ b/src/common/qca-vendor.h
@@ -195,6 +195,11 @@
QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE,
QCA_WLAN_VENDOR_ATTR_ACS_HT_ENABLED,
QCA_WLAN_VENDOR_ATTR_ACS_HT40_ENABLED,
+ QCA_WLAN_VENDOR_ATTR_ACS_VHT_ENABLED,
+ QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH,
+ QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST,
+ QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL,
+ QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_CHANNEL,
/* keep last */
QCA_WLAN_VENDOR_ATTR_ACS_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_ACS_MAX =
diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h
index 1d19fc5..e3a816f 100644
--- a/src/common/wpa_ctrl.h
+++ b/src/common/wpa_ctrl.h
@@ -227,6 +227,7 @@
#define WPS_EVENT_AP_PIN_DISABLED "WPS-AP-PIN-DISABLED "
#define AP_STA_CONNECTED "AP-STA-CONNECTED "
#define AP_STA_DISCONNECTED "AP-STA-DISCONNECTED "
+#define AP_STA_POSSIBLE_PSK_MISMATCH "AP-STA-POSSIBLE-PSK-MISMATCH "
#define AP_REJECTED_MAX_STA "AP-REJECTED-MAX-STA "
#define AP_REJECTED_BLOCKED_STA "AP-REJECTED-BLOCKED-STA "
diff --git a/src/crypto/crypto_cryptoapi.c b/src/crypto/crypto_cryptoapi.c
deleted file mode 100644
index 55a069b..0000000
--- a/src/crypto/crypto_cryptoapi.c
+++ /dev/null
@@ -1,783 +0,0 @@
-/*
- * Crypto wrapper for Microsoft CryptoAPI
- * Copyright (c) 2005-2009, Jouni Malinen <j@w1.fi>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#include "includes.h"
-#include <windows.h>
-#include <wincrypt.h>
-
-#include "common.h"
-#include "crypto.h"
-
-#ifndef MS_ENH_RSA_AES_PROV
-#ifdef UNICODE
-#define MS_ENH_RSA_AES_PROV \
-L"Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)"
-#else
-#define MS_ENH_RSA_AES_PROV \
-"Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)"
-#endif
-#endif /* MS_ENH_RSA_AES_PROV */
-
-#ifndef CALG_HMAC
-#define CALG_HMAC (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_HMAC)
-#endif
-
-#ifdef __MINGW32_VERSION
-/*
- * MinGW does not yet include all the needed definitions for CryptoAPI, so
- * define here whatever extra is needed.
- */
-
-static BOOL WINAPI
-(*CryptImportPublicKeyInfo)(HCRYPTPROV hCryptProv, DWORD dwCertEncodingType,
- PCERT_PUBLIC_KEY_INFO pInfo, HCRYPTKEY *phKey)
-= NULL; /* to be loaded from crypt32.dll */
-
-
-static int mingw_load_crypto_func(void)
-{
- HINSTANCE dll;
-
- /* MinGW does not yet have full CryptoAPI support, so load the needed
- * function here. */
-
- if (CryptImportPublicKeyInfo)
- return 0;
-
- dll = LoadLibrary("crypt32");
- if (dll == NULL) {
- wpa_printf(MSG_DEBUG, "CryptoAPI: Could not load crypt32 "
- "library");
- return -1;
- }
-
- CryptImportPublicKeyInfo = GetProcAddress(
- dll, "CryptImportPublicKeyInfo");
- if (CryptImportPublicKeyInfo == NULL) {
- wpa_printf(MSG_DEBUG, "CryptoAPI: Could not get "
- "CryptImportPublicKeyInfo() address from "
- "crypt32 library");
- return -1;
- }
-
- return 0;
-}
-
-#else /* __MINGW32_VERSION */
-
-static int mingw_load_crypto_func(void)
-{
- return 0;
-}
-
-#endif /* __MINGW32_VERSION */
-
-
-static void cryptoapi_report_error(const char *msg)
-{
- char *s, *pos;
- DWORD err = GetLastError();
-
- if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
- FORMAT_MESSAGE_FROM_SYSTEM,
- NULL, err, 0, (LPTSTR) &s, 0, NULL) == 0) {
- wpa_printf(MSG_DEBUG, "CryptoAPI: %s: %d", msg, (int) err);
- }
-
- pos = s;
- while (*pos) {
- if (*pos == '\n' || *pos == '\r') {
- *pos = '\0';
- break;
- }
- pos++;
- }
-
- wpa_printf(MSG_DEBUG, "CryptoAPI: %s: %d: (%s)", msg, (int) err, s);
- LocalFree(s);
-}
-
-
-int cryptoapi_hash_vector(ALG_ID alg, size_t hash_len, size_t num_elem,
- const u8 *addr[], const size_t *len, u8 *mac)
-{
- HCRYPTPROV prov;
- HCRYPTHASH hash;
- size_t i;
- DWORD hlen;
- int ret = 0;
-
- if (!CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL, 0)) {
- cryptoapi_report_error("CryptAcquireContext");
- return -1;
- }
-
- if (!CryptCreateHash(prov, alg, 0, 0, &hash)) {
- cryptoapi_report_error("CryptCreateHash");
- CryptReleaseContext(prov, 0);
- return -1;
- }
-
- for (i = 0; i < num_elem; i++) {
- if (!CryptHashData(hash, (BYTE *) addr[i], len[i], 0)) {
- cryptoapi_report_error("CryptHashData");
- CryptDestroyHash(hash);
- CryptReleaseContext(prov, 0);
- }
- }
-
- hlen = hash_len;
- if (!CryptGetHashParam(hash, HP_HASHVAL, mac, &hlen, 0)) {
- cryptoapi_report_error("CryptGetHashParam");
- ret = -1;
- }
-
- CryptDestroyHash(hash);
- CryptReleaseContext(prov, 0);
-
- return ret;
-}
-
-
-int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
-{
- return cryptoapi_hash_vector(CALG_MD4, 16, num_elem, addr, len, mac);
-}
-
-
-void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
-{
- u8 next, tmp;
- int i;
- HCRYPTPROV prov;
- HCRYPTKEY ckey;
- DWORD dlen;
- struct {
- BLOBHEADER hdr;
- DWORD len;
- BYTE key[8];
- } key_blob;
- DWORD mode = CRYPT_MODE_ECB;
-
- key_blob.hdr.bType = PLAINTEXTKEYBLOB;
- key_blob.hdr.bVersion = CUR_BLOB_VERSION;
- key_blob.hdr.reserved = 0;
- key_blob.hdr.aiKeyAlg = CALG_DES;
- key_blob.len = 8;
-
- /* Add parity bits to the key */
- next = 0;
- for (i = 0; i < 7; i++) {
- tmp = key[i];
- key_blob.key[i] = (tmp >> i) | next | 1;
- next = tmp << (7 - i);
- }
- key_blob.key[i] = next | 1;
-
- if (!CryptAcquireContext(&prov, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL,
- CRYPT_VERIFYCONTEXT)) {
- wpa_printf(MSG_DEBUG, "CryptoAPI: CryptAcquireContext failed: "
- "%d", (int) GetLastError());
- return;
- }
-
- if (!CryptImportKey(prov, (BYTE *) &key_blob, sizeof(key_blob), 0, 0,
- &ckey)) {
- wpa_printf(MSG_DEBUG, "CryptoAPI: CryptImportKey failed: %d",
- (int) GetLastError());
- CryptReleaseContext(prov, 0);
- return;
- }
-
- if (!CryptSetKeyParam(ckey, KP_MODE, (BYTE *) &mode, 0)) {
- wpa_printf(MSG_DEBUG, "CryptoAPI: CryptSetKeyParam(KP_MODE) "
- "failed: %d", (int) GetLastError());
- CryptDestroyKey(ckey);
- CryptReleaseContext(prov, 0);
- return;
- }
-
- os_memcpy(cypher, clear, 8);
- dlen = 8;
- if (!CryptEncrypt(ckey, 0, FALSE, 0, cypher, &dlen, 8)) {
- wpa_printf(MSG_DEBUG, "CryptoAPI: CryptEncrypt failed: %d",
- (int) GetLastError());
- os_memset(cypher, 0, 8);
- }
-
- CryptDestroyKey(ckey);
- CryptReleaseContext(prov, 0);
-}
-
-
-int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
-{
- return cryptoapi_hash_vector(CALG_MD5, 16, num_elem, addr, len, mac);
-}
-
-
-int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
-{
- return cryptoapi_hash_vector(CALG_SHA, 20, num_elem, addr, len, mac);
-}
-
-
-struct aes_context {
- HCRYPTPROV prov;
- HCRYPTKEY ckey;
-};
-
-
-void * aes_encrypt_init(const u8 *key, size_t len)
-{
- struct aes_context *akey;
- struct {
- BLOBHEADER hdr;
- DWORD len;
- BYTE key[16];
- } key_blob;
- DWORD mode = CRYPT_MODE_ECB;
-
- if (len != 16)
- return NULL;
-
- key_blob.hdr.bType = PLAINTEXTKEYBLOB;
- key_blob.hdr.bVersion = CUR_BLOB_VERSION;
- key_blob.hdr.reserved = 0;
- key_blob.hdr.aiKeyAlg = CALG_AES_128;
- key_blob.len = len;
- os_memcpy(key_blob.key, key, len);
-
- akey = os_zalloc(sizeof(*akey));
- if (akey == NULL)
- return NULL;
-
- if (!CryptAcquireContext(&akey->prov, NULL,
- MS_ENH_RSA_AES_PROV, PROV_RSA_AES,
- CRYPT_VERIFYCONTEXT)) {
- wpa_printf(MSG_DEBUG, "CryptoAPI: CryptAcquireContext failed: "
- "%d", (int) GetLastError());
- os_free(akey);
- return NULL;
- }
-
- if (!CryptImportKey(akey->prov, (BYTE *) &key_blob, sizeof(key_blob),
- 0, 0, &akey->ckey)) {
- wpa_printf(MSG_DEBUG, "CryptoAPI: CryptImportKey failed: %d",
- (int) GetLastError());
- CryptReleaseContext(akey->prov, 0);
- os_free(akey);
- return NULL;
- }
-
- if (!CryptSetKeyParam(akey->ckey, KP_MODE, (BYTE *) &mode, 0)) {
- wpa_printf(MSG_DEBUG, "CryptoAPI: CryptSetKeyParam(KP_MODE) "
- "failed: %d", (int) GetLastError());
- CryptDestroyKey(akey->ckey);
- CryptReleaseContext(akey->prov, 0);
- os_free(akey);
- return NULL;
- }
-
- return akey;
-}
-
-
-void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
-{
- struct aes_context *akey = ctx;
- DWORD dlen;
-
- os_memcpy(crypt, plain, 16);
- dlen = 16;
- if (!CryptEncrypt(akey->ckey, 0, FALSE, 0, crypt, &dlen, 16)) {
- wpa_printf(MSG_DEBUG, "CryptoAPI: CryptEncrypt failed: %d",
- (int) GetLastError());
- os_memset(crypt, 0, 16);
- }
-}
-
-
-void aes_encrypt_deinit(void *ctx)
-{
- struct aes_context *akey = ctx;
- if (akey) {
- CryptDestroyKey(akey->ckey);
- CryptReleaseContext(akey->prov, 0);
- os_free(akey);
- }
-}
-
-
-void * aes_decrypt_init(const u8 *key, size_t len)
-{
- return aes_encrypt_init(key, len);
-}
-
-
-void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
-{
- struct aes_context *akey = ctx;
- DWORD dlen;
-
- os_memcpy(plain, crypt, 16);
- dlen = 16;
-
- if (!CryptDecrypt(akey->ckey, 0, FALSE, 0, plain, &dlen)) {
- wpa_printf(MSG_DEBUG, "CryptoAPI: CryptDecrypt failed: %d",
- (int) GetLastError());
- }
-}
-
-
-void aes_decrypt_deinit(void *ctx)
-{
- aes_encrypt_deinit(ctx);
-}
-
-
-struct crypto_hash {
- enum crypto_hash_alg alg;
- int error;
- HCRYPTPROV prov;
- HCRYPTHASH hash;
- HCRYPTKEY key;
-};
-
-struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
- size_t key_len)
-{
- struct crypto_hash *ctx;
- ALG_ID calg;
- struct {
- BLOBHEADER hdr;
- DWORD len;
- BYTE key[32];
- } key_blob;
-
- os_memset(&key_blob, 0, sizeof(key_blob));
- switch (alg) {
- case CRYPTO_HASH_ALG_MD5:
- calg = CALG_MD5;
- break;
- case CRYPTO_HASH_ALG_SHA1:
- calg = CALG_SHA;
- break;
- case CRYPTO_HASH_ALG_HMAC_MD5:
- case CRYPTO_HASH_ALG_HMAC_SHA1:
- calg = CALG_HMAC;
- key_blob.hdr.bType = PLAINTEXTKEYBLOB;
- key_blob.hdr.bVersion = CUR_BLOB_VERSION;
- key_blob.hdr.reserved = 0;
- /*
- * Note: RC2 is not really used, but that can be used to
- * import HMAC keys of up to 16 byte long.
- * CRYPT_IPSEC_HMAC_KEY flag for CryptImportKey() is needed to
- * be able to import longer keys (HMAC-SHA1 uses 20-byte key).
- */
- key_blob.hdr.aiKeyAlg = CALG_RC2;
- key_blob.len = key_len;
- if (key_len > sizeof(key_blob.key))
- return NULL;
- os_memcpy(key_blob.key, key, key_len);
- break;
- default:
- return NULL;
- }
-
- ctx = os_zalloc(sizeof(*ctx));
- if (ctx == NULL)
- return NULL;
-
- ctx->alg = alg;
-
- if (!CryptAcquireContext(&ctx->prov, NULL, NULL, PROV_RSA_FULL, 0)) {
- cryptoapi_report_error("CryptAcquireContext");
- os_free(ctx);
- return NULL;
- }
-
- if (calg == CALG_HMAC) {
-#ifndef CRYPT_IPSEC_HMAC_KEY
-#define CRYPT_IPSEC_HMAC_KEY 0x00000100
-#endif
- if (!CryptImportKey(ctx->prov, (BYTE *) &key_blob,
- sizeof(key_blob), 0, CRYPT_IPSEC_HMAC_KEY,
- &ctx->key)) {
- cryptoapi_report_error("CryptImportKey");
- CryptReleaseContext(ctx->prov, 0);
- os_free(ctx);
- return NULL;
- }
- }
-
- if (!CryptCreateHash(ctx->prov, calg, ctx->key, 0, &ctx->hash)) {
- cryptoapi_report_error("CryptCreateHash");
- CryptReleaseContext(ctx->prov, 0);
- os_free(ctx);
- return NULL;
- }
-
- if (calg == CALG_HMAC) {
- HMAC_INFO info;
- os_memset(&info, 0, sizeof(info));
- switch (alg) {
- case CRYPTO_HASH_ALG_HMAC_MD5:
- info.HashAlgid = CALG_MD5;
- break;
- case CRYPTO_HASH_ALG_HMAC_SHA1:
- info.HashAlgid = CALG_SHA;
- break;
- default:
- /* unreachable */
- break;
- }
-
- if (!CryptSetHashParam(ctx->hash, HP_HMAC_INFO, (BYTE *) &info,
- 0)) {
- cryptoapi_report_error("CryptSetHashParam");
- CryptDestroyHash(ctx->hash);
- CryptReleaseContext(ctx->prov, 0);
- os_free(ctx);
- return NULL;
- }
- }
-
- return ctx;
-}
-
-
-void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len)
-{
- if (ctx == NULL || ctx->error)
- return;
-
- if (!CryptHashData(ctx->hash, (BYTE *) data, len, 0)) {
- cryptoapi_report_error("CryptHashData");
- ctx->error = 1;
- }
-}
-
-
-int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len)
-{
- int ret = 0;
- DWORD hlen;
-
- if (ctx == NULL)
- return -2;
-
- if (mac == NULL || len == NULL)
- goto done;
-
- if (ctx->error) {
- ret = -2;
- goto done;
- }
-
- hlen = *len;
- if (!CryptGetHashParam(ctx->hash, HP_HASHVAL, mac, &hlen, 0)) {
- cryptoapi_report_error("CryptGetHashParam");
- ret = -2;
- }
- *len = hlen;
-
-done:
- if (ctx->alg == CRYPTO_HASH_ALG_HMAC_SHA1 ||
- ctx->alg == CRYPTO_HASH_ALG_HMAC_MD5)
- CryptDestroyKey(ctx->key);
-
- os_free(ctx);
-
- return ret;
-}
-
-
-struct crypto_cipher {
- HCRYPTPROV prov;
- HCRYPTKEY key;
-};
-
-
-struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
- const u8 *iv, const u8 *key,
- size_t key_len)
-{
- struct crypto_cipher *ctx;
- struct {
- BLOBHEADER hdr;
- DWORD len;
- BYTE key[32];
- } key_blob;
- DWORD mode = CRYPT_MODE_CBC;
-
- key_blob.hdr.bType = PLAINTEXTKEYBLOB;
- key_blob.hdr.bVersion = CUR_BLOB_VERSION;
- key_blob.hdr.reserved = 0;
- key_blob.len = key_len;
- if (key_len > sizeof(key_blob.key))
- return NULL;
- os_memcpy(key_blob.key, key, key_len);
-
- switch (alg) {
- case CRYPTO_CIPHER_ALG_AES:
- if (key_len == 32)
- key_blob.hdr.aiKeyAlg = CALG_AES_256;
- else if (key_len == 24)
- key_blob.hdr.aiKeyAlg = CALG_AES_192;
- else
- key_blob.hdr.aiKeyAlg = CALG_AES_128;
- break;
- case CRYPTO_CIPHER_ALG_3DES:
- key_blob.hdr.aiKeyAlg = CALG_3DES;
- break;
- case CRYPTO_CIPHER_ALG_DES:
- key_blob.hdr.aiKeyAlg = CALG_DES;
- break;
- case CRYPTO_CIPHER_ALG_RC2:
- key_blob.hdr.aiKeyAlg = CALG_RC2;
- break;
- case CRYPTO_CIPHER_ALG_RC4:
- key_blob.hdr.aiKeyAlg = CALG_RC4;
- break;
- default:
- return NULL;
- }
-
- ctx = os_zalloc(sizeof(*ctx));
- if (ctx == NULL)
- return NULL;
-
- if (!CryptAcquireContext(&ctx->prov, NULL, MS_ENH_RSA_AES_PROV,
- PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) {
- cryptoapi_report_error("CryptAcquireContext");
- goto fail1;
- }
-
- if (!CryptImportKey(ctx->prov, (BYTE *) &key_blob,
- sizeof(key_blob), 0, 0, &ctx->key)) {
- cryptoapi_report_error("CryptImportKey");
- goto fail2;
- }
-
- if (!CryptSetKeyParam(ctx->key, KP_MODE, (BYTE *) &mode, 0)) {
- cryptoapi_report_error("CryptSetKeyParam(KP_MODE)");
- goto fail3;
- }
-
- if (iv && !CryptSetKeyParam(ctx->key, KP_IV, (BYTE *) iv, 0)) {
- cryptoapi_report_error("CryptSetKeyParam(KP_IV)");
- goto fail3;
- }
-
- return ctx;
-
-fail3:
- CryptDestroyKey(ctx->key);
-fail2:
- CryptReleaseContext(ctx->prov, 0);
-fail1:
- os_free(ctx);
- return NULL;
-}
-
-
-int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain,
- u8 *crypt, size_t len)
-{
- DWORD dlen;
-
- os_memcpy(crypt, plain, len);
- dlen = len;
- if (!CryptEncrypt(ctx->key, 0, FALSE, 0, crypt, &dlen, len)) {
- cryptoapi_report_error("CryptEncrypt");
- os_memset(crypt, 0, len);
- return -1;
- }
-
- return 0;
-}
-
-
-int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt,
- u8 *plain, size_t len)
-{
- DWORD dlen;
-
- os_memcpy(plain, crypt, len);
- dlen = len;
- if (!CryptDecrypt(ctx->key, 0, FALSE, 0, plain, &dlen)) {
- cryptoapi_report_error("CryptDecrypt");
- return -1;
- }
-
- return 0;
-}
-
-
-void crypto_cipher_deinit(struct crypto_cipher *ctx)
-{
- CryptDestroyKey(ctx->key);
- CryptReleaseContext(ctx->prov, 0);
- os_free(ctx);
-}
-
-
-struct crypto_public_key {
- HCRYPTPROV prov;
- HCRYPTKEY rsa;
-};
-
-struct crypto_private_key {
- HCRYPTPROV prov;
- HCRYPTKEY rsa;
-};
-
-
-struct crypto_public_key * crypto_public_key_import(const u8 *key, size_t len)
-{
- /* Use crypto_public_key_from_cert() instead. */
- return NULL;
-}
-
-
-struct crypto_private_key * crypto_private_key_import(const u8 *key,
- size_t len,
- const char *passwd)
-{
- /* TODO */
- return NULL;
-}
-
-
-struct crypto_public_key * crypto_public_key_from_cert(const u8 *buf,
- size_t len)
-{
- struct crypto_public_key *pk;
- PCCERT_CONTEXT cc;
-
- pk = os_zalloc(sizeof(*pk));
- if (pk == NULL)
- return NULL;
-
- cc = CertCreateCertificateContext(X509_ASN_ENCODING |
- PKCS_7_ASN_ENCODING, buf, len);
- if (!cc) {
- cryptoapi_report_error("CryptCreateCertificateContext");
- os_free(pk);
- return NULL;
- }
-
- if (!CryptAcquireContext(&pk->prov, NULL, MS_DEF_PROV, PROV_RSA_FULL,
- 0)) {
- cryptoapi_report_error("CryptAcquireContext");
- os_free(pk);
- CertFreeCertificateContext(cc);
- return NULL;
- }
-
- if (!CryptImportPublicKeyInfo(pk->prov, X509_ASN_ENCODING |
- PKCS_7_ASN_ENCODING,
- &cc->pCertInfo->SubjectPublicKeyInfo,
- &pk->rsa)) {
- cryptoapi_report_error("CryptImportPublicKeyInfo");
- CryptReleaseContext(pk->prov, 0);
- os_free(pk);
- CertFreeCertificateContext(cc);
- return NULL;
- }
-
- CertFreeCertificateContext(cc);
-
- return pk;
-}
-
-
-int crypto_public_key_encrypt_pkcs1_v15(struct crypto_public_key *key,
- const u8 *in, size_t inlen,
- u8 *out, size_t *outlen)
-{
- DWORD clen;
- u8 *tmp;
- size_t i;
-
- if (*outlen < inlen)
- return -1;
- tmp = malloc(*outlen);
- if (tmp == NULL)
- return -1;
-
- os_memcpy(tmp, in, inlen);
- clen = inlen;
- if (!CryptEncrypt(key->rsa, 0, TRUE, 0, tmp, &clen, *outlen)) {
- wpa_printf(MSG_DEBUG, "CryptoAPI: Failed to encrypt using "
- "public key: %d", (int) GetLastError());
- os_free(tmp);
- return -1;
- }
-
- *outlen = clen;
-
- /* Reverse the output */
- for (i = 0; i < *outlen; i++)
- out[i] = tmp[*outlen - 1 - i];
-
- os_free(tmp);
-
- return 0;
-}
-
-
-int crypto_private_key_sign_pkcs1(struct crypto_private_key *key,
- const u8 *in, size_t inlen,
- u8 *out, size_t *outlen)
-{
- /* TODO */
- return -1;
-}
-
-
-void crypto_public_key_free(struct crypto_public_key *key)
-{
- if (key) {
- CryptDestroyKey(key->rsa);
- CryptReleaseContext(key->prov, 0);
- os_free(key);
- }
-}
-
-
-void crypto_private_key_free(struct crypto_private_key *key)
-{
- if (key) {
- CryptDestroyKey(key->rsa);
- CryptReleaseContext(key->prov, 0);
- os_free(key);
- }
-}
-
-
-int crypto_global_init(void)
-{
- return mingw_load_crypto_func();
-}
-
-
-void crypto_global_deinit(void)
-{
-}
-
-
-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,
- u8 *result, size_t *result_len)
-{
- /* TODO */
- return -1;
-}
diff --git a/src/crypto/tls_schannel.c b/src/crypto/tls_schannel.c
deleted file mode 100644
index 31a2c94..0000000
--- a/src/crypto/tls_schannel.c
+++ /dev/null
@@ -1,763 +0,0 @@
-/*
- * SSL/TLS interface functions for Microsoft Schannel
- * Copyright (c) 2005-2009, Jouni Malinen <j@w1.fi>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-/*
- * FIX: Go through all SSPI functions and verify what needs to be freed
- * FIX: session resumption
- * TODO: add support for server cert chain validation
- * TODO: add support for CA cert validation
- * TODO: add support for EAP-TLS (client cert/key conf)
- */
-
-#include "includes.h"
-#include <windows.h>
-#include <wincrypt.h>
-#include <schannel.h>
-#define SECURITY_WIN32
-#include <security.h>
-#include <sspi.h>
-
-#include "common.h"
-#include "tls.h"
-
-
-struct tls_global {
- HMODULE hsecurity;
- PSecurityFunctionTable sspi;
- HCERTSTORE my_cert_store;
-};
-
-struct tls_connection {
- int established, start;
- int failed, read_alerts, write_alerts;
-
- SCHANNEL_CRED schannel_cred;
- CredHandle creds;
- CtxtHandle context;
-
- u8 eap_tls_prf[128];
- int eap_tls_prf_set;
-};
-
-
-static int schannel_load_lib(struct tls_global *global)
-{
- INIT_SECURITY_INTERFACE pInitSecurityInterface;
-
- global->hsecurity = LoadLibrary(TEXT("Secur32.dll"));
- if (global->hsecurity == NULL) {
- wpa_printf(MSG_ERROR, "%s: Could not load Secur32.dll - 0x%x",
- __func__, (unsigned int) GetLastError());
- return -1;
- }
-
- pInitSecurityInterface = (INIT_SECURITY_INTERFACE) GetProcAddress(
- global->hsecurity, "InitSecurityInterfaceA");
- if (pInitSecurityInterface == NULL) {
- wpa_printf(MSG_ERROR, "%s: Could not find "
- "InitSecurityInterfaceA from Secur32.dll",
- __func__);
- FreeLibrary(global->hsecurity);
- global->hsecurity = NULL;
- return -1;
- }
-
- global->sspi = pInitSecurityInterface();
- if (global->sspi == NULL) {
- wpa_printf(MSG_ERROR, "%s: Could not read security "
- "interface - 0x%x",
- __func__, (unsigned int) GetLastError());
- FreeLibrary(global->hsecurity);
- global->hsecurity = NULL;
- return -1;
- }
-
- return 0;
-}
-
-
-void * tls_init(const struct tls_config *conf)
-{
- struct tls_global *global;
-
- global = os_zalloc(sizeof(*global));
- if (global == NULL)
- return NULL;
- if (schannel_load_lib(global)) {
- os_free(global);
- return NULL;
- }
- return global;
-}
-
-
-void tls_deinit(void *ssl_ctx)
-{
- struct tls_global *global = ssl_ctx;
-
- if (global->my_cert_store)
- CertCloseStore(global->my_cert_store, 0);
- FreeLibrary(global->hsecurity);
- os_free(global);
-}
-
-
-int tls_get_errors(void *ssl_ctx)
-{
- return 0;
-}
-
-
-struct tls_connection * tls_connection_init(void *ssl_ctx)
-{
- struct tls_connection *conn;
-
- conn = os_zalloc(sizeof(*conn));
- if (conn == NULL)
- return NULL;
- conn->start = 1;
-
- return conn;
-}
-
-
-void tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn)
-{
- if (conn == NULL)
- return;
-
- os_free(conn);
-}
-
-
-int tls_connection_established(void *ssl_ctx, struct tls_connection *conn)
-{
- return conn ? conn->established : 0;
-}
-
-
-int tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn)
-{
- struct tls_global *global = ssl_ctx;
- if (conn == NULL)
- return -1;
-
- conn->eap_tls_prf_set = 0;
- conn->established = conn->failed = 0;
- conn->read_alerts = conn->write_alerts = 0;
- global->sspi->DeleteSecurityContext(&conn->context);
- /* FIX: what else needs to be reseted? */
-
- return 0;
-}
-
-
-int tls_global_set_params(void *tls_ctx,
- const struct tls_connection_params *params)
-{
- return -1;
-}
-
-
-int tls_global_set_verify(void *ssl_ctx, int check_crl)
-{
- return -1;
-}
-
-
-int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
- int verify_peer)
-{
- return -1;
-}
-
-
-int tls_connection_get_keys(void *ssl_ctx, struct tls_connection *conn,
- struct tls_keys *keys)
-{
- /* Schannel does not export master secret or client/server random. */
- 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)
-{
- /*
- * Cannot get master_key from Schannel, but EapKeyBlock can be used to
- * generate session keys for EAP-TLS and EAP-PEAPv0. EAP-PEAPv2 and
- * EAP-TTLS cannot use this, though, since they are using different
- * labels. The only option could be to implement TLSv1 completely here
- * and just use Schannel or CryptoAPI for low-level crypto
- * functionality..
- */
-
- if (conn == NULL || !conn->eap_tls_prf_set || server_random_first ||
- os_strcmp(label, "client EAP encryption") != 0 ||
- out_len > sizeof(conn->eap_tls_prf))
- return -1;
-
- os_memcpy(out, conn->eap_tls_prf, out_len);
-
- return 0;
-}
-
-
-static struct wpabuf * tls_conn_hs_clienthello(struct tls_global *global,
- struct tls_connection *conn)
-{
- DWORD sspi_flags, sspi_flags_out;
- SecBufferDesc outbuf;
- SecBuffer outbufs[1];
- SECURITY_STATUS status;
- TimeStamp ts_expiry;
-
- sspi_flags = ISC_REQ_REPLAY_DETECT |
- ISC_REQ_CONFIDENTIALITY |
- ISC_RET_EXTENDED_ERROR |
- ISC_REQ_ALLOCATE_MEMORY |
- ISC_REQ_MANUAL_CRED_VALIDATION;
-
- wpa_printf(MSG_DEBUG, "%s: Generating ClientHello", __func__);
-
- outbufs[0].pvBuffer = NULL;
- outbufs[0].BufferType = SECBUFFER_TOKEN;
- outbufs[0].cbBuffer = 0;
-
- outbuf.cBuffers = 1;
- outbuf.pBuffers = outbufs;
- outbuf.ulVersion = SECBUFFER_VERSION;
-
-#ifdef UNICODE
- status = global->sspi->InitializeSecurityContextW(
- &conn->creds, NULL, NULL /* server name */, sspi_flags, 0,
- SECURITY_NATIVE_DREP, NULL, 0, &conn->context,
- &outbuf, &sspi_flags_out, &ts_expiry);
-#else /* UNICODE */
- status = global->sspi->InitializeSecurityContextA(
- &conn->creds, NULL, NULL /* server name */, sspi_flags, 0,
- SECURITY_NATIVE_DREP, NULL, 0, &conn->context,
- &outbuf, &sspi_flags_out, &ts_expiry);
-#endif /* UNICODE */
- if (status != SEC_I_CONTINUE_NEEDED) {
- wpa_printf(MSG_ERROR, "%s: InitializeSecurityContextA "
- "failed - 0x%x",
- __func__, (unsigned int) status);
- return NULL;
- }
-
- if (outbufs[0].cbBuffer != 0 && outbufs[0].pvBuffer) {
- struct wpabuf *buf;
- wpa_hexdump(MSG_MSGDUMP, "SChannel - ClientHello",
- outbufs[0].pvBuffer, outbufs[0].cbBuffer);
- conn->start = 0;
- buf = wpabuf_alloc_copy(outbufs[0].pvBuffer,
- outbufs[0].cbBuffer);
- if (buf == NULL)
- return NULL;
- global->sspi->FreeContextBuffer(outbufs[0].pvBuffer);
- return buf;
- }
-
- wpa_printf(MSG_ERROR, "SChannel: Failed to generate ClientHello");
-
- return NULL;
-}
-
-
-#ifndef SECPKG_ATTR_EAP_KEY_BLOCK
-#define SECPKG_ATTR_EAP_KEY_BLOCK 0x5b
-
-typedef struct _SecPkgContext_EapKeyBlock {
- BYTE rgbKeys[128];
- BYTE rgbIVs[64];
-} SecPkgContext_EapKeyBlock, *PSecPkgContext_EapKeyBlock;
-#endif /* !SECPKG_ATTR_EAP_KEY_BLOCK */
-
-static int tls_get_eap(struct tls_global *global, struct tls_connection *conn)
-{
- SECURITY_STATUS status;
- SecPkgContext_EapKeyBlock kb;
-
- /* Note: Windows NT and Windows Me/98/95 do not support getting
- * EapKeyBlock */
-
- status = global->sspi->QueryContextAttributes(
- &conn->context, SECPKG_ATTR_EAP_KEY_BLOCK, &kb);
- if (status != SEC_E_OK) {
- wpa_printf(MSG_DEBUG, "%s: QueryContextAttributes("
- "SECPKG_ATTR_EAP_KEY_BLOCK) failed (%d)",
- __func__, (int) status);
- return -1;
- }
-
- wpa_hexdump_key(MSG_MSGDUMP, "Schannel - EapKeyBlock - rgbKeys",
- kb.rgbKeys, sizeof(kb.rgbKeys));
- wpa_hexdump_key(MSG_MSGDUMP, "Schannel - EapKeyBlock - rgbIVs",
- kb.rgbIVs, sizeof(kb.rgbIVs));
-
- os_memcpy(conn->eap_tls_prf, kb.rgbKeys, sizeof(kb.rgbKeys));
- conn->eap_tls_prf_set = 1;
- return 0;
-}
-
-
-struct wpabuf * tls_connection_handshake(void *tls_ctx,
- struct tls_connection *conn,
- const struct wpabuf *in_data,
- struct wpabuf **appl_data)
-{
- struct tls_global *global = tls_ctx;
- DWORD sspi_flags, sspi_flags_out;
- SecBufferDesc inbuf, outbuf;
- SecBuffer inbufs[2], outbufs[1];
- SECURITY_STATUS status;
- TimeStamp ts_expiry;
- struct wpabuf *out_buf = NULL;
-
- if (appl_data)
- *appl_data = NULL;
-
- if (conn->start)
- return tls_conn_hs_clienthello(global, conn);
-
- wpa_printf(MSG_DEBUG, "SChannel: %d bytes handshake data to process",
- (int) wpabuf_len(in_data));
-
- sspi_flags = ISC_REQ_REPLAY_DETECT |
- ISC_REQ_CONFIDENTIALITY |
- ISC_RET_EXTENDED_ERROR |
- ISC_REQ_ALLOCATE_MEMORY |
- ISC_REQ_MANUAL_CRED_VALIDATION;
-
- /* Input buffer for Schannel */
- inbufs[0].pvBuffer = (u8 *) wpabuf_head(in_data);
- inbufs[0].cbBuffer = wpabuf_len(in_data);
- inbufs[0].BufferType = SECBUFFER_TOKEN;
-
- /* Place for leftover data from Schannel */
- inbufs[1].pvBuffer = NULL;
- inbufs[1].cbBuffer = 0;
- inbufs[1].BufferType = SECBUFFER_EMPTY;
-
- inbuf.cBuffers = 2;
- inbuf.pBuffers = inbufs;
- inbuf.ulVersion = SECBUFFER_VERSION;
-
- /* Output buffer for Schannel */
- outbufs[0].pvBuffer = NULL;
- outbufs[0].cbBuffer = 0;
- outbufs[0].BufferType = SECBUFFER_TOKEN;
-
- outbuf.cBuffers = 1;
- outbuf.pBuffers = outbufs;
- outbuf.ulVersion = SECBUFFER_VERSION;
-
-#ifdef UNICODE
- status = global->sspi->InitializeSecurityContextW(
- &conn->creds, &conn->context, NULL, sspi_flags, 0,
- SECURITY_NATIVE_DREP, &inbuf, 0, NULL,
- &outbuf, &sspi_flags_out, &ts_expiry);
-#else /* UNICODE */
- status = global->sspi->InitializeSecurityContextA(
- &conn->creds, &conn->context, NULL, sspi_flags, 0,
- SECURITY_NATIVE_DREP, &inbuf, 0, NULL,
- &outbuf, &sspi_flags_out, &ts_expiry);
-#endif /* UNICODE */
-
- wpa_printf(MSG_MSGDUMP, "Schannel: InitializeSecurityContext -> "
- "status=%d inlen[0]=%d intype[0]=%d inlen[1]=%d "
- "intype[1]=%d outlen[0]=%d",
- (int) status, (int) inbufs[0].cbBuffer,
- (int) inbufs[0].BufferType, (int) inbufs[1].cbBuffer,
- (int) inbufs[1].BufferType,
- (int) outbufs[0].cbBuffer);
- if (status == SEC_E_OK || status == SEC_I_CONTINUE_NEEDED ||
- (FAILED(status) && (sspi_flags_out & ISC_RET_EXTENDED_ERROR))) {
- if (outbufs[0].cbBuffer != 0 && outbufs[0].pvBuffer) {
- wpa_hexdump(MSG_MSGDUMP, "SChannel - output",
- outbufs[0].pvBuffer, outbufs[0].cbBuffer);
- out_buf = wpabuf_alloc_copy(outbufs[0].pvBuffer,
- outbufs[0].cbBuffer);
- global->sspi->FreeContextBuffer(outbufs[0].pvBuffer);
- outbufs[0].pvBuffer = NULL;
- if (out_buf == NULL)
- return NULL;
- }
- }
-
- switch (status) {
- case SEC_E_INCOMPLETE_MESSAGE:
- wpa_printf(MSG_DEBUG, "Schannel: SEC_E_INCOMPLETE_MESSAGE");
- break;
- case SEC_I_CONTINUE_NEEDED:
- wpa_printf(MSG_DEBUG, "Schannel: SEC_I_CONTINUE_NEEDED");
- break;
- case SEC_E_OK:
- /* TODO: verify server certificate chain */
- wpa_printf(MSG_DEBUG, "Schannel: SEC_E_OK - Handshake "
- "completed successfully");
- conn->established = 1;
- tls_get_eap(global, conn);
-
- /* Need to return something to get final TLS ACK. */
- if (out_buf == NULL)
- out_buf = wpabuf_alloc(0);
-
- if (inbufs[1].BufferType == SECBUFFER_EXTRA) {
- wpa_hexdump(MSG_MSGDUMP, "SChannel - Encrypted "
- "application data",
- inbufs[1].pvBuffer, inbufs[1].cbBuffer);
- if (appl_data) {
- *appl_data = wpabuf_alloc_copy(
- outbufs[1].pvBuffer,
- outbufs[1].cbBuffer);
- }
- global->sspi->FreeContextBuffer(inbufs[1].pvBuffer);
- inbufs[1].pvBuffer = NULL;
- }
- break;
- case SEC_I_INCOMPLETE_CREDENTIALS:
- wpa_printf(MSG_DEBUG,
- "Schannel: SEC_I_INCOMPLETE_CREDENTIALS");
- break;
- case SEC_E_WRONG_PRINCIPAL:
- wpa_printf(MSG_DEBUG, "Schannel: SEC_E_WRONG_PRINCIPAL");
- break;
- case SEC_E_INTERNAL_ERROR:
- wpa_printf(MSG_DEBUG, "Schannel: SEC_E_INTERNAL_ERROR");
- break;
- }
-
- if (FAILED(status)) {
- wpa_printf(MSG_DEBUG, "Schannel: Handshake failed "
- "(out_buf=%p)", out_buf);
- conn->failed++;
- global->sspi->DeleteSecurityContext(&conn->context);
- return out_buf;
- }
-
- if (inbufs[1].BufferType == SECBUFFER_EXTRA) {
- /* TODO: Can this happen? What to do with this data? */
- wpa_hexdump(MSG_MSGDUMP, "SChannel - Leftover data",
- inbufs[1].pvBuffer, inbufs[1].cbBuffer);
- global->sspi->FreeContextBuffer(inbufs[1].pvBuffer);
- inbufs[1].pvBuffer = NULL;
- }
-
- return out_buf;
-}
-
-
-struct wpabuf * tls_connection_server_handshake(void *tls_ctx,
- struct tls_connection *conn,
- const struct wpabuf *in_data,
- struct wpabuf **appl_data)
-{
- return NULL;
-}
-
-
-struct wpabuf * tls_connection_encrypt(void *tls_ctx,
- struct tls_connection *conn,
- const struct wpabuf *in_data)
-{
- struct tls_global *global = tls_ctx;
- SECURITY_STATUS status;
- SecBufferDesc buf;
- SecBuffer bufs[4];
- SecPkgContext_StreamSizes sizes;
- int i;
- struct wpabuf *out;
-
- status = global->sspi->QueryContextAttributes(&conn->context,
- SECPKG_ATTR_STREAM_SIZES,
- &sizes);
- if (status != SEC_E_OK) {
- wpa_printf(MSG_DEBUG, "%s: QueryContextAttributes failed",
- __func__);
- return NULL;
- }
- wpa_printf(MSG_DEBUG, "%s: Stream sizes: header=%u trailer=%u",
- __func__,
- (unsigned int) sizes.cbHeader,
- (unsigned int) sizes.cbTrailer);
-
- out = wpabuf_alloc(sizes.cbHeader + wpabuf_len(in_data) +
- sizes.cbTrailer);
-
- os_memset(&bufs, 0, sizeof(bufs));
- bufs[0].pvBuffer = wpabuf_put(out, sizes.cbHeader);
- bufs[0].cbBuffer = sizes.cbHeader;
- bufs[0].BufferType = SECBUFFER_STREAM_HEADER;
-
- bufs[1].pvBuffer = wpabuf_put(out, 0);
- wpabuf_put_buf(out, in_data);
- bufs[1].cbBuffer = wpabuf_len(in_data);
- bufs[1].BufferType = SECBUFFER_DATA;
-
- bufs[2].pvBuffer = wpabuf_put(out, sizes.cbTrailer);
- bufs[2].cbBuffer = sizes.cbTrailer;
- bufs[2].BufferType = SECBUFFER_STREAM_TRAILER;
-
- buf.ulVersion = SECBUFFER_VERSION;
- buf.cBuffers = 3;
- buf.pBuffers = bufs;
-
- status = global->sspi->EncryptMessage(&conn->context, 0, &buf, 0);
-
- wpa_printf(MSG_MSGDUMP, "Schannel: EncryptMessage -> "
- "status=%d len[0]=%d type[0]=%d len[1]=%d type[1]=%d "
- "len[2]=%d type[2]=%d",
- (int) status,
- (int) bufs[0].cbBuffer, (int) bufs[0].BufferType,
- (int) bufs[1].cbBuffer, (int) bufs[1].BufferType,
- (int) bufs[2].cbBuffer, (int) bufs[2].BufferType);
- wpa_printf(MSG_MSGDUMP, "Schannel: EncryptMessage pointers: "
- "out_data=%p bufs %p %p %p",
- wpabuf_head(out), bufs[0].pvBuffer, bufs[1].pvBuffer,
- bufs[2].pvBuffer);
-
- for (i = 0; i < 3; i++) {
- if (bufs[i].pvBuffer && bufs[i].BufferType != SECBUFFER_EMPTY)
- {
- wpa_hexdump(MSG_MSGDUMP, "SChannel: bufs",
- bufs[i].pvBuffer, bufs[i].cbBuffer);
- }
- }
-
- if (status == SEC_E_OK) {
- wpa_printf(MSG_DEBUG, "%s: SEC_E_OK", __func__);
- wpa_hexdump_buf_key(MSG_MSGDUMP, "Schannel: Encrypted data "
- "from EncryptMessage", out);
- return out;
- }
-
- wpa_printf(MSG_DEBUG, "%s: Failed - status=%d",
- __func__, (int) status);
- wpabuf_free(out);
- return NULL;
-}
-
-
-struct wpabuf * tls_connection_decrypt(void *tls_ctx,
- struct tls_connection *conn,
- const struct wpabuf *in_data)
-{
- struct tls_global *global = tls_ctx;
- SECURITY_STATUS status;
- SecBufferDesc buf;
- SecBuffer bufs[4];
- int i;
- struct wpabuf *out, *tmp;
-
- wpa_hexdump_buf(MSG_MSGDUMP,
- "Schannel: Encrypted data to DecryptMessage", in_data);
- os_memset(&bufs, 0, sizeof(bufs));
- tmp = wpabuf_dup(in_data);
- if (tmp == NULL)
- return NULL;
- bufs[0].pvBuffer = wpabuf_mhead(tmp);
- bufs[0].cbBuffer = wpabuf_len(in_data);
- bufs[0].BufferType = SECBUFFER_DATA;
-
- bufs[1].BufferType = SECBUFFER_EMPTY;
- bufs[2].BufferType = SECBUFFER_EMPTY;
- bufs[3].BufferType = SECBUFFER_EMPTY;
-
- buf.ulVersion = SECBUFFER_VERSION;
- buf.cBuffers = 4;
- buf.pBuffers = bufs;
-
- status = global->sspi->DecryptMessage(&conn->context, &buf, 0,
- NULL);
- wpa_printf(MSG_MSGDUMP, "Schannel: DecryptMessage -> "
- "status=%d len[0]=%d type[0]=%d len[1]=%d type[1]=%d "
- "len[2]=%d type[2]=%d len[3]=%d type[3]=%d",
- (int) status,
- (int) bufs[0].cbBuffer, (int) bufs[0].BufferType,
- (int) bufs[1].cbBuffer, (int) bufs[1].BufferType,
- (int) bufs[2].cbBuffer, (int) bufs[2].BufferType,
- (int) bufs[3].cbBuffer, (int) bufs[3].BufferType);
- wpa_printf(MSG_MSGDUMP, "Schannel: DecryptMessage pointers: "
- "out_data=%p bufs %p %p %p %p",
- wpabuf_head(tmp), bufs[0].pvBuffer, bufs[1].pvBuffer,
- bufs[2].pvBuffer, bufs[3].pvBuffer);
-
- switch (status) {
- case SEC_E_INCOMPLETE_MESSAGE:
- wpa_printf(MSG_DEBUG, "%s: SEC_E_INCOMPLETE_MESSAGE",
- __func__);
- break;
- case SEC_E_OK:
- wpa_printf(MSG_DEBUG, "%s: SEC_E_OK", __func__);
- for (i = 0; i < 4; i++) {
- if (bufs[i].BufferType == SECBUFFER_DATA)
- break;
- }
- if (i == 4) {
- wpa_printf(MSG_DEBUG, "%s: No output data from "
- "DecryptMessage", __func__);
- wpabuf_free(tmp);
- return NULL;
- }
- wpa_hexdump_key(MSG_MSGDUMP, "Schannel: Decrypted data from "
- "DecryptMessage",
- bufs[i].pvBuffer, bufs[i].cbBuffer);
- out = wpabuf_alloc_copy(bufs[i].pvBuffer, bufs[i].cbBuffer);
- wpabuf_free(tmp);
- return out;
- }
-
- wpa_printf(MSG_DEBUG, "%s: Failed - status=%d",
- __func__, (int) status);
- wpabuf_free(tmp);
- return NULL;
-}
-
-
-int tls_connection_resumed(void *ssl_ctx, struct tls_connection *conn)
-{
- return 0;
-}
-
-
-int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
- u8 *ciphers)
-{
- return -1;
-}
-
-
-int tls_get_cipher(void *ssl_ctx, struct tls_connection *conn,
- char *buf, size_t buflen)
-{
- return -1;
-}
-
-
-int tls_connection_enable_workaround(void *ssl_ctx,
- struct tls_connection *conn)
-{
- return 0;
-}
-
-
-int tls_connection_client_hello_ext(void *ssl_ctx, struct tls_connection *conn,
- int ext_type, const u8 *data,
- size_t data_len)
-{
- return -1;
-}
-
-
-int tls_connection_get_failed(void *ssl_ctx, struct tls_connection *conn)
-{
- if (conn == NULL)
- return -1;
- return conn->failed;
-}
-
-
-int tls_connection_get_read_alerts(void *ssl_ctx, struct tls_connection *conn)
-{
- if (conn == NULL)
- return -1;
- return conn->read_alerts;
-}
-
-
-int tls_connection_get_write_alerts(void *ssl_ctx, struct tls_connection *conn)
-{
- if (conn == NULL)
- return -1;
- return conn->write_alerts;
-}
-
-
-int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
- const struct tls_connection_params *params)
-{
- struct tls_global *global = tls_ctx;
- ALG_ID algs[1];
- SECURITY_STATUS status;
- TimeStamp ts_expiry;
-
- if (conn == NULL)
- return -1;
-
- if (params->subject_match) {
- wpa_printf(MSG_INFO, "TLS: subject_match not supported");
- return -1;
- }
-
- if (params->altsubject_match) {
- wpa_printf(MSG_INFO, "TLS: altsubject_match not supported");
- return -1;
- }
-
- if (params->suffix_match) {
- wpa_printf(MSG_INFO, "TLS: suffix_match not supported");
- return -1;
- }
-
- if (params->domain_match) {
- wpa_printf(MSG_INFO, "TLS: domain_match not supported");
- return -1;
- }
-
- if (params->openssl_ciphers) {
- wpa_printf(MSG_INFO, "GnuTLS: openssl_ciphers not supported");
- return -1;
- }
-
- if (global->my_cert_store == NULL &&
- (global->my_cert_store = CertOpenSystemStore(0, TEXT("MY"))) ==
- NULL) {
- wpa_printf(MSG_ERROR, "%s: CertOpenSystemStore failed - 0x%x",
- __func__, (unsigned int) GetLastError());
- return -1;
- }
-
- os_memset(&conn->schannel_cred, 0, sizeof(conn->schannel_cred));
- conn->schannel_cred.dwVersion = SCHANNEL_CRED_VERSION;
- conn->schannel_cred.grbitEnabledProtocols = SP_PROT_TLS1;
- algs[0] = CALG_RSA_KEYX;
- conn->schannel_cred.cSupportedAlgs = 1;
- conn->schannel_cred.palgSupportedAlgs = algs;
- conn->schannel_cred.dwFlags |= SCH_CRED_NO_DEFAULT_CREDS;
-#ifdef UNICODE
- status = global->sspi->AcquireCredentialsHandleW(
- NULL, UNISP_NAME_W, SECPKG_CRED_OUTBOUND, NULL,
- &conn->schannel_cred, NULL, NULL, &conn->creds, &ts_expiry);
-#else /* UNICODE */
- status = global->sspi->AcquireCredentialsHandleA(
- NULL, UNISP_NAME_A, SECPKG_CRED_OUTBOUND, NULL,
- &conn->schannel_cred, NULL, NULL, &conn->creds, &ts_expiry);
-#endif /* UNICODE */
- if (status != SEC_E_OK) {
- wpa_printf(MSG_DEBUG, "%s: AcquireCredentialsHandleA failed - "
- "0x%x", __func__, (unsigned int) status);
- return -1;
- }
-
- return 0;
-}
-
-
-unsigned int tls_capabilities(void *tls_ctx)
-{
- return 0;
-}
-
-
-int tls_get_library_version(char *buf, size_t buf_len)
-{
- return os_snprintf(buf, buf_len, "schannel");
-}
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 4074b87..6a9cd74 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -1588,6 +1588,16 @@
/* Indicates whether HT40 is enabled */
int ht40_enabled;
+
+ /* Indicates whether VHT is enabled */
+ int vht_enabled;
+
+ /* Configured ACS channel width */
+ u16 ch_width;
+
+ /* ACS channel list info */
+ unsigned int ch_list_len;
+ const u8 *ch_list;
};
@@ -2657,18 +2667,6 @@
int encrypt);
/**
- * shared_freq - Get operating frequency of shared interface(s)
- * @priv: Private driver interface data
- * Returns: Operating frequency in MHz, 0 if no shared operation in
- * use, or -1 on failure
- *
- * This command can be used to request the current operating frequency
- * of any virtual interface that shares the same radio to provide
- * information for channel selection for other virtual interfaces.
- */
- int (*shared_freq)(void *priv);
-
- /**
* get_noa - Get current Notice of Absence attribute payload
* @priv: Private driver interface data
* @buf: Buffer for returning NoA
@@ -4558,10 +4556,18 @@
* struct acs_selected_channels - Data for EVENT_ACS_CHANNEL_SELECTED
* @pri_channel: Selected primary channel
* @sec_channel: Selected secondary channel
+ * @vht_seg0_center_ch: VHT mode Segment0 center channel
+ * @vht_seg1_center_ch: VHT mode Segment1 center channel
+ * @ch_width: Selected Channel width by driver. Driver may choose to
+ * change hostapd configured ACS channel width due driver internal
+ * channel restrictions.
*/
struct acs_selected_channels {
u8 pri_channel;
u8 sec_channel;
+ u8 vht_seg0_center_ch;
+ u8 vht_seg1_center_ch;
+ u16 ch_width;
} acs_selected_channels;
};
diff --git a/src/drivers/driver_atheros.c b/src/drivers/driver_atheros.c
index f464421..b8e7864 100644
--- a/src/drivers/driver_atheros.c
+++ b/src/drivers/driver_atheros.c
@@ -1694,6 +1694,13 @@
struct atheros_driver_data *drv = priv;
atheros_reset_appfilter(drv);
+
+ if (drv->wpa_ie || drv->wps_beacon_ie || drv->wps_probe_resp_ie) {
+ wpabuf_free(drv->wpa_ie);
+ wpabuf_free(drv->wps_beacon_ie);
+ wpabuf_free(drv->wps_probe_resp_ie);
+ atheros_set_opt_ie(priv, NULL, 0);
+ }
netlink_deinit(drv->netlink);
(void) linux_set_iface_flags(drv->ioctl_sock, drv->iface, 0);
if (drv->ioctl_sock >= 0)
@@ -1704,9 +1711,6 @@
l2_packet_deinit(drv->sock_xmit);
if (drv->sock_raw)
l2_packet_deinit(drv->sock_raw);
- wpabuf_free(drv->wpa_ie);
- wpabuf_free(drv->wps_beacon_ie);
- wpabuf_free(drv->wps_probe_resp_ie);
free(drv);
}
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index aaff9ab..7b3dc51 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -6522,47 +6522,6 @@
}
-static int wpa_driver_nl80211_shared_freq(void *priv)
-{
- struct i802_bss *bss = priv;
- struct wpa_driver_nl80211_data *drv = bss->drv;
- struct wpa_driver_nl80211_data *driver;
- int freq = 0;
-
- /*
- * If the same PHY is in connected state with some other interface,
- * then retrieve the assoc freq.
- */
- wpa_printf(MSG_DEBUG, "nl80211: Get shared freq for PHY %s",
- drv->phyname);
-
- dl_list_for_each(driver, &drv->global->interfaces,
- struct wpa_driver_nl80211_data, list) {
- if (drv == driver ||
- os_strcmp(drv->phyname, driver->phyname) != 0 ||
- !driver->associated)
- continue;
-
- wpa_printf(MSG_DEBUG, "nl80211: Found a match for PHY %s - %s "
- MACSTR,
- driver->phyname, driver->first_bss->ifname,
- MAC2STR(driver->first_bss->addr));
- if (is_ap_interface(driver->nlmode))
- freq = driver->first_bss->freq;
- else
- freq = nl80211_get_assoc_freq(driver);
- wpa_printf(MSG_DEBUG, "nl80211: Shared freq for PHY %s: %d",
- drv->phyname, freq);
- }
-
- if (!freq)
- wpa_printf(MSG_DEBUG, "nl80211: No shared interface for "
- "PHY (%s) in associated state", drv->phyname);
-
- return freq;
-}
-
-
static int nl80211_send_frame(void *priv, const u8 *data, size_t data_len,
int encrypt)
{
@@ -8423,12 +8382,24 @@
(params->ht_enabled &&
nla_put_flag(msg, QCA_WLAN_VENDOR_ATTR_ACS_HT_ENABLED)) ||
(params->ht40_enabled &&
- nla_put_flag(msg, QCA_WLAN_VENDOR_ATTR_ACS_HT40_ENABLED))) {
+ nla_put_flag(msg, QCA_WLAN_VENDOR_ATTR_ACS_HT40_ENABLED)) ||
+ (params->vht_enabled &&
+ nla_put_flag(msg, QCA_WLAN_VENDOR_ATTR_ACS_VHT_ENABLED)) ||
+ nla_put_u16(msg, QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH,
+ params->ch_width) ||
+ (params->ch_list_len &&
+ nla_put(msg, QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST, params->ch_list_len,
+ params->ch_list))) {
nlmsg_free(msg);
return -ENOBUFS;
}
nla_nest_end(msg, data);
+ wpa_printf(MSG_DEBUG,
+ "nl80211: ACS Params: HW_MODE: %d HT: %d HT40: %d VHT: %d BW: %d CH_LIST_LEN: %u",
+ params->hw_mode, params->ht_enabled, params->ht40_enabled,
+ params->vht_enabled, params->ch_width, params->ch_list_len);
+
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
if (ret) {
wpa_printf(MSG_DEBUG,
@@ -8498,7 +8469,6 @@
.signal_monitor = nl80211_signal_monitor,
.signal_poll = nl80211_signal_poll,
.send_frame = nl80211_send_frame,
- .shared_freq = wpa_driver_nl80211_shared_freq,
.set_param = nl80211_set_param,
.get_radio_name = nl80211_get_radio_name,
.add_pmkid = nl80211_add_pmkid,
diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h
index 802589a..64c4665 100644
--- a/src/drivers/driver_nl80211.h
+++ b/src/drivers/driver_nl80211.h
@@ -270,5 +270,6 @@
int wpa_driver_nl80211_stop_sched_scan(void *priv);
struct wpa_scan_results * wpa_driver_nl80211_get_scan_results(void *priv);
void nl80211_dump_scan(struct wpa_driver_nl80211_data *drv);
+const u8 * nl80211_get_ie(const u8 *ies, size_t ies_len, u8 ie);
#endif /* DRIVER_NL80211_H */
diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c
index 13c446f..ba1e240 100644
--- a/src/drivers/driver_nl80211_capa.c
+++ b/src/drivers/driver_nl80211_capa.c
@@ -575,22 +575,25 @@
continue;
}
vinfo = nla_data(nl);
- switch (vinfo->subcmd) {
- case QCA_NL80211_VENDOR_SUBCMD_TEST:
- drv->vendor_cmd_test_avail = 1;
- break;
- case QCA_NL80211_VENDOR_SUBCMD_ROAMING:
- drv->roaming_vendor_cmd_avail = 1;
- break;
- case QCA_NL80211_VENDOR_SUBCMD_DFS_CAPABILITY:
- drv->dfs_vendor_cmd_avail = 1;
- break;
- case QCA_NL80211_VENDOR_SUBCMD_GET_FEATURES:
- drv->get_features_vendor_cmd_avail = 1;
- break;
- case QCA_NL80211_VENDOR_SUBCMD_DO_ACS:
- drv->capa.flags |= WPA_DRIVER_FLAGS_ACS_OFFLOAD;
- break;
+ if (vinfo->vendor_id == OUI_QCA) {
+ switch (vinfo->subcmd) {
+ case QCA_NL80211_VENDOR_SUBCMD_TEST:
+ drv->vendor_cmd_test_avail = 1;
+ break;
+ case QCA_NL80211_VENDOR_SUBCMD_ROAMING:
+ drv->roaming_vendor_cmd_avail = 1;
+ break;
+ case QCA_NL80211_VENDOR_SUBCMD_DFS_CAPABILITY:
+ drv->dfs_vendor_cmd_avail = 1;
+ break;
+ case QCA_NL80211_VENDOR_SUBCMD_GET_FEATURES:
+ drv->get_features_vendor_cmd_avail = 1;
+ break;
+ case QCA_NL80211_VENDOR_SUBCMD_DO_ACS:
+ drv->capa.flags |=
+ WPA_DRIVER_FLAGS_ACS_OFFLOAD;
+ break;
+ }
}
wpa_printf(MSG_DEBUG, "nl80211: Supported vendor command: vendor_id=0x%x subcmd=%u",
diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c
index 87e412d..8cebfb2 100644
--- a/src/drivers/driver_nl80211_event.c
+++ b/src/drivers/driver_nl80211_event.c
@@ -271,6 +271,7 @@
struct nlattr *ptk_kek)
{
union wpa_event_data event;
+ const u8 *ssid;
u16 status_code;
if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) {
@@ -331,6 +332,16 @@
if (req_ie) {
event.assoc_info.req_ies = nla_data(req_ie);
event.assoc_info.req_ies_len = nla_len(req_ie);
+
+ if (cmd == NL80211_CMD_ROAM) {
+ ssid = nl80211_get_ie(event.assoc_info.req_ies,
+ event.assoc_info.req_ies_len,
+ WLAN_EID_SSID);
+ if (ssid && ssid[1] > 0 && ssid[1] <= 32) {
+ drv->ssid_len = ssid[1];
+ os_memcpy(drv->ssid, ssid + 2, ssid[1]);
+ }
+ }
}
if (resp_ie) {
event.assoc_info.resp_ies = nla_data(resp_ie);
@@ -1500,6 +1511,25 @@
nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL]);
event.acs_selected_channels.sec_channel =
nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_CHANNEL]);
+ if (tb[QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL])
+ event.acs_selected_channels.vht_seg0_center_ch =
+ nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL]);
+ if (tb[QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL])
+ event.acs_selected_channels.vht_seg1_center_ch =
+ nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_CHANNEL]);
+ if (tb[QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH])
+ event.acs_selected_channels.ch_width =
+ nla_get_u16(tb[QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH]);
+
+ wpa_printf(MSG_INFO,
+ "nl80211: ACS Results: PCH: %d SCH: %d BW: %d VHT0: %d VHT1: %d",
+ event.acs_selected_channels.pri_channel,
+ event.acs_selected_channels.sec_channel,
+ event.acs_selected_channels.ch_width,
+ event.acs_selected_channels.vht_seg0_center_ch,
+ event.acs_selected_channels.vht_seg1_center_ch);
+
+ /* Ignore ACS channel list check for backwards compatibility */
wpa_supplicant_event(drv->ctx, EVENT_ACS_CHANNEL_SELECTED, &event);
}
diff --git a/src/drivers/driver_nl80211_scan.c b/src/drivers/driver_nl80211_scan.c
index 3911f48..9cd3162 100644
--- a/src/drivers/driver_nl80211_scan.c
+++ b/src/drivers/driver_nl80211_scan.c
@@ -433,7 +433,7 @@
}
-static const u8 * nl80211_get_ie(const u8 *ies, size_t ies_len, u8 ie)
+const u8 * nl80211_get_ie(const u8 *ies, size_t ies_len, u8 ie)
{
const u8 *end, *pos;
diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c
index 6adb3dc..f584fae 100644
--- a/src/p2p/p2p.c
+++ b/src/p2p/p2p.c
@@ -2730,6 +2730,25 @@
}
+void p2p_service_flush_asp(struct p2p_data *p2p)
+{
+ struct p2ps_advertisement *adv, *prev;
+
+ if (!p2p)
+ return;
+
+ adv = p2p->p2ps_adv_list;
+ while (adv) {
+ prev = adv;
+ adv = adv->next;
+ os_free(prev);
+ }
+
+ p2p->p2ps_adv_list = NULL;
+ p2p_dbg(p2p, "All ASP advertisements flushed");
+}
+
+
int p2p_parse_dev_addr_in_p2p_ie(struct wpabuf *p2p_ie, u8 *dev_addr)
{
struct p2p_message msg;
@@ -2878,8 +2897,6 @@
void p2p_deinit(struct p2p_data *p2p)
{
- struct p2ps_advertisement *adv, *prev;
-
#ifdef CONFIG_WIFI_DISPLAY
wpabuf_free(p2p->wfd_ie_beacon);
wpabuf_free(p2p->wfd_ie_probe_req);
@@ -2913,13 +2930,7 @@
os_free(p2p->after_scan_tx);
p2p_remove_wps_vendor_extensions(p2p);
os_free(p2p->no_go_freq.range);
-
- adv = p2p->p2ps_adv_list;
- while (adv) {
- prev = adv;
- adv = adv->next;
- os_free(prev);
- }
+ p2p_service_flush_asp(p2p);
os_free(p2p);
}
diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h
index 2402db6..2e5c3dc 100644
--- a/src/p2p/p2p.h
+++ b/src/p2p/p2p.h
@@ -2242,6 +2242,7 @@
const char *adv_str, u8 svc_state,
u16 config_methods, const char *svc_info);
int p2p_service_del_asp(struct p2p_data *p2p, u32 adv_id);
+void p2p_service_flush_asp(struct p2p_data *p2p);
struct p2ps_advertisement * p2p_get_p2ps_adv_list(struct p2p_data *p2p);
#endif /* P2P_H */