wenzelm@37936: (* Title: HOL/Auth/NS_Public.thy paulson@2318: Author: Lawrence C Paulson, Cambridge University Computer Laboratory paulson@2318: Copyright 1996 University of Cambridge paulson@2318: paulson@2318: Inductive relation "ns_public" for the Needham-Schroeder Public-Key protocol. paulson@2538: Version incorporating Lowe's fix (inclusion of B's identity in round 2). paulson@2318: *) paulson@2318: wenzelm@58889: section{*Verifying the Needham-Schroeder-Lowe Public-Key Protocol*} paulson@13956: haftmann@16417: theory NS_Public imports Public begin paulson@2318: berghofe@23746: inductive_set ns_public :: "event list set" berghofe@23746: where paulson@2318: (*Initial trace is empty*) paulson@11104: Nil: "[] \ ns_public" paulson@2318: paulson@2318: (*The spy MAY say anything he CAN say. We do not expect him to paulson@2318: invent new nonces here, but he can also use NS1. Common to paulson@2318: all similar protocols.*) berghofe@23746: | Fake: "\evsf \ ns_public; X \ synth (analz (spies evsf))\ paulson@11366: \ Says Spy B X # evsf \ ns_public" paulson@2318: paulson@2318: (*Alice initiates a protocol run, sending a nonce to Bob*) berghofe@23746: | NS1: "\evs1 \ ns_public; Nonce NA \ used evs1\ paulson@13922: \ Says A B (Crypt (pubEK B) \Nonce NA, Agent A\) paulson@11104: # evs1 \ ns_public" paulson@2318: paulson@2318: (*Bob responds to Alice's message with a further nonce*) berghofe@23746: | NS2: "\evs2 \ ns_public; Nonce NB \ used evs2; paulson@13922: Says A' B (Crypt (pubEK B) \Nonce NA, Agent A\) \ set evs2\ paulson@13922: \ Says B A (Crypt (pubEK A) \Nonce NA, Nonce NB, Agent B\) paulson@11104: # evs2 \ ns_public" paulson@2318: paulson@2318: (*Alice proves her existence by sending NB back to Bob.*) berghofe@23746: | NS3: "\evs3 \ ns_public; paulson@13922: Says A B (Crypt (pubEK B) \Nonce NA, Agent A\) \ set evs3; paulson@13922: Says B' A (Crypt (pubEK A) \Nonce NA, Nonce NB, Agent B\) paulson@11104: \ set evs3\ paulson@13922: \ Says A B (Crypt (pubEK B) (Nonce NB)) # evs3 \ ns_public" paulson@11104: paulson@11104: declare knows_Spy_partsEs [elim] paulson@14200: declare knows_Spy_partsEs [elim] paulson@14200: declare analz_into_parts [dest] haftmann@56681: declare Fake_parts_insert_in_Un [dest] paulson@11104: paulson@11104: (*A "possibility property": there are traces that reach the end*) paulson@13922: lemma "\NB. \evs \ ns_public. Says A B (Crypt (pubEK B) (Nonce NB)) \ set evs" paulson@11104: apply (intro exI bexI) paulson@11104: apply (rule_tac [2] ns_public.Nil [THEN ns_public.NS1, THEN ns_public.NS2, paulson@14207: THEN ns_public.NS3], possibility) paulson@13926: done paulson@11104: paulson@11104: (** Theorems of the form X \ parts (spies evs) imply that NOBODY paulson@11104: sends messages containing X! **) paulson@11104: paulson@11104: (*Spy never sees another agent's private key! (unless it's bad at start)*) paulson@13922: lemma Spy_see_priEK [simp]: paulson@13922: "evs \ ns_public \ (Key (priEK A) \ parts (spies evs)) = (A \ bad)" paulson@11104: by (erule ns_public.induct, auto) paulson@11104: paulson@13922: lemma Spy_analz_priEK [simp]: paulson@13922: "evs \ ns_public \ (Key (priEK A) \ analz (spies evs)) = (A \ bad)" paulson@11104: by auto paulson@11104: paulson@14200: subsection{*Authenticity properties obtained from NS2*} paulson@11104: paulson@11104: paulson@11104: (*It is impossible to re-use a nonce in both NS1 and NS2, provided the nonce paulson@11104: is secret. (Honest users generate fresh nonces.)*) paulson@11104: lemma no_nonce_NS1_NS2 [rule_format]: paulson@11104: "evs \ ns_public paulson@13922: \ Crypt (pubEK C) \NA', Nonce NA, Agent D\ \ parts (spies evs) \ paulson@13922: Crypt (pubEK B) \Nonce NA, Agent A\ \ parts (spies evs) \ paulson@11104: Nonce NA \ analz (spies evs)" paulson@11104: apply (erule ns_public.induct, simp_all) paulson@11104: apply (blast intro: analz_insertI)+ paulson@11104: done paulson@11104: paulson@11104: (*Unicity for NS1: nonce NA identifies agents A and B*) paulson@11104: lemma unique_NA: paulson@13922: "\Crypt(pubEK B) \Nonce NA, Agent A \ \ parts(spies evs); paulson@13922: Crypt(pubEK B') \Nonce NA, Agent A'\ \ parts(spies evs); paulson@11104: Nonce NA \ analz (spies evs); evs \ ns_public\ paulson@11104: \ A=A' \ B=B'" paulson@11104: apply (erule rev_mp, erule rev_mp, erule rev_mp) paulson@11104: apply (erule ns_public.induct, simp_all) paulson@11104: (*Fake, NS1*) paulson@11104: apply (blast intro: analz_insertI)+ paulson@11104: done paulson@11104: paulson@11104: paulson@11104: (*Secrecy: Spy does not see the nonce sent in msg NS1 if A and B are secure paulson@11104: The major premise "Says A B ..." makes it a dest-rule, so we use paulson@11104: (erule rev_mp) rather than rule_format. *) paulson@11104: theorem Spy_not_see_NA: paulson@13922: "\Says A B (Crypt(pubEK B) \Nonce NA, Agent A\) \ set evs; paulson@11104: A \ bad; B \ bad; evs \ ns_public\ paulson@11104: \ Nonce NA \ analz (spies evs)" paulson@11104: apply (erule rev_mp) paulson@13507: apply (erule ns_public.induct, simp_all, spy_analz) paulson@11104: apply (blast dest: unique_NA intro: no_nonce_NS1_NS2)+ paulson@11104: done paulson@11104: paulson@2318: paulson@11104: (*Authentication for A: if she receives message 2 and has used NA paulson@11104: to start a run, then B has sent message 2.*) paulson@11104: lemma A_trusts_NS2_lemma [rule_format]: paulson@11104: "\A \ bad; B \ bad; evs \ ns_public\ paulson@13922: \ Crypt (pubEK A) \Nonce NA, Nonce NB, Agent B\ \ parts (spies evs) \ wenzelm@32960: Says A B (Crypt(pubEK B) \Nonce NA, Agent A\) \ set evs \ wenzelm@32960: Says B A (Crypt(pubEK A) \Nonce NA, Nonce NB, Agent B\) \ set evs" paulson@11104: apply (erule ns_public.induct, simp_all) paulson@11104: (*Fake, NS1*) paulson@11104: apply (blast dest: Spy_not_see_NA)+ paulson@11104: done paulson@11104: paulson@11104: theorem A_trusts_NS2: paulson@13922: "\Says A B (Crypt(pubEK B) \Nonce NA, Agent A\) \ set evs; paulson@13922: Says B' A (Crypt(pubEK A) \Nonce NA, Nonce NB, Agent B\) \ set evs; paulson@11104: A \ bad; B \ bad; evs \ ns_public\ paulson@13922: \ Says B A (Crypt(pubEK A) \Nonce NA, Nonce NB, Agent B\) \ set evs" paulson@11104: by (blast intro: A_trusts_NS2_lemma) paulson@11104: paulson@11104: paulson@11104: (*If the encrypted message appears then it originated with Alice in NS1*) paulson@11104: lemma B_trusts_NS1 [rule_format]: paulson@11104: "evs \ ns_public paulson@13922: \ Crypt (pubEK B) \Nonce NA, Agent A\ \ parts (spies evs) \ wenzelm@32960: Nonce NA \ analz (spies evs) \ wenzelm@32960: Says A B (Crypt (pubEK B) \Nonce NA, Agent A\) \ set evs" paulson@11104: apply (erule ns_public.induct, simp_all) paulson@11104: (*Fake*) paulson@11104: apply (blast intro!: analz_insertI) paulson@11104: done paulson@11104: paulson@11104: paulson@14200: subsection{*Authenticity properties obtained from NS2*} paulson@11104: paulson@11104: (*Unicity for NS2: nonce NB identifies nonce NA and agents A, B paulson@11104: [unicity of B makes Lowe's fix work] paulson@11104: [proof closely follows that for unique_NA] *) paulson@11104: paulson@11104: lemma unique_NB [dest]: paulson@13922: "\Crypt(pubEK A) \Nonce NA, Nonce NB, Agent B\ \ parts(spies evs); paulson@13922: Crypt(pubEK A') \Nonce NA', Nonce NB, Agent B'\ \ parts(spies evs); paulson@11104: Nonce NB \ analz (spies evs); evs \ ns_public\ paulson@11104: \ A=A' \ NA=NA' \ B=B'" paulson@11104: apply (erule rev_mp, erule rev_mp, erule rev_mp) paulson@11104: apply (erule ns_public.induct, simp_all) paulson@11104: (*Fake, NS2*) paulson@11104: apply (blast intro: analz_insertI)+ paulson@11104: done paulson@11104: paulson@11104: paulson@11104: (*Secrecy: Spy does not see the nonce sent in msg NS2 if A and B are secure*) paulson@11104: theorem Spy_not_see_NB [dest]: paulson@13922: "\Says B A (Crypt (pubEK A) \Nonce NA, Nonce NB, Agent B\) \ set evs; paulson@11104: A \ bad; B \ bad; evs \ ns_public\ paulson@11104: \ Nonce NB \ analz (spies evs)" paulson@11104: apply (erule rev_mp) paulson@13507: apply (erule ns_public.induct, simp_all, spy_analz) paulson@11104: apply (blast intro: no_nonce_NS1_NS2)+ paulson@11104: done paulson@11104: paulson@11104: paulson@11104: (*Authentication for B: if he receives message 3 and has used NB paulson@11104: in message 2, then A has sent message 3.*) paulson@11104: lemma B_trusts_NS3_lemma [rule_format]: paulson@11104: "\A \ bad; B \ bad; evs \ ns_public\ \ paulson@13922: Crypt (pubEK B) (Nonce NB) \ parts (spies evs) \ paulson@13922: Says B A (Crypt (pubEK A) \Nonce NA, Nonce NB, Agent B\) \ set evs \ paulson@13922: Says A B (Crypt (pubEK B) (Nonce NB)) \ set evs" paulson@11104: by (erule ns_public.induct, auto) paulson@11104: paulson@11104: theorem B_trusts_NS3: paulson@13922: "\Says B A (Crypt (pubEK A) \Nonce NA, Nonce NB, Agent B\) \ set evs; paulson@13922: Says A' B (Crypt (pubEK B) (Nonce NB)) \ set evs; paulson@11104: A \ bad; B \ bad; evs \ ns_public\ paulson@13922: \ Says A B (Crypt (pubEK B) (Nonce NB)) \ set evs" paulson@11104: by (blast intro: B_trusts_NS3_lemma) paulson@11104: paulson@14200: subsection{*Overall guarantee for B*} paulson@11104: paulson@11104: (*If NS3 has been sent and the nonce NB agrees with the nonce B joined with paulson@11104: NA, then A initiated the run using NA.*) paulson@11104: theorem B_trusts_protocol: paulson@11104: "\A \ bad; B \ bad; evs \ ns_public\ \ paulson@13922: Crypt (pubEK B) (Nonce NB) \ parts (spies evs) \ paulson@13922: Says B A (Crypt (pubEK A) \Nonce NA, Nonce NB, Agent B\) \ set evs \ paulson@13922: Says A B (Crypt (pubEK B) \Nonce NA, Agent A\) \ set evs" paulson@11104: by (erule ns_public.induct, auto) paulson@2318: paulson@2318: end