untrusted comment: signature from openbsd 6.0 base secret key RWSho3oKSqgLQzcYx1qpk3xo94+fk008L6WnGNF5Rq+pk+B8EeR8RUe9I0jZN9REXpEKpAKpqGE4v/2/P86nedk8e2Ywvdl79Qs= OpenBSD 6.0 errata 041, August 30, 2017 State transition errors could cause reinstallation of old WPA keys. Apply by doing: signify -Vep /etc/signify/openbsd-60-base.pub -x 041_net80211_replay.patch.sig \ -m - | (cd /usr/src && patch -p0) And then rebuild and install a new kernel: cd /usr/src/sys/arch/`machine`/conf KK=`sysctl -n kern.osversion | cut -d# -f1` config $KK cd ../compile/$KK make make install Index: sys/net80211/ieee80211_crypto.c =================================================================== RCS file: /cvs/src/sys/net80211/ieee80211_crypto.c,v retrieving revision 1.66 diff -u -p -r1.66 ieee80211_crypto.c --- sys/net80211/ieee80211_crypto.c 24 Nov 2015 13:45:06 -0000 1.66 +++ sys/net80211/ieee80211_crypto.c 29 Aug 2017 21:20:52 -0000 @@ -76,7 +76,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) { @@ -86,15 +85,23 @@ ieee80211_crypto_detach(struct ifnet *if } /* clear all group keys from memory */ + ieee80211_crypto_clear_groupkeys(ic); + + /* clear pre-shared key from memory */ + explicit_bzero(ic->ic_psk, IEEE80211_PMK_LEN); +} + +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)); } - - /* clear pre-shared key from memory */ - explicit_bzero(ic->ic_psk, IEEE80211_PMK_LEN); } /* Index: sys/net80211/ieee80211_crypto.h =================================================================== RCS file: /cvs/src/sys/net80211/ieee80211_crypto.h,v retrieving revision 1.23 diff -u -p -r1.23 ieee80211_crypto.h --- sys/net80211/ieee80211_crypto.h 5 Dec 2015 16:26:53 -0000 1.23 +++ sys/net80211/ieee80211_crypto.h 29 Aug 2017 21:20:52 -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.103 diff -u -p -r1.103 ieee80211_node.c --- sys/net80211/ieee80211_node.c 21 May 2016 09:07:11 -0000 1.103 +++ sys/net80211/ieee80211_node.c 29 Aug 2017 21:20:52 -0000 @@ -1430,6 +1430,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.60.2.1 diff -u -p -r1.60.2.1 ieee80211_node.h --- sys/net80211/ieee80211_node.h 1 Mar 2017 20:57:51 -0000 1.60.2.1 +++ sys/net80211/ieee80211_node.h 29 Aug 2017 21:20:52 -0000 @@ -291,6 +291,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 */ }; RB_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.25.6.2 diff -u -p -r1.25.6.2 ieee80211_pae_input.c --- sys/net80211/ieee80211_pae_input.c 2 Aug 2017 16:51:38 -0000 1.25.6.2 +++ sys/net80211/ieee80211_pae_input.c 29 Aug 2017 21:20:52 -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.68.2.2 diff -u -p -r1.68.2.2 ieee80211_proto.c --- sys/net80211/ieee80211_proto.c 2 Mar 2017 09:47:32 -0000 1.68.2.2 +++ sys/net80211/ieee80211_proto.c 29 Aug 2017 21:20:52 -0000 @@ -904,6 +904,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; @@ -915,6 +916,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 @@ -958,6 +960,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"));