/******************************************************************************* Modelling and Analysis of 802.11 4-Way Handshake Attacks and Security Properties AUTHORS Attack against the 4-way handshake, when the supplicant when (victim) still accepts plaintext retransmissions of message 3 if a PTK is installed. Notation: pmk = Pairwise Master Key ptk = Pairwise Transient Key, composed of: kck = Key Confirmation Key kek = Key Encryption Key tk = Temporal Key gtk = Group Temporal Key A_ = Events only in authenticator process S_ = Events only in supplicant process *******************************************************************************/ theory Krack_fig4 begin builtins: symmetric-encryption, multiset functions: true/0, CalcPtk/1, mic/2, kck/1, kek/1, tk/1, verifyMic/3 equations: verifyMic(mic(m,k), m, k) = true let Supplicant = new ~S_id; out(~S_id); !( out(<'AuthRequest', ~S_id>); in(<'AuthResponse', ~S_id, cs>); out(<'AssociationRequest', ~S_id, cs>); in(<'AssociationResponse', ~S_id, cs>); event S_HasPmk(~S_id, ~pmk); // Initial 4-way handshake new ~tid; in(A_id); let pat_msg1_contents = <'Header1', r, ANonce, cs> in in(pat_msg1_contents); new ~SNonce; let tptk = CalcPtk(<~pmk, ANonce, ~SNonce, A_id, ~S_id>) in event S_ComputesPtk(~S_id, ~tid, tptk); let msg2_contents = <'Header2', r, ~SNonce, cs> in out()>); let msg3_contents = <'Header3', r+'1', ANonce, cs, senc(gtk, )> in in()>); event S_ReceivesGtk(~S_id, ~tid, gtk); let ptk = tptk in event S_RunningPtk(~S_id, A_id, ptk); event S_RunningGtk(~S_id, A_id, ); event S_RunningCs(~S_id, A_id, ); let msg4_contents = <'Header4', r+'1', cs> in out()>); event S_InstallsPtk(~S_id, ptk); // MLME-SETKEYS.request event S_InstallsGtk(~S_id, gtk); // MLME-SETKEYS.request (( event S_CommitPtk(~S_id, A_id, ptk); event S_CommitGtk(~S_id, A_id, ); event S_CommitCs(~S_id, A_id, ); event S_Branch1() ) + ( let msg3_rtx_contents = <'Header3', r+'1'+'1', ANonce, cs, senc(gtk2, )> in in()>); let ptk = tptk in event S_RunningPtk(~S_id, A_id, ptk); event S_RunningGtk(~S_id, A_id, ); event S_RunningCs(~S_id, A_id, ); let msg4_rtx_contents = <'Header4', r+'1'+'1', cs> in out(senc()>, tk(ptk))); event S_InstallsPtk(~S_id, ptk); // MLME-SETKEYS.request event S_InstallsGtk(~S_id, gtk2); // MLME-SETKEYS.request event S_CommitPtk(~S_id, A_id, ptk); event S_CommitGtk(~S_id, A_id, ); event S_CommitCs(~S_id, A_id, ); event S_Branch2() )) ) let Authenticator = new ~A_id; out(~A_id); !( new ~tid; in(<'AuthRequest', S_id>); out(<'AuthResponse', S_id, 'CCMP'>); let cs = 'CCMP' in in(<'AssociationRequest', S_id, cs>); out(<'AssociationResponse', S_id, cs>); event A_HasPmk(~A_id, ~pmk); // Initial 4-way handshake new ~r; new ~ANonce; in(S_id); let pat_msg1_contents = <'Header1', ~r, ~ANonce, cs> in out(pat_msg1_contents); let ptk = CalcPtk(<~pmk, ~ANonce, SNonce, ~A_id, S_id>) in let msg2_contents = <'Header2', ~r, SNonce, cs> in in()>); new ~gtk; event A_GeneratesGtk(~gtk); event A_RunningPtk(~A_id, S_id, ptk); event A_RunningGtk(~A_id, S_id, <~ANonce, SNonce, ~gtk>); event A_RunningCs(~A_id, S_id, <~ANonce, SNonce, cs>); event A_InstallsGtk(~gtk); // MLME-SETKEYS.request let msg3_contents = <'Header3', ~r+'1', ~ANonce, cs, senc(~gtk, )> in out()>); (( let msg4_contents = <'Header4', ~r+'1', cs> in in()>); event A_InstallsPtk(ptk); // MLME-SETKEYS.request event A_CommitPtk(~A_id, S_id, ptk); event A_CommitGtk(~A_id, S_id, <~ANonce, SNonce, ~gtk>); event A_CommitCs(~A_id, S_id, <~ANonce, SNonce, cs>); event A_Branch1() )+ ( let msg3_rtx_contents = <'Header3', ~r+'1'+'1', ~ANonce, cs, senc(~gtk, )> in out()>); // Msg4(r+1) could have been received here (ignored) let msg4_rtx_contents = <'Header4', ~r+'1'+'1', cs> in in(senc()>, tk(ptk))); // Msg4(r+1) could have been received here (ignored) event A_InstallsPtk(ptk); // MLME-SETKEYS.request event A_CommitPtk(~A_id, S_id, ptk); event A_CommitGtk(~A_id, S_id, <~ANonce, SNonce, ~gtk>); event A_CommitCs(~A_id, S_id, <~ANonce, SNonce, cs>); event A_Branch2() )) ) // Main process starts here new ~pmk; (!Supplicant || Authenticator) lemma CorrectnessS1: exists-trace "Ex #i. S_Branch1()@i" // This lemma is expected to be falisified after activating countermeasure. lemma CorrectnessS2: exists-trace "Ex #i. S_Branch2()@i" lemma CorrectnessA1: exists-trace "Ex #i. A_Branch1()@i" lemma CorrectnessA2: exists-trace "Ex #i. A_Branch2()@i" // The KRACK attack does not exist. lemma NoKrackPtk: "All id ptk #i. S_InstallsPtk(id, ptk)@i ==> not(Ex #j. S_InstallsPtk(id, ptk)@j & (j (pmk1=pmk2)" // b) Ensure that the security association keys are fresh. lemma FreshPtk: all-traces "All id tid1 tid2 ptk #t1 #t2. S_ComputesPtk(id, tid1, ptk)@t1 & S_ComputesPtk(id, tid2, ptk)@t2 ==> (tid1=tid2)" lemma FreshGtk: all-traces "All id tid1 tid2 gtk #t1 #t2. S_ReceivesGtk(id, tid1, gtk)@t1 & S_ReceivesGtk(id, tid2, gtk)@t2 ==> (tid1=tid2)" // c) Synchronize the installation of one or more temporal keys into the MAC. lemma AgreementPtk: all-traces "(All X Y ptk #i. A_CommitPtk(X, Y, ptk)@i ==> ((Ex #j. S_RunningPtk(Y, X, ptk)@j & (j ((Ex #j. A_RunningPtk(Y, X, ptk)@j & (j ((Ex #j. S_RunningGtk(Y, X, gtk)@j & (j ((Ex #j. A_RunningGtk(Y, X, gtk)@j & (j (not (Ex #j. K(ptk)@j))" lemma SecretGtk: all-traces "All id gtk #i. S_InstallsGtk(id, gtk)@i ==> (not (Ex #j. K(gtk)@j))" // d) Transfer the GTK from the Authenticator to the Supplicant. lemma SameGtk: all-traces "All S gtk #i. S_InstallsGtk(S, gtk)@i ==> (Ex #j. A_GeneratesGtk(gtk)@j & (j ((Ex #j. S_RunningCs(Y, X, cs)@j & (j ((Ex #j. A_RunningCs(Y, X, cs)@j & (j (#i=#j)" lemma NoGtkReuse: all-traces "All id gtk #i #j. S_InstallsGtk(id, gtk)@i & S_InstallsGtk(id, gtk)@j ==> (#i=#j)" // Uncomment the following to enforce restrictions and verify the proposed as well as standard properties // Enforcing f) as restrictions /* restriction RestNoPtkReuse: "All id ptk #i #j. S_InstallsPtk(id, ptk)@i & S_InstallsPtk(id, ptk)@j ==> (#i=#j)" restriction RestNoGtkReuse: "All id gtk #i #j. S_InstallsGtk(id, gtk)@i & S_InstallsGtk(id, gtk)@j ==> (#i=#j)" */ end /* WITHOUT RESTRICTIONS ============================================================================= summary of summaries: analyzed: krack_fig4_011.sapic CorrectnessS1 (exists-trace): verified (11 steps) CorrectnessS2 (exists-trace): verified (13 steps) CorrectnessA1 (exists-trace): verified (12 steps) CorrectnessA2 (exists-trace): verified (14 steps) NoKrackPtk (all-traces): falsified - found trace (16 steps) ConfirmPmk (all-traces): verified (4 steps) FreshPtk (all-traces): verified (4 steps) FreshGtk (all-traces): verified (104 steps) AgreementPtk (all-traces): verified (114 steps) AgreementGtk (all-traces): verified (186 steps) SecretPtk (all-traces): verified (77 steps) SecretGtk (all-traces): verified (127 steps) SameGtk (all-traces): verified (35 steps) AgreementCs (all-traces): verified (114 steps) NoPtkReuse (all-traces): falsified - found trace (17 steps) NoGtkReuse (all-traces): falsified - found trace (17 steps) ============================================================================== real 3m54.551s user 8m51.112s sys 1m16.558s */ ============================================================================== summary of summaries: analyzed: krack_fig4_011.sapic CorrectnessS1 (exists-trace): verified (11 steps) CorrectnessS2 (exists-trace): falsified - no trace found (2 steps) CorrectnessA1 (exists-trace): verified (12 steps) CorrectnessA2 (exists-trace): verified (14 steps) NoKrackPtk (all-traces): verified (2 steps) ConfirmPmk (all-traces): verified (4 steps) FreshPtk (all-traces): verified (4 steps) FreshGtk (all-traces): verified (104 steps) AgreementPtk (all-traces): verified (91 steps) AgreementGtk (all-traces): verified (127 steps) SecretPtk (all-traces): verified (22 steps) SecretGtk (all-traces): verified (42 steps) SameGtk (all-traces): verified (14 steps) AgreementCs (all-traces): verified (91 steps) NoPtkReuse (all-traces): verified (2 steps) NoGtkReuse (all-traces): verified (2 steps) ============================================================================== real 0m30.998s user 1m13.637s sys 0m11.054s /* WITH RESTRICTIONS */