[openfirmware] [commit] r2652 - ofw/wifi
repository service
svn at openfirmware.info
Tue Oct 25 00:56:15 CEST 2011
Author: lwalter
Date: Tue Oct 25 00:56:15 2011
New Revision: 2652
URL: http://tracker.coreboot.org/trac/openfirmware/changeset/2652
Log:
Make eapol key handshake more robust and fix WPA/WPA2 auto cipher bug
Modified:
ofw/wifi/data.fth
ofw/wifi/eapol.fth
Modified: ofw/wifi/data.fth
==============================================================================
--- ofw/wifi/data.fth Mon Oct 24 08:53:41 2011 (r2651)
+++ ofw/wifi/data.fth Tue Oct 25 00:56:15 2011 (r2652)
@@ -27,6 +27,8 @@
: set-key-type ( ctp ctg ktype -- ) " set-key-type" $call-parent ;
: set-country-info ( adr len -- ) " set-country-info" $call-parent ;
: set-atim-window ( n -- ) " set-atim-window" $call-parent ;
+: set-gtk-idx ( n -- ) " set-gtk-idx" ['] $call-parent catch if 3drop then ;
+: disconnected? ( -- flag ) " disconnected?" $call-parent ;
\ =======================================================================
\ Global data
Modified: ofw/wifi/eapol.fth
==============================================================================
--- ofw/wifi/eapol.fth Mon Oct 24 08:53:41 2011 (r2651)
+++ ofw/wifi/eapol.fth Tue Oct 25 00:56:15 2011 (r2652)
@@ -9,9 +9,38 @@
: vtype ( adr len -- ) debug? if ??cr type cr else 2drop then ;
\ =======================================================================
-\ EAPOL data definitions
+\ Handshake variables and helper words
+
+false value send-error?
+2 constant send-retry-cnt
+
+d# 30,000 constant timeout-eapol-limit
+d# 5,000 constant timeout-msg-limit
+
+0 value timeout-eapol \ Global timeout value in ms
+0 value timeout-msg \ Timeout waiting for msg from AP in ms
+
+: set-eapol-timeout ( -- ) get-msecs timeout-eapol-limit + to timeout-eapol ;
+: set-msg-timeout ( -- ) get-msecs timeout-msg-limit + to timeout-msg ;
+: eapol-timeout? ( -- timeout? ) get-msecs timeout-eapol >= ;
+: msg-timeout? ( -- timeout? ) get-msecs timeout-msg >= ;
+: timeout? ( -- timeout? ) eapol-timeout? msg-timeout? or ;
+
+false value done-pairwise-key?
+false value done-group-key?
-d# 10,000 constant eapol-wait
+: done? ( -- done? ) done-group-key? done-pairwise-key? and ;
+
+: send-eapol-msg ( adr len -- ok? )
+ send-retry-cnt 0 do
+ 2dup tuck write-force = if 2drop true unloop exit then
+ loop 2drop
+ false " Fail to send message" vtype
+ true to send-error?
+;
+
+\ =======================================================================
+\ EAPOL data definitions
1 value eapol-ver
3 constant eapol-key
@@ -68,6 +97,13 @@
1000 constant ki-encr-key \ >kdata encrypted (WPA2)
2000 constant ki-smk-msg \ STSL master key
+\ Vendor IE's OUI
+h# 0050f2.01 constant oui-wpa \ Microsoft OUI's
+h# 0050f2.02 constant oui-wmm
+h# 0050f2.04 constant oui-wps
+h# 00904c.33 constant oui-ht \ Broadcom OUI's
+h# 00904c.34 constant oui-ht+
+
\ =======================================================================
\ Nonce
@@ -179,14 +215,13 @@
\ =======================================================================
\ Group temporal keys (GTK)
-false value done-group-key?
-
d# 32 dup constant /gtk buffer: gtk
0 value gtk-idx \ Active GTK idx
d# 32 buffer: ek \ Temporary rc4 key
: install-group-key ( -- ) gtk ctype-g ct>klen set-gtk ;
+: install-gtk-idx ( -- ) ktype kt-wpa2 = if gtk-idx set-gtk-idx then ;
: set-gtk-supplicant ( adr -- )
dup gtk d# 16 move
@@ -252,12 +287,54 @@
then
;
+\ =======================================================================
+\ WPA/WPA2 handshake states
+\ State Comment Process
+\ s1/4 initial state Reset wait for 1/4 timeout
+\ authenticate done pairwise key received? = false
+\ associate done group key received? = false
+\ Wait for 1/4 msg from AP
+\ 1/4 timeout -> exit fail
+\ s3/4 got 1/4 msg Send 2/4 msg to AP
+\ Reset 3/4 timeout
+\ Wait for 3/4 msg from AP
+\ 3/4 timeout -> s2
+\ got 3/4 msg -> send 4/4 msg to AP
+\ If we got group key, exit ok
+\ Reset 1/2 timeout
+\ s1/2 pairwise key done Wait for 1/2 msg from AP
+\ 1/2 timeout -> s2
+\ got 1/2 msg -> send 2/2 msg to AP
+\ exit ok
+\ exit ok Install keys
+\
+\ Anytime a 1/4 msg is received, goto s3/4
+\ Anytime deauthenticate is received, exit fail
+\ Global timeout, exit fail
+
+0 value eapol-state
+0 constant s0/4 \ Initial state; also invalid msg
+1 constant s1/4 \ Waiting for 1/4 from AP; also msg#
+2 constant s3/4 \ Waiting for 3/4 from AP; also msg#
+3 constant s1/2 \ Waiting for 1/2 from AP; also msg#
+
+: set-s/4 ( -- )
+ false to done-group-key?
+ false to done-pairwise-key?
+ set-msg-timeout
+;
+: set-s0/4 ( -- ) s0/4 to eapol-state set-s/4 ;
+: set-s1/4 ( -- ) s1/4 to eapol-state set-s/4 ;
+: set-s3/4 ( -- ) s3/4 to eapol-state set-s/4 ;
+: set-s1/2 ( -- )
+ false to done-group-key?
+ s1/2 to eapol-state
+ set-msg-timeout
+;
\ =======================================================================
\ WPA/WPA2 pairwise keys four-way handshake
-
-false value pairwise-rekey?
-false value group-rekey?
+\ WPA group key 2-way handshake
/buf buffer: data
@@ -269,35 +346,9 @@
ktype kt-wpa2 = if ki-encr-key or ki-secure or then ;
: pct>kinfo4 ( -- kinfo ) pct>kinfo2 ktype kt-wpa2 = if ki-secure or then ;
-: wait-for-eapol-key ( -- flag )
- false eapol-wait 0 do
- data /buf read-force 0> if
- data >etype be-w@ eapol-type = \ EAPOL frame
- data >ptype c@ eapol-key = and \ EAPOL-key
- data >rcnt last-rcnt /rcnt comp and if \ A new eapol-key record
- data >rcnt last-rcnt! \ Update last replay counter
- drop true
- leave
- then
- then
- 1 ms
- loop
-;
-
-: process-1-of-4 ( -- ok? )
- " Process EAPOL-key message 1 of 4" vtype
- data >ver c@ to eapol-ver
- data >dtype c@ kt>dtype <> if false exit then \ Descriptor type mismatch
- data >kinfo be-w@ pct>kinfo1 <> if false exit then \ Bad key info
- data >klen be-w@ ctype-p ct>klen <> if false exit then \ Bad key len
- data >knonce anonce$ move \ Save authenticator nonce
- true
-;
-
-: wait-for-1-of-4 ( -- ok? )
- " Waiting for EAPOL-key message 1 of 4..." vtype
- wait-for-eapol-key if process-1-of-4 else false then
-;
+: gct>kinfo ( -- kinfo ) ctype-p ct-aes = if ki-sha1-aes else ki-md5-rc4 then ;
+: gct>kinfo1 ( -- kinfo ) gct>kinfo ki-mic or ki-secure or ki-ack or ;
+: gct>kinfo2 ( -- kinfo ) gct>kinfo ki-mic or ki-secure or ;
: set-eapolbuf-common ( -- )
eapolbuf /eapol-key erase
@@ -310,132 +361,168 @@
ctype-p ct>klen eapolbuf >klen be-w! \ Key length
last-rcnt eapolbuf >rcnt /rcnt move \ Replay counter
;
-: send-2-of-4 ( -- error? )
+
+: resync-gtk ( -- )
+ last-rcnt++
+ set-eapolbuf-common
+ 0 eapolbuf >klen be-w! \ Key length
+ /eapol-body eapolbuf >plen be-w! \ Packet length
+ ctype-g ct>klen eapolbuf >klen be-w! \ Key length
+ gct>kinfo ki-request or eapolbuf >kinfo be-w! \ Key info
+ eapolbuf /eapol-key send-eapol-msg
+;
+
+: send-2/4 ( -- ok? )
" Send EAPOL-key message 2 of 4" vtype
compute-snonce
compute-ptk-supplicant
set-eapolbuf-common
- /eapol-body wpa-ie$ nip + eapolbuf >plen be-w! \ Packet length
- pct>kinfo2 eapolbuf >kinfo be-w! \ Key info
- snonce eapolbuf >knonce /nonce move \ Supplicant nonce
- wpa-ie$ nip eapolbuf >kdlen be-w! \ Key data length
- wpa-ie$ eapolbuf >kdata swap move \ Key data is WPA IE (or RSN IE)
+ /eapol-body wpa-ie$ nip + eapolbuf >plen be-w! \ Packet length
+ pct>kinfo2 eapolbuf >kinfo be-w! \ Key info
+ snonce eapolbuf >knonce /nonce move \ Supplicant nonce
+ wpa-ie$ nip eapolbuf >kdlen be-w! \ Key data length
+ wpa-ie$ eapolbuf >kdata swap move \ Key data is WPA IE (or RSN IE)
eapolbuf >ver eapolbuf >plen be-w@ 4 + ctype-p compute-mic
- mic eapolbuf >kmic /mic move \ Key mic
- eapolbuf /eapol-key wpa-ie$ nip + tuck write-force <>
+ mic eapolbuf >kmic /mic move \ Key mic
+ eapolbuf /eapol-key wpa-ie$ nip + send-eapol-msg
;
-
-: process-3-of-4 ( -- ok? )
- " Process EAPOL-key message 3 of 4" vtype
- data >dtype c@ kt>dtype <> if false exit then \ Descriptor type mismatch
- data >kinfo be-w@ pct>kinfo3 <> if false exit then \ Bad key info
- data >klen be-w@ ctype-p ct>klen <> if false exit then \ Bad key len
- data >knonce anonce /nonce comp if false exit then \ Nonce differ
- data ctype-p mic-ok? 0= if true to pairwise-rekey? false exit then \ Bad mic
- data >kinfo be-w@ ki-encr-key and if data decrypt-parse-ie else true then
-;
-: wait-for-3-of-4 ( -- ok? )
- " Waiting for EAPOL-key message 3 of 4..." vtype
- wait-for-eapol-key if process-3-of-4 else false then
-;
-
-: send-4-of-4 ( -- error? )
+: send-4/4 ( -- ok? )
" Send EAPOL-key message 4 of 4" vtype
set-eapolbuf-common
- /eapol-body eapolbuf >plen be-w! \ Packet length
- pct>kinfo4 eapolbuf >kinfo be-w! \ Key info
+ /eapol-body eapolbuf >plen be-w! \ Packet length
+ pct>kinfo4 eapolbuf >kinfo be-w! \ Key info
eapolbuf >ver eapolbuf >plen be-w@ 4 + ctype-p compute-mic
- mic eapolbuf >kmic /mic move \ Key mic
- eapolbuf /eapol-key tuck write-force <>
+ mic eapolbuf >kmic /mic move \ Key mic
+ eapolbuf /eapol-key send-eapol-msg
;
-
-: do-pairwise-key-handshake ( -- ok? )
- false
- wait-for-1-of-4 0= if ." Failed to get the first pairwise key" cr exit then
- send-2-of-4 if ." Failed to send the second pairwise key" cr exit then
- wait-for-3-of-4 0= if ." Failed to get the third pairwise key" cr exit then
- send-4-of-4 if ." Failed to send the fourth pairwise key" cr exit then
- install-pairwise-key
- done-group-key? if install-group-key then
- drop true
+: send-2/2 ( -- ok? )
+ " Send EAPOL-key message 2 of 2" vtype
+ set-eapolbuf-common
+ /eapol-body eapolbuf >plen be-w! \ Packet length
+ gct>kinfo2 eapolbuf >kinfo be-w! \ Key info
+ ctype-g ct>klen eapolbuf >klen be-w! \ Key length
+ eapolbuf >ver eapolbuf >plen be-w@ 4 + ctype-p compute-mic
+ mic eapolbuf >kmic /mic move \ Key mic
+ eapolbuf /eapol-key send-eapol-msg
+;
+: 1/4-valid? ( -- ok? )
+ data >dtype c@ kt>dtype <> if false exit then \ Descriptor type mismatch
+ data >klen be-w@ ctype-p ct>klen <> if false exit then \ Bad key len
+ true
;
-
-\ =======================================================================
-\ WPA group keys 2-way handshake
-
-: gct>kinfo ( -- kinfo ) ctype-g ct-aes = if ki-sha1-aes else ki-md5-rc4 then ;
-: gct>kinfo1 ( -- kinfo ) gct>kinfo ki-mic or ki-secure or ki-ack or ;
-: gct>kinfo2 ( -- kinfo ) gct>kinfo ki-mic or ki-secure or ;
-
-: process-1-of-2 ( -- ok? )
- " Process EAPOL-key message 1 of 2" vtype
- data >dtype c@ kt>dtype <> if false exit then \ Descriptor type mismatch data >kinfo be-w@ ki-idx-mask invert and gct>kinfo1 <> if false exit then \ Bad key info
- data >klen be-w@ ctype-g ct>klen <> if false exit then \ Bad key len
- data ctype-p mic-ok? 0= if true to group-rekey? false exit then \ Bad mic
- data decrypt-gtk
+: process-1/4 ( -- )
+ " Process EAPOL-key message 1 of 4" vtype
+ eapol-state s1/4 <> if " Unexpected pairwise key message 1 of 4" vtype then
+ 1/4-valid? if
+ data >ver c@ to eapol-ver
+ data >knonce anonce$ move
+ send-2/4 if set-s3/4 then
+ then
;
-: wait-for-1-of-2 ( -- ok? )
- " Waiting for EAPOL-key message 1 of 2..." vtype
- wait-for-eapol-key if process-1-of-2 else false then
+: 3/4-valid? ( -- ok? )
+ data >dtype c@ kt>dtype <> if false exit then \ Descriptor type mismatch
+ data >klen be-w@ ctype-p ct>klen <> if false exit then \ Bad key len
+ data >knonce anonce /nonce comp if false exit then \ Nonce differ
+ data ctype-p mic-ok? 0= if false exit then \ Bad mic
+ data >kinfo be-w@ ki-encr-key and if data decrypt-parse-ie else true then
;
-
-: send-2-of-2 ( -- error? )
- " Send EAPOL-key message 2 of 2" vtype
- set-eapolbuf-common
- /eapol-body eapolbuf >plen be-w! \ Packet length
- gct>kinfo2 eapolbuf >kinfo be-w! \ Key info
- eapolbuf >ver eapolbuf >plen be-w@ 4 + ctype-g compute-mic
- mic eapolbuf >kmic /mic move \ Key mic
- eapolbuf /eapol-key tuck write-force <>
+: process-3/4 ( -- )
+ " Process EAPOL-key message 3 of 4" vtype
+ eapol-state s3/4 = if
+ 3/4-valid? if
+ send-4/4 if
+ install-pairwise-key
+ true to done-pairwise-key?
+ " Install pairwise key" vtype
+ done-group-key? if
+ \ WPA2 3/4 contains the group key
+ " Install group key" vtype
+ install-gtk-idx
+ install-group-key
+ else
+ " Wait for group key message 1 of 2" vtype
+ set-s1/2
+ then
+ then
+ then
+ else
+ " Unexpected pairwise key message 3 of 4" vtype
+ then
;
-
-: do-group-key-handshake ( -- )
- wait-for-1-of-2 0= if ." Failed to get the first group key" cr exit then
- send-2-of-2 if ." Failed to send the second group key" cr exit then
- install-group-key
+: 1/2-valid? ( -- ok? )
+ data >dtype c@ kt>dtype <> if false exit then \ Descriptor type mismatch
+ data >klen be-w@ ctype-g ct>klen <> if false exit then \ Bad key len
+ data ctype-p mic-ok? 0= if false exit then \ Bad MIC
+ data decrypt-gtk
;
-
-\ =======================================================================
-\ WPA/WPA2 keys handshake
-
-: request-rekey ( ki-pairwise -- )
- " Send rekey message" vtype
- last-rcnt++
- set-eapolbuf-common
- 0 eapolbuf >klen be-w! \ Key length
- /eapol-body eapolbuf >plen be-w! \ Packet length
- ( ki-pairwise ) dup gct>kinfo or ki-request or ki-error or ki-mic or
- eapolbuf >kinfo be-w! \ Key info
- eapolbuf >ver eapolbuf >plen be-w@ 4 +
- rot ( ki-pairwise ) if ctype-p else ctype-g then compute-mic
- mic eapolbuf >kmic /mic move \ Key mic
- eapolbuf /eapol-key tuck write-force <>
+: process-1/2 ( -- )
+ eapol-state s1/2 = if
+ 1/2-valid? if
+ send-2/2 if
+ " Install group key" vtype
+ install-gtk-idx
+ install-group-key
+ true to done-group-key?
+ then
+ then
+ else
+ " Unexpected group key message 1 of 2" vtype
+ then
;
-
-: resync-gtk ( -- ) 0 request-rekey ;
-
-: (do-key-handshakes) ( -- )
- false to done-group-key?
- false to pairwise-rekey?
- do-pairwise-key-handshake if
- done-group-key? 0= if
- 2 0 do
- false to group-rekey?
- do-group-key-handshake
- group-rekey? if resync-gtk else leave then
- loop
+: get-eapol-msg# ( -- state )
+ data >kinfo be-w@
+ dup ki-pairwise and if \ Pairwise key info
+ dup pct>kinfo1 = if drop s1/4 exit then
+ pct>kinfo3 = if s3/4 exit then
+ else
+ ki-idx-mask invert and gct>kinfo1 = if s1/2 exit then
+ then
+ s0/4
+;
+: process-eapol-key ( -- )
+ get-eapol-msg# case
+ s1/4 of process-1/4 endof
+ s3/4 of process-3/4 endof
+ s1/2 of process-1/2 endof
+ endcase
+;
+: (process-eapol) ( -- )
+ data >etype be-w@ eapol-type = \ EAPOL frame
+ data >ptype c@ eapol-key = and if \ EAPOL-key
+ data >ver c@ to eapol-ver
+ data >rcnt last-rcnt /rcnt comp 0> if \ A new eapol-key record
+ data >rcnt /rcnt cdump cr
+ data >rcnt last-rcnt! \ Update last replay counter
+ process-eapol-key
+ else
+ " Same replay count; packet discarded" vtype
then
+ else
+ " Non EAPOL frame received" vtype
then
;
-
+: (do-key-handshakes) ( -- )
+ begin
+ data /buf read-force 0> if (process-eapol) then
+ timeout? disconnected? or done? or send-error? or until
+;
: do-key-handshakes ( -- )
- 2 0 do
+ false to send-error?
+ set-eapol-timeout
+ set-s1/4
+ (do-key-handshakes)
+ done? disconnected? or send-error? or if exit then
+ done-pairwise-key? if
+ " Timeout waiting for group key; request group key" vtype
+ resync-gtk
+ set-eapol-timeout
+ set-s1/2
(do-key-handshakes)
- pairwise-rekey? if ki-pairwise request-rekey else leave then
- loop
+ else
+ " Timeout waiting for 4-way handshake" vtype
+ then
;
-
\ =======================================================================
\ Scan dump
@@ -447,6 +534,21 @@
loop cr
;
+: .vendor ( adr -- )
+ dup 2 + swap 1+ c@ ( adr' len )
+ ?dup 0= if drop exit then
+ dup 4 < if ." Vendor Specific: " cdump cr exit then
+ over be-l@ case ( adr len )
+ oui-wpa of ." WPA: " endof
+ oui-wmm of ." WMM: " endof
+ oui-wps of ." WPS: " endof
+ oui-ht of ." HT: " endof
+ oui-ht+ of ." More HT: " endof
+ ( otherwise ) ." Vendor Specific: "
+ endcase
+ cdump cr
+;
+
: .ie ( adr -- )
dup c@ ." "
case
@@ -482,7 +584,7 @@
cr endof
d# 48 of ." Robust security network: " dup 2 + swap 1+ c@ cdump cr endof
d# 50 of ." Extended supported rates (Mbit/s): " .rates endof
- d# 221 of ." Wi-Fi Protected Access: " dup 2 + swap 1+ c@ cdump cr endof
+ d# 221 of .vendor endof
( default ) ." Unknown IE type: " swap dup 1+ c@ 2 + cdump cr
endcase
;
@@ -573,14 +675,6 @@
dup le-w@ swap 2 + swap d# 19 /string ( adr' len' )
r> (find-ie) ( adr' len' true | false )
;
-: find-ie2 ( ie-adr,len adr ie-type -- adr len true | false )
- >r ( ie-adr,len adr ) ( R: ie-type )
- dup le-w@ swap 2 + swap d# 19 /string
- ( ie-adr,len adr len ) ( R: ie-type )
- 3 pick rot - - ( ie-adr,len len' ) ( R: ie-type )
- swap /string ( adr' len' ) ( R: ie-type )
- r> (find-ie) ( adr' len' true | false )
-;
: find-ssid ( ssid$ scanbuf-adr -- ap-adr' true | false )
false swap ( ssid$ flag adr )
dup 3 + ( ssid$ flag 'ap )
@@ -728,14 +822,19 @@
dup 0= if ." Keys in wifi-cfg are not valid - " then
;
-h# 0050.f201 constant wpa-tag
-: process-wpa-ie ( ie-adr,len adr -- )
- \ Some AP such as Linksys has a bogus WPA IE in addition to the real thing.
- \ Skip over the bad one and see if there's another WPA IE
- 2 pick be-l@ wpa-tag = if drop set-wpa-ktype exit then
- d# 221 find-ie2 if
- over be-l@ wpa-tag = if set-wpa-ktype else 2drop then
- then
+: (process-vendor-ie) ( adr -- )
+ dup 2 + swap 1+ c@ ( adr' len )
+ dup 4 > if
+ over be-l@ oui-wpa = if set-wpa-ktype exit then
+ then 2drop
+;
+
+: process-vendor-ie ( adr -- )
+ dup le-w@ swap 2 + swap d# 19 /string ( adr' len )
+ begin dup 0> while ( adr len )
+ over c@ h# dd = if over (process-vendor-ie) then
+ over 1+ c@ 2 + /string ( adr' len' )
+ repeat 2drop
;
: ssid-valid? ( adr -- flag )
@@ -754,7 +853,7 @@
dup 6 find-ie if drop 2 + le-w@ set-atim-window then \ ATIM window
dup 7 find-ie 0= if null$ then do-set-country-info \ Country channel/power info
dup d# 48 find-ie if set-wpa2-ktype drop key-ok? exit then \ Favor RSN(WPA2) over WPA
- dup d# 221 find-ie if 2 pick process-wpa-ie then
+ dup process-vendor-ie \ E.g. WPA
drop key-ok?
;
@@ -764,7 +863,7 @@
cr
ktype=wpa? if
do-key-handshakes
- done-group-key?
+ done?
else
true
then
@@ -831,15 +930,8 @@
" Process EAPOL message" vtype
2dup vdump
data swap move
- data >ptype c@ eapol-key = and if \ EAPOL-key
- data >rcnt last-rcnt /rcnt comp if \ A new eapol-key record
- " Got EAPOL-key message 1 of 2" vtype
- data >rcnt last-rcnt! \ Update last replay counter
- process-1-of-2 if
- send-2-of-2 0= if install-group-key then
- then
- then
- then
+ set-s1/2
+ (process-eapol)
;
More information about the openfirmware
mailing list