/* ************************************************************************* * Ralink Tech Inc. * 5F., No.36, Taiyuan St., Jhubei City, * Hsinchu County 302, * Taiwan, R.O.C. * * (c) Copyright 2002-2007, Ralink Technology, Inc. * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * ************************************************************************* Module Name: wpa.c Abstract: Revision History: Who When What -------- ---------- ---------------------------------------------- Jan Lee 03-07-22 Initial Paul Lin 03-11-28 Modify for supplicant */ #include "../rt_config.h" #define WPARSNIE 0xdd #define WPA2RSNIE 0x30 //extern UCHAR BIT8[]; UCHAR CipherWpaPskTkip[] = { 0xDD, 0x16, // RSN IE 0x00, 0x50, 0xf2, 0x01, // oui 0x01, 0x00, // Version 0x00, 0x50, 0xf2, 0x02, // Multicast 0x01, 0x00, // Number of unicast 0x00, 0x50, 0xf2, 0x02, // unicast 0x01, 0x00, // number of authentication method 0x00, 0x50, 0xf2, 0x02 // authentication }; UCHAR CipherWpaPskTkipLen = (sizeof(CipherWpaPskTkip) / sizeof(UCHAR)); UCHAR CipherWpaPskAes[] = { 0xDD, 0x16, // RSN IE 0x00, 0x50, 0xf2, 0x01, // oui 0x01, 0x00, // Version 0x00, 0x50, 0xf2, 0x04, // Multicast 0x01, 0x00, // Number of unicast 0x00, 0x50, 0xf2, 0x04, // unicast 0x01, 0x00, // number of authentication method 0x00, 0x50, 0xf2, 0x02 // authentication }; UCHAR CipherWpaPskAesLen = (sizeof(CipherWpaPskAes) / sizeof(UCHAR)); UCHAR CipherSuiteCiscoCCKM[] = { 0xDD, 0x16, // RSN IE 0x00, 0x50, 0xf2, 0x01, // oui 0x01, 0x00, // Version 0x00, 0x40, 0x96, 0x01, // Multicast 0x01, 0x00, // Number of uicast 0x00, 0x40, 0x96, 0x01, // unicast 0x01, 0x00, // number of authentication method 0x00, 0x40, 0x96, 0x00 // Authentication }; UCHAR CipherSuiteCiscoCCKMLen = (sizeof(CipherSuiteCiscoCCKM) / sizeof(UCHAR)); UCHAR CipherSuiteCiscoCCKM24[] = { 0xDD, 0x18, // RSN IE 0x00, 0x50, 0xf2, 0x01, // oui 0x01, 0x00, // Version 0x00, 0x40, 0x96, 0x01, // Multicast 0x01, 0x00, // Number of uicast 0x00, 0x40, 0x96, 0x01, // unicast 0x01, 0x00, // number of authentication method 0x00, 0x40, 0x96, 0x00, 0x28, 0x00// Authentication }; UCHAR CipherSuiteCiscoCCKM24Len = (sizeof(CipherSuiteCiscoCCKM24) / sizeof(UCHAR)); UCHAR CipherSuiteCCXTkip[] = { 0xDD, 0x16, // RSN IE 0x00, 0x50, 0xf2, 0x01, // oui 0x01, 0x00, // Version 0x00, 0x50, 0xf2, 0x02, // Multicast 0x01, 0x00, // Number of unicast 0x00, 0x50, 0xf2, 0x02, // unicast 0x01, 0x00, // number of authentication method 0x00, 0x50, 0xf2, 0x01 // authentication }; UCHAR CipherSuiteCCXTkipLen = (sizeof(CipherSuiteCCXTkip) / sizeof(UCHAR)); UCHAR CCX_LLC_HDR[] = {0xAA, 0xAA, 0x03, 0x00, 0x40, 0x96, 0x00, 0x02}; UCHAR LLC_NORMAL[] = {0xAA, 0xAA, 0x03, 0x00, 0x00, 0x00}; UCHAR EAPOL_FRAME[] = {0x88, 0x8E}; BOOLEAN CheckRSNIE( IN PRTMP_ADAPTER pAd, IN PUCHAR pData, IN UCHAR DataLen, OUT UCHAR *Offset); void inc_byte_array(UCHAR *counter, int len); /* ======================================================================== Routine Description: Classify WPA EAP message type Arguments: EAPType Value of EAP message type MsgType Internal Message definition for MLME state machine Return Value: TRUE Found appropriate message type FALSE No appropriate message type IRQL = DISPATCH_LEVEL Note: All these constants are defined in wpa.h For supplicant, there is only EAPOL Key message avaliable ======================================================================== */ BOOLEAN WpaMsgTypeSubst( IN UCHAR EAPType, OUT INT *MsgType) { switch (EAPType) { case EAPPacket: *MsgType = MT2_EAPPacket; break; case EAPOLStart: *MsgType = MT2_EAPOLStart; break; case EAPOLLogoff: *MsgType = MT2_EAPOLLogoff; break; case EAPOLKey: *MsgType = MT2_EAPOLKey; break; case EAPOLASFAlert: *MsgType = MT2_EAPOLASFAlert; break; default: return FALSE; } return TRUE; } /* ========================================================================== Description: association state machine init, including state transition and timer init Parameters: S - pointer to the association state machine ========================================================================== */ VOID WpaPskStateMachineInit( IN PRTMP_ADAPTER pAd, IN STATE_MACHINE *S, OUT STATE_MACHINE_FUNC Trans[]) { StateMachineInit(S, Trans, MAX_WPA_PSK_STATE, MAX_WPA_PSK_MSG, (STATE_MACHINE_FUNC)Drop, WPA_PSK_IDLE, WPA_MACHINE_BASE); StateMachineSetAction(S, WPA_PSK_IDLE, MT2_EAPOLKey, (STATE_MACHINE_FUNC)WpaEAPOLKeyAction); } /* ========================================================================== Description: This is state machine function. When receiving EAPOL packets which is for 802.1x key management. Use both in WPA, and WPAPSK case. In this function, further dispatch to different functions according to the received packet. 3 categories are : 1. normal 4-way pairwisekey and 2-way groupkey handshake 2. MIC error (Countermeasures attack) report packet from STA. 3. Request for pairwise/group key update from STA Return: ========================================================================== */ VOID WpaEAPOLKeyAction( IN PRTMP_ADAPTER pAd, IN MLME_QUEUE_ELEM *Elem) { INT MsgType = EAPOL_MSG_INVALID; PKEY_DESCRIPTER pKeyDesc; PHEADER_802_11 pHeader; //red UCHAR ZeroReplay[LEN_KEY_DESC_REPLAY]; UCHAR EapolVr; KEY_INFO peerKeyInfo; DBGPRINT(RT_DEBUG_TRACE, ("-----> WpaEAPOLKeyAction\n")); // Get 802.11 header first pHeader = (PHEADER_802_11) Elem->Msg; // Get EAPoL-Key Descriptor pKeyDesc = (PKEY_DESCRIPTER) &Elem->Msg[(LENGTH_802_11 + LENGTH_802_1_H + LENGTH_EAPOL_H)]; NdisZeroMemory((PUCHAR)&peerKeyInfo, sizeof(peerKeyInfo)); NdisMoveMemory((PUCHAR)&peerKeyInfo, (PUCHAR)&pKeyDesc->KeyInfo, sizeof(KEY_INFO)); *((USHORT *)&peerKeyInfo) = cpu2le16(*((USHORT *)&peerKeyInfo)); // 1. Check EAPOL frame version and type EapolVr = (UCHAR) Elem->Msg[LENGTH_802_11+LENGTH_802_1_H]; if (((EapolVr != EAPOL_VER) && (EapolVr != EAPOL_VER2)) || ((pKeyDesc->Type != WPA1_KEY_DESC) && (pKeyDesc->Type != WPA2_KEY_DESC))) { DBGPRINT(RT_DEBUG_ERROR, ("Key descripter does not match with WPA rule\n")); return; } // First validate replay counter, only accept message with larger replay counter // Let equal pass, some AP start with all zero replay counter NdisZeroMemory(ZeroReplay, LEN_KEY_DESC_REPLAY); if((RTMPCompareMemory(pKeyDesc->ReplayCounter, pAd->StaCfg.ReplayCounter, LEN_KEY_DESC_REPLAY) != 1) && (RTMPCompareMemory(pKeyDesc->ReplayCounter, ZeroReplay, LEN_KEY_DESC_REPLAY) != 0)) { DBGPRINT(RT_DEBUG_ERROR, (" ReplayCounter not match \n")); return; } // Process WPA2PSK frame if(pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK) { if((peerKeyInfo.KeyType == PAIRWISEKEY) && (peerKeyInfo.EKD_DL == 0) && (peerKeyInfo.KeyAck == 1) && (peerKeyInfo.KeyMic == 0) && (peerKeyInfo.Secure == 0) && (peerKeyInfo.Error == 0) && (peerKeyInfo.Request == 0)) { MsgType = EAPOL_PAIR_MSG_1; DBGPRINT(RT_DEBUG_TRACE, ("Receive EAPOL Key Pairwise Message 1\n")); } else if((peerKeyInfo.KeyType == PAIRWISEKEY) && (peerKeyInfo.EKD_DL == 1) && (peerKeyInfo.KeyAck == 1) && (peerKeyInfo.KeyMic == 1) && (peerKeyInfo.Secure == 1) && (peerKeyInfo.Error == 0) && (peerKeyInfo.Request == 0)) { MsgType = EAPOL_PAIR_MSG_3; DBGPRINT(RT_DEBUG_TRACE, ("Receive EAPOL Key Pairwise Message 3\n")); } else if((peerKeyInfo.KeyType == GROUPKEY) && (peerKeyInfo.EKD_DL == 1) && (peerKeyInfo.KeyAck == 1) && (peerKeyInfo.KeyMic == 1) && (peerKeyInfo.Secure == 1) && (peerKeyInfo.Error == 0) && (peerKeyInfo.Request == 0)) { MsgType = EAPOL_GROUP_MSG_1; DBGPRINT(RT_DEBUG_TRACE, ("Receive EAPOL Key Group Message 1\n")); } // We will assume link is up (assoc suceess and port not secured). // All state has to be able to process message from previous state switch(pAd->StaCfg.WpaState) { case SS_START: if(MsgType == EAPOL_PAIR_MSG_1) { Wpa2PairMsg1Action(pAd, Elem); pAd->StaCfg.WpaState = SS_WAIT_MSG_3; } break; case SS_WAIT_MSG_3: if(MsgType == EAPOL_PAIR_MSG_1) { Wpa2PairMsg1Action(pAd, Elem); pAd->StaCfg.WpaState = SS_WAIT_MSG_3; } else if(MsgType == EAPOL_PAIR_MSG_3) { Wpa2PairMsg3Action(pAd, Elem); pAd->StaCfg.WpaState = SS_WAIT_GROUP; } break; case SS_WAIT_GROUP: // When doing group key exchange case SS_FINISH: // This happened when update group key if(MsgType == EAPOL_PAIR_MSG_1) { // Reset port secured variable pAd->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED; Wpa2PairMsg1Action(pAd, Elem); pAd->StaCfg.WpaState = SS_WAIT_MSG_3; } else if(MsgType == EAPOL_PAIR_MSG_3) { // Reset port secured variable pAd->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED; Wpa2PairMsg3Action(pAd, Elem); pAd->StaCfg.WpaState = SS_WAIT_GROUP; } else if(MsgType == EAPOL_GROUP_MSG_1) { WpaGroupMsg1Action(pAd, Elem); pAd->StaCfg.WpaState = SS_FINISH; } break; default: break; } } // Process WPAPSK Frame // Classify message Type, either pairwise message 1, 3, or group message 1 for supplicant else if(pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK) { if((peerKeyInfo.KeyType == PAIRWISEKEY) && (peerKeyInfo.KeyIndex == 0) && (peerKeyInfo.KeyAck == 1) && (peerKeyInfo.KeyMic == 0) && (peerKeyInfo.Secure == 0) && (peerKeyInfo.Error == 0) && (peerKeyInfo.Request == 0)) { MsgType = EAPOL_PAIR_MSG_1; DBGPRINT(RT_DEBUG_TRACE, ("Receive EAPOL Key Pairwise Message 1\n")); } else if((peerKeyInfo.KeyType == PAIRWISEKEY) && (peerKeyInfo.KeyIndex == 0) && (peerKeyInfo.KeyAck == 1) && (peerKeyInfo.KeyMic == 1) && (peerKeyInfo.Secure == 0) && (peerKeyInfo.Error == 0) && (peerKeyInfo.Request == 0)) { MsgType = EAPOL_PAIR_MSG_3; DBGPRINT(RT_DEBUG_TRACE, ("Receive EAPOL Key Pairwise Message 3\n")); } else if((peerKeyInfo.KeyType == GROUPKEY) && (peerKeyInfo.KeyIndex != 0) && (peerKeyInfo.KeyAck == 1) && (peerKeyInfo.KeyMic == 1) && (peerKeyInfo.Secure == 1) && (peerKeyInfo.Error == 0) && (peerKeyInfo.Request == 0)) { MsgType = EAPOL_GROUP_MSG_1; DBGPRINT(RT_DEBUG_TRACE, ("Receive EAPOL Key Group Message 1\n")); } // We will assume link is up (assoc suceess and port not secured). // All state has to be able to process message from previous state switch(pAd->StaCfg.WpaState) { case SS_START: if(MsgType == EAPOL_PAIR_MSG_1) { WpaPairMsg1Action(pAd, Elem); pAd->StaCfg.WpaState = SS_WAIT_MSG_3; } break; case SS_WAIT_MSG_3: if(MsgType == EAPOL_PAIR_MSG_1) { WpaPairMsg1Action(pAd, Elem); pAd->StaCfg.WpaState = SS_WAIT_MSG_3; } else if(MsgType == EAPOL_PAIR_MSG_3) { WpaPairMsg3Action(pAd, Elem); pAd->StaCfg.WpaState = SS_WAIT_GROUP; } break; case SS_WAIT_GROUP: // When doing group key exchange case SS_FINISH: // This happened when update group key if(MsgType == EAPOL_PAIR_MSG_1) { WpaPairMsg1Action(pAd, Elem); pAd->StaCfg.WpaState = SS_WAIT_MSG_3; // Reset port secured variable pAd->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED; } else if(MsgType == EAPOL_PAIR_MSG_3) { WpaPairMsg3Action(pAd, Elem); pAd->StaCfg.WpaState = SS_WAIT_GROUP; // Reset port secured variable pAd->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED; } else if(MsgType == EAPOL_GROUP_MSG_1) { WpaGroupMsg1Action(pAd, Elem); pAd->StaCfg.WpaState = SS_FINISH; } break; default: break; } } DBGPRINT(RT_DEBUG_TRACE, ("<----- WpaEAPOLKeyAction\n")); } /* ======================================================================== Routine Description: Process Pairwise key 4-way handshaking Arguments: pAd Pointer to our adapter Elem Message body Return Value: None Note: ======================================================================== */ VOID WpaPairMsg1Action( IN PRTMP_ADAPTER pAd, IN MLME_QUEUE_ELEM *Elem) { PHEADER_802_11 pHeader; UCHAR *mpool, *PTK, *digest; PUCHAR pOutBuffer = NULL; UCHAR Header802_3[14]; ULONG FrameLen = 0; PEAPOL_PACKET pMsg1; EAPOL_PACKET Packet; UCHAR Mic[16]; DBGPRINT(RT_DEBUG_TRACE, ("WpaPairMsg1Action ----->\n")); // allocate memory pool os_alloc_mem(pAd, (PUCHAR *)&mpool, 256); if (mpool == NULL) return; // PTK Len = 80. PTK = (UCHAR *) ROUND_UP(mpool, 4); // digest Len = 80. digest = (UCHAR *) ROUND_UP(PTK + 80, 4); pHeader = (PHEADER_802_11) Elem->Msg; // Process message 1 from authenticator pMsg1 = (PEAPOL_PACKET) &Elem->Msg[LENGTH_802_11 + LENGTH_802_1_H]; // 1. Save Replay counter, it will use to verify message 3 and construct message 2 NdisMoveMemory(pAd->StaCfg.ReplayCounter, pMsg1->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY); // 2. Save ANonce NdisMoveMemory(pAd->StaCfg.ANonce, pMsg1->KeyDesc.KeyNonce, LEN_KEY_DESC_NONCE); // Generate random SNonce GenRandom(pAd, pAd->CurrentAddress, pAd->StaCfg.SNonce); // Calc PTK(ANonce, SNonce) WpaCountPTK(pAd, pAd->StaCfg.PMK, pAd->StaCfg.ANonce, pAd->CommonCfg.Bssid, pAd->StaCfg.SNonce, pAd->CurrentAddress, PTK, LEN_PTK); // Save key to PTK entry NdisMoveMemory(pAd->StaCfg.PTK, PTK, LEN_PTK); // init 802.3 header and Fill Packet MAKE_802_3_HEADER(Header802_3, pAd->CommonCfg.Bssid, pAd->CurrentAddress, EAPOL); // Zero Message 2 body NdisZeroMemory(&Packet, sizeof(Packet)); Packet.ProVer = EAPOL_VER; Packet.ProType = EAPOLKey; // // Message 2 as EAPOL-Key(0,1,0,0,0,P,0,SNonce,MIC,RSN IE) // Packet.KeyDesc.Type = WPA1_KEY_DESC; // 1. Key descriptor version and appropriate RSN IE if(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) { Packet.KeyDesc.KeyInfo.KeyDescVer = 2; } else // TKIP { Packet.KeyDesc.KeyInfo.KeyDescVer = 1; } // fill in Data Material and its length Packet.KeyDesc.KeyData[0] = IE_WPA; Packet.KeyDesc.KeyData[1] = pAd->StaCfg.RSNIE_Len; Packet.KeyDesc.KeyDataLen[1] = pAd->StaCfg.RSNIE_Len + 2; NdisMoveMemory(&Packet.KeyDesc.KeyData[2], pAd->StaCfg.RSN_IE, pAd->StaCfg.RSNIE_Len); // Update packet length after decide Key data payload Packet.Body_Len[1] = sizeof(KEY_DESCRIPTER) - MAX_LEN_OF_RSNIE + Packet.KeyDesc.KeyDataLen[1]; // Update Key length Packet.KeyDesc.KeyLength[0] = pMsg1->KeyDesc.KeyLength[0]; Packet.KeyDesc.KeyLength[1] = pMsg1->KeyDesc.KeyLength[1]; // 2. Key Type PeerKey Packet.KeyDesc.KeyInfo.KeyType = PAIRWISEKEY; // 3. KeyMic field presented Packet.KeyDesc.KeyInfo.KeyMic = 1; //Convert to little-endian format. *((USHORT *)&Packet.KeyDesc.KeyInfo) = cpu2le16(*((USHORT *)&Packet.KeyDesc.KeyInfo)); // 4. Fill SNonce NdisMoveMemory(Packet.KeyDesc.KeyNonce, pAd->StaCfg.SNonce, LEN_KEY_DESC_NONCE); // 5. Key Replay Count NdisMoveMemory(Packet.KeyDesc.ReplayCounter, pAd->StaCfg.ReplayCounter, LEN_KEY_DESC_REPLAY); // Send EAPOL(0, 1, 0, 0, 0, P, 0, SNonce, MIC, RSN_IE) // Out buffer for transmitting message 2 MlmeAllocateMemory(pAd, (PUCHAR *)&pOutBuffer); // allocate memory if(pOutBuffer == NULL) { os_free_mem(pAd, mpool); return; } // Prepare EAPOL frame for MIC calculation // Be careful, only EAPOL frame is counted for MIC calculation MakeOutgoingFrame(pOutBuffer, &FrameLen, Packet.Body_Len[1] + 4, &Packet, END_OF_ARGS); // 6. Prepare and Fill MIC value NdisZeroMemory(Mic, sizeof(Mic)); if(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) { // AES HMAC_SHA1(pOutBuffer, FrameLen, PTK, LEN_EAP_MICK, digest); NdisMoveMemory(Mic, digest, LEN_KEY_DESC_MIC); } else { // TKIP hmac_md5(PTK, LEN_EAP_MICK, pOutBuffer, FrameLen, Mic); } NdisMoveMemory(Packet.KeyDesc.KeyMic, Mic, LEN_KEY_DESC_MIC); //hex_dump("MIC", Mic, LEN_KEY_DESC_MIC); MakeOutgoingFrame(pOutBuffer, &FrameLen, LENGTH_802_3, &Header802_3, Packet.Body_Len[1] + 4, &Packet, END_OF_ARGS); // 5. Copy frame to Tx ring and send Msg 2 to authenticator RTMPToWirelessSta(pAd, Header802_3, LENGTH_802_3, (PUCHAR)&Packet, Packet.Body_Len[1] + 4, TRUE); MlmeFreeMemory(pAd, (PUCHAR)pOutBuffer); os_free_mem(pAd, (PUCHAR)mpool); DBGPRINT(RT_DEBUG_TRACE, ("WpaPairMsg1Action <-----\n")); } VOID Wpa2PairMsg1Action( IN PRTMP_ADAPTER pAd, IN MLME_QUEUE_ELEM *Elem) { PHEADER_802_11 pHeader; UCHAR *mpool, *PTK, *digest; PUCHAR pOutBuffer = NULL; UCHAR Header802_3[14]; ULONG FrameLen = 0; PEAPOL_PACKET pMsg1; EAPOL_PACKET Packet; UCHAR Mic[16]; DBGPRINT(RT_DEBUG_TRACE, ("Wpa2PairMsg1Action ----->\n")); // allocate memory pool os_alloc_mem(pAd, (PUCHAR *)&mpool, 256); if (mpool == NULL) return; // PTK Len = 80. PTK = (UCHAR *) ROUND_UP(mpool, 4); // digest Len = 80. digest = (UCHAR *) ROUND_UP(PTK + 80, 4); pHeader = (PHEADER_802_11) Elem->Msg; // Process message 1 from authenticator pMsg1 = (PEAPOL_PACKET) &Elem->Msg[LENGTH_802_11 + LENGTH_802_1_H]; // 1. Save Replay counter, it will use to verify message 3 and construct message 2 NdisMoveMemory(pAd->StaCfg.ReplayCounter, pMsg1->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY); // 2. Save ANonce NdisMoveMemory(pAd->StaCfg.ANonce, pMsg1->KeyDesc.KeyNonce, LEN_KEY_DESC_NONCE); // Generate random SNonce GenRandom(pAd, pAd->CurrentAddress, pAd->StaCfg.SNonce); if(pMsg1->KeyDesc.KeyDataLen[1] > 0 ) { // cached PMKID } // Calc PTK(ANonce, SNonce) WpaCountPTK(pAd, pAd->StaCfg.PMK, pAd->StaCfg.ANonce, pAd->CommonCfg.Bssid, pAd->StaCfg.SNonce, pAd->CurrentAddress, PTK, LEN_PTK); // Save key to PTK entry NdisMoveMemory(pAd->StaCfg.PTK, PTK, LEN_PTK); // init 802.3 header and Fill Packet MAKE_802_3_HEADER(Header802_3, pAd->CommonCfg.Bssid, pAd->CurrentAddress, EAPOL); // Zero message 2 body NdisZeroMemory(&Packet, sizeof(Packet)); Packet.ProVer = EAPOL_VER; Packet.ProType = EAPOLKey; // // Message 2 as EAPOL-Key(0,1,0,0,0,P,0,SNonce,MIC,RSN IE) // Packet.KeyDesc.Type = WPA2_KEY_DESC; // 1. Key descriptor version and appropriate RSN IE if(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) { Packet.KeyDesc.KeyInfo.KeyDescVer = 2; } else // TKIP { Packet.KeyDesc.KeyInfo.KeyDescVer = 1; } // fill in Data Material and its length Packet.KeyDesc.KeyData[0] = IE_WPA2; Packet.KeyDesc.KeyData[1] = pAd->StaCfg.RSNIE_Len; Packet.KeyDesc.KeyDataLen[1] = pAd->StaCfg.RSNIE_Len + 2; NdisMoveMemory(&Packet.KeyDesc.KeyData[2], pAd->StaCfg.RSN_IE, pAd->StaCfg.RSNIE_Len); // Update packet length after decide Key data payload Packet.Body_Len[1] = sizeof(KEY_DESCRIPTER) - MAX_LEN_OF_RSNIE + Packet.KeyDesc.KeyDataLen[1]; // 2. Key Type PeerKey Packet.KeyDesc.KeyInfo.KeyType = PAIRWISEKEY; // 3. KeyMic field presented Packet.KeyDesc.KeyInfo.KeyMic = 1; // Update Key Length Packet.KeyDesc.KeyLength[0] = 0; Packet.KeyDesc.KeyLength[1] = pMsg1->KeyDesc.KeyLength[1]; // 4. Fill SNonce NdisMoveMemory(Packet.KeyDesc.KeyNonce, pAd->StaCfg.SNonce, LEN_KEY_DESC_NONCE); // 5. Key Replay Count NdisMoveMemory(Packet.KeyDesc.ReplayCounter, pAd->StaCfg.ReplayCounter, LEN_KEY_DESC_REPLAY); // Convert to little-endian format. *((USHORT *)&Packet.KeyDesc.KeyInfo) = cpu2le16(*((USHORT *)&Packet.KeyDesc.KeyInfo)); // Send EAPOL-Key(0,1,0,0,0,P,0,SNonce,MIC,RSN IE) // Out buffer for transmitting message 2 MlmeAllocateMemory(pAd, (PUCHAR *)&pOutBuffer); // allocate memory if(pOutBuffer == NULL) { os_free_mem(pAd, mpool); return; } // Prepare EAPOL frame for MIC calculation // Be careful, only EAPOL frame is counted for MIC calculation MakeOutgoingFrame(pOutBuffer, &FrameLen, Packet.Body_Len[1] + 4, &Packet, END_OF_ARGS); // 6. Prepare and Fill MIC value NdisZeroMemory(Mic, sizeof(Mic)); if(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) { // AES HMAC_SHA1(pOutBuffer, FrameLen, PTK, LEN_EAP_MICK, digest); NdisMoveMemory(Mic, digest, LEN_KEY_DESC_MIC); } else { hmac_md5(PTK, LEN_EAP_MICK, pOutBuffer, FrameLen, Mic); } NdisMoveMemory(Packet.KeyDesc.KeyMic, Mic, LEN_KEY_DESC_MIC); // Make Transmitting frame MakeOutgoingFrame(pOutBuffer, &FrameLen, LENGTH_802_3, &Header802_3, Packet.Body_Len[1] + 4, &Packet, END_OF_ARGS); // 5. Copy frame to Tx ring RTMPToWirelessSta(pAd, Header802_3, LENGTH_802_3, (PUCHAR)&Packet, Packet.Body_Len[1] + 4, TRUE); MlmeFreeMemory(pAd, pOutBuffer); os_free_mem(pAd, mpool); DBGPRINT(RT_DEBUG_TRACE, ("Wpa2PairMsg1Action <-----\n")); } /* ======================================================================== Routine Description: Process Pairwise key 4-way handshaking Arguments: pAd Pointer to our adapter Elem Message body Return Value: None Note: ======================================================================== */ VOID WpaPairMsg3Action( IN PRTMP_ADAPTER pAd, IN MLME_QUEUE_ELEM *Elem) { PHEADER_802_11 pHeader; PUCHAR pOutBuffer = NULL; UCHAR Header802_3[14]; ULONG FrameLen = 0; EAPOL_PACKET Packet; PEAPOL_PACKET pMsg3; UCHAR Mic[16], OldMic[16]; MAC_TABLE_ENTRY *pEntry = NULL; UCHAR skip_offset; KEY_INFO peerKeyInfo; DBGPRINT(RT_DEBUG_TRACE, ("WpaPairMsg3Action ----->\n")); // Record 802.11 header & the received EAPOL packet Msg3 pHeader = (PHEADER_802_11) Elem->Msg; pMsg3 = (PEAPOL_PACKET) &Elem->Msg[LENGTH_802_11 + LENGTH_802_1_H]; NdisZeroMemory((PUCHAR)&peerKeyInfo, sizeof(peerKeyInfo)); NdisMoveMemory((PUCHAR)&peerKeyInfo, (PUCHAR)&pMsg3->KeyDesc.KeyInfo, sizeof(KEY_INFO)); *((USHORT*)&peerKeyInfo) = cpu2le16(*((USHORT*)&peerKeyInfo)); // 1. Verify cipher type match if (pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled && (peerKeyInfo.KeyDescVer != 2)) { return; } else if(pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled && (peerKeyInfo.KeyDescVer != 1)) { return; } // Verify RSN IE //if (!RTMPEqualMemory(pMsg3->KeyDesc.KeyData, pAd->MacTab.Content[BSSID_WCID].RSN_IE, pAd->MacTab.Content[BSSID_WCID].RSNIE_Len)) if (!CheckRSNIE(pAd, pMsg3->KeyDesc.KeyData, pMsg3->KeyDesc.KeyDataLen[1], &skip_offset)) { DBGPRINT(RT_DEBUG_ERROR, ("RSN_IE Different in Msg 3 of WPA1 4-way handshake!! \n")); hex_dump("The original RSN_IE", pAd->MacTab.Content[BSSID_WCID].RSN_IE, pAd->MacTab.Content[BSSID_WCID].RSNIE_Len); hex_dump("The received RSN_IE", pMsg3->KeyDesc.KeyData, pMsg3->KeyDesc.KeyDataLen[1]); return; } else DBGPRINT(RT_DEBUG_TRACE, ("RSN_IE VALID in Msg 3 of WPA1 4-way handshake!! \n")); // 2. Check MIC value // Save the MIC and replace with zero NdisMoveMemory(OldMic, pMsg3->KeyDesc.KeyMic, LEN_KEY_DESC_MIC); NdisZeroMemory(pMsg3->KeyDesc.KeyMic, LEN_KEY_DESC_MIC); if(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) { // AES UCHAR digest[80]; HMAC_SHA1((PUCHAR) pMsg3, pMsg3->Body_Len[1] + 4, pAd->StaCfg.PTK, LEN_EAP_MICK, digest); NdisMoveMemory(Mic, digest, LEN_KEY_DESC_MIC); } else // TKIP { hmac_md5(pAd->StaCfg.PTK, LEN_EAP_MICK, (PUCHAR) pMsg3, pMsg3->Body_Len[1] + 4, Mic); } if(!NdisEqualMemory(OldMic, Mic, LEN_KEY_DESC_MIC)) { DBGPRINT(RT_DEBUG_ERROR, (" MIC Different in msg 3 of 4-way handshake!!!!!!!!!! \n")); return; } else DBGPRINT(RT_DEBUG_TRACE, (" MIC VALID in msg 3 of 4-way handshake!!!!!!!!!! \n")); // 3. Check Replay Counter, it has to be larger than last one. No need to be exact one larger if(RTMPCompareMemory(pMsg3->KeyDesc.ReplayCounter, pAd->StaCfg.ReplayCounter, LEN_KEY_DESC_REPLAY) != 1) return; // Update new replay counter NdisMoveMemory(pAd->StaCfg.ReplayCounter, pMsg3->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY); // 4. Double check ANonce if(!NdisEqualMemory(pAd->StaCfg.ANonce, pMsg3->KeyDesc.KeyNonce, LEN_KEY_DESC_NONCE)) return; // init 802.3 header and Fill Packet MAKE_802_3_HEADER(Header802_3, pAd->CommonCfg.Bssid, pAd->CurrentAddress, EAPOL); // Zero Message 4 body NdisZeroMemory(&Packet, sizeof(Packet)); Packet.ProVer = EAPOL_VER; Packet.ProType = EAPOLKey; Packet.Body_Len[1] = sizeof(KEY_DESCRIPTER) - MAX_LEN_OF_RSNIE; // No data field // // Message 4 as EAPOL-Key(0,1,0,0,0,P,0,0,MIC,0) // Packet.KeyDesc.Type = WPA1_KEY_DESC; // Key descriptor version and appropriate RSN IE Packet.KeyDesc.KeyInfo.KeyDescVer = peerKeyInfo.KeyDescVer; // Update Key Length Packet.KeyDesc.KeyLength[0] = pMsg3->KeyDesc.KeyLength[0]; Packet.KeyDesc.KeyLength[1] = pMsg3->KeyDesc.KeyLength[1]; // Key Type PeerKey Packet.KeyDesc.KeyInfo.KeyType = PAIRWISEKEY; // KeyMic field presented Packet.KeyDesc.KeyInfo.KeyMic = 1; // In Msg3, KeyInfo.secure =0 if Group Key HS to come. 1 if no group key HS // Station sends Msg4 KeyInfo.secure should be the same as that in Msg.3 Packet.KeyDesc.KeyInfo.Secure= peerKeyInfo.Secure; // Convert to little-endian format. *((USHORT *)&Packet.KeyDesc.KeyInfo) = cpu2le16(*((USHORT *)&Packet.KeyDesc.KeyInfo)); // Key Replay count NdisMoveMemory(Packet.KeyDesc.ReplayCounter, pMsg3->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY); // Out buffer for transmitting message 4 MlmeAllocateMemory(pAd, (PUCHAR *)&pOutBuffer); // allocate memory if(pOutBuffer == NULL) return; // Prepare EAPOL frame for MIC calculation // Be careful, only EAPOL frame is counted for MIC calculation MakeOutgoingFrame(pOutBuffer, &FrameLen, Packet.Body_Len[1] + 4, &Packet, END_OF_ARGS); // Prepare and Fill MIC value NdisZeroMemory(Mic, sizeof(Mic)); if(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) { // AES UCHAR digest[80]; HMAC_SHA1(pOutBuffer, FrameLen, pAd->StaCfg.PTK, LEN_EAP_MICK, digest); NdisMoveMemory(Mic, digest, LEN_KEY_DESC_MIC); } else { hmac_md5(pAd->StaCfg.PTK, LEN_EAP_MICK, pOutBuffer, FrameLen, Mic); } NdisMoveMemory(Packet.KeyDesc.KeyMic, Mic, LEN_KEY_DESC_MIC); // Update PTK // Prepare pair-wise key information into shared key table NdisZeroMemory(&pAd->SharedKey[BSS0][0], sizeof(CIPHER_KEY)); pAd->SharedKey[BSS0][0].KeyLen = LEN_TKIP_EK; NdisMoveMemory(pAd->SharedKey[BSS0][0].Key, &pAd->StaCfg.PTK[32], LEN_TKIP_EK); NdisMoveMemory(pAd->SharedKey[BSS0][0].RxMic, &pAd->StaCfg.PTK[48], LEN_TKIP_RXMICK); NdisMoveMemory(pAd->SharedKey[BSS0][0].TxMic, &pAd->StaCfg.PTK[48+LEN_TKIP_RXMICK], LEN_TKIP_TXMICK); // Decide its ChiperAlg if (pAd->StaCfg.PairCipher == Ndis802_11Encryption2Enabled) pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_TKIP; else if (pAd->StaCfg.PairCipher == Ndis802_11Encryption3Enabled) pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_AES; else pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_NONE; // Update these related information to MAC_TABLE_ENTRY pEntry = &pAd->MacTab.Content[BSSID_WCID]; NdisMoveMemory(pEntry->PairwiseKey.Key, &pAd->StaCfg.PTK[32], LEN_TKIP_EK); NdisMoveMemory(pEntry->PairwiseKey.RxMic, &pAd->StaCfg.PTK[48], LEN_TKIP_RXMICK); NdisMoveMemory(pEntry->PairwiseKey.TxMic, &pAd->StaCfg.PTK[48+LEN_TKIP_RXMICK], LEN_TKIP_TXMICK); pEntry->PairwiseKey.CipherAlg = pAd->SharedKey[BSS0][0].CipherAlg; // Update pairwise key information to ASIC Shared Key Table AsicAddSharedKeyEntry(pAd, BSS0, 0, pAd->SharedKey[BSS0][0].CipherAlg, pAd->SharedKey[BSS0][0].Key, pAd->SharedKey[BSS0][0].TxMic, pAd->SharedKey[BSS0][0].RxMic); // Update ASIC WCID attribute table and IVEIV table RTMPAddWcidAttributeEntry(pAd, BSS0, 0, pAd->SharedKey[BSS0][0].CipherAlg, pEntry); // Make transmitting frame MakeOutgoingFrame(pOutBuffer, &FrameLen, LENGTH_802_3, &Header802_3, Packet.Body_Len[1] + 4, &Packet, END_OF_ARGS); // Copy frame to Tx ring and Send Message 4 to authenticator RTMPToWirelessSta(pAd, Header802_3, LENGTH_802_3, (PUCHAR)&Packet, Packet.Body_Len[1] + 4, TRUE); MlmeFreeMemory(pAd, (PUCHAR)pOutBuffer); DBGPRINT(RT_DEBUG_TRACE, ("WpaPairMsg3Action <-----\n")); } VOID Wpa2PairMsg3Action( IN PRTMP_ADAPTER pAd, IN MLME_QUEUE_ELEM *Elem) { PHEADER_802_11 pHeader; PUCHAR pOutBuffer = NULL; UCHAR Header802_3[14]; ULONG FrameLen = 0; EAPOL_PACKET Packet; PEAPOL_PACKET pMsg3; UCHAR Mic[16], OldMic[16]; UCHAR *mpool, *KEYDATA, *digest; UCHAR Key[32]; MAC_TABLE_ENTRY *pEntry = NULL; KEY_INFO peerKeyInfo; // allocate memory os_alloc_mem(pAd, (PUCHAR *)&mpool, 1024); if(mpool == NULL) return; // KEYDATA Len = 512. KEYDATA = (UCHAR *) ROUND_UP(mpool, 4); // digest Len = 80. digest = (UCHAR *) ROUND_UP(KEYDATA + 512, 4); DBGPRINT(RT_DEBUG_TRACE, ("Wpa2PairMsg3Action ----->\n")); pHeader = (PHEADER_802_11) Elem->Msg; // Process message 3 frame. pMsg3 = (PEAPOL_PACKET) &Elem->Msg[LENGTH_802_11 + LENGTH_802_1_H]; NdisZeroMemory((PUCHAR)&peerKeyInfo, sizeof(peerKeyInfo)); NdisMoveMemory((PUCHAR)&peerKeyInfo, (PUCHAR)&pMsg3->KeyDesc.KeyInfo, sizeof(KEY_INFO)); *((USHORT*)&peerKeyInfo) = cpu2le16(*((USHORT*)&peerKeyInfo)); // 1. Verify cipher type match if (pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled && (peerKeyInfo.KeyDescVer!= 2)) { os_free_mem(pAd, (PUCHAR)mpool); return; } else if(pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled && (peerKeyInfo.KeyDescVer != 1)) { os_free_mem(pAd, (PUCHAR)mpool); return; } // 2. Check MIC value // Save the MIC and replace with zero NdisMoveMemory(OldMic, pMsg3->KeyDesc.KeyMic, LEN_KEY_DESC_MIC); NdisZeroMemory(pMsg3->KeyDesc.KeyMic, LEN_KEY_DESC_MIC); if (pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) { // AES HMAC_SHA1((PUCHAR) pMsg3, pMsg3->Body_Len[1] + 4, pAd->StaCfg.PTK, LEN_EAP_MICK, digest); NdisMoveMemory(Mic, digest, LEN_KEY_DESC_MIC); } else { hmac_md5(pAd->StaCfg.PTK, LEN_EAP_MICK, (PUCHAR) pMsg3, pMsg3->Body_Len[1] + 4, Mic); } if(!NdisEqualMemory(OldMic, Mic, LEN_KEY_DESC_MIC)) { DBGPRINT(RT_DEBUG_ERROR, (" MIC Different in msg 3 of 4-way handshake!!!!!!!!!! \n")); os_free_mem(pAd, (PUCHAR)mpool); return; } else DBGPRINT(RT_DEBUG_TRACE, (" MIC VALID in msg 3 of 4-way handshake!!!!!!!!!! \n")); // 3. Check Replay Counter, it has to be larger than last one. No need to be exact one larger if(RTMPCompareMemory(pMsg3->KeyDesc.ReplayCounter, pAd->StaCfg.ReplayCounter, LEN_KEY_DESC_REPLAY) != 1) { os_free_mem(pAd, (PUCHAR)mpool); return; } // Update new replay counter NdisMoveMemory(pAd->StaCfg.ReplayCounter, pMsg3->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY); // 4. Double check ANonce if(!NdisEqualMemory(pAd->StaCfg.ANonce, pMsg3->KeyDesc.KeyNonce, LEN_KEY_DESC_NONCE)) { os_free_mem(pAd, (PUCHAR)mpool); return; } // Obtain GTK // 5. Decrypt GTK from Key Data DBGPRINT_RAW(RT_DEBUG_TRACE, ("EKD = %d\n", peerKeyInfo.EKD_DL)); if(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) { // Decrypt AES GTK AES_GTK_KEY_UNWRAP(&pAd->StaCfg.PTK[16], KEYDATA, pMsg3->KeyDesc.KeyDataLen[1],pMsg3->KeyDesc.KeyData); } else // TKIP { INT i; // Decrypt TKIP GTK // Construct 32 bytes RC4 Key NdisMoveMemory(Key, pMsg3->KeyDesc.KeyIv, 16); NdisMoveMemory(&Key[16], &pAd->StaCfg.PTK[16], 16); ARCFOUR_INIT(&pAd->PrivateInfo.WEPCONTEXT, Key, 32); //discard first 256 bytes for(i = 0; i < 256; i++) ARCFOUR_BYTE(&pAd->PrivateInfo.WEPCONTEXT); // Decrypt GTK. Becareful, there is no ICV to check the result is correct or not ARCFOUR_DECRYPT(&pAd->PrivateInfo.WEPCONTEXT, KEYDATA, pMsg3->KeyDesc.KeyData, pMsg3->KeyDesc.KeyDataLen[1]); } if (!ParseKeyData(pAd, KEYDATA, pMsg3->KeyDesc.KeyDataLen[1], 1)) { os_free_mem(pAd, (PUCHAR)mpool); return; } // Update GTK to ASIC // Update group key information to ASIC Shared Key Table AsicAddSharedKeyEntry(pAd, BSS0, pAd->StaCfg.DefaultKeyId, pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg, pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].Key, pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].TxMic, pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].RxMic); // Update ASIC WCID attribute table and IVEIV table RTMPAddWcidAttributeEntry(pAd, BSS0, pAd->StaCfg.DefaultKeyId, pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg, NULL); // init 802.3 header and Fill Packet MAKE_802_3_HEADER(Header802_3, pAd->CommonCfg.Bssid, pAd->CurrentAddress, EAPOL); // Zero message 4 body NdisZeroMemory(&Packet, sizeof(Packet)); Packet.ProVer = EAPOL_VER; Packet.ProType = EAPOLKey; Packet.Body_Len[1] = sizeof(KEY_DESCRIPTER) - MAX_LEN_OF_RSNIE; // No data field // // Message 4 as EAPOL-Key(0,1,0,0,0,P,0,0,MIC,0) // Packet.KeyDesc.Type = WPA2_KEY_DESC; // Key descriptor version and appropriate RSN IE Packet.KeyDesc.KeyInfo.KeyDescVer = peerKeyInfo.KeyDescVer; // Update Key Length Packet.KeyDesc.KeyLength[0] = pMsg3->KeyDesc.KeyLength[0]; Packet.KeyDesc.KeyLength[1] = pMsg3->KeyDesc.KeyLength[1]; // Key Type PeerKey Packet.KeyDesc.KeyInfo.KeyType = PAIRWISEKEY; // KeyMic field presented Packet.KeyDesc.KeyInfo.KeyMic = 1; Packet.KeyDesc.KeyInfo.Secure = 1; // Convert to little-endian format. *((USHORT *)&Packet.KeyDesc.KeyInfo) = cpu2le16(*((USHORT *)&Packet.KeyDesc.KeyInfo)); // Key Replay count NdisMoveMemory(Packet.KeyDesc.ReplayCounter, pMsg3->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY); // Out buffer for transmitting message 4 MlmeAllocateMemory(pAd, (PUCHAR *)&pOutBuffer); // allocate memory if(pOutBuffer == NULL) { os_free_mem(pAd, (PUCHAR)mpool); return; } // Prepare EAPOL frame for MIC calculation // Be careful, only EAPOL frame is counted for MIC calculation MakeOutgoingFrame(pOutBuffer, &FrameLen, Packet.Body_Len[1] + 4, &Packet, END_OF_ARGS); // Prepare and Fill MIC value NdisZeroMemory(Mic, sizeof(Mic)); if(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) { // AES HMAC_SHA1(pOutBuffer, FrameLen, pAd->StaCfg.PTK, LEN_EAP_MICK, digest); NdisMoveMemory(Mic, digest, LEN_KEY_DESC_MIC); } else { hmac_md5(pAd->StaCfg.PTK, LEN_EAP_MICK, pOutBuffer, FrameLen, Mic); } NdisMoveMemory(Packet.KeyDesc.KeyMic, Mic, LEN_KEY_DESC_MIC); // Update PTK // Prepare pair-wise key information into shared key table NdisZeroMemory(&pAd->SharedKey[BSS0][0], sizeof(CIPHER_KEY)); pAd->SharedKey[BSS0][0].KeyLen = LEN_TKIP_EK; NdisMoveMemory(pAd->SharedKey[BSS0][0].Key, &pAd->StaCfg.PTK[32], LEN_TKIP_EK); NdisMoveMemory(pAd->SharedKey[BSS0][0].RxMic, &pAd->StaCfg.PTK[48], LEN_TKIP_RXMICK); NdisMoveMemory(pAd->SharedKey[BSS0][0].TxMic, &pAd->StaCfg.PTK[48+LEN_TKIP_RXMICK], LEN_TKIP_TXMICK); // Decide its ChiperAlg if (pAd->StaCfg.PairCipher == Ndis802_11Encryption2Enabled) pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_TKIP; else if (pAd->StaCfg.PairCipher == Ndis802_11Encryption3Enabled) pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_AES; else pAd->SharedKey[BSS0][0].CipherAlg = CIPHER_NONE; // Update these related information to MAC_TABLE_ENTRY pEntry = &pAd->MacTab.Content[BSSID_WCID]; NdisMoveMemory(&pEntry->PairwiseKey.Key, &pAd->StaCfg.PTK[32], LEN_TKIP_EK); NdisMoveMemory(&pEntry->PairwiseKey.RxMic, &pAd->StaCfg.PTK[48], LEN_TKIP_RXMICK); NdisMoveMemory(&pEntry->PairwiseKey.TxMic, &pAd->StaCfg.PTK[48+LEN_TKIP_RXMICK], LEN_TKIP_TXMICK); pEntry->PairwiseKey.CipherAlg = pAd->SharedKey[BSS0][0].CipherAlg; // Update pairwise key information to ASIC Shared Key Table AsicAddSharedKeyEntry(pAd, BSS0, 0, pAd->SharedKey[BSS0][0].CipherAlg, pAd->SharedKey[BSS0][0].Key, pAd->SharedKey[BSS0][0].TxMic, pAd->SharedKey[BSS0][0].RxMic); // Update ASIC WCID attribute table and IVEIV table RTMPAddWcidAttributeEntry(pAd, BSS0, 0, pAd->SharedKey[BSS0][0].CipherAlg, pEntry); // Make Transmitting frame MakeOutgoingFrame(pOutBuffer, &FrameLen, LENGTH_802_3, &Header802_3, Packet.Body_Len[1] + 4, &Packet, END_OF_ARGS); // Copy frame to Tx ring and Send Message 4 to authenticator RTMPToWirelessSta(pAd, Header802_3, LENGTH_802_3, (PUCHAR)&Packet, Packet.Body_Len[1] + 4, TRUE); // set 802.1x port control //pAd->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; STA_PORT_SECURED(pAd); // Indicate Connected for GUI pAd->IndicateMediaState = NdisMediaStateConnected; MlmeFreeMemory(pAd, (PUCHAR)pOutBuffer); os_free_mem(pAd, (PUCHAR)mpool); // send wireless event - for set key done WPA2 if (pAd->CommonCfg.bWirelessEvent) RTMPSendWirelessEvent(pAd, IW_SET_KEY_DONE_WPA2_EVENT_FLAG, pEntry->Addr, BSS0, 0); DBGPRINT(RT_DEBUG_ERROR, ("Wpa2PairMsg3Action <-----\n")); } /* ======================================================================== Routine Description: Process Group key 2-way handshaking Arguments: pAd Pointer to our adapter Elem Message body Return Value: None Note: ======================================================================== */ VOID WpaGroupMsg1Action( IN PRTMP_ADAPTER pAd, IN MLME_QUEUE_ELEM *Elem) { PUCHAR pOutBuffer = NULL; UCHAR Header802_3[14]; ULONG FrameLen = 0; EAPOL_PACKET Packet; PEAPOL_PACKET pGroup; UCHAR *mpool, *digest, *KEYDATA; UCHAR Mic[16], OldMic[16]; UCHAR GTK[32], Key[32]; KEY_INFO peerKeyInfo; // allocate memory os_alloc_mem(pAd, (PUCHAR *)&mpool, 1024); if(mpool == NULL) return; // digest Len = 80. digest = (UCHAR *) ROUND_UP(mpool, 4); // KEYDATA Len = 512. KEYDATA = (UCHAR *) ROUND_UP(digest + 80, 4); DBGPRINT(RT_DEBUG_TRACE, ("WpaGroupMsg1Action ----->\n")); // Process Group Message 1 frame. skip 802.11 header(24) & LLC_SNAP header(8) pGroup = (PEAPOL_PACKET) &Elem->Msg[LENGTH_802_11 + LENGTH_802_1_H]; NdisZeroMemory((PUCHAR)&peerKeyInfo, sizeof(peerKeyInfo)); NdisMoveMemory((PUCHAR)&peerKeyInfo, (PUCHAR)&pGroup->KeyDesc.KeyInfo, sizeof(KEY_INFO)); *((USHORT*)&peerKeyInfo) = cpu2le16(*((USHORT*)&peerKeyInfo)); // 0. Check cipher type match if (pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled && (peerKeyInfo.KeyDescVer != 2)) { os_free_mem(pAd, (PUCHAR)mpool); return; } else if (pAd->StaCfg.WepStatus == Ndis802_11Encryption2Enabled && (peerKeyInfo.KeyDescVer != 1)) { os_free_mem(pAd, (PUCHAR)mpool); return; } // 1. Verify Replay counter // Check Replay Counter, it has to be larger than last one. No need to be exact one larger if(RTMPCompareMemory(pGroup->KeyDesc.ReplayCounter, pAd->StaCfg.ReplayCounter, LEN_KEY_DESC_REPLAY) != 1) { os_free_mem(pAd, (PUCHAR)mpool); return; } // Update new replay counter NdisMoveMemory(pAd->StaCfg.ReplayCounter, pGroup->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY); // 2. Verify MIC is valid // Save the MIC and replace with zero NdisMoveMemory(OldMic, pGroup->KeyDesc.KeyMic, LEN_KEY_DESC_MIC); NdisZeroMemory(pGroup->KeyDesc.KeyMic, LEN_KEY_DESC_MIC); if(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) { // AES HMAC_SHA1((PUCHAR) pGroup, pGroup->Body_Len[1] + 4, pAd->StaCfg.PTK, LEN_EAP_MICK, digest); NdisMoveMemory(Mic, digest, LEN_KEY_DESC_MIC); } else { // TKIP hmac_md5(pAd->StaCfg.PTK, LEN_EAP_MICK, (PUCHAR) pGroup, pGroup->Body_Len[1] + 4, Mic); } if(!NdisEqualMemory(OldMic, Mic, LEN_KEY_DESC_MIC)) { DBGPRINT(RT_DEBUG_ERROR, (" MIC Different in group msg 1 of 2-way handshake!!!!!!!!!! \n")); MlmeFreeMemory(pAd, (PUCHAR)mpool); return; } else DBGPRINT(RT_DEBUG_TRACE, (" MIC VALID in group msg 1 of 2-way handshake!!!!!!!!!! \n")); // 3. Decrypt GTK from Key Data if (pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) { // Decrypt AES GTK AES_GTK_KEY_UNWRAP(&pAd->StaCfg.PTK[16], KEYDATA, pGroup->KeyDesc.KeyDataLen[1], pGroup->KeyDesc.KeyData); } else // TKIP { INT i; // Decrypt TKIP GTK // Construct 32 bytes RC4 Key NdisMoveMemory(Key, pGroup->KeyDesc.KeyIv, 16); NdisMoveMemory(&Key[16], &pAd->StaCfg.PTK[16], 16); ARCFOUR_INIT(&pAd->PrivateInfo.WEPCONTEXT, Key, 32); //discard first 256 bytes for(i = 0; i < 256; i++) ARCFOUR_BYTE(&pAd->PrivateInfo.WEPCONTEXT); // Decrypt GTK. Becareful, there is no ICV to check the result is correct or not ARCFOUR_DECRYPT(&pAd->PrivateInfo.WEPCONTEXT, KEYDATA, pGroup->KeyDesc.KeyData, pGroup->KeyDesc.KeyDataLen[1]); } // Process decrypted key data material // Parse keyData to handle KDE format for WPA2PSK if (peerKeyInfo.EKD_DL) { if (!ParseKeyData(pAd, KEYDATA, pGroup->KeyDesc.KeyDataLen[1], 0)) { os_free_mem(pAd, (PUCHAR)mpool); return; } } else // WPAPSK { // set key material, TxMic and RxMic for WPAPSK NdisMoveMemory(GTK, KEYDATA, 32); NdisMoveMemory(pAd->StaCfg.GTK, GTK, 32); pAd->StaCfg.DefaultKeyId = peerKeyInfo.KeyIndex; // Prepare pair-wise key information into shared key table NdisZeroMemory(&pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId], sizeof(CIPHER_KEY)); pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].KeyLen = LEN_TKIP_EK; NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].Key, GTK, LEN_TKIP_EK); NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].RxMic, >K[16], LEN_TKIP_RXMICK); NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].TxMic, >K[24], LEN_TKIP_TXMICK); // Update Shared Key CipherAlg pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_NONE; if (pAd->StaCfg.GroupCipher == Ndis802_11Encryption2Enabled) pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_TKIP; else if (pAd->StaCfg.GroupCipher == Ndis802_11Encryption3Enabled) pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_AES; //hex_dump("Group Key :", pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].Key, LEN_TKIP_EK); } // Update group key information to ASIC Shared Key Table AsicAddSharedKeyEntry(pAd, BSS0, pAd->StaCfg.DefaultKeyId, pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg, pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].Key, pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].TxMic, pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].RxMic); // Update ASIC WCID attribute table and IVEIV table RTMPAddWcidAttributeEntry(pAd, BSS0, pAd->StaCfg.DefaultKeyId, pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg, NULL); // set 802.1x port control //pAd->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED; STA_PORT_SECURED(pAd); // Indicate Connected for GUI pAd->IndicateMediaState = NdisMediaStateConnected; // init header and Fill Packet MAKE_802_3_HEADER(Header802_3, pAd->CommonCfg.Bssid, pAd->CurrentAddress, EAPOL); // Zero Group message 1 body NdisZeroMemory(&Packet, sizeof(Packet)); Packet.ProVer = EAPOL_VER; Packet.ProType = EAPOLKey; Packet.Body_Len[1] = sizeof(KEY_DESCRIPTER) - MAX_LEN_OF_RSNIE; // No data field // // Group Message 2 as EAPOL-Key(1,0,0,0,G,0,0,MIC,0) // if (pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK) { Packet.KeyDesc.Type = WPA2_KEY_DESC; } else { Packet.KeyDesc.Type = WPA1_KEY_DESC; } // Key descriptor version and appropriate RSN IE Packet.KeyDesc.KeyInfo.KeyDescVer = peerKeyInfo.KeyDescVer; // Update Key Length Packet.KeyDesc.KeyLength[0] = pGroup->KeyDesc.KeyLength[0]; Packet.KeyDesc.KeyLength[1] = pGroup->KeyDesc.KeyLength[1]; // Key Index as G-Msg 1 if(pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK) Packet.KeyDesc.KeyInfo.KeyIndex = peerKeyInfo.KeyIndex; // Key Type Group key Packet.KeyDesc.KeyInfo.KeyType = GROUPKEY; // KeyMic field presented Packet.KeyDesc.KeyInfo.KeyMic = 1; // Secure bit Packet.KeyDesc.KeyInfo.Secure = 1; // Convert to little-endian format. *((USHORT *)&Packet.KeyDesc.KeyInfo) = cpu2le16(*((USHORT *)&Packet.KeyDesc.KeyInfo)); // Key Replay count NdisMoveMemory(Packet.KeyDesc.ReplayCounter, pGroup->KeyDesc.ReplayCounter, LEN_KEY_DESC_REPLAY); // Out buffer for transmitting group message 2 MlmeAllocateMemory(pAd, (PUCHAR *)&pOutBuffer); // allocate memory if(pOutBuffer == NULL) { MlmeFreeMemory(pAd, (PUCHAR)mpool); return; } // Prepare EAPOL frame for MIC calculation // Be careful, only EAPOL frame is counted for MIC calculation MakeOutgoingFrame(pOutBuffer, &FrameLen, Packet.Body_Len[1] + 4, &Packet, END_OF_ARGS); // Prepare and Fill MIC value NdisZeroMemory(Mic, sizeof(Mic)); if(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) { // AES HMAC_SHA1(pOutBuffer, FrameLen, pAd->StaCfg.PTK, LEN_EAP_MICK, digest); NdisMoveMemory(Mic, digest, LEN_KEY_DESC_MIC); } else { hmac_md5(pAd->StaCfg.PTK, LEN_EAP_MICK, pOutBuffer, FrameLen, Mic); } NdisMoveMemory(Packet.KeyDesc.KeyMic, Mic, LEN_KEY_DESC_MIC); MakeOutgoingFrame(pOutBuffer, &FrameLen, LENGTH_802_3, &Header802_3, Packet.Body_Len[1] + 4, &Packet, END_OF_ARGS); // 5. Copy frame to Tx ring and prepare for encryption RTMPToWirelessSta(pAd, Header802_3, LENGTH_802_3, (PUCHAR)&Packet, Packet.Body_Len[1] + 4, FALSE); // 6 Free allocated memory MlmeFreeMemory(pAd, (PUCHAR)pOutBuffer); os_free_mem(pAd, (PUCHAR)mpool); // send wireless event - for set key done WPA2 if (pAd->CommonCfg.bWirelessEvent) RTMPSendWirelessEvent(pAd, IW_SET_KEY_DONE_WPA2_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0); DBGPRINT(RT_DEBUG_TRACE, ("WpaGroupMsg1Action <-----\n")); } /* ======================================================================== Routine Description: Init WPA MAC header Arguments: pAd Pointer to our adapter Return Value: None Note: ======================================================================== */ VOID WpaMacHeaderInit( IN PRTMP_ADAPTER pAd, IN OUT PHEADER_802_11 pHdr80211, IN UCHAR wep, IN PUCHAR pAddr1) { NdisZeroMemory(pHdr80211, sizeof(HEADER_802_11)); pHdr80211->FC.Type = BTYPE_DATA; pHdr80211->FC.ToDs = 1; if (wep == 1) pHdr80211->FC.Wep = 1; // Addr1: BSSID, Addr2: SA, Addr3: DA COPY_MAC_ADDR(pHdr80211->Addr1, pAddr1); COPY_MAC_ADDR(pHdr80211->Addr2, pAd->CurrentAddress); COPY_MAC_ADDR(pHdr80211->Addr3, pAd->CommonCfg.Bssid); pHdr80211->Sequence = pAd->Sequence; } /* ======================================================================== Routine Description: Copy frame from waiting queue into relative ring buffer and set appropriate ASIC register to kick hardware encryption before really sent out to air. Arguments: pAd Pointer to our adapter PNDIS_PACKET Pointer to outgoing Ndis frame NumberOfFrag Number of fragment required Return Value: None Note: ======================================================================== */ VOID RTMPToWirelessSta( IN PRTMP_ADAPTER pAd, IN PUCHAR pHeader802_3, IN UINT HdrLen, IN PUCHAR pData, IN UINT DataLen, IN BOOLEAN is4wayFrame) { NDIS_STATUS Status; PNDIS_PACKET pPacket; UCHAR Index; do { // 1. build a NDIS packet and call RTMPSendPacket(); // be careful about how/when to release this internal allocated NDIS PACKET buffer Status = RTMPAllocateNdisPacket(pAd, &pPacket, pHeader802_3, HdrLen, pData, DataLen); if (Status != NDIS_STATUS_SUCCESS) break; if (is4wayFrame) RTMP_SET_PACKET_CLEAR_EAP_FRAME(pPacket, 1); else RTMP_SET_PACKET_CLEAR_EAP_FRAME(pPacket, 0); // 2. send out the packet Status = STASendPacket(pAd, pPacket); if(Status == NDIS_STATUS_SUCCESS) { // Dequeue one frame from TxSwQueue0..3 queue and process it // There are three place calling dequeue for TX ring. // 1. Here, right after queueing the frame. // 2. At the end of TxRingTxDone service routine. // 3. Upon NDIS call RTMPSendPackets if((!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) && (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS))) { for(Index = 0; Index < 5; Index ++) if(pAd->TxSwQueue[Index].Number > 0) RTMPDeQueuePacket(pAd, FALSE, Index, MAX_TX_PROCESS); } } } while(FALSE); } /* ======================================================================== Routine Description: Check Sanity RSN IE form AP Arguments: Return Value: ======================================================================== */ BOOLEAN CheckRSNIE( IN PRTMP_ADAPTER pAd, IN PUCHAR pData, IN UCHAR DataLen, OUT UCHAR *Offset) { PUCHAR pVIE; UCHAR len; PEID_STRUCT pEid; BOOLEAN result = FALSE; pVIE = pData; len = DataLen; *Offset = 0; while (len > sizeof(RSNIE2)) { pEid = (PEID_STRUCT) pVIE; // WPA RSN IE if ((pEid->Eid == IE_WPA) && (NdisEqualMemory(pEid->Octet, WPA_OUI, 4))) { if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA || pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPAPSK) && (NdisEqualMemory(pVIE, pAd->MacTab.Content[BSSID_WCID].RSN_IE, pAd->MacTab.Content[BSSID_WCID].RSNIE_Len)) && (pAd->MacTab.Content[BSSID_WCID].RSNIE_Len == (pEid->Len + 2))) { DBGPRINT(RT_DEBUG_TRACE, ("CheckRSNIE ==> WPA/WPAPSK RSN IE matched in Msg 3, Length(%d) \n", (pEid->Len + 2))); result = TRUE; } *Offset += (pEid->Len + 2); } // WPA2 RSN IE else if ((pEid->Eid == IE_RSN) && (NdisEqualMemory(pEid->Octet + 2, RSN_OUI, 3))) { if ((pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2 || pAd->StaCfg.AuthMode == Ndis802_11AuthModeWPA2PSK) && (NdisEqualMemory(pVIE, pAd->MacTab.Content[BSSID_WCID].RSN_IE, pAd->MacTab.Content[BSSID_WCID].RSNIE_Len)) && (pAd->MacTab.Content[BSSID_WCID].RSNIE_Len == (pEid->Len + 2))) { DBGPRINT(RT_DEBUG_TRACE, ("CheckRSNIE ==> WPA2/WPA2PSK RSN IE matched in Msg 3, Length(%d) \n", (pEid->Len + 2))); result = TRUE; } *Offset += (pEid->Len + 2); } else { break; } pVIE += (pEid->Len + 2); len -= (pEid->Len + 2); } DBGPRINT(RT_DEBUG_TRACE, ("CheckRSNIE ==> skip_offset(%d) \n", *Offset)); return result; } /* ======================================================================== Routine Description: Parse KEYDATA field. KEYDATA[] May contain 2 RSN IE and optionally GTK. GTK is encaptulated in KDE format at p.83 802.11i D10 Arguments: Return Value: Note: 802.11i D10 ======================================================================== */ BOOLEAN ParseKeyData( IN PRTMP_ADAPTER pAd, IN PUCHAR pKeyData, IN UCHAR KeyDataLen, IN UCHAR bPairewise) { PKDE_ENCAP pKDE = NULL; PUCHAR pMyKeyData = pKeyData; UCHAR KeyDataLength = KeyDataLen; UCHAR GTKLEN; UCHAR skip_offset; // Verify The RSN IE contained in Pairewise-Msg 3 and skip it if (bPairewise) { // Check RSN IE whether it is WPA2/WPA2PSK if (!CheckRSNIE(pAd, pKeyData, KeyDataLen, &skip_offset)) { DBGPRINT(RT_DEBUG_ERROR, ("ParseKeyData ==> WPA2/WPA2PSK RSN IE mismatched \n")); hex_dump("Get KEYDATA :", pKeyData, KeyDataLen); return FALSE; } else { // skip RSN IE pMyKeyData += skip_offset; KeyDataLength -= skip_offset; //DBGPRINT(RT_DEBUG_TRACE, ("ParseKeyData ==> WPA2/WPA2PSK RSN IE matched in Msg 3, Length(%d) \n", skip_offset)); } } DBGPRINT(RT_DEBUG_TRACE,("ParseKeyData ==> KeyDataLength %d without RSN_IE \n", KeyDataLength)); // Parse EKD format if (KeyDataLength >= 8) { pKDE = (PKDE_ENCAP) pMyKeyData; } else { DBGPRINT(RT_DEBUG_ERROR, ("ERROR: KeyDataLength is too short \n")); return FALSE; } // Sanity check - shared key index should not be 0 if (pKDE->GTKEncap.Kid == 0) { DBGPRINT(RT_DEBUG_ERROR, ("ERROR: GTK Key index zero \n")); return FALSE; } // Sanity check - KED length if (KeyDataLength < (pKDE->Len + 2)) { DBGPRINT(RT_DEBUG_ERROR, ("ERROR: The len from KDE is too short \n")); return FALSE; } // Get GTK length - refer to IEEE 802.11i-2004 p.82 GTKLEN = pKDE->Len -6; if (GTKLEN < LEN_AES_KEY) { DBGPRINT(RT_DEBUG_ERROR, ("ERROR: GTK Key length is too short (%d) \n", GTKLEN)); return FALSE; } else DBGPRINT(RT_DEBUG_TRACE, ("GTK Key with KDE formet got index=%d, len=%d \n", pKDE->GTKEncap.Kid, GTKLEN)); // Update GTK // set key material, TxMic and RxMic for WPAPSK NdisMoveMemory(pAd->StaCfg.GTK, pKDE->GTKEncap.GTK, 32); pAd->StaCfg.DefaultKeyId = pKDE->GTKEncap.Kid; // Update shared key table NdisZeroMemory(&pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId], sizeof(CIPHER_KEY)); pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].KeyLen = LEN_TKIP_EK; NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].Key, pKDE->GTKEncap.GTK, LEN_TKIP_EK); NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].RxMic, &pKDE->GTKEncap.GTK[16], LEN_TKIP_RXMICK); NdisMoveMemory(pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].TxMic, &pKDE->GTKEncap.GTK[24], LEN_TKIP_TXMICK); // Update Shared Key CipherAlg pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_NONE; if (pAd->StaCfg.GroupCipher == Ndis802_11Encryption2Enabled) pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_TKIP; else if (pAd->StaCfg.GroupCipher == Ndis802_11Encryption3Enabled) pAd->SharedKey[BSS0][pAd->StaCfg.DefaultKeyId].CipherAlg = CIPHER_AES; return TRUE; } /* ======================================================================== Routine Description: Cisco CCKM PRF function Arguments: key Cisco Base Transient Key (BTK) key_len The key length of the BTK data Ruquest Number(RN) + BSSID data_len The length of the data output Store for PTK(Pairwise transient keys) len The length of the output Return Value: None Note: 802.1i Annex F.9 ======================================================================== */ VOID CCKMPRF( IN UCHAR *key, IN INT key_len, IN UCHAR *data, IN INT data_len, OUT UCHAR *output, IN INT len) { INT i; UCHAR input[1024]; INT currentindex = 0; INT total_len; NdisMoveMemory(input, data, data_len); total_len = data_len; input[total_len] = 0; total_len++; for (i = 0; i < (len + 19) / 20; i++) { HMAC_SHA1(input, total_len, key, key_len, &output[currentindex]); currentindex += 20; input[total_len - 1]++; } } /* ======================================================================== Routine Description: Process MIC error indication and record MIC error timer. Arguments: pAd Pointer to our adapter pWpaKey Pointer to the WPA key structure Return Value: None IRQL = DISPATCH_LEVEL Note: ======================================================================== */ VOID RTMPReportMicError( IN PRTMP_ADAPTER pAd, IN PCIPHER_KEY pWpaKey) { ULONG Now; UCHAR unicastKey = (pWpaKey->Type == PAIRWISE_KEY ? 1:0); // Record Last MIC error time and count Now = jiffies; if (pAd->StaCfg.MicErrCnt == 0) { pAd->StaCfg.MicErrCnt++; pAd->StaCfg.LastMicErrorTime = Now; NdisZeroMemory(pAd->StaCfg.ReplayCounter, 8); } else if (pAd->StaCfg.MicErrCnt == 1) { if ((pAd->StaCfg.LastMicErrorTime + (60 * OS_HZ)) < Now) { // Update Last MIC error time, this did not violate two MIC errors within 60 seconds pAd->StaCfg.LastMicErrorTime = Now; } else { if (pAd->CommonCfg.bWirelessEvent) RTMPSendWirelessEvent(pAd, IW_COUNTER_MEASURES_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0); pAd->StaCfg.LastMicErrorTime = Now; // Violate MIC error counts, MIC countermeasures kicks in pAd->StaCfg.MicErrCnt++; // We shall block all reception // We shall clean all Tx ring and disassoicate from AP after next EAPOL frame // // No necessary to clean all Tx ring, on RTMPHardTransmit will stop sending non-802.1X EAPOL packets // if pAd->StaCfg.MicErrCnt greater than 2. // // RTMPRingCleanUp(pAd, QID_AC_BK); // RTMPRingCleanUp(pAd, QID_AC_BE); // RTMPRingCleanUp(pAd, QID_AC_VI); // RTMPRingCleanUp(pAd, QID_AC_VO); // RTMPRingCleanUp(pAd, QID_HCCA); } } else { // MIC error count >= 2 // This should not happen ; } MlmeEnqueue(pAd, MLME_CNTL_STATE_MACHINE, OID_802_11_MIC_FAILURE_REPORT_FRAME, 1, &unicastKey); if (pAd->StaCfg.MicErrCnt == 2) { RTMPSetTimer(&pAd->StaCfg.WpaDisassocAndBlockAssocTimer, 100); } } #ifdef WPA_SUPPLICANT_SUPPORT #define LENGTH_EAP_H 4 // If the received frame is EAP-Packet ,find out its EAP-Code (Request(0x01), Response(0x02), Success(0x03), Failure(0x04)). INT WpaCheckEapCode( IN PRTMP_ADAPTER pAd, IN PUCHAR pFrame, IN USHORT FrameLen, IN USHORT OffSet) { PUCHAR pData; INT result = 0; if( FrameLen < OffSet + LENGTH_EAPOL_H + LENGTH_EAP_H ) return result; pData = pFrame + OffSet; // skip offset bytes if(*(pData+1) == EAPPacket) // 802.1x header - Packet Type { result = *(pData+4); // EAP header - Code } return result; } VOID WpaSendMicFailureToWpaSupplicant( IN PRTMP_ADAPTER pAd, IN BOOLEAN bUnicast) { union iwreq_data wrqu; char custom[IW_CUSTOM_MAX] = {0}; sprintf(custom, "MLME-MICHAELMICFAILURE.indication"); if (bUnicast) sprintf(custom, "%s unicast", custom); wrqu.data.length = strlen(custom); wireless_send_event(pAd->net_dev, IWEVCUSTOM, &wrqu, custom); return; } #endif // WPA_SUPPLICANT_SUPPORT // VOID WpaMicFailureReportFrame( IN PRTMP_ADAPTER pAd, IN MLME_QUEUE_ELEM *Elem) { PUCHAR pOutBuffer = NULL; UCHAR Header802_3[14]; ULONG FrameLen = 0; EAPOL_PACKET Packet; UCHAR Mic[16]; BOOLEAN bUnicast; DBGPRINT(RT_DEBUG_TRACE, ("WpaMicFailureReportFrame ----->\n")); bUnicast = (Elem->Msg[0] == 1 ? TRUE:FALSE); pAd->Sequence = ((pAd->Sequence) + 1) & (MAX_SEQ_NUMBER); // init 802.3 header and Fill Packet MAKE_802_3_HEADER(Header802_3, pAd->CommonCfg.Bssid, pAd->CurrentAddress, EAPOL); NdisZeroMemory(&Packet, sizeof(Packet)); Packet.ProVer = EAPOL_VER; Packet.ProType = EAPOLKey; Packet.KeyDesc.Type = WPA1_KEY_DESC; // Request field presented Packet.KeyDesc.KeyInfo.Request = 1; if(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) { Packet.KeyDesc.KeyInfo.KeyDescVer = 2; } else // TKIP { Packet.KeyDesc.KeyInfo.KeyDescVer = 1; } Packet.KeyDesc.KeyInfo.KeyType = (bUnicast ? PAIRWISEKEY : GROUPKEY); // KeyMic field presented Packet.KeyDesc.KeyInfo.KeyMic = 1; // Error field presented Packet.KeyDesc.KeyInfo.Error = 1; // Update packet length after decide Key data payload Packet.Body_Len[1] = sizeof(KEY_DESCRIPTER) - MAX_LEN_OF_RSNIE; // Key Replay Count NdisMoveMemory(Packet.KeyDesc.ReplayCounter, pAd->StaCfg.ReplayCounter, LEN_KEY_DESC_REPLAY); inc_byte_array(pAd->StaCfg.ReplayCounter, 8); // Convert to little-endian format. *((USHORT *)&Packet.KeyDesc.KeyInfo) = cpu2le16(*((USHORT *)&Packet.KeyDesc.KeyInfo)); MlmeAllocateMemory(pAd, (PUCHAR *)&pOutBuffer); // allocate memory if(pOutBuffer == NULL) { return; } // Prepare EAPOL frame for MIC calculation // Be careful, only EAPOL frame is counted for MIC calculation MakeOutgoingFrame(pOutBuffer, &FrameLen, Packet.Body_Len[1] + 4, &Packet, END_OF_ARGS); // Prepare and Fill MIC value NdisZeroMemory(Mic, sizeof(Mic)); if(pAd->StaCfg.WepStatus == Ndis802_11Encryption3Enabled) { // AES UCHAR digest[20] = {0}; HMAC_SHA1(pOutBuffer, FrameLen, pAd->StaCfg.PTK, LEN_EAP_MICK, digest); NdisMoveMemory(Mic, digest, LEN_KEY_DESC_MIC); } else { // TKIP hmac_md5(pAd->StaCfg.PTK, LEN_EAP_MICK, pOutBuffer, FrameLen, Mic); } NdisMoveMemory(Packet.KeyDesc.KeyMic, Mic, LEN_KEY_DESC_MIC); MakeOutgoingFrame(pOutBuffer, &FrameLen, LENGTH_802_3, &Header802_3, Packet.Body_Len[1] + 4, &Packet, END_OF_ARGS); // opy frame to Tx ring and send MIC failure report frame to authenticator RTMPToWirelessSta(pAd, Header802_3, LENGTH_802_3, (PUCHAR)&Packet, Packet.Body_Len[1] + 4, FALSE); MlmeFreeMemory(pAd, (PUCHAR)pOutBuffer); DBGPRINT(RT_DEBUG_TRACE, ("WpaMicFailureReportFrame <-----\n")); } /** from wpa_supplicant * inc_byte_array - Increment arbitrary length byte array by one * @counter: Pointer to byte array * @len: Length of the counter in bytes * * This function increments the last byte of the counter by one and continues * rolling over to more significant bytes if the byte was incremented from * 0xff to 0x00. */ void inc_byte_array(UCHAR *counter, int len) { int pos = len - 1; while (pos >= 0) { counter[pos]++; if (counter[pos] != 0) break; pos--; } } VOID WpaDisassocApAndBlockAssoc( IN PVOID SystemSpecific1, IN PVOID FunctionContext, IN PVOID SystemSpecific2, IN PVOID SystemSpecific3) { RTMP_ADAPTER *pAd = (PRTMP_ADAPTER)FunctionContext; MLME_DISASSOC_REQ_STRUCT DisassocReq; // disassoc from current AP first DBGPRINT(RT_DEBUG_TRACE, ("RTMPReportMicError - disassociate with current AP after sending second continuous EAPOL frame\n")); DisassocParmFill(pAd, &DisassocReq, pAd->CommonCfg.Bssid, REASON_MIC_FAILURE); MlmeEnqueue(pAd, ASSOC_STATE_MACHINE, MT2_MLME_DISASSOC_REQ, sizeof(MLME_DISASSOC_REQ_STRUCT), &DisassocReq); pAd->Mlme.CntlMachine.CurrState = CNTL_WAIT_DISASSOC; pAd->StaCfg.bBlockAssoc = TRUE; }