(***************************************************************************** * 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 Protocol imports DistinctList begin section{* Protocol Specifications *} subsection{* Types and Operations *} subsubsection{* Patterns *} type_synonym id = string datatype varid = AVar id | MVar id datatype pattern = PConst id | PFresh id | PVar varid | PHash pattern | PTup pattern pattern | PEnc pattern pattern | PSign pattern pattern | PSymK pattern pattern | PShrK "varid set" (* variables denoting a set of agents sharing a key *) | PAsymPK pattern | PAsymSK pattern (* bi-directional keys between two agents referenced by variables *) definition sKbd :: "varid \ varid \ pattern" where "sKbd a b = PShrK {a, b}" text{* Free variables *} fun FV :: "pattern \ varid set" where "FV (PVar v) = {v}" | "FV (PHash m) = FV m" | "FV (PTup x y) = FV x \ FV y" | "FV (PEnc m k) = FV m \ FV k" | "FV (PSign m k) = FV m \ FV k" | "FV (PSymK a b) = FV a \ FV b" | "FV (PShrK A) = A" | "FV (PAsymPK a) = FV a" | "FV (PAsymSK a) = FV a" | "FV (_) = {}" lemma FV_sKbd [simp]: "FV (sKbd a b) = {a, b}" by (auto simp: sKbd_def) text{* Free message variables *} fun FMV :: "pattern \ id set" where "FMV (PVar (MVar v)) = {v}" | "FMV (PHash m) = FMV m" | "FMV (PTup x y) = FMV x \ FMV y" | "FMV (PEnc m k) = FMV m \ FMV k" | "FMV (PSign m k) = FMV m \ FMV k" | "FMV (PSymK a b) = FMV a \ FMV b" | "FMV (PShrK A) = {v. MVar v \ A}" | "FMV (PAsymPK a) = FMV a" | "FMV (PAsymSK a) = FMV a" | "FMV (_) = {}" lemma FMV_sKbd [simp]: "FMV (sKbd a b) = {v. MVar v = a \ MVar v = b}" by (auto simp: sKbd_def) fun FAV :: "pattern \ id set" where "FAV (PVar (AVar a)) = {a}" | "FAV (PHash m) = FAV m" | "FAV (PTup x y) = FAV x \ FAV y" | "FAV (PEnc m k) = FAV m \ FAV k" | "FAV (PSign m k) = FAV m \ FAV k" | "FAV (PSymK a b) = FAV a \ FAV b" | "FAV (PShrK A) = {v. AVar v \ A}" | "FAV (PAsymPK a) = FAV a" | "FAV (PAsymSK a) = FAV a" | "FAV (_) = {}" lemma FAV_sKbd [simp]: "FAV (sKbd a b) = {v. AVar v = a \ AVar v = b}" by (auto simp: sKbd_def) subsubsection{* Roles *} text{* Roles are non-empty lists of unique send and receive steps such that no long-term keys are used in message texts and all nonce variables are received before they are sent. The labels allow to make steps with identical message unique. They are currently defaulted to strings, but could be anything. *} type_synonym lbl = string datatype notetype = RandGen | State | SessKey datatype rolestep = Send lbl pattern | Recv lbl pattern | Note lbl notetype pattern fun stepPat :: "rolestep \ pattern" where "stepPat (Send lbl msg) = msg" | "stepPat (Recv lbl msg) = msg" | "stepPat (Note lbl ty msg) = msg" fun noteType :: "rolestep \ notetype" where "noteType (Note l ty pt) = ty" fun sendStep :: "rolestep \ bool" where "sendStep (Send lbl msg) = True" | "sendStep (Recv lbl msg) = False" | "sendStep (Note lbl ty msg) = False" fun noteStep :: "rolestep \ bool" where "noteStep (Send lbl msg) = False" | "noteStep (Recv lbl msg) = False" | "noteStep (Note lbl ty msg) = True" abbreviation recvStep where "recvStep x \ \sendStep x \ \ noteStep x" lemma sendStepD [simp]: assumes inStep: "sendStep step" shows "\ l pt. step = (Send l pt)" using inStep proof(cases step) qed auto lemma recvStepD [simp]: assumes inStep: "recvStep step" shows "\ l pt. step = (Recv l pt)" using inStep proof(cases step) qed auto lemma noteStepD [simp]: assumes inStep: "noteStep step" shows "\ l ty pt. step = (Note l ty pt)" using inStep proof(cases step) qed auto type_synonym "role" = "rolestep list" fun recv_before :: "id set \ role \ bool" where "recv_before bound [] = True" | "recv_before bound (Recv _ msg # xs) = recv_before (bound \ FMV msg) xs" | "recv_before bound (Note _ _ msg # xs) = ((\ v. v \ FMV msg \ v \ bound) \ recv_before bound xs)" | "recv_before bound (Send _ msg # xs) = ((\ v. v \ FMV msg \ v \ bound) \ recv_before bound xs)" locale wf_role = distinct_list R for R :: "role" + assumes recv_msgVar_first [iff]: "recv_before {} R" subsubsection{* Protocols *} type_synonym proto = "role set" locale wf_proto = fixes P :: proto assumes wf_roles: "R \ P \ wf_role R" subsection{* Properties *} subsubsection{* Well-Formed Roles *} lemma recv_before_sent_distinct_Send_FV: "\ recv_before V (R@ Send lbl pt # R'); distinct (R @ Send lbl pt # R'); v \ FMV pt; v \ V \ \ \ lbl' pt'. Recv lbl' pt' \ set R \ v \ FMV pt'" proof(induct R arbitrary: V) case (Cons step R) note IH = this show ?case proof(cases step) case (Send lbl pt) thus ?thesis using IH by auto next case (Recv lbl pt) thus ?thesis using IH by (auto, fast) next case (Note lbl ty pt) thus ?thesis using IH by auto qed qed simp lemma recv_before_note_distinct_Note_FV: "\ recv_before V (R@ Note lbl ty pt # R'); distinct (R @ Note lbl ty pt # R'); v \ FMV pt; v \ V \ \ \ lbl' pt'. Recv lbl' pt' \ set R \ v \ FMV pt'" proof(induct R arbitrary: V) case (Cons Note R) note IH = this show ?case proof(cases Note) case (Send lbl pt) thus ?thesis using IH by auto next case (Recv lbl pt) thus ?thesis using IH by (auto, fast) next case (Note lbl ty pt) thus ?thesis using IH by auto qed qed simp lemma (in wf_role) Send_FV: assumes Send: "Send lbl pt \ set R" (is "?send \ set R") and FV: "v \ FMV pt" shows "\ lbl' pt'. listOrd R (Recv lbl' pt') (Send lbl pt) \ v \ FMV pt'" using Send proof - let ?send = "Send lbl pt" and "\ lbl' pt'. ?received lbl' pt'" = ?thesis assume "?send \ set R" then obtain ys zs where split: "R = ys @ ?send # zs" by (blast dest!: split_list) moreover have "distinct R" and "recv_before {} R" by auto ultimately obtain lbl' pt' where "Recv lbl' pt' \ set ys" and "v \ FMV pt'" by (fastforce dest!: recv_before_sent_distinct_Send_FV intro!: FV) hence "?received lbl' pt'" using split by auto thus ?thesis by blast qed lemma (in wf_role) Note_FV: assumes Note: "Note lbl ty pt \ set R" (is "?note \ set R") and FV: "v \ FMV pt" shows "\ lbl' pt'. listOrd R (Recv lbl' pt') (Note lbl ty pt) \ v \ FMV pt'" using Note proof - let ?send = "Note lbl ty pt" and "\ lbl' pt'. ?received lbl' pt'" = ?thesis assume "?note \ set R" then obtain ys zs where split: "R = ys @ ?note # zs" by (blast dest!: split_list) moreover have "distinct R" and "recv_before {} R" by auto ultimately obtain lbl' pt' where "Recv lbl' pt' \ set ys" and "v \ FMV pt'" by (fastforce dest!: recv_before_note_distinct_Note_FV intro!: FV) hence "?received lbl' pt'" using split by auto thus ?thesis by blast qed lemma FV_FAV_conv[iff]: "(a \ FAV pt) = ((AVar a) \ FV pt)" proof(induct pt) case (PVar vid) thus ?case by(cases vid) auto qed auto lemma FV_FMV_conv[iff]: "(v \ FMV pt) = ((MVar v) \ FV pt)" proof(induct pt) case (PVar vid) thus ?case by(cases vid) auto qed auto definition aVars:: "role \ varid set" where "aVars role = foldr (\ st se. (AVar ` FAV (stepPat st)) \ se) role {}" lemma aVars_singleton[iff]: "AVar a \ aVars []" by(fastforce simp add: aVars_def) lemma aVars_Nil [iff]: "aVars [] = {}" by (auto simp: aVars_def) lemma aVars_Cons [simp]: "aVars (s#xs) = (AVar ` FAV (stepPat s) \ aVars xs)" by (auto simp: aVars_def) lemma aVars_FAV_conv: "(AVar a \ aVars R) = (\ s \ set R. \ pt. (stepPat s = pt \ a \ FAV pt))" by (induct R) ( fastforce simp add: aVars_def)+ definition lastComStep :: "role \ rolestep" where "lastComStep rs = (case (filter (\ s. \ (noteStep s)) rs) of (x#xs) \ Some (last (x#xs)) |([]) \ None)" definition firstComStep :: "role \ rolestep" where "firstComStep rs = (case (filter (\ s. \ (noteStep s)) rs) of (x#xs) \ Some x |([]) \ None)" lemma lastComStep_Nil [iff]: "lastComStep [] = None" by (auto simp: lastComStep_def) lemma lastComStep_Cons [simp]: "lastComStep (x#xs) = (let s = lastComStep xs in if (noteStep x) then s else if (s = None) then Some x else s )" proof (cases "[s\xs . \ noteStep s]") qed (fastforce simp add: lastComStep_def)+ lemma firstComStep_Nil [iff]: "firstComStep [] = None" by (auto simp: firstComStep_def) lemma firstComStep_Cons [simp]: "firstComStep (x#xs) = ( if (noteStep x) then firstComStep xs else Some x )" proof (cases "[s\xs . \ noteStep s]") qed (fastforce simp add: firstComStep_def)+ end