3 Copyright 1996 University of Cambridge |
3 Copyright 1996 University of Cambridge |
4 |
4 |
5 Original file is ../Auth/NS_Public_Bad |
5 Original file is ../Auth/NS_Public_Bad |
6 *) |
6 *) |
7 |
7 |
8 section{*Analyzing the Needham-Schroeder Public-Key Protocol in UNITY*} |
8 section\<open>Analyzing the Needham-Schroeder Public-Key Protocol in UNITY\<close> |
9 |
9 |
10 theory NSP_Bad imports "../../Auth/Public" "../UNITY_Main" begin |
10 theory NSP_Bad imports "../../Auth/Public" "../UNITY_Main" begin |
11 |
11 |
12 text{*This is the flawed version, vulnerable to Lowe's attack. |
12 text\<open>This is the flawed version, vulnerable to Lowe's attack. |
13 From page 260 of |
13 From page 260 of |
14 Burrows, Abadi and Needham. A Logic of Authentication. |
14 Burrows, Abadi and Needham. A Logic of Authentication. |
15 Proc. Royal Soc. 426 (1989). |
15 Proc. Royal Soc. 426 (1989). |
16 *} |
16 \<close> |
17 |
17 |
18 type_synonym state = "event list" |
18 type_synonym state = "event list" |
19 |
19 |
20 (*The spy MAY say anything he CAN say. We do not expect him to |
20 (*The spy MAY say anything he CAN say. We do not expect him to |
21 invent new nonces here, but he can also use NS1. Common to |
21 invent new nonces here, but he can also use NS1. Common to |
61 |
61 |
62 declare spies_partsEs [elim] |
62 declare spies_partsEs [elim] |
63 declare analz_into_parts [dest] |
63 declare analz_into_parts [dest] |
64 declare Fake_parts_insert_in_Un [dest] |
64 declare Fake_parts_insert_in_Un [dest] |
65 |
65 |
66 text{*For other theories, e.g. Mutex and Lift, using [iff] slows proofs down. |
66 text\<open>For other theories, e.g. Mutex and Lift, using [iff] slows proofs down. |
67 Here, it facilitates re-use of the Auth proofs.*} |
67 Here, it facilitates re-use of the Auth proofs.\<close> |
68 |
68 |
69 declare Fake_def [THEN def_act_simp, iff] |
69 declare Fake_def [THEN def_act_simp, iff] |
70 declare NS1_def [THEN def_act_simp, iff] |
70 declare NS1_def [THEN def_act_simp, iff] |
71 declare NS2_def [THEN def_act_simp, iff] |
71 declare NS2_def [THEN def_act_simp, iff] |
72 declare NS3_def [THEN def_act_simp, iff] |
72 declare NS3_def [THEN def_act_simp, iff] |
73 |
73 |
74 declare Nprg_def [THEN def_prg_Init, simp] |
74 declare Nprg_def [THEN def_prg_Init, simp] |
75 |
75 |
76 |
76 |
77 text{*A "possibility property": there are traces that reach the end. |
77 text\<open>A "possibility property": there are traces that reach the end. |
78 Replace by LEADSTO proof!*} |
78 Replace by LEADSTO proof!\<close> |
79 lemma "A \<noteq> B ==> |
79 lemma "A \<noteq> B ==> |
80 \<exists>NB. \<exists>s \<in> reachable Nprg. Says A B (Crypt (pubK B) (Nonce NB)) \<in> set s" |
80 \<exists>NB. \<exists>s \<in> reachable Nprg. Says A B (Crypt (pubK B) (Nonce NB)) \<in> set s" |
81 apply (intro exI bexI) |
81 apply (intro exI bexI) |
82 apply (rule_tac [2] act = "totalize_act NS3" in reachable.Acts) |
82 apply (rule_tac [2] act = "totalize_act NS3" in reachable.Acts) |
83 apply (rule_tac [3] act = "totalize_act NS2" in reachable.Acts) |
83 apply (rule_tac [3] act = "totalize_act NS2" in reachable.Acts) |
86 apply (simp_all (no_asm_simp) add: Nprg_def totalize_act_def) |
86 apply (simp_all (no_asm_simp) add: Nprg_def totalize_act_def) |
87 apply auto |
87 apply auto |
88 done |
88 done |
89 |
89 |
90 |
90 |
91 subsection{*Inductive Proofs about @{term ns_public}*} |
91 subsection\<open>Inductive Proofs about @{term ns_public}\<close> |
92 |
92 |
93 lemma ns_constrainsI: |
93 lemma ns_constrainsI: |
94 "(!!act s s'. [| act \<in> {Id, Fake, NS1, NS2, NS3}; |
94 "(!!act s s'. [| act \<in> {Id, Fake, NS1, NS2, NS3}; |
95 (s,s') \<in> act; s \<in> A |] ==> s' \<in> A') |
95 (s,s') \<in> act; s \<in> A |] ==> s' \<in> A') |
96 ==> Nprg \<in> A co A'" |
96 ==> Nprg \<in> A co A'" |
97 apply (simp add: Nprg_def mk_total_program_def) |
97 apply (simp add: Nprg_def mk_total_program_def) |
98 apply (rule constrainsI, auto) |
98 apply (rule constrainsI, auto) |
99 done |
99 done |
100 |
100 |
101 |
101 |
102 text{*This ML code does the inductions directly.*} |
102 text\<open>This ML code does the inductions directly.\<close> |
103 ML{* |
103 ML\<open> |
104 fun ns_constrains_tac ctxt i = |
104 fun ns_constrains_tac ctxt i = |
105 SELECT_GOAL |
105 SELECT_GOAL |
106 (EVERY |
106 (EVERY |
107 [REPEAT (eresolve_tac ctxt @{thms Always_ConstrainsI} 1), |
107 [REPEAT (eresolve_tac ctxt @{thms Always_ConstrainsI} 1), |
108 REPEAT (resolve_tac ctxt [@{thm StableI}, @{thm stableI}, @{thm constrains_imp_Constrains}] 1), |
108 REPEAT (resolve_tac ctxt [@{thm StableI}, @{thm stableI}, @{thm constrains_imp_Constrains}] 1), |
119 [resolve_tac ctxt @{thms AlwaysI} 1, |
119 [resolve_tac ctxt @{thms AlwaysI} 1, |
120 force_tac ctxt 1, |
120 force_tac ctxt 1, |
121 (*"reachable" gets in here*) |
121 (*"reachable" gets in here*) |
122 resolve_tac ctxt [@{thm Always_reachable} RS @{thm Always_ConstrainsI} RS @{thm StableI}] 1, |
122 resolve_tac ctxt [@{thm Always_reachable} RS @{thm Always_ConstrainsI} RS @{thm StableI}] 1, |
123 ns_constrains_tac ctxt 1]; |
123 ns_constrains_tac ctxt 1]; |
124 *} |
124 \<close> |
125 |
125 |
126 method_setup ns_induct = {* |
126 method_setup ns_induct = \<open> |
127 Scan.succeed (SIMPLE_METHOD' o ns_induct_tac) *} |
127 Scan.succeed (SIMPLE_METHOD' o ns_induct_tac)\<close> |
128 "for inductive reasoning about the Needham-Schroeder protocol" |
128 "for inductive reasoning about the Needham-Schroeder protocol" |
129 |
129 |
130 text{*Converts invariants into statements about reachable states*} |
130 text\<open>Converts invariants into statements about reachable states\<close> |
131 lemmas Always_Collect_reachableD = |
131 lemmas Always_Collect_reachableD = |
132 Always_includes_reachable [THEN subsetD, THEN CollectD] |
132 Always_includes_reachable [THEN subsetD, THEN CollectD] |
133 |
133 |
134 text{*Spy never sees another agent's private key! (unless it's bad at start)*} |
134 text\<open>Spy never sees another agent's private key! (unless it's bad at start)\<close> |
135 lemma Spy_see_priK: |
135 lemma Spy_see_priK: |
136 "Nprg \<in> Always {s. (Key (priK A) \<in> parts (spies s)) = (A \<in> bad)}" |
136 "Nprg \<in> Always {s. (Key (priK A) \<in> parts (spies s)) = (A \<in> bad)}" |
137 apply ns_induct |
137 apply ns_induct |
138 apply blast |
138 apply blast |
139 done |
139 done |
143 "Nprg \<in> Always {s. (Key (priK A) \<in> analz (spies s)) = (A \<in> bad)}" |
143 "Nprg \<in> Always {s. (Key (priK A) \<in> analz (spies s)) = (A \<in> bad)}" |
144 by (rule Always_reachable [THEN Always_weaken], auto) |
144 by (rule Always_reachable [THEN Always_weaken], auto) |
145 declare Spy_analz_priK [THEN Always_Collect_reachableD, simp] |
145 declare Spy_analz_priK [THEN Always_Collect_reachableD, simp] |
146 |
146 |
147 |
147 |
148 subsection{*Authenticity properties obtained from NS2*} |
148 subsection\<open>Authenticity properties obtained from NS2\<close> |
149 |
149 |
150 text{*It is impossible to re-use a nonce in both NS1 and NS2 provided the |
150 text\<open>It is impossible to re-use a nonce in both NS1 and NS2 provided the |
151 nonce is secret. (Honest users generate fresh nonces.)*} |
151 nonce is secret. (Honest users generate fresh nonces.)\<close> |
152 lemma no_nonce_NS1_NS2: |
152 lemma no_nonce_NS1_NS2: |
153 "Nprg |
153 "Nprg |
154 \<in> Always {s. Crypt (pubK C) \<lbrace>NA', Nonce NA\<rbrace> \<in> parts (spies s) --> |
154 \<in> Always {s. Crypt (pubK C) \<lbrace>NA', Nonce NA\<rbrace> \<in> parts (spies s) --> |
155 Crypt (pubK B) \<lbrace>Nonce NA, Agent A\<rbrace> \<in> parts (spies s) --> |
155 Crypt (pubK B) \<lbrace>Nonce NA, Agent A\<rbrace> \<in> parts (spies s) --> |
156 Nonce NA \<in> analz (spies s)}" |
156 Nonce NA \<in> analz (spies s)}" |
157 apply ns_induct |
157 apply ns_induct |
158 apply (blast intro: analz_insertI)+ |
158 apply (blast intro: analz_insertI)+ |
159 done |
159 done |
160 |
160 |
161 text{*Adding it to the claset slows down proofs...*} |
161 text\<open>Adding it to the claset slows down proofs...\<close> |
162 lemmas no_nonce_NS1_NS2_reachable = |
162 lemmas no_nonce_NS1_NS2_reachable = |
163 no_nonce_NS1_NS2 [THEN Always_Collect_reachableD, rule_format] |
163 no_nonce_NS1_NS2 [THEN Always_Collect_reachableD, rule_format] |
164 |
164 |
165 |
165 |
166 text{*Unicity for NS1: nonce NA identifies agents A and B*} |
166 text\<open>Unicity for NS1: nonce NA identifies agents A and B\<close> |
167 lemma unique_NA_lemma: |
167 lemma unique_NA_lemma: |
168 "Nprg |
168 "Nprg |
169 \<in> Always {s. Nonce NA \<notin> analz (spies s) --> |
169 \<in> Always {s. Nonce NA \<notin> analz (spies s) --> |
170 Crypt(pubK B) \<lbrace>Nonce NA, Agent A\<rbrace> \<in> parts(spies s) --> |
170 Crypt(pubK B) \<lbrace>Nonce NA, Agent A\<rbrace> \<in> parts(spies s) --> |
171 Crypt(pubK B') \<lbrace>Nonce NA, Agent A'\<rbrace> \<in> parts(spies s) --> |
171 Crypt(pubK B') \<lbrace>Nonce NA, Agent A'\<rbrace> \<in> parts(spies s) --> |
172 A=A' & B=B'}" |
172 A=A' & B=B'}" |
173 apply ns_induct |
173 apply ns_induct |
174 apply auto |
174 apply auto |
175 txt{*Fake, NS1 are non-trivial*} |
175 txt\<open>Fake, NS1 are non-trivial\<close> |
176 done |
176 done |
177 |
177 |
178 text{*Unicity for NS1: nonce NA identifies agents A and B*} |
178 text\<open>Unicity for NS1: nonce NA identifies agents A and B\<close> |
179 lemma unique_NA: |
179 lemma unique_NA: |
180 "[| Crypt(pubK B) \<lbrace>Nonce NA, Agent A\<rbrace> \<in> parts(spies s); |
180 "[| Crypt(pubK B) \<lbrace>Nonce NA, Agent A\<rbrace> \<in> parts(spies s); |
181 Crypt(pubK B') \<lbrace>Nonce NA, Agent A'\<rbrace> \<in> parts(spies s); |
181 Crypt(pubK B') \<lbrace>Nonce NA, Agent A'\<rbrace> \<in> parts(spies s); |
182 Nonce NA \<notin> analz (spies s); |
182 Nonce NA \<notin> analz (spies s); |
183 s \<in> reachable Nprg |] |
183 s \<in> reachable Nprg |] |
184 ==> A=A' & B=B'" |
184 ==> A=A' & B=B'" |
185 by (blast dest: unique_NA_lemma [THEN Always_Collect_reachableD]) |
185 by (blast dest: unique_NA_lemma [THEN Always_Collect_reachableD]) |
186 |
186 |
187 |
187 |
188 text{*Secrecy: Spy does not see the nonce sent in msg NS1 if A and B are secure*} |
188 text\<open>Secrecy: Spy does not see the nonce sent in msg NS1 if A and B are secure\<close> |
189 lemma Spy_not_see_NA: |
189 lemma Spy_not_see_NA: |
190 "[| A \<notin> bad; B \<notin> bad |] |
190 "[| A \<notin> bad; B \<notin> bad |] |
191 ==> Nprg \<in> Always |
191 ==> Nprg \<in> Always |
192 {s. Says A B (Crypt(pubK B) \<lbrace>Nonce NA, Agent A\<rbrace>) \<in> set s |
192 {s. Says A B (Crypt(pubK B) \<lbrace>Nonce NA, Agent A\<rbrace>) \<in> set s |
193 --> Nonce NA \<notin> analz (spies s)}" |
193 --> Nonce NA \<notin> analz (spies s)}" |
194 apply ns_induct |
194 apply ns_induct |
195 txt{*NS3*} |
195 txt\<open>NS3\<close> |
196 prefer 4 apply (blast intro: no_nonce_NS1_NS2_reachable) |
196 prefer 4 apply (blast intro: no_nonce_NS1_NS2_reachable) |
197 txt{*NS2*} |
197 txt\<open>NS2\<close> |
198 prefer 3 apply (blast dest: unique_NA) |
198 prefer 3 apply (blast dest: unique_NA) |
199 txt{*NS1*} |
199 txt\<open>NS1\<close> |
200 prefer 2 apply blast |
200 prefer 2 apply blast |
201 txt{*Fake*} |
201 txt\<open>Fake\<close> |
202 apply spy_analz |
202 apply spy_analz |
203 done |
203 done |
204 |
204 |
205 |
205 |
206 text{*Authentication for A: if she receives message 2 and has used NA |
206 text\<open>Authentication for A: if she receives message 2 and has used NA |
207 to start a run, then B has sent message 2.*} |
207 to start a run, then B has sent message 2.\<close> |
208 lemma A_trusts_NS2: |
208 lemma A_trusts_NS2: |
209 "[| A \<notin> bad; B \<notin> bad |] |
209 "[| A \<notin> bad; B \<notin> bad |] |
210 ==> Nprg \<in> Always |
210 ==> Nprg \<in> Always |
211 {s. Says A B (Crypt(pubK B) \<lbrace>Nonce NA, Agent A\<rbrace>) \<in> set s & |
211 {s. Says A B (Crypt(pubK B) \<lbrace>Nonce NA, Agent A\<rbrace>) \<in> set s & |
212 Crypt(pubK A) \<lbrace>Nonce NA, Nonce NB\<rbrace> \<in> parts (knows Spy s) |
212 Crypt(pubK A) \<lbrace>Nonce NA, Nonce NB\<rbrace> \<in> parts (knows Spy s) |
215 apply (insert Spy_not_see_NA [of A B NA], simp, ns_induct) |
215 apply (insert Spy_not_see_NA [of A B NA], simp, ns_induct) |
216 apply (auto dest: unique_NA) |
216 apply (auto dest: unique_NA) |
217 done |
217 done |
218 |
218 |
219 |
219 |
220 text{*If the encrypted message appears then it originated with Alice in NS1*} |
220 text\<open>If the encrypted message appears then it originated with Alice in NS1\<close> |
221 lemma B_trusts_NS1: |
221 lemma B_trusts_NS1: |
222 "Nprg \<in> Always |
222 "Nprg \<in> Always |
223 {s. Nonce NA \<notin> analz (spies s) --> |
223 {s. Nonce NA \<notin> analz (spies s) --> |
224 Crypt (pubK B) \<lbrace>Nonce NA, Agent A\<rbrace> \<in> parts (spies s) |
224 Crypt (pubK B) \<lbrace>Nonce NA, Agent A\<rbrace> \<in> parts (spies s) |
225 --> Says A B (Crypt (pubK B) \<lbrace>Nonce NA, Agent A\<rbrace>) \<in> set s}" |
225 --> Says A B (Crypt (pubK B) \<lbrace>Nonce NA, Agent A\<rbrace>) \<in> set s}" |
226 apply ns_induct |
226 apply ns_induct |
227 apply blast |
227 apply blast |
228 done |
228 done |
229 |
229 |
230 |
230 |
231 subsection{*Authenticity properties obtained from NS2*} |
231 subsection\<open>Authenticity properties obtained from NS2\<close> |
232 |
232 |
233 text{*Unicity for NS2: nonce NB identifies nonce NA and agent A. |
233 text\<open>Unicity for NS2: nonce NB identifies nonce NA and agent A. |
234 Proof closely follows that of @{text unique_NA}.*} |
234 Proof closely follows that of \<open>unique_NA\<close>.\<close> |
235 lemma unique_NB_lemma: |
235 lemma unique_NB_lemma: |
236 "Nprg |
236 "Nprg |
237 \<in> Always {s. Nonce NB \<notin> analz (spies s) --> |
237 \<in> Always {s. Nonce NB \<notin> analz (spies s) --> |
238 Crypt (pubK A) \<lbrace>Nonce NA, Nonce NB\<rbrace> \<in> parts (spies s) --> |
238 Crypt (pubK A) \<lbrace>Nonce NA, Nonce NB\<rbrace> \<in> parts (spies s) --> |
239 Crypt(pubK A') \<lbrace>Nonce NA', Nonce NB\<rbrace> \<in> parts(spies s) --> |
239 Crypt(pubK A') \<lbrace>Nonce NA', Nonce NB\<rbrace> \<in> parts(spies s) --> |
240 A=A' & NA=NA'}" |
240 A=A' & NA=NA'}" |
241 apply ns_induct |
241 apply ns_induct |
242 apply auto |
242 apply auto |
243 txt{*Fake, NS2 are non-trivial*} |
243 txt\<open>Fake, NS2 are non-trivial\<close> |
244 done |
244 done |
245 |
245 |
246 lemma unique_NB: |
246 lemma unique_NB: |
247 "[| Crypt(pubK A) \<lbrace>Nonce NA, Nonce NB\<rbrace> \<in> parts(spies s); |
247 "[| Crypt(pubK A) \<lbrace>Nonce NA, Nonce NB\<rbrace> \<in> parts(spies s); |
248 Crypt(pubK A') \<lbrace>Nonce NA', Nonce NB\<rbrace> \<in> parts(spies s); |
248 Crypt(pubK A') \<lbrace>Nonce NA', Nonce NB\<rbrace> \<in> parts(spies s); |
251 ==> A=A' & NA=NA'" |
251 ==> A=A' & NA=NA'" |
252 apply (blast dest: unique_NB_lemma [THEN Always_Collect_reachableD]) |
252 apply (blast dest: unique_NB_lemma [THEN Always_Collect_reachableD]) |
253 done |
253 done |
254 |
254 |
255 |
255 |
256 text{*NB remains secret PROVIDED Alice never responds with round 3*} |
256 text\<open>NB remains secret PROVIDED Alice never responds with round 3\<close> |
257 lemma Spy_not_see_NB: |
257 lemma Spy_not_see_NB: |
258 "[| A \<notin> bad; B \<notin> bad |] |
258 "[| A \<notin> bad; B \<notin> bad |] |
259 ==> Nprg \<in> Always |
259 ==> Nprg \<in> Always |
260 {s. Says B A (Crypt (pubK A) \<lbrace>Nonce NA, Nonce NB\<rbrace>) \<in> set s & |
260 {s. Says B A (Crypt (pubK A) \<lbrace>Nonce NA, Nonce NB\<rbrace>) \<in> set s & |
261 (ALL C. Says A C (Crypt (pubK C) (Nonce NB)) \<notin> set s) |
261 (ALL C. Says A C (Crypt (pubK C) (Nonce NB)) \<notin> set s) |
262 --> Nonce NB \<notin> analz (spies s)}" |
262 --> Nonce NB \<notin> analz (spies s)}" |
263 apply ns_induct |
263 apply ns_induct |
264 apply (simp_all (no_asm_simp) add: all_conj_distrib) |
264 apply (simp_all (no_asm_simp) add: all_conj_distrib) |
265 txt{*NS3: because NB determines A*} |
265 txt\<open>NS3: because NB determines A\<close> |
266 prefer 4 apply (blast dest: unique_NB) |
266 prefer 4 apply (blast dest: unique_NB) |
267 txt{*NS2: by freshness and unicity of NB*} |
267 txt\<open>NS2: by freshness and unicity of NB\<close> |
268 prefer 3 apply (blast intro: no_nonce_NS1_NS2_reachable) |
268 prefer 3 apply (blast intro: no_nonce_NS1_NS2_reachable) |
269 txt{*NS1: by freshness*} |
269 txt\<open>NS1: by freshness\<close> |
270 prefer 2 apply blast |
270 prefer 2 apply blast |
271 txt{*Fake*} |
271 txt\<open>Fake\<close> |
272 apply spy_analz |
272 apply spy_analz |
273 done |
273 done |
274 |
274 |
275 |
275 |
276 |
276 |
277 text{*Authentication for B: if he receives message 3 and has used NB |
277 text\<open>Authentication for B: if he receives message 3 and has used NB |
278 in message 2, then A has sent message 3--to somebody....*} |
278 in message 2, then A has sent message 3--to somebody....\<close> |
279 lemma B_trusts_NS3: |
279 lemma B_trusts_NS3: |
280 "[| A \<notin> bad; B \<notin> bad |] |
280 "[| A \<notin> bad; B \<notin> bad |] |
281 ==> Nprg \<in> Always |
281 ==> Nprg \<in> Always |
282 {s. Crypt (pubK B) (Nonce NB) \<in> parts (spies s) & |
282 {s. Crypt (pubK B) (Nonce NB) \<in> parts (spies s) & |
283 Says B A (Crypt (pubK A) \<lbrace>Nonce NA, Nonce NB\<rbrace>) \<in> set s |
283 Says B A (Crypt (pubK A) \<lbrace>Nonce NA, Nonce NB\<rbrace>) \<in> set s |
284 --> (\<exists>C. Says A C (Crypt (pubK C) (Nonce NB)) \<in> set s)}" |
284 --> (\<exists>C. Says A C (Crypt (pubK C) (Nonce NB)) \<in> set s)}" |
285 (*insert an invariant for use in some of the subgoals*) |
285 (*insert an invariant for use in some of the subgoals*) |
286 apply (insert Spy_not_see_NB [of A B NA NB], simp, ns_induct) |
286 apply (insert Spy_not_see_NB [of A B NA NB], simp, ns_induct) |
287 apply (simp_all (no_asm_simp) add: ex_disj_distrib) |
287 apply (simp_all (no_asm_simp) add: ex_disj_distrib) |
288 apply auto |
288 apply auto |
289 txt{*NS3: because NB determines A. This use of @{text unique_NB} is robust.*} |
289 txt\<open>NS3: because NB determines A. This use of \<open>unique_NB\<close> is robust.\<close> |
290 apply (blast intro: unique_NB [THEN conjunct1]) |
290 apply (blast intro: unique_NB [THEN conjunct1]) |
291 done |
291 done |
292 |
292 |
293 |
293 |
294 text{*Can we strengthen the secrecy theorem? NO*} |
294 text\<open>Can we strengthen the secrecy theorem? NO\<close> |
295 lemma "[| A \<notin> bad; B \<notin> bad |] |
295 lemma "[| A \<notin> bad; B \<notin> bad |] |
296 ==> Nprg \<in> Always |
296 ==> Nprg \<in> Always |
297 {s. Says B A (Crypt (pubK A) \<lbrace>Nonce NA, Nonce NB\<rbrace>) \<in> set s |
297 {s. Says B A (Crypt (pubK A) \<lbrace>Nonce NA, Nonce NB\<rbrace>) \<in> set s |
298 --> Nonce NB \<notin> analz (spies s)}" |
298 --> Nonce NB \<notin> analz (spies s)}" |
299 apply ns_induct |
299 apply ns_induct |
300 apply auto |
300 apply auto |
301 txt{*Fake*} |
301 txt\<open>Fake\<close> |
302 apply spy_analz |
302 apply spy_analz |
303 txt{*NS2: by freshness and unicity of NB*} |
303 txt\<open>NS2: by freshness and unicity of NB\<close> |
304 apply (blast intro: no_nonce_NS1_NS2_reachable) |
304 apply (blast intro: no_nonce_NS1_NS2_reachable) |
305 txt{*NS3: unicity of NB identifies A and NA, but not B*} |
305 txt\<open>NS3: unicity of NB identifies A and NA, but not B\<close> |
306 apply (frule_tac A'=A in Says_imp_spies [THEN parts.Inj, THEN unique_NB]) |
306 apply (frule_tac A'=A in Says_imp_spies [THEN parts.Inj, THEN unique_NB]) |
307 apply (erule Says_imp_spies [THEN parts.Inj], auto) |
307 apply (erule Says_imp_spies [THEN parts.Inj], auto) |
308 apply (rename_tac s B' C) |
308 apply (rename_tac s B' C) |
309 txt{*This is the attack! |
309 txt\<open>This is the attack! |
310 @{subgoals[display,indent=0,margin=65]} |
310 @{subgoals[display,indent=0,margin=65]} |
311 *} |
311 \<close> |
312 oops |
312 oops |
313 |
313 |
314 |
314 |
315 (* |
315 (* |
316 THIS IS THE ATTACK! |
316 THIS IS THE ATTACK! |