(***************************************************************************** * ESPL --- an embedded security protocol logic * http://people.inf.ethz.ch/meiersi/espl/ * * Copyright (c) 2009-2011, Simon Meier, ETH Zurich, Switzerland * * Extension to compromising adversaries: * * Copyright (c) 2010-2011, Martin Schaub, ETH Zurich, Switzerland * * All rights reserved. See file LICENCE for more information. ******************************************************************************) theory ExecMessage imports Protocol begin subsection{* Execution Messages *} typedef tid = "UNIV :: nat set" by blast datatype execlit = EConst id | EAgent id | ENonce id tid | EveNonce id datatype execmsg = Lit execlit | Tup execmsg execmsg | Enc execmsg execmsg | Hash execmsg | K execmsg execmsg | KShr "id set" (* a set of agent sharing this key *) | PK execmsg | SK execmsg text{*Concrete syntax: messages appear as {|A,B,NA|}, etc...*} syntax "@MTuple" :: "['a, args] => 'a * 'b" ("(2{|_,/ _|})") syntax (xsymbols) "@MTuple" :: "['a, args] => 'a * 'b" ("(2\_,/ _\)") translations "{|x, y, z|}" == "{|x, {|y, z|}|}" "{|x, y|}" == "(CONST Tup) x y" text{* A shallow reference to bi-directional keys between two agents. Used only in proofs, but not in specifications. Hence, it can be ignored for soundness. *} definition Agent :: "execmsg set" where "Agent \ { Lit (EAgent a) | a. True}" definition agents :: "execmsg set \ id set" where "agents M = {a. Lit (EAgent a) \ M}" definition Kbd :: "execmsg \ execmsg \ execmsg" where "Kbd a b = (if (a \ Agent \ b \ Agent) then KShr (agents {a, b}) else undefined)" lemma Kbd_commute [simp]: "Kbd x y = Kbd y x" by (auto simp: Kbd_def agents_def) lemma size_Kbd [simp]: "\ a \ Agent; b \ Agent \ \ size (Kbd a b) = 0" by ( auto simp: Kbd_def) lemma Kbd_free [simp]: "\ a \ Agent; b \ Agent \ \ Kbd a b \ Lit l" "\ a \ Agent; b \ Agent \ \ Kbd a b \ Tup x y" "\ a \ Agent; b \ Agent \ \ Kbd a b \ Enc x y" "\ a \ Agent; b \ Agent \ \ Kbd a b \ Hash x" "\ a \ Agent; b \ Agent \ \ Kbd a b \ K x y" "\ a \ Agent; b \ Agent \ \ Kbd a b \ PK x" "\ a \ Agent; b \ Agent \ \ Kbd a b \ SK x" by (auto simp: Kbd_def) declare Kbd_free[symmetric, simp] lemma Kbd_split_inj: "\ a \ Agent; b \ Agent; x \ Agent; y \ Agent \ \ (Kbd a b = Kbd x y) = (a = x \ b = y \ a = y \ b = x)" apply(clarsimp simp: Kbd_def Agent_def agents_def set_eq_iff) apply(rule iffI) apply(rename_tac a b x y) apply(safe) apply(drule_tac x="a" in spec) apply(simp) apply(drule_tac x="y" in spec) apply(simp) apply(drule_tac x="x" in spec) apply(simp) apply(drule_tac x="b" in spec) apply(simp) done lemma Kbd_non_split_inj [simp]: "\ a \ Agent; b \ Agent; x \ Agent \ \ (Kbd a b = Kbd x b) = (a = x)" "\ a \ Agent; b \ Agent; x \ Agent \ \ (Kbd a b = Kbd b x) = (a = x)" "\ a \ Agent; b \ Agent; x \ Agent \ \ (Kbd b a = Kbd x b) = (a = x)" "\ a \ Agent; b \ Agent; x \ Agent \ \ (Kbd b a = Kbd b x) = (a = x)" "\ a \ Agent; y \ Agent; x \ Agent \ \ (Kbd a a = Kbd x y) = (a = y \ x = y)" "\ a \ Agent; b \ Agent; x \ Agent \ \ (Kbd a b = Kbd x x) = (a = x \ b = x)" by (auto simp: Kbd_split_inj) lemma Kbd_cases [ consumes 1 , case_names Agent_a Agent_b Agent_x Agent_y noswap swapped]: "\ Kbd a b = Kbd x y; a \ Agent; b \ Agent; x \ Agent; y \ Agent; \ a = x; b = y \ \ R; \ a = y; b = x \ \ R \ \ R" by (auto simp: Kbd_split_inj) subsection{* Operations *} type_synonym store = "varid \ tid \ execmsg" fun inv :: "execmsg \ execmsg" where "inv (PK m) = SK m" | "inv (SK m) = PK m" | "inv m = m" lemma inv_Kbd [simp]: "\ a \ Agent; b \ Agent \ \ inv (Kbd a b) = Kbd a b" by(auto simp: Kbd_def) (* TODO: Move *) fun opt_map2 :: "('a \ 'b \ 'c) \ 'a option \ 'b option \ 'c option" where "opt_map2 f (Some x) (Some y) = Some (f x y)" | "opt_map2 f _ _ = None" lemma Some_opt_map2 [simp]: "(Some x = opt_map2 f a b) = (\ y z. x = f y z \ Some y = a \ Some z = b)" "(opt_map2 f a b = Some x) = (\ y z. x = f y z \ Some y = a \ Some z = b)" by (cases a, simp, cases b, simp_all add: eq_commute)+ lemma Some_if_pushL [simp]: "(Some x = (if b then Some y else None)) = (b \ x = y)" "((if b then Some y else None) = Some x) = (b \ x = y)" by (auto split: if_splits) lemma Some_if_pushR [simp]: "(Some x = (if b then None else Some y)) = (\b \ x = y)" "((if b then None else Some y) = Some x) = (\b \ x = y)" by (auto split: if_splits) lemma Some_Option_map [simp]: "(Some x = Option.map f a) = (\y. x = f y \ Some y = a)" "(Option.map f a = Some x) = (\y. x = f y \ Some y = a)" by (cases a, auto)+ fun inst :: "store \ tid \ pattern \ execmsg option" where "inst s i (PConst c) = Some (Lit (EConst c))" | "inst s i (PFresh n) = Some (Lit (ENonce n i))" | "inst s i (PVar v) = Some (s (v, i))" | "inst s i (PTup x y) = opt_map2 Tup (inst s i x) (inst s i y)" | "inst s i (PEnc m k) = opt_map2 Enc (inst s i m) (inst s i k)" | "inst s i (PSign m k) = opt_map2 Tup (inst s i m) (opt_map2 Enc (inst s i m) (Option.map inv (inst s i k)))" | "inst s i (PHash m) = Option.map Hash (inst s i m)" | "inst s i (PSymK a b) = opt_map2 K (inst s i a) (inst s i b)" | "inst s i (PAsymPK a) = Option.map PK (inst s i a)" | "inst s i (PAsymSK a) = Option.map SK (inst s i a)" | "inst s i (PShrK V) = (if (\ v \ V. s (v, i) \ Agent) then Some (KShr (agents {s (v, i) | v. v \ V})) else None)" text{* We assume that recipients making use of shared keys look them up in a table. This lookup only succeeds if agent identities are given. *} lemma Some_inst_sKbd [simp]: "(Some m = inst s i (sKbd a b)) = (m = Kbd (s (a, i)) (s (b, i)) \ s (a, i) \ Agent \ s (b, i) \ Agent )" by (auto simp: sKbd_def Kbd_def Agent_def agents_def) fun unpair :: "execmsg \ execmsg set" where "unpair (Tup x y) = unpair x \ unpair y" | "unpair m = {m}" text{* We do not use neither subterms nor parts in our reasoning infrastructure. However it used to formulate a few lemmas illustrating the relation between Paulsons' approach and ours. *} fun subterms :: "execmsg \ execmsg set" where "subterms (Lit l) = {Lit l}" | "subterms (Tup x y) = insert (Tup x y) (subterms x \ subterms y)" | "subterms (Enc m k) = insert (Enc m k) (subterms m \ subterms k)" | "subterms (Hash m) = insert (Hash m) (subterms m)" | "subterms (K a b) = insert (K a b) (subterms a \ subterms b)" | "subterms (PK a) = insert (PK a) (subterms a)" | "subterms (SK a) = insert (SK a) (subterms a)" | "subterms (KShr A) = insert (KShr A) {Lit (EAgent a) | a. a \ A}" fun parts :: "execmsg \ execmsg set" where "parts (Lit l) = {Lit l}" | "parts (Tup x y) = insert (Tup x y) (parts x \ parts y)" | "parts (Enc m k) = insert (Enc m k) (parts m)" | "parts (Hash m) = {Hash m}" | "parts (K a b) = {K a b}" | "parts (PK a) = {PK a}" | "parts (SK a) = {SK a}" | "parts (KShr A) = {KShr A}" fun pairParts :: "execmsg \ execmsg set" where "pairParts (Tup x y) = insert (Tup x y) (pairParts x \ pairParts y)" | "pairParts m = {m}" lemma pairParts_Kbd [simp]: "\ a \ Agent; b \ Agent \ \ pairParts (Kbd a b) = {Kbd a b}" by (auto simp: Kbd_def) inductive_set infer :: "execmsg set \ execmsg set" for M :: "execmsg set" where Inj [simp,intro]: "m \ M \ m \ infer M" | Tup: "\ x \ infer M; y \ infer M \ \ Tup x y \ infer M" | Fst: "Tup x y \ infer M \ x \ infer M" | Snd: "Tup x y \ infer M \ y \ infer M" | Hash: "m \ infer M \ Hash m \ infer M" | Enc: "\ m \ infer M; k \ infer M \ \ Enc m k \ infer M" | Dec: "\ Enc m k \ infer M; inv k \ infer M \ \ m \ infer M" subsection{* Properties *} subsubsection{* Agents *} lemma notin_Agent [iff]: "Lit (EConst x) \ Agent" "Lit (EAgent x) \ Agent" "Lit (ENonce x i) \ Agent" "Lit (EveNonce x) \ Agent" "Tup m1 m2 \ Agent" "Enc m1 m2 \ Agent" "Hash m1 \ Agent" "K m1 m2 \ Agent" "KShr V \ Agent" "PK m1 \ Agent" "SK m1 \ Agent" "\ a \ Agent; b \ Agent \ \ Kbd a b \ Agent" by (auto simp: Kbd_def Agent_def) subsubsection{* Unification modulo key-inversion *} lemma size_inv [simp]: "size (inv x) = size x" by (cases x) auto lemma inv_eqs [iff]: "(inv x = Lit m) = (x = Lit m)" "(inv x = Tup m1 m2) = (x = Tup m1 m2)" "(inv x = Enc m1 m2) = (x = Enc m1 m2)" "(inv x = Hash m1) = (x = Hash m1)" "(inv x = K m1 m2) = (x = K m1 m2)" "(inv x = PK m1) = (x = SK m1)" "(inv x = SK m1) = (x = PK m1)" "(Lit m = inv x) = (x = Lit m)" "(Tup m1 m2 = inv x) = (x = Tup m1 m2)" "(Enc m1 m2 = inv x) = (x = Enc m1 m2)" "(Hash m1 = inv x) = (x = Hash m1)" "(K m1 m2 = inv x) = (x = K m1 m2)" "(PK m1 = inv x) = (x = SK m1)" "(SK m1 = inv x) = (x = PK m1)" "(KShr A = inv x) = (x = KShr A)" "\ a \ Agent; b \ Agent \ \ (Kbd a b = inv x) = (x = Kbd a b)" by (auto) (induct x, simp+)+ lemma inv_inj [iff]: "(inv x = inv y) = (x = y)" by (auto) (induct x, auto) subsubsection{* @{term subterms} *} lemma subterms_trans: "\ x \ subterms y; y \ subterms z \ \ x \ subterms z" by(induct z, auto) lemma unpair_subset_subterms: "unpair m \ subterms m" by(induct m, auto) lemmas unpair_subtermsD = subsetD[OF unpair_subset_subterms, rule_format] subsubsection{* @{term infer} *} text{* Monotonicity *} lemma infer_mono [trans]: "M \ N \ infer M \ infer N" by(auto, erule infer.induct, auto intro: infer.intros) lemma infer_increasing: "M \ infer M" by(blast) text{* Converse fails: A message composed from subterms of both sets is not in the union of the individual inferable sets. *} lemma infer_Un: "infer M \ infer N \ infer (M \ N)" by(intro Un_least infer_mono Un_upper1 Un_upper2) lemmas infer_UnD = subsetD[OF infer_Un, rule_format] lemma infer_insert: "insert x (infer M) \ infer (insert x M)" by(blast intro: infer_mono[THEN [2] rev_subsetD]) text{* Idempotence and transitivity *} lemma infer_inferD [dest!]: "x \ infer (infer M) \ x \ infer M" by (induct rule: infer.induct) (auto intro: infer.intros) lemma infer_idem [iff]: "infer (infer M) = infer M" by blast lemma infer_subset_iff [simp]: "(infer M \ infer N) = (M \ infer N)" (is "?lhs = ?rhs") proof assume ?lhs have "M \ infer M" by(rule infer_increasing) also note `?lhs` finally show ?rhs . next assume ?rhs hence "infer M \ infer (infer N)" by(rule infer_mono) thus ?lhs by simp qed lemma infer_trans: "\ x \ infer M; M \ infer N \ \ x \ infer N" by (drule infer_mono, blast) text{*Cut; Lemma 2 of Lowe*} lemma infer_cut: "\ y \ infer (insert x M); x \ infer M \ \ y \ infer M" by (erule infer_trans, blast) lemma Tup_in_infer [simp]: "Tup x y \ infer M = (x \ infer M \ y \ infer M)" by(blast intro: infer.intros) lemma infer_insert_Tup [simp]: "infer (insert (Tup x y) M) = infer (insert x (insert y M))" by(safe, (erule infer.induct, auto intro: infer.intros)+) lemma infer_insertI [intro]: "x \ infer M \ x \ infer (insert y M)" by(erule rev_subsetD[OF _ infer_mono], blast) lemma infer_finite_support: assumes "m \ infer M" shows "\ N. N \ M \ finite N \ m \ infer N" (is "\ N. ?support m N") using assms proof(induct rule: infer.induct) case (Inj m) hence "?support m {m}" by fast thus ?case by blast next case (Hash m) then obtain Nm where "?support m Nm" by blast hence "?support (Hash m) Nm" by (blast intro: infer.intros) thus ?case by blast next case (Tup x y) note IH = this obtain Nx where "?support x Nx" using IH by blast moreover obtain Ny where "?support y Ny" using IH by blast ultimately have "?support (Tup x y) (Nx \ Ny)" by (blast intro: infer.intros infer_UnD) thus ?case by blast next case (Fst x y) then obtain Nxy where "?support \x, y\ Nxy" by blast hence "?support x Nxy" by (blast intro: infer.intros) thus ?case by blast next case (Snd x y) then obtain Nxy where "?support \x, y\ Nxy" by blast hence "?support y Nxy" by (blast intro: infer.intros) thus ?case by blast next case (Enc m k) note IH = this obtain Nm where "?support m Nm" using IH by blast moreover obtain Nk where "?support k Nk" using IH by blast ultimately have "?support (Enc m k) (Nm \ Nk)" by (blast intro: infer.intros infer_UnD) thus ?case by blast next case (Dec m k) note IH = this obtain Nmk where "?support (Enc m k) Nmk" using IH by blast moreover obtain Nk where "?support (inv k) Nk" using IH by blast ultimately have "?support m (Nmk \ Nk)" by (blast intro: infer.intros infer_UnD) thus ?case by blast qed subsubsection{* @{term pairParts} *} lemma pairParts_mono [iff]: "m \ pairParts m" by(induct m rule: pairParts.induct, auto) lemma pairParts_idem: "m' \ pairParts m \ pairParts m' \ pairParts m" by(induct m, auto) lemmas pairParts_idemD = subsetD[OF pairParts_idem, rule_format] lemma pairParts_in_infer: "\ x \ pairParts m; m \ infer M \ \ x \ infer M" by(induct m arbitrary: x, auto) lemma unpair_subset_pairParts: "unpair m \ pairParts m" by(induct m, auto) lemmas unpair_subset_pairPartsD = subsetD[OF unpair_subset_pairParts, rule_format] subsection{* Initial Intruder Knowledge *} definition IK0 :: "execmsg set" where "IK0 \ { Lit (EConst c) | c. True} \ { Lit (EveNonce a) | a. True} \ { Lit (EAgent a) | a. True} \ { PK (Lit (EAgent a)) | a. True} \ { KShr {} }" lemma IK0_unpair_inv: "m \ IK0 \ unpair m = {m}" by(auto simp: IK0_def image_def) lemma in_IK0_by_unpair: "\ m \ unpair m'; m' \ IK0 \ \ m \ IK0" by(frule IK0_unpair_inv, auto) lemma notin_IK0 [iff]: "SK a \ IK0" "K a b \ IK0" "Enc m k \ IK0" "Hash m \ IK0" "Lit (ENonce n i) \ IK0" "Tup x y \ IK0" "A \ {} \ KShr A \ IK0" "\ a \ Agent; b \ Agent \ \ Kbd a b \ IK0" by (auto simp: IK0_def Kbd_def agents_def Agent_def) lemma in_IK0_simps [iff]: "Lit (EConst c) \ IK0" "Lit (EveNonce n) \ IK0" "Lit (EAgent a) \ IK0" "PK (Lit (EAgent a)) \ IK0" "KShr {} \ IK0" by(auto simp: IK0_def) end