untrusted comment: signature from openbsd 6.1 base secret key RWQEQa33SgQSEloZjPqFuBpjbCKFPBgnFy5UtpQ8PKrq1HXqPI5u06SBhddcqm4UsdODwT9hqzBpzOxreAC+EIpNW+qzbXaFWQM= OpenBSD 6.1 errata 027, August 30, 2017 State transition errors could cause reinstallation of old WPA keys. Apply by doing: signify -Vep /etc/signify/openbsd-61-base.pub -x 027_net80211_replay.patch.sig \ -m - | (cd /usr/src && patch -p0) And then rebuild and install a new kernel: KK=`sysctl -n kern.osversion | cut -d# -f1` cd /usr/src/sys/arch/`machine`/compile/$KK make obj make config make make install Index: sys/net80211/ieee80211_crypto.c =================================================================== RCS file: /cvs/src/sys/net80211/ieee80211_crypto.c,v retrieving revision 1.69 diff -u -p -r1.69 ieee80211_crypto.c --- sys/net80211/ieee80211_crypto.c 23 Mar 2017 04:10:10 -0000 1.69 +++ sys/net80211/ieee80211_crypto.c 29 Aug 2017 20:27:26 -0000 @@ -80,7 +80,6 @@ ieee80211_crypto_detach(struct ifnet *if { struct ieee80211com *ic = (void *)ifp; struct ieee80211_pmk *pmk; - int i; /* purge the PMKSA cache */ while ((pmk = TAILQ_FIRST(&ic->ic_pmksa)) != NULL) { @@ -90,12 +89,7 @@ ieee80211_crypto_detach(struct ifnet *if } /* clear all group keys from memory */ - for (i = 0; i < IEEE80211_GROUP_NKID; i++) { - struct ieee80211_key *k = &ic->ic_nw_keys[i]; - if (k->k_cipher != IEEE80211_CIPHER_NONE) - (*ic->ic_delete_key)(ic, NULL, k); - explicit_bzero(k, sizeof(*k)); - } + ieee80211_crypto_clear_groupkeys(ic); /* clear pre-shared key from memory */ explicit_bzero(ic->ic_psk, IEEE80211_PMK_LEN); @@ -103,6 +97,19 @@ ieee80211_crypto_detach(struct ifnet *if #ifndef IEEE80211_STA_ONLY timeout_del(&ic->ic_tkip_micfail_timeout); #endif +} + +void +ieee80211_crypto_clear_groupkeys(struct ieee80211com *ic) +{ + int i; + + for (i = 0; i < IEEE80211_GROUP_NKID; i++) { + struct ieee80211_key *k = &ic->ic_nw_keys[i]; + if (k->k_cipher != IEEE80211_CIPHER_NONE) + (*ic->ic_delete_key)(ic, NULL, k); + explicit_bzero(k, sizeof(*k)); + } } /* Index: sys/net80211/ieee80211_crypto.h =================================================================== RCS file: /cvs/src/sys/net80211/ieee80211_crypto.h,v retrieving revision 1.24 diff -u -p -r1.24 ieee80211_crypto.h --- sys/net80211/ieee80211_crypto.h 17 Dec 2016 18:35:54 -0000 1.24 +++ sys/net80211/ieee80211_crypto.h 29 Aug 2017 20:28:24 -0000 @@ -111,6 +111,7 @@ struct ieee80211_node; void ieee80211_crypto_attach(struct ifnet *); void ieee80211_crypto_detach(struct ifnet *); +void ieee80211_crypto_clear_groupkeys(struct ieee80211com *); struct ieee80211_key *ieee80211_get_txkey(struct ieee80211com *, const struct ieee80211_frame *, struct ieee80211_node *); struct ieee80211_key *ieee80211_get_rxkey(struct ieee80211com *, Index: sys/net80211/ieee80211_node.c =================================================================== RCS file: /cvs/src/sys/net80211/ieee80211_node.c,v retrieving revision 1.115 diff -u -p -r1.115 ieee80211_node.c --- sys/net80211/ieee80211_node.c 4 Mar 2017 12:44:27 -0000 1.115 +++ sys/net80211/ieee80211_node.c 29 Aug 2017 20:24:22 -0000 @@ -1532,6 +1532,7 @@ ieee80211_node_join_rsn(struct ieee80211 ni->ni_key_count = 0; ni->ni_port_valid = 0; ni->ni_flags &= ~IEEE80211_NODE_TXRXPROT; + ni->ni_flags &= ~IEEE80211_NODE_RSN_NEW_PTK; ni->ni_replaycnt = -1; /* XXX */ ni->ni_rsn_retries = 0; ni->ni_rsncipher = ni->ni_rsnciphers; Index: sys/net80211/ieee80211_node.h =================================================================== RCS file: /cvs/src/sys/net80211/ieee80211_node.h,v retrieving revision 1.68 diff -u -p -r1.68 ieee80211_node.h --- sys/net80211/ieee80211_node.h 12 Mar 2017 03:13:50 -0000 1.68 +++ sys/net80211/ieee80211_node.h 29 Aug 2017 20:25:21 -0000 @@ -296,6 +296,7 @@ struct ieee80211_node { #define IEEE80211_NODE_HT 0x0400 /* HT negotiated */ #define IEEE80211_NODE_SA_QUERY 0x0800 /* SA Query in progress */ #define IEEE80211_NODE_SA_QUERY_FAILED 0x1000 /* last SA Query failed */ +#define IEEE80211_NODE_RSN_NEW_PTK 0x2000 /* expecting a new PTK */ }; RBT_HEAD(ieee80211_tree, ieee80211_node); Index: sys/net80211/ieee80211_pae_input.c =================================================================== RCS file: /cvs/src/sys/net80211/ieee80211_pae_input.c,v retrieving revision 1.28.4.1 diff -u -p -r1.28.4.1 ieee80211_pae_input.c --- sys/net80211/ieee80211_pae_input.c 1 Aug 2017 22:30:29 -0000 1.28.4.1 +++ sys/net80211/ieee80211_pae_input.c 29 Aug 2017 20:25:59 -0000 @@ -47,6 +47,8 @@ void ieee80211_recv_4way_msg2(struct iee struct ieee80211_eapol_key *, struct ieee80211_node *, const u_int8_t *); #endif +int ieee80211_must_update_group_key(struct ieee80211_key *, const uint8_t *, + int); void ieee80211_recv_4way_msg3(struct ieee80211com *, struct ieee80211_eapol_key *, struct ieee80211_node *); #ifndef IEEE80211_STA_ONLY @@ -261,6 +263,9 @@ ieee80211_recv_4way_msg1(struct ieee8021 ieee80211_derive_ptk(ni->ni_rsnakms, ni->ni_pmk, ni->ni_macaddr, ic->ic_myaddr, ni->ni_nonce, ic->ic_nonce, &tptk); + /* We are now expecting a new pairwise key. */ + ni->ni_flags |= IEEE80211_NODE_RSN_NEW_PTK; + if (ic->ic_if.if_flags & IFF_DEBUG) printf("%s: received msg %d/%d of the %s handshake from %s\n", ic->ic_if.if_xname, 1, 4, "4-way", @@ -335,6 +340,14 @@ ieee80211_recv_4way_msg2(struct ieee8021 } #endif /* IEEE80211_STA_ONLY */ +int +ieee80211_must_update_group_key(struct ieee80211_key *k, const uint8_t *gtk, + int len) +{ + return (k->k_cipher == IEEE80211_CIPHER_NONE || k->k_len != len || + memcmp(k->k_key, gtk, len) != 0); +} + /* * Process Message 3 of the 4-Way Handshake (sent by Authenticator). */ @@ -515,7 +528,8 @@ ieee80211_recv_4way_msg3(struct ieee8021 if (ieee80211_send_4way_msg4(ic, ni) != 0) return; /* ..authenticator will retry */ - if (ni->ni_rsncipher != IEEE80211_CIPHER_USEGROUP) { + if (ni->ni_rsncipher != IEEE80211_CIPHER_USEGROUP && + (ni->ni_flags & IEEE80211_NODE_RSN_NEW_PTK)) { u_int64_t prsc; /* check that key length matches that of pairwise cipher */ @@ -538,9 +552,13 @@ ieee80211_recv_4way_msg3(struct ieee8021 reason = IEEE80211_REASON_AUTH_LEAVE; goto deauth; } + ni->ni_flags &= ~IEEE80211_NODE_RSN_NEW_PTK; ni->ni_flags &= ~IEEE80211_NODE_TXRXPROT; ni->ni_flags |= IEEE80211_NODE_RXPROT; - } + } else if (ni->ni_rsncipher != IEEE80211_CIPHER_USEGROUP) + printf("%s: unexpected pairwise key update received from %s\n", + ic->ic_if.if_xname, ether_sprintf(ni->ni_macaddr)); + if (gtk != NULL) { u_int8_t kid; @@ -553,20 +571,24 @@ ieee80211_recv_4way_msg3(struct ieee8021 /* map GTK to 802.11 key */ kid = gtk[6] & 3; k = &ic->ic_nw_keys[kid]; - memset(k, 0, sizeof(*k)); - k->k_id = kid; /* 0-3 */ - k->k_cipher = ni->ni_rsngroupcipher; - k->k_flags = IEEE80211_KEY_GROUP; - if (gtk[6] & (1 << 2)) - k->k_flags |= IEEE80211_KEY_TX; - k->k_rsc[0] = LE_READ_6(key->rsc); - k->k_len = keylen; - memcpy(k->k_key, >k[8], k->k_len); - /* install the GTK */ - if ((*ic->ic_set_key)(ic, ni, k) != 0) { - reason = IEEE80211_REASON_AUTH_LEAVE; - goto deauth; - } + if (ieee80211_must_update_group_key(k, >k[8], keylen)) { + memset(k, 0, sizeof(*k)); + k->k_id = kid; /* 0-3 */ + k->k_cipher = ni->ni_rsngroupcipher; + k->k_flags = IEEE80211_KEY_GROUP; + if (gtk[6] & (1 << 2)) + k->k_flags |= IEEE80211_KEY_TX; + k->k_rsc[0] = LE_READ_6(key->rsc); + k->k_len = keylen; + memcpy(k->k_key, >k[8], k->k_len); + /* install the GTK */ + if ((*ic->ic_set_key)(ic, ni, k) != 0) { + reason = IEEE80211_REASON_AUTH_LEAVE; + goto deauth; + } + } else + printf("%s: reused group key update received from %s\n", + ic->ic_if.if_xname, ether_sprintf(ni->ni_macaddr)); } if (igtk != NULL) { /* implies MFP && gtk != NULL */ u_int16_t kid; @@ -584,18 +606,22 @@ ieee80211_recv_4way_msg3(struct ieee8021 } /* map IGTK to 802.11 key */ k = &ic->ic_nw_keys[kid]; - memset(k, 0, sizeof(*k)); - k->k_id = kid; /* either 4 or 5 */ - k->k_cipher = ni->ni_rsngroupmgmtcipher; - k->k_flags = IEEE80211_KEY_IGTK; - k->k_mgmt_rsc = LE_READ_6(&igtk[8]); /* IPN */ - k->k_len = 16; - memcpy(k->k_key, &igtk[14], k->k_len); - /* install the IGTK */ - if ((*ic->ic_set_key)(ic, ni, k) != 0) { - reason = IEEE80211_REASON_AUTH_LEAVE; - goto deauth; - } + if (ieee80211_must_update_group_key(k, &igtk[14], 16)) { + memset(k, 0, sizeof(*k)); + k->k_id = kid; /* either 4 or 5 */ + k->k_cipher = ni->ni_rsngroupmgmtcipher; + k->k_flags = IEEE80211_KEY_IGTK; + k->k_mgmt_rsc = LE_READ_6(&igtk[8]); /* IPN */ + k->k_len = 16; + memcpy(k->k_key, &igtk[14], k->k_len); + /* install the IGTK */ + if ((*ic->ic_set_key)(ic, ni, k) != 0) { + reason = IEEE80211_REASON_AUTH_LEAVE; + goto deauth; + } + } else + printf("%s: reused group key update received from %s\n", + ic->ic_if.if_xname, ether_sprintf(ni->ni_macaddr)); } if (info & EAPOL_KEY_INSTALL) ni->ni_flags |= IEEE80211_NODE_TXRXPROT; @@ -821,20 +847,24 @@ ieee80211_recv_rsn_group_msg1(struct iee /* map GTK to 802.11 key */ kid = gtk[6] & 3; k = &ic->ic_nw_keys[kid]; - memset(k, 0, sizeof(*k)); - k->k_id = kid; /* 0-3 */ - k->k_cipher = ni->ni_rsngroupcipher; - k->k_flags = IEEE80211_KEY_GROUP; - if (gtk[6] & (1 << 2)) - k->k_flags |= IEEE80211_KEY_TX; - k->k_rsc[0] = LE_READ_6(key->rsc); - k->k_len = keylen; - memcpy(k->k_key, >k[8], k->k_len); - /* install the GTK */ - if ((*ic->ic_set_key)(ic, ni, k) != 0) { - reason = IEEE80211_REASON_AUTH_LEAVE; - goto deauth; - } + if (ieee80211_must_update_group_key(k, >k[8], keylen)) { + memset(k, 0, sizeof(*k)); + k->k_id = kid; /* 0-3 */ + k->k_cipher = ni->ni_rsngroupcipher; + k->k_flags = IEEE80211_KEY_GROUP; + if (gtk[6] & (1 << 2)) + k->k_flags |= IEEE80211_KEY_TX; + k->k_rsc[0] = LE_READ_6(key->rsc); + k->k_len = keylen; + memcpy(k->k_key, >k[8], k->k_len); + /* install the GTK */ + if ((*ic->ic_set_key)(ic, ni, k) != 0) { + reason = IEEE80211_REASON_AUTH_LEAVE; + goto deauth; + } + } else + printf("%s: reused group key update received from %s\n", + ic->ic_if.if_xname, ether_sprintf(ni->ni_macaddr)); if (igtk != NULL) { /* implies MFP */ /* check that the IGTK KDE is valid */ if (igtk[1] != 4 + 24) { @@ -849,18 +879,22 @@ ieee80211_recv_rsn_group_msg1(struct iee } /* map IGTK to 802.11 key */ k = &ic->ic_nw_keys[kid]; - memset(k, 0, sizeof(*k)); - k->k_id = kid; /* either 4 or 5 */ - k->k_cipher = ni->ni_rsngroupmgmtcipher; - k->k_flags = IEEE80211_KEY_IGTK; - k->k_mgmt_rsc = LE_READ_6(&igtk[8]); /* IPN */ - k->k_len = 16; - memcpy(k->k_key, &igtk[14], k->k_len); - /* install the IGTK */ - if ((*ic->ic_set_key)(ic, ni, k) != 0) { - reason = IEEE80211_REASON_AUTH_LEAVE; - goto deauth; - } + if (ieee80211_must_update_group_key(k, &igtk[14], 16)) { + memset(k, 0, sizeof(*k)); + k->k_id = kid; /* either 4 or 5 */ + k->k_cipher = ni->ni_rsngroupmgmtcipher; + k->k_flags = IEEE80211_KEY_IGTK; + k->k_mgmt_rsc = LE_READ_6(&igtk[8]); /* IPN */ + k->k_len = 16; + memcpy(k->k_key, &igtk[14], k->k_len); + /* install the IGTK */ + if ((*ic->ic_set_key)(ic, ni, k) != 0) { + reason = IEEE80211_REASON_AUTH_LEAVE; + goto deauth; + } + } else + printf("%s: reused group key update received from %s\n", + ic->ic_if.if_xname, ether_sprintf(ni->ni_macaddr)); } if (info & EAPOL_KEY_SECURE) { #ifndef IEEE80211_STA_ONLY @@ -901,6 +935,7 @@ ieee80211_recv_wpa_group_msg1(struct iee u_int16_t info; u_int8_t kid; int keylen; + const uint8_t *gtk; #ifndef IEEE80211_STA_ONLY if (ic->ic_opmode != IEEE80211_M_STA && @@ -946,23 +981,27 @@ ieee80211_recv_wpa_group_msg1(struct iee /* map GTK to 802.11 key */ kid = (info >> EAPOL_KEY_WPA_KID_SHIFT) & 3; k = &ic->ic_nw_keys[kid]; - memset(k, 0, sizeof(*k)); - k->k_id = kid; /* 0-3 */ - k->k_cipher = ni->ni_rsngroupcipher; - k->k_flags = IEEE80211_KEY_GROUP; - if (info & EAPOL_KEY_WPA_TX) - k->k_flags |= IEEE80211_KEY_TX; - k->k_rsc[0] = LE_READ_6(key->rsc); - k->k_len = keylen; - /* key data field contains the GTK */ - memcpy(k->k_key, &key[1], k->k_len); - /* install the GTK */ - if ((*ic->ic_set_key)(ic, ni, k) != 0) { - IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_DEAUTH, - IEEE80211_REASON_AUTH_LEAVE); - ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); - return; - } + gtk = (const uint8_t *)&key[1]; /* key data field contains the GTK */ + if (ieee80211_must_update_group_key(k, gtk, keylen)) { + memset(k, 0, sizeof(*k)); + k->k_id = kid; /* 0-3 */ + k->k_cipher = ni->ni_rsngroupcipher; + k->k_flags = IEEE80211_KEY_GROUP; + if (info & EAPOL_KEY_WPA_TX) + k->k_flags |= IEEE80211_KEY_TX; + k->k_rsc[0] = LE_READ_6(key->rsc); + k->k_len = keylen; + memcpy(k->k_key, gtk, k->k_len); + /* install the GTK */ + if ((*ic->ic_set_key)(ic, ni, k) != 0) { + IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_DEAUTH, + IEEE80211_REASON_AUTH_LEAVE); + ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); + return; + } + } else + printf("%s: reused group key update received from %s\n", + ic->ic_if.if_xname, ether_sprintf(ni->ni_macaddr)); if (info & EAPOL_KEY_SECURE) { #ifndef IEEE80211_STA_ONLY if (ic->ic_opmode != IEEE80211_M_IBSS || Index: sys/net80211/ieee80211_proto.c =================================================================== RCS file: /cvs/src/sys/net80211/ieee80211_proto.c,v retrieving revision 1.74 diff -u -p -r1.74 ieee80211_proto.c --- sys/net80211/ieee80211_proto.c 2 Mar 2017 09:41:27 -0000 1.74 +++ sys/net80211/ieee80211_proto.c 29 Aug 2017 20:29:04 -0000 @@ -903,6 +903,7 @@ justcleanup: break; } ni->ni_rsn_supp_state = RSNA_SUPP_INITIALIZE; + ieee80211_crypto_clear_groupkeys(ic); break; case IEEE80211_S_SCAN: ic->ic_flags &= ~IEEE80211_F_SIBSS; @@ -914,6 +915,7 @@ justcleanup: ni->ni_associd = 0; ni->ni_rstamp = 0; ni->ni_rsn_supp_state = RSNA_SUPP_INITIALIZE; + ieee80211_crypto_clear_groupkeys(ic); switch (ostate) { case IEEE80211_S_INIT: #ifndef IEEE80211_STA_ONLY @@ -957,6 +959,7 @@ justcleanup: break; case IEEE80211_S_AUTH: ni->ni_rsn_supp_state = RSNA_SUPP_INITIALIZE; + ieee80211_crypto_clear_groupkeys(ic); switch (ostate) { case IEEE80211_S_INIT: DPRINTF(("invalid transition\n"));