Theory m3_sig
section ‹Refinement 3a: Signature-based Dolev-Yao Protocol (Variant A)›
theory m3_sig imports m2_auth_chan "../Refinement/Message"
begin
text ‹We implement the channel protocol of the previous refinement with
signatures and add a full-fledged Dolev-Yao adversary. In this variant, the
adversary is realized using Paulson's closure operators for message derivation
(as opposed to a collection of one-step derivation events a la Strand spaces).
›
text ‹Proof tool configuration. Avoid annoying automatic unfolding of
‹dom› (again).›
declare domIff [simp, iff del]
declare analz_into_parts [dest]
subsection ‹State›
text ‹We extend the state of @{term m1} with insecure and authentic
channels between each pair of agents.›
record m3_state = m1_state +
IK :: "msg set"
type_synonym
m3_obs = m1_state
definition
m3_obs :: "m3_state ⇒ m3_obs" where
"m3_obs s ≡ ⦇
runs = runs s
⦈"
subsection ‹Events›
definition
m3_step1 :: "[rid_t, agent, agent, nonce] ⇒ (m3_state × m3_state) set"
where
"m3_step1 Ra A B Na ≡ {(s, s1).
Ra ∉ dom (runs s) ∧
Na = Ra$0 ∧
s1 = s⦇
runs := (runs s)(Ra ↦ (Init, [A, B], [])),
IK := insert ⦃Agent A, Agent B, Nonce Na⦄ (IK s)
⦈
}"
definition
m3_step2 :: "[rid_t, agent, agent, nonce, nonce] ⇒ (m3_state × m3_state) set"
where
"m3_step2 Rb A B Na Nb ≡ {(s, s1).
Rb ∉ dom (runs s) ∧
Nb = Rb$0 ∧
⦃Agent A, Agent B, Nonce Na⦄ ∈ IK s ∧
s1 = s⦇
runs := (runs s)(Rb ↦ (Resp, [A, B], [aNon Na])),
IK := insert (Crypt (priK B) ⦃Nonce Nb, Nonce Na, Agent A⦄) (IK s)
⦈
}"
definition
m3_step3 :: "[rid_t, agent, agent, nonce, nonce] ⇒ (m3_state × m3_state) set"
where
"m3_step3 Ra A B Na Nb ≡ {(s, s1).
runs s Ra = Some (Init, [A, B], []) ∧
Na = Ra$0 ∧
Crypt (priK B) ⦃Nonce Nb, Nonce Na, Agent A⦄ ∈ IK s ∧
s1 = s⦇
runs := (runs s)(Ra ↦ (Init, [A, B], [aNon Nb]))
⦈
}"
text ‹The intruder messages are now generated by a full-fledged Dolev-Yao
intruder.›
definition
m3_DY_fake :: "(m3_state × m3_state) set"
where
"m3_DY_fake ≡ {(s, s1).
s1 = s⦇
IK := synth (analz (IK s))
⦈
}"
text ‹Transition system.›
definition
m3_init :: "m3_state set"
where
"m3_init ≡ { ⦇
runs = Map.empty,
IK = (Key`priK`bad) ∪ (Key`range pubK) ∪ (Key`shrK`bad)
⦈ }"
definition
m3_trans :: "(m3_state × m3_state) set" where
"m3_trans ≡ (⋃ A B Ra Rb Na Nb.
m3_step1 Ra A B Na ∪
m3_step2 Rb A B Na Nb ∪
m3_step3 Ra A B Na Nb ∪
m3_DY_fake ∪
Id
)"
definition
m3 :: "(m3_state, m3_obs) spec" where
"m3 ≡ ⦇
init = m3_init,
trans = m3_trans,
obs = m3_obs
⦈"
lemmas m3_defs =
m3_def m3_init_def m3_trans_def m3_obs_def
m3_step1_def m3_step2_def m3_step3_def
m3_DY_fake_def
subsection ‹Invariants›
text ‹Specialize injectiveness of parts to enable aggressive application.›
lemmas parts_Inj_IK = parts.Inj [where H="IK s" for s]
lemmas analz_Inj_IK = analz.Inj [where H="IK s" for s]
text ‹The following invariants do not depend on the protocol messages.
We want to keep this compilation refinement from channel protocols to
full-fledged Dolev-Yao protocols as generic as possible.›
subsubsection ‹inv1: Long-term key secrecy›
text ‹Private signing keys are secret, that is, the intruder only knows
private keys of corrupted agents.
The invariant uses the weaker @{term parts} operator instead of the perhaps
more intuitive @{term analz} in its premise. This strengthens the invariant
and potentially simplifies its proof.
›
definition
m3_inv1_lkeysec :: "m3_state set" where
"m3_inv1_lkeysec ≡ {s. ∀ A.
Key (priK A) ∈ analz (IK s) ⟶ A ∈ bad
}"
lemmas m3_inv1_lkeysecI =
m3_inv1_lkeysec_def [THEN setc_def_to_intro, rule_format]
lemmas m3_inv1_lkeysecE [elim] =
m3_inv1_lkeysec_def [THEN setc_def_to_elim, rule_format]
lemmas m3_inv1_lkeysecD =
m3_inv1_lkeysec_def [THEN setc_def_to_dest, rule_format, rotated 1]
lemma PO_m3_inv1_lkeysec_init [iff]:
"init m3 ⊆ m3_inv1_lkeysec"
by (auto simp add: PO_hoare_def m3_defs intro!: m3_inv1_lkeysecI)
lemma PO_m3_inv1_lkeysec_trans [iff]:
"{m3_inv1_lkeysec} trans m3 {> m3_inv1_lkeysec}"
by (auto simp add: PO_hoare_def m3_defs intro!: m3_inv1_lkeysecI)
lemma PO_m3_inv1_lkeysec [iff]: "reach m3 ⊆ m3_inv1_lkeysec"
by (rule inv_rule_basic) (auto)
subsubsection ‹inv2: Intruder knows long-term keys of bad guys›
definition
m3_inv2_badkeys :: "m3_state set"
where
"m3_inv2_badkeys ≡ {s. ∀C.
C ∈ bad ⟶ Key (priK C) ∈ analz (IK s)
}"
lemmas m3_inv2_badkeysI =
m3_inv2_badkeys_def [THEN setc_def_to_intro, rule_format]
lemmas m3_inv2_badkeysE [elim] =
m3_inv2_badkeys_def [THEN setc_def_to_elim, rule_format]
lemmas m3_inv2_badkeysD [dest] =
m3_inv2_badkeys_def [THEN setc_def_to_dest, rule_format, rotated 1]
text ‹Invariance proof.›
lemma PO_m3_inv2_badkeys_init [iff]:
"init m3 ⊆ m3_inv2_badkeys"
by (auto simp add: m3_defs m3_inv2_badkeys_def)
lemma PO_m3_inv2_badkeys_trans [iff]:
"{m3_inv2_badkeys} trans m3 {> m3_inv2_badkeys}"
by (auto simp add: PO_hoare_defs m3_defs intro!: m3_inv2_badkeysI)
lemma PO_m3_inv2_badkeys [iff]: "reach m3 ⊆ m3_inv2_badkeys"
by (rule inv_rule_basic) (auto)
subsubsection ‹inv3: Intruder knows all public keys (NOT USED)›
text ‹This invariant is only needed with equality in ‹R23_msgs›.›
definition
m3_inv3_pubkeys :: "m3_state set"
where
"m3_inv3_pubkeys ≡ {s. ∀C.
Key (pubK C) ∈ analz (IK s)
}"
lemmas m3_inv3_pubkeysI =
m3_inv3_pubkeys_def [THEN setc_def_to_intro, rule_format]
lemmas m3_inv3_pubkeysE [elim] =
m3_inv3_pubkeys_def [THEN setc_def_to_elim, rule_format]
lemmas m3_inv3_pubkeysD [dest] =
m3_inv3_pubkeys_def [THEN setc_def_to_dest, rule_format, rotated 1]
text ‹Invariance proof.›
lemma PO_m3_inv3_pubkeys_init [iff]:
"init m3 ⊆ m3_inv3_pubkeys"
by (auto simp add: m3_defs m3_inv3_pubkeys_def)
lemma PO_m3_inv3_pubkeys_trans [iff]:
"{m3_inv3_pubkeys} trans m3 {> m3_inv3_pubkeys}"
by (auto simp add: PO_hoare_defs m3_defs intro!: m3_inv3_pubkeysI)
lemma PO_m3_inv3_pubkeys [iff]: "reach m3 ⊆ m3_inv3_pubkeys"
by (rule inv_rule_basic) (auto)
subsection ‹Refinement›
text ‹Automatic tool tuning. Tame too-agressive pair decomposition, which is
declared as a safe elim rule ([elim!]).›
lemmas MPair_parts [rule del, elim]
lemmas MPair_analz [rule del, elim]
subsubsection ‹Simulation relation›
abbreviation
nonces :: "msg set ⇒ nonce set"
where
"nonces H ≡ {N. Nonce N ∈ analz H}"
abbreviation
ink :: "chmsg set ⇒ nonce set"
where
"ink H ≡ {N. aNon N ∈ extr ik0 H}"
text ‹Abstraction function on sets of messages.›
inductive_set
abs_msg :: "msg set ⇒ chmsg set"
for H :: "msg set"
where
am_M1:
"⦃Agent A, Agent B, Nonce Na⦄ ∈ H
⟹ Insec A B (Msg [aNon Na]) ∈ abs_msg H"
| am_M2:
"Crypt (priK B) ⦃Nonce Nb, Nonce Na, Agent A⦄ ∈ H
⟹ Auth B A (Msg [aNon Nb, aNon Na]) ∈ abs_msg H"
text ‹The simulation relation is canonical. It states that the protocol
messages in the intruder knowledge refine the abstract messages appearing in
the channels @{term Insec} and @{term Auth}.›
definition
R23_msgs :: "(m2_state × m3_state) set" where
"R23_msgs ≡ {(s, t). abs_msg (parts (IK t)) ⊆ chan s}"
definition
R23_ink :: "(m2_state × m3_state) set" where
"R23_ink ≡ {(s, t). nonces (IK t) ⊆ ink (chan s)}"
definition
R23_preserved :: "(m2_state × m3_state) set" where
"R23_preserved ≡ {(s, t). runs s = runs t}"
definition
R23 :: "(m2_state × m3_state) set" where
"R23 ≡ R23_msgs ∩ R23_ink ∩ R23_preserved"
lemmas R23_defs = R23_def R23_msgs_def R23_ink_def R23_preserved_def
text ‹Mediator function: nothing new.›
definition
med32 :: "m3_obs ⇒ m2_obs" where
"med32 ≡ id"
lemmas R23_msgsI =
R23_msgs_def [THEN rel_def_to_intro, simplified, rule_format]
lemmas R23_msgsE [elim] =
R23_msgs_def [THEN rel_def_to_elim, simplified, rule_format]
lemmas R23_msgsE' [elim] =
R23_msgs_def [THEN rel_def_to_dest, simplified, rule_format, THEN subsetD]
lemmas R23_inkI =
R23_ink_def [THEN rel_def_to_intro, simplified, rule_format]
lemmas R23_inkE [elim] =
R23_ink_def [THEN rel_def_to_elim, simplified, rule_format]
lemmas R23_preservedI =
R23_preserved_def [THEN rel_def_to_intro, simplified, rule_format]
lemmas R23_preservedE [elim] =
R23_preserved_def [THEN rel_def_to_elim, simplified, rule_format]
lemmas R23_intros = R23_msgsI R23_inkI R23_preservedI
subsubsection ‹Facts about the abstraction function›
declare abs_msg.intros [intro!]
declare abs_msg.cases [elim!]
lemma abs_msg_empty: "abs_msg {} = {}"
by (auto)
lemma abs_msg_Un [simp]:
"abs_msg (G ∪ H) = abs_msg G ∪ abs_msg H"
by (auto)
lemma abs_msg_mono [elim]:
"⟦ m ∈ abs_msg G; G ⊆ H ⟧ ⟹ m ∈ abs_msg H"
by (auto)
lemma abs_msg_insert_mono [intro]:
"⟦ m ∈ abs_msg H ⟧ ⟹ m ∈ abs_msg (insert m' H)"
by (auto)
text ‹Abstraction of concretely fakeable message yields abstractly fakeable
messages. This is the key lemma for the refinement of the intruder.›
lemma abs_msg_DY_subset_fakeable:
"⟦ (s, t) ∈ R23_msgs; (s, t) ∈ R23_ink; t ∈ m3_inv1_lkeysec ⟧
⟹ abs_msg (synth (analz (IK t))) ⊆ fake ik0 (dom (runs s)) (chan s)"
apply (auto)
apply (rule fake_intros, auto)
apply (rule fake_Inj, auto)
apply (rule fake_intros, auto)
done
lemma absmsg_parts_subset_fakeable:
"⟦ (s, t) ∈ R23_msgs ⟧
⟹ abs_msg (parts (IK t)) ⊆ fake ik0 (-dom (runs s)) (chan s)"
by (rule_tac B="chan s" in subset_trans) (auto)
declare abs_msg_DY_subset_fakeable [simp, intro!]
declare absmsg_parts_subset_fakeable [simp, intro!]
subsubsection ‹Refinement proof›
lemma PO_m3_step1_refines_m2_step1:
"{R23}
(m2_step1 Ra A B Na), (m3_step1 Ra A B Na)
{> R23}"
by (auto simp add: PO_rhoare_defs R23_def m2_defs m3_defs intro!: R23_intros)
(auto)
lemma PO_m3_step2_refines_m2_step2:
"{R23 }
(m2_step2 Rb A B Na Nb), (m3_step2 Rb A B Na Nb)
{> R23}"
by (auto simp add: PO_rhoare_defs R23_def m2_defs m3_defs intro!: R23_intros)
(auto)
lemma PO_m3_step3_refines_m2_step3:
"{R23}
(m2_step3 Ra A B Na Nb), (m3_step3 Ra A B Na Nb)
{> R23}"
by (auto simp add: PO_rhoare_defs R23_def m2_defs m3_defs intro!: R23_intros)
(auto)
text ‹The Dolev-Yao fake event refines the abstract fake event.›
lemma PO_m3_DY_fake_refines_m2_fake:
"{R23 ∩ UNIV × (m3_inv1_lkeysec ∩ m3_inv2_badkeys)}
m2_fake, m3_DY_fake
{> R23}"
by (auto simp add: PO_rhoare_defs R23_def m2_defs m3_defs)
(rule R23_intros, auto)+
text ‹All together now...›
lemmas PO_m3_trans_refines_m2_trans =
PO_m3_step1_refines_m2_step1 PO_m3_step2_refines_m2_step2
PO_m3_step3_refines_m2_step3 PO_m3_DY_fake_refines_m2_fake
lemma PO_m3_refines_init_m2 [iff]:
"init m3 ⊆ R23``(init m2)"
by (auto simp add: R23_defs m2_defs m3_defs)
lemma PO_m3_refines_trans_m2 [iff]:
"{R23 ∩ UNIV × (m3_inv2_badkeys ∩ m3_inv1_lkeysec)}
(trans m2), (trans m3)
{> R23}"
apply (auto simp add: m3_def m3_trans_def m2_def m2_trans_def)
apply (blast intro!: PO_m3_trans_refines_m2_trans)+
done
lemma PO_obs_consistent [iff]:
"obs_consistent R23 med32 m2 m3"
by (auto simp add: obs_consistent_def R23_def med32_def m2_defs m3_defs)
lemma PO_m3_refines_m2:
"refines
(R23 ∩ UNIV × (m3_inv2_badkeys ∩ m3_inv1_lkeysec))
med32 m2 m3"
by (rule Refinement_using_invariants) (auto)
end