scyther-proof-0.10.0.0: data/isabelle/src/ESPLogic/Protocol.thy
(*****************************************************************************
* 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
| PAny --{* wildcard for matching *}
text{* Bi-directional keys between two agents referenced by variables *}
definition sKbd :: "varid \<Rightarrow> varid \<Rightarrow> pattern"
where "sKbd a b = PShrK {a, b}"
text{* Free variables *}
fun FV :: "pattern \<Rightarrow> varid set"
where
"FV (PVar v) = {v}"
| "FV (PHash m) = FV m"
| "FV (PTup x y) = FV x \<union> FV y"
| "FV (PEnc m k) = FV m \<union> FV k"
| "FV (PSign m k) = FV m \<union> FV k"
| "FV (PSymK a b) = FV a \<union> 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 \<Rightarrow> id set"
where
"FMV (PVar (MVar v)) = {v}"
| "FMV (PHash m) = FMV m"
| "FMV (PTup x y) = FMV x \<union> FMV y"
| "FMV (PEnc m k) = FMV m \<union> FMV k"
| "FMV (PSign m k) = FMV m \<union> FMV k"
| "FMV (PSymK a b) = FMV a \<union> FMV b"
| "FMV (PShrK A) = {v. MVar v \<in> A}"
| "FMV (PAsymPK a) = FMV a"
| "FMV (PAsymSK a) = FMV a"
| "FMV (_) = {}"
lemma FMV_sKbd [simp]:
"FMV (sKbd a b) = {v. MVar v = a \<or> MVar v = b}"
by (auto simp: sKbd_def)
text{* Free agent variables *}
fun FAV :: "pattern \<Rightarrow> id set"
where
"FAV (PVar (AVar a)) = {a}"
| "FAV (PHash m) = FAV m"
| "FAV (PTup x y) = FAV x \<union> FAV y"
| "FAV (PEnc m k) = FAV m \<union> FAV k"
| "FAV (PSign m k) = FAV m \<union> FAV k"
| "FAV (PSymK a b) = FAV a \<union> FAV b"
| "FAV (PShrK A) = {v. AVar v \<in> A}"
| "FAV (PAsymPK a) = FAV a"
| "FAV (PAsymSK a) = FAV a"
| "FAV (_) = {}"
lemma FAV_sKbd [simp]:
"FAV (sKbd a b) = {v. AVar v = a \<or> AVar v = b}"
by (auto simp: sKbd_def)
subsubsection{* Role Steps *}
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.
Additionally, match steps can be used to express local constraints
on variables and messages. Matching may be positive (equality
must hold in order to execute the step) or negative.
Note steps indicate possible points of dynamic information
leakage.
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
| Match lbl bool varid pattern
| Note lbl notetype pattern
text {*
Free message variables guaranteed to be instantiated (having
a semantic source) after a role step was executed.
*}
fun sourced_vars :: "rolestep \<Rightarrow> id set"
where
"sourced_vars (Recv lbl pt) = FMV pt"
| "sourced_vars (Match lbl True v pt) = FMV pt"
| "sourced_vars _ = {}"
text {*
Free message variables which must have been obtained previously
when performing a role step.
*}
fun used_vars :: "rolestep \<Rightarrow> id set"
where
"used_vars (Send lbl msg) = FMV msg"
| "used_vars (Recv lbl pt) = {}"
| "used_vars (Match lbl True v pt) = {m. v = MVar m}"
| "used_vars (Match lbl False v pt) = {m. v = MVar m} \<union> FMV pt"
| "used_vars (Note lbl ty msg) = FMV msg"
text {* Free variables of a role step *}
fun FV_rolestep :: "rolestep \<Rightarrow> varid set"
where
"FV_rolestep (Send lbl pt) = FV pt"
| "FV_rolestep (Recv lbl pt) = FV pt"
| "FV_rolestep (Match lbl eq v pt) = {v} \<union> FV pt"
| "FV_rolestep (Note lbl ty pt) = FV pt"
text {* Free agent variables of a role step *}
fun FAV_rolestep :: "rolestep \<Rightarrow> id set"
where
"FAV_rolestep (Send lbl pt) = FAV pt"
| "FAV_rolestep (Recv lbl pt) = FAV pt"
| "FAV_rolestep (Match lbl eq v pt) = {a. v = AVar a} \<union> FAV pt"
| "FAV_rolestep (Note lbl ty pt) = FAV pt"
text {* The pattern of a rolestep *}
fun stepPat :: "rolestep \<Rightarrow> pattern"
where
"stepPat (Send lbl pt) = pt"
| "stepPat (Recv lbl pt) = pt"
| "stepPat (Match lbl eq v pt) = pt"
| "stepPat (Note lbl ty pt) = pt"
text {* The variable to match with (or not) *}
fun matchVar :: "rolestep \<Rightarrow> varid"
where
"matchVar (Match l eq v pt) = v"
| "matchVar _ = undefined"
text {* The type of possible information leakage *}
fun noteType :: "rolestep \<Rightarrow> notetype"
where
"noteType (Note l ty pt) = ty"
| "noteType _ = undefined"
text {* Predicates for step types *}
fun sendStep :: "rolestep \<Rightarrow> bool"
where
"sendStep (Send lbl pt) = True"
| "sendStep _ = False"
fun noteStep :: "rolestep \<Rightarrow> bool"
where
"noteStep (Note lbl ty pt) = True"
| "noteStep _ = False"
fun recvStep :: "rolestep \<Rightarrow> bool"
where
"recvStep (Recv lbl pt) = True"
| "recvStep _ = False"
fun matchStep :: "rolestep \<Rightarrow> bool"
where
"matchStep (Match lbl eq v pt) = True"
| "matchStep _ = False"
text {* Distinguishing positive and negative match steps *}
fun matchEqStep :: "rolestep \<Rightarrow> bool"
where
"matchEqStep (Match lbl True v pt) = True"
| "matchEqStep _ = False"
fun notMatchStep :: "rolestep \<Rightarrow> bool"
where
"notMatchStep (Match lbl False v pt) = True"
| "notMatchStep _ = False"
lemma sendStepD [simp]:
assumes inStep: "sendStep step"
shows "\<exists> l pt. step = (Send l pt)"
using inStep
proof(cases step)
qed auto
lemma recvStepD [simp]:
assumes inStep: "recvStep step"
shows "\<exists> l v. step = (Recv l v)"
using inStep
proof(cases step)
qed auto
lemma matchStepD [simp]:
assumes inStep: "matchStep step"
shows "\<exists> l eq v pt. step = (Match l eq v pt)"
using inStep
proof (cases step)
qed auto
lemma matchEqStepD [simp]:
assumes inStep: "matchEqStep step"
shows "\<exists> l v pt. step = (Match l True v pt)"
using inStep
proof (cases step)
case (Match lbl eq v pt)
thus ?thesis using inStep by (cases eq, auto)
qed auto
lemma notMatchStepD [simp]:
assumes inStep: "notMatchStep step"
shows "\<exists> l v pt. step = (Match l False v pt)"
using inStep
proof (cases step)
case (Match lbl eq v pt)
thus ?thesis using inStep by (cases eq, auto)
qed auto
lemma noteStepD [simp]:
assumes inStep: "noteStep step"
shows "\<exists> l ty pt. step = (Note l ty pt)"
using inStep
proof(cases step)
qed auto
subsubsection{* Roles *}
type_synonym "role" = "rolestep list"
text{*
Message variables whose values are semantically used in a
role step, i.e., sent or matched against, must have been
instantiated in an earlier step of the role.
*}
fun source_before_use :: "id set \<Rightarrow> role \<Rightarrow> bool"
where
"source_before_use bound [] = True"
| "source_before_use bound (step # xs) =
((used_vars step \<subseteq> bound)
\<and> source_before_use (bound \<union> sourced_vars step) xs)"
locale wf_role =
distinct_list R for R :: "role" +
assumes source_msgVar_first [iff]: "source_before_use {} R"
subsubsection{* Protocols *}
type_synonym proto = "role set"
locale wf_proto =
fixes P :: proto
assumes wf_roles: "R \<in> P \<Longrightarrow> wf_role R"
subsection{* Properties *}
subsubsection{* Well-Formed Roles *}
lemma source_before_use_distinct:
"\<lbrakk> source_before_use V (R @ step # R');
distinct (R @ step # R');
v \<in> used_vars step; v \<notin> V
\<rbrakk> \<Longrightarrow>
(\<exists> step'. step' \<in> set R \<and> v \<in> sourced_vars step')"
proof (induct R arbitrary: V)
case (Cons step R)
note IH = this show ?case
proof (cases step)
case Send thus ?thesis using IH by fastforce
next
case Recv thus ?thesis using IH by fastforce
next
case Match thus ?thesis using IH by fastforce
next
case Note thus ?thesis using IH by fastforce
qed
qed auto
lemma (in wf_role) source_use_ord:
assumes useR: "ustep \<in> set R"
and useV: "v \<in> used_vars ustep"
shows "\<exists> sstep. v \<in> sourced_vars sstep \<and> listOrd R sstep ustep" (is "\<exists> sstep. ?source sstep")
using useR
proof -
assume "ustep \<in> set R"
then obtain ys zs
where split: "R = ys @ ustep # zs" by (blast dest!: split_list)
moreover have "distinct R" and "source_before_use {} R" by auto
ultimately obtain sstep where "v \<in> sourced_vars sstep" and "sstep \<in> set ys"
by (fastforce dest!: source_before_use_distinct intro!: useV)
hence "?source sstep" using split by fastforce
thus ?thesis by blast
qed
subsubsection{* Auxiliary Lemmas *}
lemma FV_FAV_conv[iff]:
"(a \<in> FAV pt) = ((AVar a) \<in> FV pt)"
proof(induct pt)
case (PVar vid)
thus ?case
by(cases vid) auto
qed auto
lemma FV_FMV_conv[iff]:
"(v \<in> FMV pt) = ((MVar v) \<in> FV pt)"
proof(induct pt)
case (PVar vid)
thus ?case
by(cases vid) auto
qed auto
lemma sourced_imp_FV[dest]:
"v \<in> sourced_vars st \<Longrightarrow> MVar v \<in> FV_rolestep st"
proof (cases st)
case (Match lbl eq mv pt)
assume "v \<in> sourced_vars st"
thus ?thesis using Match by (cases eq, auto)
qed auto
lemma used_imp_FV[dest]:
"v \<in> used_vars st \<Longrightarrow> MVar v \<in> FV_rolestep st"
proof (cases st)
case (Match lbl eq mv pt)
assume "v \<in> used_vars st"
thus ?thesis using Match by (cases eq, auto)
qed auto
lemma source_noteD[dest]:
"\<lbrakk> v \<in> sourced_vars st; noteStep st \<rbrakk> \<Longrightarrow> False"
by (auto dest: noteStepD)
definition aVars:: "role \<Rightarrow> varid set"
where
"aVars role = foldr (\<lambda> st se. (AVar ` FAV_rolestep st) \<union> se) role {}"
lemma aVars_singleton[iff]:
"AVar a \<notin> 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_rolestep s \<union> aVars xs)"
by (auto simp: aVars_def)
lemma aVars_FAV_conv:
"(AVar a \<in> aVars R) = (\<exists> s \<in> set R. a \<in> FAV_rolestep s)"
by (induct R) ( fastforce simp add: aVars_def)+
definition lastComStep :: "role \<rightharpoonup> rolestep"
where
"lastComStep rs = (case (filter (\<lambda> s. \<not> (noteStep s)) rs) of
(x#xs) \<Rightarrow> Some (last (x#xs))
|([]) \<Rightarrow> None)"
definition firstComStep :: "role \<rightharpoonup> rolestep"
where
"firstComStep rs = (case (filter (\<lambda> s. \<not> (noteStep s)) rs) of
(x#xs) \<Rightarrow> Some x
|([]) \<Rightarrow> 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\<leftarrow>xs . \<not> 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\<leftarrow>xs . \<not> noteStep s]")
qed (fastforce simp add: firstComStep_def)+
end