1 (* Title: HOL/Auth/NS_Shared |
1 (* Title: HOL/Auth/NS_Shared |
2 ID: $Id$ |
2 ID: $Id$ |
3 Author: Lawrence C Paulson, Cambridge University Computer Laboratory |
3 Author: Lawrence C Paulson and Giampaolo Bella |
4 Copyright 1996 University of Cambridge |
4 Copyright 1996 University of Cambridge |
5 *) |
5 *) |
6 |
6 |
7 header{*The Needham-Schroeder Shared-Key Protocol*} |
7 header{*Needham-Schroeder Shared-Key Protocol and the Issues Property*} |
8 |
8 |
9 theory NS_Shared imports Public begin |
9 theory NS_Shared imports Public begin |
10 |
10 |
11 text{* |
11 text{* |
12 From page 247 of |
12 From page 247 of |
13 Burrows, Abadi and Needham (1989). A Logic of Authentication. |
13 Burrows, Abadi and Needham (1989). A Logic of Authentication. |
14 Proc. Royal Soc. 426 |
14 Proc. Royal Soc. 426 |
15 *} |
15 *} |
|
16 |
|
17 constdefs |
|
18 |
|
19 (* A is the true creator of X if she has sent X and X never appeared on |
|
20 the trace before this event. Recall that traces grow from head. *) |
|
21 Issues :: "[agent, agent, msg, event list] => bool" |
|
22 ("_ Issues _ with _ on _") |
|
23 "A Issues B with X on evs == |
|
24 \<exists>Y. Says A B Y \<in> set evs & X \<in> parts {Y} & |
|
25 X \<notin> parts (spies (takeWhile (% z. z \<noteq> Says A B Y) (rev evs)))" |
|
26 |
16 |
27 |
17 consts ns_shared :: "event list set" |
28 consts ns_shared :: "event list set" |
18 inductive "ns_shared" |
29 inductive "ns_shared" |
19 intros |
30 intros |
20 (*Initial trace is empty*) |
31 (*Initial trace is empty*) |
240 text{*In messages of this form, the session key uniquely identifies the rest*} |
251 text{*In messages of this form, the session key uniquely identifies the rest*} |
241 lemma unique_session_keys: |
252 lemma unique_session_keys: |
242 "\<lbrakk>Says Server A (Crypt (shrK A) \<lbrace>NA, Agent B, Key K, X\<rbrace>) \<in> set evs; |
253 "\<lbrakk>Says Server A (Crypt (shrK A) \<lbrace>NA, Agent B, Key K, X\<rbrace>) \<in> set evs; |
243 Says Server A' (Crypt (shrK A') \<lbrace>NA', Agent B', Key K, X'\<rbrace>) \<in> set evs; |
254 Says Server A' (Crypt (shrK A') \<lbrace>NA', Agent B', Key K, X'\<rbrace>) \<in> set evs; |
244 evs \<in> ns_shared\<rbrakk> \<Longrightarrow> A=A' \<and> NA=NA' \<and> B=B' \<and> X = X'" |
255 evs \<in> ns_shared\<rbrakk> \<Longrightarrow> A=A' \<and> NA=NA' \<and> B=B' \<and> X = X'" |
245 apply (erule rev_mp, erule rev_mp, erule ns_shared.induct, simp_all, blast+) |
256 by (erule rev_mp, erule rev_mp, erule ns_shared.induct, simp_all, blast+) |
246 done |
257 |
247 |
258 |
248 |
259 subsubsection{*Crucial secrecy property: Spy doesn't see the keys sent in NS2*} |
249 subsubsection{*Crucial secrecy property: Spy does not see the keys sent in msg NS2*} |
|
250 |
260 |
251 text{*Beware of @{text "[rule_format]"} and the universal quantifier!*} |
261 text{*Beware of @{text "[rule_format]"} and the universal quantifier!*} |
252 lemma secrecy_lemma: |
262 lemma secrecy_lemma: |
253 "\<lbrakk>Says Server A (Crypt (shrK A) \<lbrace>NA, Agent B, Key K, |
263 "\<lbrakk>Says Server A (Crypt (shrK A) \<lbrace>NA, Agent B, Key K, |
254 Crypt (shrK B) \<lbrace>Key K, Agent A\<rbrace>\<rbrace>) |
264 Crypt (shrK B) \<lbrace>Key K, Agent A\<rbrace>\<rbrace>) |
331 "evs \<in> ns_shared \<Longrightarrow> |
341 "evs \<in> ns_shared \<Longrightarrow> |
332 Key K \<notin> analz (spies evs) \<longrightarrow> |
342 Key K \<notin> analz (spies evs) \<longrightarrow> |
333 Says Server A (Crypt (shrK A) \<lbrace>NA, Agent B, Key K, X\<rbrace>) \<in> set evs \<longrightarrow> |
343 Says Server A (Crypt (shrK A) \<lbrace>NA, Agent B, Key K, X\<rbrace>) \<in> set evs \<longrightarrow> |
334 Crypt K (Nonce NB) \<in> parts (spies evs) \<longrightarrow> |
344 Crypt K (Nonce NB) \<in> parts (spies evs) \<longrightarrow> |
335 (\<exists>A'. Says A' B X \<in> set evs)" |
345 (\<exists>A'. Says A' B X \<in> set evs)" |
336 apply (erule ns_shared.induct, force, drule_tac [4] NS3_msg_in_parts_spies, analz_mono_contra) |
346 apply (erule ns_shared.induct, force) |
|
347 apply (drule_tac [4] NS3_msg_in_parts_spies) |
|
348 apply analz_mono_contra |
337 apply (simp_all add: ex_disj_distrib, blast) |
349 apply (simp_all add: ex_disj_distrib, blast) |
338 txt{*NS2*} |
350 txt{*NS2*} |
339 apply (blast dest!: new_keys_not_used Crypt_imp_keysFor) |
351 apply (blast dest!: new_keys_not_used Crypt_imp_keysFor) |
340 txt{*NS4*} |
352 txt{*NS4*} |
341 apply (blast dest: B_trusts_NS3 |
353 apply (blast dest: B_trusts_NS3 |
350 Says Server A |
362 Says Server A |
351 (Crypt (shrK A) \<lbrace>NA, Agent B, Key K, |
363 (Crypt (shrK A) \<lbrace>NA, Agent B, Key K, |
352 Crypt (shrK B) \<lbrace>Key K, Agent A\<rbrace>\<rbrace>) \<in> set evs \<longrightarrow> |
364 Crypt (shrK B) \<lbrace>Key K, Agent A\<rbrace>\<rbrace>) \<in> set evs \<longrightarrow> |
353 Crypt K \<lbrace>Nonce NB, Nonce NB\<rbrace> \<in> parts (spies evs) \<longrightarrow> |
365 Crypt K \<lbrace>Nonce NB, Nonce NB\<rbrace> \<in> parts (spies evs) \<longrightarrow> |
354 Says A B (Crypt K \<lbrace>Nonce NB, Nonce NB\<rbrace>) \<in> set evs" |
366 Says A B (Crypt K \<lbrace>Nonce NB, Nonce NB\<rbrace>) \<in> set evs" |
355 apply (erule ns_shared.induct, force, drule_tac [4] NS3_msg_in_parts_spies, analz_mono_contra, simp_all, blast) |
367 apply (erule ns_shared.induct, force) |
|
368 apply (drule_tac [4] NS3_msg_in_parts_spies) |
|
369 apply (analz_mono_contra, simp_all, blast) |
356 txt{*NS2*} |
370 txt{*NS2*} |
357 apply (blast dest!: new_keys_not_used Crypt_imp_keysFor) |
371 apply (blast dest!: new_keys_not_used Crypt_imp_keysFor) |
358 txt{*NS5*} |
372 txt{*NS5*} |
359 apply (blast dest!: A_trusts_NS2 |
373 apply (blast dest!: A_trusts_NS2 |
360 dest: Says_imp_knows_Spy [THEN analz.Inj] |
374 dest: Says_imp_knows_Spy [THEN analz.Inj] |
370 A \<notin> bad; B \<notin> bad; evs \<in> ns_shared\<rbrakk> |
384 A \<notin> bad; B \<notin> bad; evs \<in> ns_shared\<rbrakk> |
371 \<Longrightarrow> Says A B (Crypt K \<lbrace>Nonce NB, Nonce NB\<rbrace>) \<in> set evs" |
385 \<Longrightarrow> Says A B (Crypt K \<lbrace>Nonce NB, Nonce NB\<rbrace>) \<in> set evs" |
372 by (blast intro: B_trusts_NS5_lemma |
386 by (blast intro: B_trusts_NS5_lemma |
373 dest: B_trusts_NS3 Spy_not_see_encrypted_key) |
387 dest: B_trusts_NS3 Spy_not_see_encrypted_key) |
374 |
388 |
|
389 text{*Unaltered so far wrt original version*} |
|
390 |
|
391 subsection{*Lemmas for reasoning about predicate "Issues"*} |
|
392 |
|
393 lemma spies_Says_rev: "spies (evs @ [Says A B X]) = insert X (spies evs)" |
|
394 apply (induct_tac "evs") |
|
395 apply (induct_tac [2] "a", auto) |
|
396 done |
|
397 |
|
398 lemma spies_Gets_rev: "spies (evs @ [Gets A X]) = spies evs" |
|
399 apply (induct_tac "evs") |
|
400 apply (induct_tac [2] "a", auto) |
|
401 done |
|
402 |
|
403 lemma spies_Notes_rev: "spies (evs @ [Notes A X]) = |
|
404 (if A:bad then insert X (spies evs) else spies evs)" |
|
405 apply (induct_tac "evs") |
|
406 apply (induct_tac [2] "a", auto) |
|
407 done |
|
408 |
|
409 lemma spies_evs_rev: "spies evs = spies (rev evs)" |
|
410 apply (induct_tac "evs") |
|
411 apply (induct_tac [2] "a") |
|
412 apply (simp_all (no_asm_simp) add: spies_Says_rev spies_Gets_rev spies_Notes_rev) |
|
413 done |
|
414 |
|
415 lemmas parts_spies_evs_revD2 = spies_evs_rev [THEN equalityD2, THEN parts_mono] |
|
416 |
|
417 lemma spies_takeWhile: "spies (takeWhile P evs) <= spies evs" |
|
418 apply (induct_tac "evs") |
|
419 apply (induct_tac [2] "a", auto) |
|
420 txt{* Resembles @{text"used_subset_append"} in theory Event.*} |
|
421 done |
|
422 |
|
423 lemmas parts_spies_takeWhile_mono = spies_takeWhile [THEN parts_mono] |
|
424 |
|
425 |
|
426 subsection{*Guarantees of non-injective agreement on the session key, and |
|
427 of key distribution. They also express forms of freshness of certain messages, |
|
428 namely that agents were alive after something happened.*} |
|
429 |
|
430 lemma B_Issues_A: |
|
431 "\<lbrakk> Says B A (Crypt K (Nonce Nb)) \<in> set evs; |
|
432 Key K \<notin> analz (spies evs); |
|
433 A \<notin> bad; B \<notin> bad; evs \<in> ns_shared \<rbrakk> |
|
434 \<Longrightarrow> B Issues A with (Crypt K (Nonce Nb)) on evs" |
|
435 apply (simp (no_asm) add: Issues_def) |
|
436 apply (rule exI) |
|
437 apply (rule conjI, assumption) |
|
438 apply (simp (no_asm)) |
|
439 apply (erule rev_mp) |
|
440 apply (erule rev_mp) |
|
441 apply (erule ns_shared.induct, analz_mono_contra) |
|
442 apply (simp_all) |
|
443 txt{*fake*} |
|
444 apply blast |
|
445 apply (simp_all add: takeWhile_tail) |
|
446 txt{*NS3 remains by pure coincidence!*} |
|
447 apply (force dest!: A_trusts_NS2 Says_Server_message_form) |
|
448 txt{*NS4 would be the non-trivial case can be solved by Nb being used*} |
|
449 apply (blast dest: parts_spies_takeWhile_mono [THEN subsetD] |
|
450 parts_spies_evs_revD2 [THEN subsetD]) |
|
451 done |
|
452 |
|
453 text{*Tells A that B was alive after she sent him the session key. The |
|
454 session key must be assumed confidential for this deduction to be meaningful, |
|
455 but that assumption can be relaxed by the appropriate argument. |
|
456 |
|
457 Precisely, the theorem guarantees (to A) key distribution of the session key |
|
458 to B. It also guarantees (to A) non-injective agreement of B with A on the |
|
459 session key. Both goals are available to A in the sense of Goal Availability. |
|
460 *} |
|
461 lemma A_authenticates_and_keydist_to_B: |
|
462 "\<lbrakk>Crypt K (Nonce NB) \<in> parts (spies evs); |
|
463 Crypt (shrK A) \<lbrace>NA, Agent B, Key K, X\<rbrace> \<in> parts (spies evs); |
|
464 Key K \<notin> analz(knows Spy evs); |
|
465 A \<notin> bad; B \<notin> bad; evs \<in> ns_shared\<rbrakk> |
|
466 \<Longrightarrow> B Issues A with (Crypt K (Nonce NB)) on evs" |
|
467 by (blast intro: A_trusts_NS4_lemma B_Issues_A dest: A_trusts_NS2) |
|
468 |
|
469 lemma A_trusts_NS5: |
|
470 "\<lbrakk> Crypt K \<lbrace>Nonce NB, Nonce NB\<rbrace> \<in> parts(spies evs); |
|
471 Crypt (shrK A) \<lbrace>Nonce NA, Agent B, Key K, X\<rbrace> \<in> parts(spies evs); |
|
472 Key K \<notin> analz (spies evs); |
|
473 A \<notin> bad; B \<notin> bad; evs \<in> ns_shared \<rbrakk> |
|
474 \<Longrightarrow> Says A B (Crypt K \<lbrace>Nonce NB, Nonce NB\<rbrace>) \<in> set evs"; |
|
475 apply (erule rev_mp) |
|
476 apply (erule rev_mp) |
|
477 apply (erule rev_mp) |
|
478 apply (erule ns_shared.induct, analz_mono_contra) |
|
479 apply (frule_tac [5] Says_S_message_form) |
|
480 apply (simp_all) |
|
481 txt{*Fake*} |
|
482 apply blast |
|
483 txt{*NS2*} |
|
484 apply (force dest!: Crypt_imp_keysFor) |
|
485 txt{*NS3, much quicker having installed @{term Says_S_message_form} before simplication*} |
|
486 apply fastsimp |
|
487 txt{*NS5, the most important case, can be solved by unicity*} |
|
488 apply (case_tac "Aa \<in> bad") |
|
489 apply (force dest!: Says_imp_spies [THEN analz.Inj, THEN analz.Decrypt, THEN analz.Snd, THEN analz.Snd, THEN analz.Fst]) |
|
490 apply (blast dest: A_trusts_NS2 unique_session_keys) |
|
491 done |
|
492 |
|
493 lemma A_Issues_B: |
|
494 "\<lbrakk> Says A B (Crypt K \<lbrace>Nonce NB, Nonce NB\<rbrace>) \<in> set evs; |
|
495 Key K \<notin> analz (spies evs); |
|
496 A \<notin> bad; B \<notin> bad; evs \<in> ns_shared \<rbrakk> |
|
497 \<Longrightarrow> A Issues B with (Crypt K \<lbrace>Nonce NB, Nonce NB\<rbrace>) on evs" |
|
498 apply (simp (no_asm) add: Issues_def) |
|
499 apply (rule exI) |
|
500 apply (rule conjI, assumption) |
|
501 apply (simp (no_asm)) |
|
502 apply (erule rev_mp) |
|
503 apply (erule rev_mp) |
|
504 apply (erule ns_shared.induct, analz_mono_contra) |
|
505 apply (simp_all) |
|
506 txt{*fake*} |
|
507 apply blast |
|
508 apply (simp_all add: takeWhile_tail) |
|
509 txt{*NS3 remains by pure coincidence!*} |
|
510 apply (force dest!: A_trusts_NS2 Says_Server_message_form) |
|
511 txt{*NS5 is the non-trivial case and cannot be solved as in @{term B_Issues_A}! because NB is not fresh. We need @{term A_trusts_NS5}, proved for this very purpose*} |
|
512 apply (blast dest: A_trusts_NS5 parts_spies_takeWhile_mono [THEN subsetD] |
|
513 parts_spies_evs_revD2 [THEN subsetD]) |
|
514 done |
|
515 |
|
516 text{*Tells B that A was alive after B issued NB. |
|
517 |
|
518 Precisely, the theorem guarantees (to B) key distribution of the session key to A. It also guarantees (to B) non-injective agreement of A with B on the session key. Both goals are available to B in the sense of Goal Availability. |
|
519 *} |
|
520 lemma B_authenticates_and_keydist_to_A: |
|
521 "\<lbrakk>Crypt K \<lbrace>Nonce NB, Nonce NB\<rbrace> \<in> parts (spies evs); |
|
522 Crypt (shrK B) \<lbrace>Key K, Agent A\<rbrace> \<in> parts (spies evs); |
|
523 Key K \<notin> analz (spies evs); |
|
524 A \<notin> bad; B \<notin> bad; evs \<in> ns_shared\<rbrakk> |
|
525 \<Longrightarrow> A Issues B with (Crypt K \<lbrace>Nonce NB, Nonce NB\<rbrace>) on evs" |
|
526 by (blast intro: A_Issues_B B_trusts_NS5_lemma dest: B_trusts_NS3) |
|
527 |
375 end |
528 end |