author | paulson |
Tue, 12 Aug 2003 13:35:03 +0200 | |
changeset 14145 | 2e31b8cc8788 |
parent 13956 | 8fe7e12290e1 |
child 14200 | d8598e24f8fa |
permissions | -rw-r--r-- |
2449 | 1 |
(* Title: HOL/Auth/Recur |
2 |
ID: $Id$ |
|
3 |
Author: Lawrence C Paulson, Cambridge University Computer Laboratory |
|
4 |
Copyright 1996 University of Cambridge |
|
5 |
||
6 |
Inductive relation "recur" for the Recursive Authentication protocol. |
|
7 |
*) |
|
8 |
||
11264 | 9 |
theory Recur = Shared: |
2449 | 10 |
|
13922 | 11 |
text{*End marker for message bundles*} |
11264 | 12 |
syntax END :: "msg" |
5434
9b4bed3f394c
Got rid of not_Says_to_self and most uses of ~= in definitions and theorems
paulson
parents:
5359
diff
changeset
|
13 |
translations "END" == "Number 0" |
9b4bed3f394c
Got rid of not_Says_to_self and most uses of ~= in definitions and theorems
paulson
parents:
5359
diff
changeset
|
14 |
|
2449 | 15 |
(*Two session keys are distributed to each agent except for the initiator, |
2516
4d68fbe6378b
Now with Andy Gordon's treatment of freshness to replace newN/K
paulson
parents:
2485
diff
changeset
|
16 |
who receives one. |
2449 | 17 |
Perhaps the two session keys could be bundled into a single message. |
18 |
*) |
|
2516
4d68fbe6378b
Now with Andy Gordon's treatment of freshness to replace newN/K
paulson
parents:
2485
diff
changeset
|
19 |
consts respond :: "event list => (msg*msg*key)set" |
4d68fbe6378b
Now with Andy Gordon's treatment of freshness to replace newN/K
paulson
parents:
2485
diff
changeset
|
20 |
inductive "respond evs" (*Server's response to the nested message*) |
11264 | 21 |
intros |
22 |
One: "Key KAB \<notin> used evs |
|
23 |
==> (Hash[Key(shrK A)] {|Agent A, Agent B, Nonce NA, END|}, |
|
5434
9b4bed3f394c
Got rid of not_Says_to_self and most uses of ~= in definitions and theorems
paulson
parents:
5359
diff
changeset
|
24 |
{|Crypt (shrK A) {|Key KAB, Agent B, Nonce NA|}, END|}, |
11264 | 25 |
KAB) \<in> respond evs" |
2449 | 26 |
|
2532 | 27 |
(*The most recent session key is passed up to the caller*) |
11264 | 28 |
Cons: "[| (PA, RA, KAB) \<in> respond evs; |
29 |
Key KBC \<notin> used evs; Key KBC \<notin> parts {RA}; |
|
5434
9b4bed3f394c
Got rid of not_Says_to_self and most uses of ~= in definitions and theorems
paulson
parents:
5359
diff
changeset
|
30 |
PA = Hash[Key(shrK A)] {|Agent A, Agent B, Nonce NA, P|} |] |
11264 | 31 |
==> (Hash[Key(shrK B)] {|Agent B, Agent C, Nonce NB, PA|}, |
32 |
{|Crypt (shrK B) {|Key KBC, Agent C, Nonce NB|}, |
|
2550
8d8344bcf98a
Re-ordering of certificates so that session keys appear in decreasing order
paulson
parents:
2532
diff
changeset
|
33 |
Crypt (shrK B) {|Key KAB, Agent A, Nonce NB|}, |
2516
4d68fbe6378b
Now with Andy Gordon's treatment of freshness to replace newN/K
paulson
parents:
2485
diff
changeset
|
34 |
RA|}, |
4d68fbe6378b
Now with Andy Gordon's treatment of freshness to replace newN/K
paulson
parents:
2485
diff
changeset
|
35 |
KBC) |
11264 | 36 |
\<in> respond evs" |
2449 | 37 |
|
38 |
||
2481 | 39 |
(*Induction over "respond" can be difficult due to the complexity of the |
2532 | 40 |
subgoals. Set "responses" captures the general form of certificates. |
2449 | 41 |
*) |
11264 | 42 |
consts responses :: "event list => msg set" |
43 |
inductive "responses evs" |
|
44 |
intros |
|
2449 | 45 |
(*Server terminates lists*) |
11264 | 46 |
Nil: "END \<in> responses evs" |
2449 | 47 |
|
11264 | 48 |
Cons: "[| RA \<in> responses evs; Key KAB \<notin> used evs |] |
2516
4d68fbe6378b
Now with Andy Gordon's treatment of freshness to replace newN/K
paulson
parents:
2485
diff
changeset
|
49 |
==> {|Crypt (shrK B) {|Key KAB, Agent A, Nonce NB|}, |
11264 | 50 |
RA|} \<in> responses evs" |
2449 | 51 |
|
52 |
||
11264 | 53 |
consts recur :: "event list set" |
3519
ab0a9fbed4c0
Changing "lost" from a parameter of protocol definitions to a constant.
paulson
parents:
3466
diff
changeset
|
54 |
inductive "recur" |
11264 | 55 |
intros |
2449 | 56 |
(*Initial trace is empty*) |
11264 | 57 |
Nil: "[] \<in> recur" |
2449 | 58 |
|
2532 | 59 |
(*The spy MAY say anything he CAN say. Common to |
2449 | 60 |
all similar protocols.*) |
11264 | 61 |
Fake: "[| evsf \<in> recur; X \<in> synth (analz (knows Spy evsf)) |] |
62 |
==> Says Spy B X # evsf \<in> recur" |
|
2449 | 63 |
|
64 |
(*Alice initiates a protocol run. |
|
5434
9b4bed3f394c
Got rid of not_Says_to_self and most uses of ~= in definitions and theorems
paulson
parents:
5359
diff
changeset
|
65 |
END is a placeholder to terminate the nesting.*) |
11264 | 66 |
RA1: "[| evs1: recur; Nonce NA \<notin> used evs1 |] |
5434
9b4bed3f394c
Got rid of not_Says_to_self and most uses of ~= in definitions and theorems
paulson
parents:
5359
diff
changeset
|
67 |
==> Says A B (Hash[Key(shrK A)] {|Agent A, Agent B, Nonce NA, END|}) |
11264 | 68 |
# evs1 \<in> recur" |
2449 | 69 |
|
70 |
(*Bob's response to Alice's message. C might be the Server. |
|
4552
bb8ff763c93d
Simplified proofs by omitting PA = {|XA, ...|} from RA2
paulson
parents:
3683
diff
changeset
|
71 |
We omit PA = {|XA, Agent A, Agent B, Nonce NA, P|} because |
bb8ff763c93d
Simplified proofs by omitting PA = {|XA, ...|} from RA2
paulson
parents:
3683
diff
changeset
|
72 |
it complicates proofs, so B may respond to any message at all!*) |
11264 | 73 |
RA2: "[| evs2: recur; Nonce NB \<notin> used evs2; |
74 |
Says A' B PA \<in> set evs2 |] |
|
2516
4d68fbe6378b
Now with Andy Gordon's treatment of freshness to replace newN/K
paulson
parents:
2485
diff
changeset
|
75 |
==> Says B C (Hash[Key(shrK B)] {|Agent B, Agent C, Nonce NB, PA|}) |
11264 | 76 |
# evs2 \<in> recur" |
2449 | 77 |
|
2550
8d8344bcf98a
Re-ordering of certificates so that session keys appear in decreasing order
paulson
parents:
2532
diff
changeset
|
78 |
(*The Server receives Bob's message and prepares a response.*) |
11264 | 79 |
RA3: "[| evs3: recur; Says B' Server PB \<in> set evs3; |
80 |
(PB,RB,K) \<in> respond evs3 |] |
|
81 |
==> Says Server B RB # evs3 \<in> recur" |
|
2449 | 82 |
|
83 |
(*Bob receives the returned message and compares the Nonces with |
|
2516
4d68fbe6378b
Now with Andy Gordon's treatment of freshness to replace newN/K
paulson
parents:
2485
diff
changeset
|
84 |
those in the message he previously sent the Server.*) |
11264 | 85 |
RA4: "[| evs4: recur; |
86 |
Says B C {|XH, Agent B, Agent C, Nonce NB, |
|
87 |
XA, Agent A, Agent B, Nonce NA, P|} \<in> set evs4; |
|
88 |
Says C' B {|Crypt (shrK B) {|Key KBC, Agent C, Nonce NB|}, |
|
89 |
Crypt (shrK B) {|Key KAB, Agent A, Nonce NB|}, |
|
90 |
RA|} \<in> set evs4 |] |
|
91 |
==> Says B A RA # evs4 \<in> recur" |
|
5359 | 92 |
|
93 |
(*No "oops" message can easily be expressed. Each session key is |
|
11264 | 94 |
associated--in two separate messages--with two nonces. This is |
5359 | 95 |
one try, but it isn't that useful. Re domino attack, note that |
96 |
Recur.ML proves that each session key is secure provided the two |
|
97 |
peers are, even if there are compromised agents elsewhere in |
|
98 |
the chain. Oops cases proved using parts_cut, Key_in_keysFor_parts, |
|
99 |
etc. |
|
100 |
||
11264 | 101 |
Oops: "[| evso: recur; Says Server B RB \<in> set evso; |
102 |
RB \<in> responses evs'; Key K \<in> parts {RB} |] |
|
103 |
==> Notes Spy {|Key K, RB|} # evso \<in> recur" |
|
5359 | 104 |
*) |
11264 | 105 |
|
106 |
||
107 |
declare Says_imp_knows_Spy [THEN analz.Inj, dest] |
|
108 |
declare parts.Body [dest] |
|
109 |
declare analz_into_parts [dest] |
|
110 |
declare Fake_parts_insert_in_Un [dest] |
|
111 |
||
112 |
||
113 |
(** Possibility properties: traces that reach the end |
|
114 |
ONE theorem would be more elegant and faster! |
|
115 |
By induction on a list of agents (no repetitions) |
|
116 |
**) |
|
117 |
||
118 |
||
13922 | 119 |
text{*Simplest case: Alice goes directly to the server*} |
11264 | 120 |
lemma "\<exists>K NA. \<exists>evs \<in> recur. |
121 |
Says Server A {|Crypt (shrK A) {|Key K, Agent Server, Nonce NA|}, |
|
122 |
END|} \<in> set evs" |
|
123 |
apply (intro exI bexI) |
|
124 |
apply (rule_tac [2] recur.Nil [THEN recur.RA1, |
|
13922 | 125 |
THEN recur.RA3 [OF _ _ respond.One]], possibility) |
11264 | 126 |
done |
127 |
||
128 |
||
13922 | 129 |
text{*Case two: Alice, Bob and the server*} |
11264 | 130 |
lemma "\<exists>K. \<exists>NA. \<exists>evs \<in> recur. |
131 |
Says B A {|Crypt (shrK A) {|Key K, Agent B, Nonce NA|}, |
|
132 |
END|} \<in> set evs" |
|
13507 | 133 |
apply (cut_tac Nonce_supply2 Key_supply2, clarify) |
11264 | 134 |
apply (intro exI bexI) |
11270
a315a3862bb4
better treatment of methods: uses Method.ctxt_args to refer to current
paulson
parents:
11264
diff
changeset
|
135 |
apply (rule_tac [2] |
a315a3862bb4
better treatment of methods: uses Method.ctxt_args to refer to current
paulson
parents:
11264
diff
changeset
|
136 |
recur.Nil [THEN recur.RA1, |
a315a3862bb4
better treatment of methods: uses Method.ctxt_args to refer to current
paulson
parents:
11264
diff
changeset
|
137 |
THEN recur.RA2, |
a315a3862bb4
better treatment of methods: uses Method.ctxt_args to refer to current
paulson
parents:
11264
diff
changeset
|
138 |
THEN recur.RA3 [OF _ _ respond.One [THEN respond.Cons]], |
a315a3862bb4
better treatment of methods: uses Method.ctxt_args to refer to current
paulson
parents:
11264
diff
changeset
|
139 |
THEN recur.RA4]) |
a315a3862bb4
better treatment of methods: uses Method.ctxt_args to refer to current
paulson
parents:
11264
diff
changeset
|
140 |
apply (tactic "basic_possibility_tac") |
a315a3862bb4
better treatment of methods: uses Method.ctxt_args to refer to current
paulson
parents:
11264
diff
changeset
|
141 |
apply (tactic |
a315a3862bb4
better treatment of methods: uses Method.ctxt_args to refer to current
paulson
parents:
11264
diff
changeset
|
142 |
"DEPTH_SOLVE (eresolve_tac [asm_rl, less_not_refl2, less_not_refl3] 1)") |
11264 | 143 |
done |
144 |
||
145 |
(*Case three: Alice, Bob, Charlie and the server |
|
11270
a315a3862bb4
better treatment of methods: uses Method.ctxt_args to refer to current
paulson
parents:
11264
diff
changeset
|
146 |
Rather slow (16 seconds) to run every time... |
a315a3862bb4
better treatment of methods: uses Method.ctxt_args to refer to current
paulson
parents:
11264
diff
changeset
|
147 |
lemma "\<exists>K. \<exists>NA. \<exists>evs \<in> recur. |
11264 | 148 |
Says B A {|Crypt (shrK A) {|Key K, Agent B, Nonce NA|}, |
149 |
END|} \<in> set evs" |
|
13507 | 150 |
apply (tactic "cut_facts_tac [Nonce_supply3, Key_supply3] 1", clarify) |
11270
a315a3862bb4
better treatment of methods: uses Method.ctxt_args to refer to current
paulson
parents:
11264
diff
changeset
|
151 |
apply (intro exI bexI) |
a315a3862bb4
better treatment of methods: uses Method.ctxt_args to refer to current
paulson
parents:
11264
diff
changeset
|
152 |
apply (rule_tac [2] |
a315a3862bb4
better treatment of methods: uses Method.ctxt_args to refer to current
paulson
parents:
11264
diff
changeset
|
153 |
recur.Nil [THEN recur.RA1, |
a315a3862bb4
better treatment of methods: uses Method.ctxt_args to refer to current
paulson
parents:
11264
diff
changeset
|
154 |
THEN recur.RA2, THEN recur.RA2, |
a315a3862bb4
better treatment of methods: uses Method.ctxt_args to refer to current
paulson
parents:
11264
diff
changeset
|
155 |
THEN recur.RA3 |
a315a3862bb4
better treatment of methods: uses Method.ctxt_args to refer to current
paulson
parents:
11264
diff
changeset
|
156 |
[OF _ _ respond.One |
a315a3862bb4
better treatment of methods: uses Method.ctxt_args to refer to current
paulson
parents:
11264
diff
changeset
|
157 |
[THEN respond.Cons, THEN respond.Cons]], |
a315a3862bb4
better treatment of methods: uses Method.ctxt_args to refer to current
paulson
parents:
11264
diff
changeset
|
158 |
THEN recur.RA4, THEN recur.RA4]) |
a315a3862bb4
better treatment of methods: uses Method.ctxt_args to refer to current
paulson
parents:
11264
diff
changeset
|
159 |
apply (tactic "basic_possibility_tac") |
a315a3862bb4
better treatment of methods: uses Method.ctxt_args to refer to current
paulson
parents:
11264
diff
changeset
|
160 |
apply (tactic |
a315a3862bb4
better treatment of methods: uses Method.ctxt_args to refer to current
paulson
parents:
11264
diff
changeset
|
161 |
"DEPTH_SOLVE (swap_res_tac [refl, conjI, disjCI] 1 ORELSE \ |
a315a3862bb4
better treatment of methods: uses Method.ctxt_args to refer to current
paulson
parents:
11264
diff
changeset
|
162 |
\ eresolve_tac [asm_rl, less_not_refl2, less_not_refl3] 1)") |
a315a3862bb4
better treatment of methods: uses Method.ctxt_args to refer to current
paulson
parents:
11264
diff
changeset
|
163 |
done |
a315a3862bb4
better treatment of methods: uses Method.ctxt_args to refer to current
paulson
parents:
11264
diff
changeset
|
164 |
*) |
11264 | 165 |
|
166 |
(**** Inductive proofs about recur ****) |
|
167 |
||
168 |
lemma respond_imp_not_used: "(PA,RB,KAB) \<in> respond evs ==> Key KAB \<notin> used evs" |
|
169 |
by (erule respond.induct, simp_all) |
|
170 |
||
171 |
lemma Key_in_parts_respond [rule_format]: |
|
172 |
"[| Key K \<in> parts {RB}; (PB,RB,K') \<in> respond evs |] ==> Key K \<notin> used evs" |
|
173 |
apply (erule rev_mp, erule respond.induct) |
|
174 |
apply (auto dest: Key_not_used respond_imp_not_used) |
|
175 |
done |
|
176 |
||
13922 | 177 |
text{*Simple inductive reasoning about responses*} |
11264 | 178 |
lemma respond_imp_responses: |
179 |
"(PA,RB,KAB) \<in> respond evs ==> RB \<in> responses evs" |
|
180 |
apply (erule respond.induct) |
|
181 |
apply (blast intro!: respond_imp_not_used responses.intros)+ |
|
182 |
done |
|
183 |
||
184 |
||
185 |
(** For reasoning about the encrypted portion of messages **) |
|
186 |
||
187 |
lemmas RA2_analz_spies = Says_imp_spies [THEN analz.Inj] |
|
188 |
||
189 |
lemma RA4_analz_spies: |
|
190 |
"Says C' B {|Crypt K X, X', RA|} \<in> set evs ==> RA \<in> analz (spies evs)" |
|
191 |
by blast |
|
192 |
||
193 |
||
194 |
(*RA2_analz... and RA4_analz... let us treat those cases using the same |
|
195 |
argument as for the Fake case. This is possible for most, but not all, |
|
196 |
proofs: Fake does not invent new nonces (as in RA2), and of course Fake |
|
197 |
messages originate from the Spy. *) |
|
198 |
||
199 |
lemmas RA2_parts_spies = RA2_analz_spies [THEN analz_into_parts] |
|
200 |
lemmas RA4_parts_spies = RA4_analz_spies [THEN analz_into_parts] |
|
201 |
||
202 |
||
203 |
(** Theorems of the form X \<notin> parts (spies evs) imply that NOBODY |
|
204 |
sends messages containing X! **) |
|
205 |
||
206 |
(** Spy never sees another agent's shared key! (unless it's bad at start) **) |
|
207 |
||
208 |
lemma Spy_see_shrK [simp]: |
|
209 |
"evs \<in> recur ==> (Key (shrK A) \<in> parts (spies evs)) = (A \<in> bad)" |
|
13507 | 210 |
apply (erule recur.induct, auto) |
13922 | 211 |
txt{*RA3. It's ugly to call auto twice, but it seems necessary.*} |
11264 | 212 |
apply (auto dest: Key_in_parts_respond simp add: parts_insert_spies) |
213 |
done |
|
214 |
||
215 |
lemma Spy_analz_shrK [simp]: |
|
216 |
"evs \<in> recur ==> (Key (shrK A) \<in> analz (spies evs)) = (A \<in> bad)" |
|
217 |
by auto |
|
218 |
||
219 |
lemma Spy_see_shrK_D [dest!]: |
|
220 |
"[|Key (shrK A) \<in> parts (knows Spy evs); evs \<in> recur|] ==> A \<in> bad" |
|
221 |
by (blast dest: Spy_see_shrK) |
|
222 |
||
223 |
||
224 |
(*** Proofs involving analz ***) |
|
225 |
||
226 |
(** Session keys are not used to encrypt other session keys **) |
|
227 |
||
228 |
(*Version for "responses" relation. Handles case RA3 in the theorem below. |
|
229 |
Note that it holds for *any* set H (not just "spies evs") |
|
230 |
satisfying the inductive hypothesis.*) |
|
231 |
lemma resp_analz_image_freshK_lemma: |
|
232 |
"[| RB \<in> responses evs; |
|
233 |
\<forall>K KK. KK \<subseteq> - (range shrK) --> |
|
234 |
(Key K \<in> analz (Key`KK Un H)) = |
|
235 |
(K \<in> KK | Key K \<in> analz H) |] |
|
236 |
==> \<forall>K KK. KK \<subseteq> - (range shrK) --> |
|
237 |
(Key K \<in> analz (insert RB (Key`KK Un H))) = |
|
238 |
(K \<in> KK | Key K \<in> analz (insert RB H))" |
|
239 |
by (erule responses.induct, |
|
240 |
simp_all del: image_insert |
|
241 |
add: analz_image_freshK_simps) |
|
242 |
||
243 |
||
13922 | 244 |
text{*Version for the protocol. Proof is almost trivial, thanks to the lemma.*} |
11264 | 245 |
lemma raw_analz_image_freshK: |
246 |
"evs \<in> recur ==> |
|
247 |
\<forall>K KK. KK \<subseteq> - (range shrK) --> |
|
248 |
(Key K \<in> analz (Key`KK Un (spies evs))) = |
|
249 |
(K \<in> KK | Key K \<in> analz (spies evs))" |
|
250 |
apply (erule recur.induct) |
|
251 |
apply (drule_tac [4] RA2_analz_spies, |
|
11281 | 252 |
drule_tac [5] respond_imp_responses, |
13507 | 253 |
drule_tac [6] RA4_analz_spies, analz_freshK, spy_analz) |
13922 | 254 |
txt{*RA3*} |
11264 | 255 |
apply (simp_all add: resp_analz_image_freshK_lemma) |
256 |
done |
|
257 |
||
258 |
||
259 |
(*Instance of the lemma with H replaced by (spies evs): |
|
260 |
[| RB \<in> responses evs; evs \<in> recur; |] |
|
261 |
==> KK \<subseteq> - (range shrK) --> |
|
262 |
Key K \<in> analz (insert RB (Key`KK Un spies evs)) = |
|
263 |
(K \<in> KK | Key K \<in> analz (insert RB (spies evs))) |
|
264 |
*) |
|
265 |
lemmas resp_analz_image_freshK = |
|
266 |
resp_analz_image_freshK_lemma [OF _ raw_analz_image_freshK] |
|
267 |
||
268 |
lemma analz_insert_freshK: |
|
269 |
"[| evs \<in> recur; KAB \<notin> range shrK |] |
|
11655 | 270 |
==> (Key K \<in> analz (insert (Key KAB) (spies evs))) = |
11264 | 271 |
(K = KAB | Key K \<in> analz (spies evs))" |
272 |
by (simp del: image_insert |
|
273 |
add: analz_image_freshK_simps raw_analz_image_freshK) |
|
274 |
||
275 |
||
13922 | 276 |
text{*Everything that's hashed is already in past traffic. *} |
11270
a315a3862bb4
better treatment of methods: uses Method.ctxt_args to refer to current
paulson
parents:
11264
diff
changeset
|
277 |
lemma Hash_imp_body: |
a315a3862bb4
better treatment of methods: uses Method.ctxt_args to refer to current
paulson
parents:
11264
diff
changeset
|
278 |
"[| Hash {|Key(shrK A), X|} \<in> parts (spies evs); |
11264 | 279 |
evs \<in> recur; A \<notin> bad |] ==> X \<in> parts (spies evs)" |
280 |
apply (erule rev_mp) |
|
281 |
apply (erule recur.induct, |
|
11281 | 282 |
drule_tac [6] RA4_parts_spies, |
283 |
drule_tac [5] respond_imp_responses, |
|
284 |
drule_tac [4] RA2_parts_spies) |
|
13922 | 285 |
txt{*RA3 requires a further induction*} |
13507 | 286 |
apply (erule_tac [5] responses.induct, simp_all) |
13922 | 287 |
txt{*Fake*} |
11264 | 288 |
apply (blast intro: parts_insertI) |
289 |
done |
|
290 |
||
291 |
||
292 |
(** The Nonce NA uniquely identifies A's message. |
|
293 |
This theorem applies to steps RA1 and RA2! |
|
294 |
||
295 |
Unicity is not used in other proofs but is desirable in its own right. |
|
296 |
**) |
|
297 |
||
298 |
lemma unique_NA: |
|
299 |
"[| Hash {|Key(shrK A), Agent A, B, NA, P|} \<in> parts (spies evs); |
|
300 |
Hash {|Key(shrK A), Agent A, B',NA, P'|} \<in> parts (spies evs); |
|
301 |
evs \<in> recur; A \<notin> bad |] |
|
302 |
==> B=B' & P=P'" |
|
303 |
apply (erule rev_mp, erule rev_mp) |
|
304 |
apply (erule recur.induct, |
|
11281 | 305 |
drule_tac [5] respond_imp_responses) |
11264 | 306 |
apply (force, simp_all) |
13922 | 307 |
txt{*Fake*} |
11264 | 308 |
apply blast |
309 |
apply (erule_tac [3] responses.induct) |
|
13922 | 310 |
txt{*RA1,2: creation of new Nonce*} |
11264 | 311 |
apply simp_all |
312 |
apply (blast dest!: Hash_imp_body)+ |
|
313 |
done |
|
314 |
||
315 |
||
316 |
(*** Lemmas concerning the Server's response |
|
317 |
(relations "respond" and "responses") |
|
318 |
***) |
|
319 |
||
320 |
lemma shrK_in_analz_respond [simp]: |
|
321 |
"[| RB \<in> responses evs; evs \<in> recur |] |
|
322 |
==> (Key (shrK B) \<in> analz (insert RB (spies evs))) = (B:bad)" |
|
323 |
by (erule responses.induct, |
|
324 |
simp_all del: image_insert |
|
325 |
add: analz_image_freshK_simps resp_analz_image_freshK) |
|
326 |
||
327 |
||
328 |
lemma resp_analz_insert_lemma: |
|
329 |
"[| Key K \<in> analz (insert RB H); |
|
330 |
\<forall>K KK. KK \<subseteq> - (range shrK) --> |
|
331 |
(Key K \<in> analz (Key`KK Un H)) = |
|
332 |
(K \<in> KK | Key K \<in> analz H); |
|
333 |
RB \<in> responses evs |] |
|
334 |
==> (Key K \<in> parts{RB} | Key K \<in> analz H)" |
|
335 |
apply (erule rev_mp, erule responses.induct) |
|
336 |
apply (simp_all del: image_insert |
|
337 |
add: analz_image_freshK_simps resp_analz_image_freshK_lemma) |
|
13922 | 338 |
txt{*Simplification using two distinct treatments of "image"*} |
13507 | 339 |
apply (simp add: parts_insert2, blast) |
11264 | 340 |
done |
341 |
||
342 |
lemmas resp_analz_insert = |
|
343 |
resp_analz_insert_lemma [OF _ raw_analz_image_freshK] |
|
344 |
||
13922 | 345 |
text{*The last key returned by respond indeed appears in a certificate*} |
11264 | 346 |
lemma respond_certificate: |
347 |
"(Hash[Key(shrK A)] {|Agent A, B, NA, P|}, RA, K) \<in> respond evs |
|
348 |
==> Crypt (shrK A) {|Key K, B, NA|} \<in> parts {RA}" |
|
349 |
apply (ind_cases "(X, RA, K) \<in> respond evs") |
|
350 |
apply simp_all |
|
351 |
done |
|
352 |
||
353 |
(*This unicity proof differs from all the others in the HOL/Auth directory. |
|
354 |
The conclusion isn't quite unicity but duplicity, in that there are two |
|
355 |
possibilities. Also, the presence of two different matching messages in |
|
356 |
the inductive step complicates the case analysis. Unusually for such proofs, |
|
357 |
the quantifiers appear to be necessary.*) |
|
358 |
lemma unique_lemma [rule_format]: |
|
359 |
"(PB,RB,KXY) \<in> respond evs ==> |
|
360 |
\<forall>A B N. Crypt (shrK A) {|Key K, Agent B, N|} \<in> parts {RB} --> |
|
361 |
(\<forall>A' B' N'. Crypt (shrK A') {|Key K, Agent B', N'|} \<in> parts {RB} --> |
|
362 |
(A'=A & B'=B) | (A'=B & B'=A))" |
|
363 |
apply (erule respond.induct) |
|
364 |
apply (simp_all add: all_conj_distrib) |
|
365 |
apply (blast dest: respond_certificate) |
|
366 |
done |
|
367 |
||
368 |
lemma unique_session_keys: |
|
369 |
"[| Crypt (shrK A) {|Key K, Agent B, N|} \<in> parts {RB}; |
|
370 |
Crypt (shrK A') {|Key K, Agent B', N'|} \<in> parts {RB}; |
|
371 |
(PB,RB,KXY) \<in> respond evs |] |
|
372 |
==> (A'=A & B'=B) | (A'=B & B'=A)" |
|
373 |
by (rule unique_lemma, auto) |
|
374 |
||
375 |
||
376 |
(** Crucial secrecy property: Spy does not see the keys sent in msg RA3 |
|
377 |
Does not in itself guarantee security: an attack could violate |
|
378 |
the premises, e.g. by having A=Spy **) |
|
379 |
||
380 |
lemma respond_Spy_not_see_session_key [rule_format]: |
|
381 |
"[| (PB,RB,KAB) \<in> respond evs; evs \<in> recur |] |
|
382 |
==> \<forall>A A' N. A \<notin> bad & A' \<notin> bad --> |
|
383 |
Crypt (shrK A) {|Key K, Agent A', N|} \<in> parts{RB} --> |
|
384 |
Key K \<notin> analz (insert RB (spies evs))" |
|
385 |
apply (erule respond.induct) |
|
386 |
apply (frule_tac [2] respond_imp_responses) |
|
387 |
apply (frule_tac [2] respond_imp_not_used) |
|
388 |
apply (simp_all del: image_insert |
|
389 |
add: analz_image_freshK_simps split_ifs shrK_in_analz_respond |
|
390 |
resp_analz_image_freshK parts_insert2) |
|
13922 | 391 |
txt{*Base case of respond*} |
11264 | 392 |
apply blast |
13922 | 393 |
txt{*Inductive step of respond*} |
13507 | 394 |
apply (intro allI conjI impI, simp_all) |
13956 | 395 |
txt{*by unicity, either @{term "B=Aa"} or @{term "B=A'"}, a contradiction |
396 |
if @{term "B \<in> bad"}*} |
|
13935 | 397 |
apply (blast dest: unique_session_keys respond_certificate) |
11264 | 398 |
apply (blast dest!: respond_certificate) |
399 |
apply (blast dest!: resp_analz_insert) |
|
400 |
done |
|
401 |
||
402 |
||
403 |
lemma Spy_not_see_session_key: |
|
404 |
"[| Crypt (shrK A) {|Key K, Agent A', N|} \<in> parts (spies evs); |
|
405 |
A \<notin> bad; A' \<notin> bad; evs \<in> recur |] |
|
406 |
==> Key K \<notin> analz (spies evs)" |
|
407 |
apply (erule rev_mp) |
|
408 |
apply (erule recur.induct) |
|
409 |
apply (drule_tac [4] RA2_analz_spies, |
|
410 |
frule_tac [5] respond_imp_responses, |
|
411 |
drule_tac [6] RA4_analz_spies, |
|
412 |
simp_all add: split_ifs analz_insert_eq analz_insert_freshK) |
|
13922 | 413 |
txt{*Fake*} |
11264 | 414 |
apply spy_analz |
13922 | 415 |
txt{*RA2*} |
11264 | 416 |
apply blast |
13922 | 417 |
txt{*RA3 remains*} |
11264 | 418 |
apply (simp add: parts_insert_spies) |
13922 | 419 |
txt{*Now we split into two cases. A single blast could do it, but it would take |
420 |
a CPU minute.*} |
|
11264 | 421 |
apply (safe del: impCE) |
13922 | 422 |
txt{*RA3, case 1: use lemma previously proved by induction*} |
11264 | 423 |
apply (blast elim: rev_notE [OF _ respond_Spy_not_see_session_key]) |
13922 | 424 |
txt{*RA3, case 2: K is an old key*} |
11264 | 425 |
apply (blast dest: resp_analz_insert dest: Key_in_parts_respond) |
13922 | 426 |
txt{*RA4*} |
11264 | 427 |
apply blast |
428 |
done |
|
429 |
||
430 |
(**** Authenticity properties for Agents ****) |
|
431 |
||
13922 | 432 |
text{*The response never contains Hashes*} |
11264 | 433 |
lemma Hash_in_parts_respond: |
434 |
"[| Hash {|Key (shrK B), M|} \<in> parts (insert RB H); |
|
435 |
(PB,RB,K) \<in> respond evs |] |
|
436 |
==> Hash {|Key (shrK B), M|} \<in> parts H" |
|
437 |
apply (erule rev_mp) |
|
13507 | 438 |
apply (erule respond_imp_responses [THEN responses.induct], auto) |
11264 | 439 |
done |
440 |
||
13922 | 441 |
text{*Only RA1 or RA2 can have caused such a part of a message to appear. |
11264 | 442 |
This result is of no use to B, who cannot verify the Hash. Moreover, |
443 |
it can say nothing about how recent A's message is. It might later be |
|
13922 | 444 |
used to prove B's presence to A at the run's conclusion.*} |
11264 | 445 |
lemma Hash_auth_sender [rule_format]: |
446 |
"[| Hash {|Key(shrK A), Agent A, Agent B, NA, P|} \<in> parts(spies evs); |
|
447 |
A \<notin> bad; evs \<in> recur |] |
|
448 |
==> Says A B (Hash[Key(shrK A)] {|Agent A, Agent B, NA, P|}) \<in> set evs" |
|
449 |
apply (unfold HPair_def) |
|
450 |
apply (erule rev_mp) |
|
451 |
apply (erule recur.induct, |
|
11281 | 452 |
drule_tac [6] RA4_parts_spies, |
453 |
drule_tac [4] RA2_parts_spies, |
|
11264 | 454 |
simp_all) |
13922 | 455 |
txt{*Nil*} |
11264 | 456 |
apply force |
13922 | 457 |
txt{*Fake, RA3*} |
11281 | 458 |
apply (blast dest: Hash_in_parts_respond)+ |
11264 | 459 |
done |
460 |
||
461 |
(** These two results subsume (for all agents) the guarantees proved |
|
462 |
separately for A and B in the Otway-Rees protocol. |
|
463 |
**) |
|
464 |
||
465 |
||
13922 | 466 |
text{*Certificates can only originate with the Server.*} |
11264 | 467 |
lemma Cert_imp_Server_msg: |
468 |
"[| Crypt (shrK A) Y \<in> parts (spies evs); |
|
469 |
A \<notin> bad; evs \<in> recur |] |
|
470 |
==> \<exists>C RC. Says Server C RC \<in> set evs & |
|
471 |
Crypt (shrK A) Y \<in> parts {RC}" |
|
472 |
apply (erule rev_mp, erule recur.induct, simp_all) |
|
13922 | 473 |
txt{*Fake*} |
11264 | 474 |
apply blast |
13922 | 475 |
txt{*RA1*} |
11264 | 476 |
apply blast |
13922 | 477 |
txt{*RA2: it cannot be a new Nonce, contradiction.*} |
11264 | 478 |
apply blast |
13922 | 479 |
txt{*RA3. Pity that the proof is so brittle: this step requires the rewriting, |
480 |
which however would break all other steps.*} |
|
11264 | 481 |
apply (simp add: parts_insert_spies, blast) |
13922 | 482 |
txt{*RA4*} |
11264 | 483 |
apply blast |
484 |
done |
|
485 |
||
486 |
end |