diff options
Diffstat (limited to 'src')
39 files changed, 664 insertions, 304 deletions
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) |
