diff -r 2a3cc8e1723a -r f2024fed9f0c src/HOL/Auth/NS_Shared.thy --- a/src/HOL/Auth/NS_Shared.thy Tue Feb 13 01:32:54 2001 +0100 +++ b/src/HOL/Auth/NS_Shared.thy Tue Feb 13 13:16:27 2001 +0100 @@ -10,69 +10,387 @@ Proc. Royal Soc. 426 (1989) *) -NS_Shared = Shared + +theory NS_Shared = Shared: -consts ns_shared :: event list set +consts ns_shared :: "event list set" inductive "ns_shared" - intrs - (*Initial trace is empty*) - Nil "[]: ns_shared" + intros + (*Initial trace is empty*) + Nil: "[] \ ns_shared" + (*The spy MAY say anything he CAN say. We do not expect him to + invent new nonces here, but he can also use NS1. Common to + all similar protocols.*) + Fake: "\evs \ ns_shared; X \ synth (analz (spies evs))\ + \ Says Spy B X # evs \ ns_shared" + + (*Alice initiates a protocol run, requesting to talk to any B*) + NS1: "\evs1 \ ns_shared; Nonce NA \ used evs1\ + \ Says A Server \Agent A, Agent B, Nonce NA\ # evs1 \ ns_shared" + + (*Server's response to Alice's message. + !! It may respond more than once to A's request !! + Server doesn't know who the true sender is, hence the A' in + the sender field.*) + NS2: "\evs2 \ ns_shared; Key KAB \ used evs2; + Says A' Server \Agent A, Agent B, Nonce NA\ \ set evs2\ + \ Says Server A + (Crypt (shrK A) + \Nonce NA, Agent B, Key KAB, + (Crypt (shrK B) \Key KAB, Agent A\)\) + # evs2 \ ns_shared" + + (*We can't assume S=Server. Agent A "remembers" her nonce. + Need A \ Server because we allow messages to self.*) + NS3: "\evs3 \ ns_shared; A \ Server; + Says S A (Crypt (shrK A) \Nonce NA, Agent B, Key K, X\) \ set evs3; + Says A Server \Agent A, Agent B, Nonce NA\ \ set evs3\ + \ Says A B X # evs3 \ ns_shared" + + (*Bob's nonce exchange. He does not know who the message came + from, but responds to A because she is mentioned inside.*) + NS4: "\evs4 \ ns_shared; Nonce NB \ used evs4; + Says A' B (Crypt (shrK B) \Key K, Agent A\) \ set evs4\ + \ Says B A (Crypt K (Nonce NB)) # evs4 \ ns_shared" - (*The spy MAY say anything he CAN say. We do not expect him to - invent new nonces here, but he can also use NS1. Common to - all similar protocols.*) - Fake "[| evs: ns_shared; X: synth (analz (spies evs)) |] - ==> Says Spy B X # evs : ns_shared" + (*Alice responds with Nonce NB if she has seen the key before. + Maybe should somehow check Nonce NA again. + We do NOT send NB-1 or similar as the Spy cannot spoof such things. + Letting the Spy add or subtract 1 lets him send \nonces. + Instead we distinguish the messages by sending the nonce twice.*) + NS5: "\evs5 \ ns_shared; + Says B' A (Crypt K (Nonce NB)) \ set evs5; + Says S A (Crypt (shrK A) \Nonce NA, Agent B, Key K, X\) + \ set evs5\ + \ Says A B (Crypt K \Nonce NB, Nonce NB\) # evs5 \ ns_shared" + + (*This message models possible leaks of session keys. + The two Nonces identify the protocol run: the rule insists upon + the true senders in order to make them accurate.*) + Oops: "\evso \ ns_shared; Says B A (Crypt K (Nonce NB)) \ set evso; + Says Server A (Crypt (shrK A) \Nonce NA, Agent B, Key K, X\) + \ set evso\ + \ Notes Spy \Nonce NA, Nonce NB, Key K\ # evso \ ns_shared" + +declare knows_Spy_partsEs [elim] +declare analz_subset_parts [THEN subsetD, dest] +declare Fake_parts_insert [THEN subsetD, dest] +declare image_eq_UN [simp] (*accelerates proofs involving nested images*) + + +(*A "possibility property": there are traces that reach the end*) +lemma "A \ Server \ \N K. \evs \ ns_shared. + Says A B (Crypt K \Nonce N, Nonce N\) \ set evs" +apply (intro exI bexI) +apply (rule_tac [2] ns_shared.Nil + [THEN ns_shared.NS1, THEN ns_shared.NS2, THEN ns_shared.NS3, + THEN ns_shared.NS4, THEN ns_shared.NS5]) +apply possibility +done + +(*This version is similar, while instantiating ?K and ?N to epsilon-terms +lemma "A \ Server \ \evs \ ns_shared. + Says A B (Crypt ?K \Nonce ?N, Nonce ?N\) \ set evs" +*) + + +(**** Inductive proofs about ns_shared ****) + +(*Forwarding lemmas, to aid simplification*) - (*Alice initiates a protocol run, requesting to talk to any B*) - NS1 "[| evs1: ns_shared; Nonce NA ~: used evs1 |] - ==> Says A Server {|Agent A, Agent B, Nonce NA|} # evs1 - : ns_shared" +(*For reasoning about the encrypted portion of message NS3*) +lemma NS3_msg_in_parts_spies: + "Says S A (Crypt KA \N, B, K, X\) \ set evs \ X \ parts (spies evs)" +by blast + +(*For reasoning about the Oops message*) +lemma Oops_parts_spies: + "Says Server A (Crypt (shrK A) \NA, B, K, X\) \ set evs + \ K \ parts (spies evs)" +by blast + +(** Theorems of the form X \ parts (spies evs) imply that NOBODY + sends messages containing X! **) + +(*Spy never sees another agent's shared key! (unless it's bad at start)*) +lemma Spy_see_shrK [simp]: + "evs \ ns_shared \ (Key (shrK A) \ parts (spies evs)) = (A \ bad)" +apply (erule ns_shared.induct, force, frule_tac [4] NS3_msg_in_parts_spies) +apply simp_all +apply blast+; +done + + +lemma Spy_analz_shrK [simp]: + "evs \ ns_shared \ (Key (shrK A) \ analz (spies evs)) = (A \ bad)" +by auto + + +(*Nobody can have used non-existent keys!*) +lemma new_keys_not_used [rule_format, simp]: + "evs \ ns_shared \ Key K \ used evs \ K \ keysFor (parts (spies evs))" +apply (erule ns_shared.induct, force, frule_tac [4] NS3_msg_in_parts_spies) +apply simp_all +(*Fake, NS2, NS4, NS5*) +apply (blast dest!: keysFor_parts_insert)+ +done + + +(** Lemmas concerning the form of items passed in messages **) + +(*Describes the form of K, X and K' when the Server sends this message.*) +lemma Says_Server_message_form: + "\Says Server A (Crypt K' \N, Agent B, Key K, X\) \ set evs; + evs \ ns_shared\ + \ K \ range shrK \ + X = (Crypt (shrK B) \Key K, Agent A\) \ + K' = shrK A" +by (erule rev_mp, erule ns_shared.induct, auto) + - (*Server's response to Alice's message. - !! It may respond more than once to A's request !! - Server doesn't know who the true sender is, hence the A' in - the sender field.*) - NS2 "[| evs2: ns_shared; Key KAB ~: used evs2; - Says A' Server {|Agent A, Agent B, Nonce NA|} : set evs2 |] - ==> Says Server A - (Crypt (shrK A) - {|Nonce NA, Agent B, Key KAB, - (Crypt (shrK B) {|Key KAB, Agent A|})|}) - # evs2 : ns_shared" +(*If the encrypted message appears then it originated with the Server*) +lemma A_trusts_NS2: + "\Crypt (shrK A) \NA, Agent B, Key K, X\ \ parts (spies evs); + A \ bad; evs \ ns_shared\ + \ Says Server A (Crypt (shrK A) \NA, Agent B, Key K, X\) \ set evs" +apply (erule rev_mp) +apply (erule ns_shared.induct, force, drule_tac [4] NS3_msg_in_parts_spies) +apply auto +done + +lemma cert_A_form: + "\Crypt (shrK A) \NA, Agent B, Key K, X\ \ parts (spies evs); + A \ bad; evs \ ns_shared\ + \ K \ range shrK \ X = (Crypt (shrK B) \Key K, Agent A\)" +by (blast dest!: A_trusts_NS2 Says_Server_message_form) + +(*EITHER describes the form of X when the following message is sent, + OR reduces it to the Fake case. + Use Says_Server_message_form if applicable.*) +lemma Says_S_message_form: + "\Says S A (Crypt (shrK A) \Nonce NA, Agent B, Key K, X\) \ set evs; + evs \ ns_shared\ + \ (K \ range shrK \ X = (Crypt (shrK B) \Key K, Agent A\)) + \ X \ analz (spies evs)" +apply (frule Says_imp_knows_Spy) +(*mystery: why is this frule needed?*) +apply (blast dest: cert_A_form analz.Inj) +done + +(*Alternative version also provable +lemma Says_S_message_form2: + "\Says S A (Crypt (shrK A) \Nonce NA, Agent B, Key K, X\) \ set evs; + evs \ ns_shared\ + \ Says Server A (Crypt (shrK A) \Nonce NA, Agent B, Key K, X\) \ set evs + \ X \ analz (spies evs)" +apply (case_tac "A \ bad") +apply (force dest!: Says_imp_knows_Spy [THEN analz.Inj]); +by (blast dest!: A_trusts_NS2 Says_Server_message_form) +*) + + +(**** + SESSION KEY COMPROMISE THEOREM. To prove theorems of the form + + Key K \ analz (insert (Key KAB) (spies evs)) \ + Key K \ analz (spies evs) + + A more general formula must be proved inductively. +****) - (*We can't assume S=Server. Agent A "remembers" her nonce. - Need A ~= Server because we allow messages to self.*) - NS3 "[| evs3: ns_shared; A ~= Server; - Says S A (Crypt (shrK A) {|Nonce NA, Agent B, Key K, X|}) - : set evs3; - Says A Server {|Agent A, Agent B, Nonce NA|} : set evs3 |] - ==> Says A B X # evs3 : ns_shared" +(*NOT useful in this form, but it says that session keys are not used + to encrypt messages containing other keys, in the actual protocol. + We require that agents should behave like this subsequently also.*) +lemma "\evs \ ns_shared; Kab \ range shrK\ \ + (Crypt KAB X) \ parts (spies evs) \ + Key K \ parts {X} \ Key K \ parts (spies evs)" +apply (erule ns_shared.induct, force, frule_tac [4] NS3_msg_in_parts_spies) +apply simp_all +(*Fake*) +apply (blast dest: parts_insert_subset_Un) +(*Base, NS4 and NS5*) +apply auto +done + + +(** Session keys are not used to encrypt other session keys **) + +(*The equality makes the induction hypothesis easier to apply*) + +lemma analz_image_freshK [rule_format]: + "evs \ ns_shared \ + \K KK. KK \ - (range shrK) \ + (Key K \ analz (Key`KK \ (spies evs))) = + (K \ KK \ Key K \ analz (spies evs))" +apply (erule ns_shared.induct, force) +apply (frule_tac [7] Says_Server_message_form) +apply (erule_tac [4] Says_S_message_form [THEN disjE]) +apply (analz_freshK) +apply (spy_analz) +done + + +lemma analz_insert_freshK: + "\evs \ ns_shared; KAB \ range shrK\ \ + Key K \ analz (insert (Key KAB) (spies evs)) = + (K = KAB \ Key K \ analz (spies evs))" +by (simp only: analz_image_freshK analz_image_freshK_simps) + + +(** The session key K uniquely identifies the message **) - (*Bob's nonce exchange. He does not know who the message came - from, but responds to A because she is mentioned inside.*) - NS4 "[| evs4: ns_shared; Nonce NB ~: used evs4; - Says A' B (Crypt (shrK B) {|Key K, Agent A|}) : set evs4 |] - ==> Says B A (Crypt K (Nonce NB)) # evs4 - : ns_shared" +(*In messages of this form, the session key uniquely identifies the rest*) +lemma unique_session_keys: + "\Says Server A (Crypt (shrK A) \NA, Agent B, Key K, X\) \ set evs; + Says Server A' (Crypt (shrK A') \NA', Agent B', Key K, X'\) \ set evs; + evs \ ns_shared\ \ A=A' \ NA=NA' \ B=B' \ X = X'" +apply (erule rev_mp, erule rev_mp, erule ns_shared.induct) +apply simp_all +apply blast+ +done + + +(** Crucial secrecy property: Spy does not see the keys sent in msg NS2 **) + +lemma secrecy_lemma [rule_format]: + "\Says Server A (Crypt (shrK A) \NA, Agent B, Key K, + Crypt (shrK B) \Key K, Agent A\\) + \ set evs; + A \ bad; B \ bad; evs \ ns_shared\ + \ (\NB. Notes Spy \NA, NB, Key K\ \ set evs) \ + Key K \ analz (spies evs)" +apply (erule rev_mp) +apply (erule ns_shared.induct, force) +apply (frule_tac [7] Says_Server_message_form) +apply (frule_tac [4] Says_S_message_form) +apply (erule_tac [5] disjE) +apply (simp_all add: analz_insert_eq analz_insert_freshK pushes split_ifs) +apply spy_analz (*Fake*) +apply blast (*NS2*) +(*NS3, Server sub-case*) (**LEVEL 6 **) +apply clarify +apply (frule Says_imp_knows_Spy [THEN parts.Inj, THEN A_trusts_NS2]) +apply (blast dest: Says_imp_knows_Spy [THEN analz.Inj, THEN Crypt_Spy_analz_bad]) +apply assumption +apply (blast dest: unique_session_keys)+ (*also proves Oops*) +done + + +(*Final version: Server's message in the most abstract form*) +lemma Spy_not_see_encrypted_key: + "\Says Server A (Crypt K' \NA, Agent B, Key K, X\) \ set evs; + \NB. Notes Spy \NA, NB, Key K\ \ set evs; + A \ bad; B \ bad; evs \ ns_shared\ + \ Key K \ analz (spies evs)" +apply (frule Says_Server_message_form, assumption) +apply (auto dest: Says_Server_message_form secrecy_lemma) +done + + +(**** Guarantees available at various stages of protocol ***) - (*Alice responds with Nonce NB if she has seen the key before. - Maybe should somehow check Nonce NA again. - We do NOT send NB-1 or similar as the Spy cannot spoof such things. - Letting the Spy add or subtract 1 lets him send ALL nonces. - Instead we distinguish the messages by sending the nonce twice.*) - NS5 "[| evs5: ns_shared; - Says B' A (Crypt K (Nonce NB)) : set evs5; - Says S A (Crypt (shrK A) {|Nonce NA, Agent B, Key K, X|}) - : set evs5 |] - ==> Says A B (Crypt K {|Nonce NB, Nonce NB|}) # evs5 : ns_shared" - - (*This message models possible leaks of session keys. - The two Nonces identify the protocol run: the rule insists upon - the true senders in order to make them accurate.*) - Oops "[| evso: ns_shared; Says B A (Crypt K (Nonce NB)) : set evso; - Says Server A (Crypt (shrK A) {|Nonce NA, Agent B, Key K, X|}) - : set evso |] - ==> Notes Spy {|Nonce NA, Nonce NB, Key K|} # evso : ns_shared" +(*If the encrypted message appears then it originated with the Server*) +lemma B_trusts_NS3: + "\Crypt (shrK B) \Key K, Agent A\ \ parts (spies evs); + B \ bad; evs \ ns_shared\ + \ \NA. Says Server A + (Crypt (shrK A) \NA, Agent B, Key K, + Crypt (shrK B) \Key K, Agent A\\) + \ set evs" +apply (erule rev_mp) +apply (erule ns_shared.induct, force, drule_tac [4] NS3_msg_in_parts_spies) +apply auto +done + + +lemma A_trusts_NS4_lemma [rule_format]: + "evs \ ns_shared \ + Key K \ analz (spies evs) \ + Says Server A (Crypt (shrK A) \NA, Agent B, Key K, X\) \ set evs \ + Crypt K (Nonce NB) \ parts (spies evs) \ + Says B A (Crypt K (Nonce NB)) \ set evs" +apply (erule ns_shared.induct, force, drule_tac [4] NS3_msg_in_parts_spies) +apply analz_mono_contra +apply simp_all +apply blast (*Fake*) +(*NS2: contradiction from the assumptions + Key K \ used evs2 and Crypt K (Nonce NB) \ parts (spies evs2) *) +apply (force dest!: Crypt_imp_keysFor) +apply blast (*NS3*) +(*NS4*) +apply clarify; +apply (frule Says_imp_knows_Spy [THEN analz.Inj]) +apply (blast dest: Says_imp_knows_Spy [THEN analz.Inj] Crypt_Spy_analz_bad + B_trusts_NS3 unique_session_keys) +done + +(*This version no longer assumes that K is secure*) +lemma A_trusts_NS4: + "\Crypt K (Nonce NB) \ parts (spies evs); + Crypt (shrK A) \NA, Agent B, Key K, X\ \ parts (spies evs); + \NB. Notes Spy \NA, NB, Key K\ \ set evs; + A \ bad; B \ bad; evs \ ns_shared\ + \ Says B A (Crypt K (Nonce NB)) \ set evs" +by (blast intro: A_trusts_NS4_lemma + dest: A_trusts_NS2 Spy_not_see_encrypted_key) + +(*If the session key has been used in NS4 then somebody has forwarded + component X in some instance of NS4. Perhaps an interesting property, + but not needed (after all) for the proofs below.*) +theorem NS4_implies_NS3 [rule_format]: + "evs \ ns_shared \ + Key K \ analz (spies evs) \ + Says Server A (Crypt (shrK A) \NA, Agent B, Key K, X\) \ set evs \ + Crypt K (Nonce NB) \ parts (spies evs) \ + (\A'. Says A' B X \ set evs)" +apply (erule ns_shared.induct, force, drule_tac [4] NS3_msg_in_parts_spies) +apply analz_mono_contra +apply (simp_all add: ex_disj_distrib) +apply blast (*Fake*) +apply (blast dest!: new_keys_not_used Crypt_imp_keysFor) (*NS2*) +apply blast (*NS3*) +(*NS4*) +apply (case_tac "Ba \ bad") +apply (blast dest: Says_imp_knows_Spy [THEN analz.Inj] Crypt_Spy_analz_bad); +apply (frule Says_imp_knows_Spy [THEN parts.Inj, THEN B_trusts_NS3], + assumption+) +apply (blast dest: unique_session_keys) +done + + +lemma B_trusts_NS5_lemma [rule_format]: + "\B \ bad; evs \ ns_shared\ \ + Key K \ analz (spies evs) \ + Says Server A + (Crypt (shrK A) \NA, Agent B, Key K, + Crypt (shrK B) \Key K, Agent A\\) \ set evs \ + Crypt K \Nonce NB, Nonce NB\ \ parts (spies evs) \ + Says A B (Crypt K \Nonce NB, Nonce NB\) \ set evs" +apply (erule ns_shared.induct, force, drule_tac [4] NS3_msg_in_parts_spies) +apply analz_mono_contra +apply simp_all +apply blast (*Fake*) +apply (blast dest!: new_keys_not_used Crypt_imp_keysFor) (*NS2*) +apply (blast dest!: cert_A_form) (*NS3*) +(**LEVEL 5**) +(*NS5*) +apply clarify +apply (case_tac "Aa \ bad") +apply (blast dest: Says_imp_knows_Spy [THEN analz.Inj] Crypt_Spy_analz_bad); +apply (blast dest: A_trusts_NS2 unique_session_keys) +done + + +(*Very strong Oops condition reveals protocol's weakness*) +lemma B_trusts_NS5: + "\Crypt K \Nonce NB, Nonce NB\ \ parts (spies evs); + Crypt (shrK B) \Key K, Agent A\ \ parts (spies evs); + \NA NB. Notes Spy \NA, NB, Key K\ \ set evs; + A \ bad; B \ bad; evs \ ns_shared\ + \ Says A B (Crypt K \Nonce NB, Nonce NB\) \ set evs" +apply (drule B_trusts_NS3, clarify+) +apply (blast intro: B_trusts_NS5_lemma + dest: dest: Spy_not_see_encrypted_key) +(*surprisingly delicate proof due to quantifier interactions*) +done end