Theory Public_SET

(*  Title:      HOL/SET_Protocol/Public_SET.thy
    Author:     Giampaolo Bella
    Author:     Fabio Massacci
    Author:     Lawrence C Paulson
*)

section‹The Public-Key Theory, Modified for SET›

theory Public_SET
imports Event_SET
begin

subsection‹Symmetric and Asymmetric Keys›

text‹definitions influenced by the wish to assign asymmetric keys 
  - since the beginning - only to RCA and CAs, namely we need a partial 
  function on type Agent›


text‹The SET specs mention two signature keys for CAs - we only have one›

consts
  publicKey :: "[bool, agent]  key"
    ― ‹the boolean is TRUE if a signing key›

abbreviation "pubEK == publicKey False"
abbreviation "pubSK == publicKey True"

(*BEWARE!! priEK, priSK DON'T WORK with inj, range, image, etc.*)
abbreviation "priEK A == invKey (pubEK A)"
abbreviation "priSK A == invKey (pubSK A)"

text‹By freeness of agents, no two agents have the same key. Since
 termTrueFalse, no agent has the same signing and encryption keys.›

specification (publicKey)
  injective_publicKey:
    "publicKey b A = publicKey c A'  b=c  A=A'"
(*<*)
   apply (rule exI [of _ "%b A. 2 * nat_of_agent A + (if b then 1 else 0)"]) 
   apply (auto simp add: inj_on_def inj_nat_of_agent [THEN inj_eq] split: agent.split) 
   apply (drule_tac f="%x. x mod 2" in arg_cong, simp add: mod_Suc)+
(*or this, but presburger won't abstract out the function applications
   apply presburger+
*)
   done                       
(*>*)

axiomatization where
  (*No private key equals any public key (essential to ensure that private
    keys are private!) *)
  privateKey_neq_publicKey [iff]:
      "invKey (publicKey b A)  publicKey b' A'"

declare privateKey_neq_publicKey [THEN not_sym, iff]

  
subsection‹Initial Knowledge›

text‹This information is not necessary.  Each protocol distributes any needed
certificates, and anyway our proofs require a formalization of the Spy's 
knowledge only.  However, the initial knowledge is as follows:
   All agents know RCA's public keys;
   RCA and CAs know their own respective keys;
   RCA (has already certified and therefore) knows all CAs public keys; 
   Spy knows all keys of all bad agents.›

overloading initState  "initState"
begin

primrec initState where
(*<*)
  initState_CA:
    "initState (CA i)  =
       (if i=0 then Key ` ({priEK RCA, priSK RCA} 
                            pubEK ` (range CA)  pubSK ` (range CA))
        else {Key (priEK (CA i)), Key (priSK (CA i)),
              Key (pubEK (CA i)), Key (pubSK (CA i)),
              Key (pubEK RCA), Key (pubSK RCA)})"

| initState_Cardholder:
    "initState (Cardholder i)  =    
       {Key (priEK (Cardholder i)), Key (priSK (Cardholder i)),
        Key (pubEK (Cardholder i)), Key (pubSK (Cardholder i)),
        Key (pubEK RCA), Key (pubSK RCA)}"

| initState_Merchant:
    "initState (Merchant i)  =    
       {Key (priEK (Merchant i)), Key (priSK (Merchant i)),
        Key (pubEK (Merchant i)), Key (pubSK (Merchant i)),
        Key (pubEK RCA), Key (pubSK RCA)}"

| initState_PG:
    "initState (PG i)  = 
       {Key (priEK (PG i)), Key (priSK (PG i)),
        Key (pubEK (PG i)), Key (pubSK (PG i)),
        Key (pubEK RCA), Key (pubSK RCA)}"
(*>*)
| initState_Spy:
    "initState Spy = Key ` (invKey ` pubEK ` bad 
                            invKey ` pubSK ` bad 
                            range pubEK  range pubSK)"

end


text‹Injective mapping from agents to PANs: an agent can have only one card›

consts  pan :: "agent  nat"

specification (pan)
  inj_pan: "inj pan"
  ― ‹No two agents have the same PAN›
(*<*)
   apply (rule exI [of _ "nat_of_agent"]) 
   apply (simp add: inj_on_def inj_nat_of_agent [THEN inj_eq]) 
   done
(*>*)

declare inj_pan [THEN inj_eq, iff]

consts
  XOR :: "nat*nat  nat"  ― ‹no properties are assumed of exclusive-or›


subsection‹Signature Primitives›

definition
 (* Signature = Message + signed Digest *)
  sign :: "[key, msg]msg"
  where "sign K X = X, Crypt K (Hash X) "

definition
 (* Signature Only = signed Digest Only *)
  signOnly :: "[key, msg]msg"
  where "signOnly K X = Crypt K (Hash X)"

definition
 (* Signature for Certificates = Message + signed Message *)
  signCert :: "[key, msg]msg"
  where "signCert K X = X, Crypt K X "

definition
 (* Certification Authority's Certificate.
    Contains agent name, a key, a number specifying the key's target use,
              a key to sign the entire certificate.

    Should prove if signK=priSK RCA and C=CA i,
                  then Ka=pubEK i or pubSK i depending on T  ??
 *)
  cert :: "[agent, key, msg, key]  msg"
  where "cert A Ka T signK = signCert signK Agent A, Key Ka, T"

definition
 (* Cardholder's Certificate.
    Contains a PAN, the certified key Ka, the PANSecret PS,
    a number specifying the target use for Ka, the signing key signK.
 *)
  certC :: "[nat, key, nat, msg, key]  msg"
  where "certC PAN Ka PS T signK =
    signCert signK Hash Nonce PS, Pan PAN, Key Ka, T"

(*cert and certA have no repeated elements, so they could be abbreviations,
  but that's tricky and makes proofs slower*)

abbreviation "onlyEnc == Number 0"
abbreviation "onlySig == Number (Suc 0)"
abbreviation "authCode == Number (Suc (Suc 0))"

subsection‹Encryption Primitives›

definition EXcrypt :: "[key,key,msg,msg]  msg" where
  ― ‹Extra Encryption›
    (*K: the symmetric key   EK: the public encryption key*)
    "EXcrypt K EK M m =
       Crypt K M, Hash m, Crypt EK Key K, m"

definition EXHcrypt :: "[key,key,msg,msg]  msg" where
  ― ‹Extra Encryption with Hashing›
    (*K: the symmetric key   EK: the public encryption key*)
    "EXHcrypt K EK M m =
       Crypt K M, Hash m, Crypt EK Key K, m, Hash M"

definition Enc :: "[key,key,key,msg]  msg" where
  ― ‹Simple Encapsulation with SIGNATURE›
    (*SK: the sender's signing key
      K: the symmetric key
      EK: the public encryption key*)
    "Enc SK K EK M =
       Crypt K (sign SK M), Crypt EK (Key K)"

definition EncB :: "[key,key,key,msg,msg]  msg" where
  ― ‹Encapsulation with Baggage.  Keys as above, and baggage b.›
    "EncB SK K EK M b =
       Enc SK K EK M, Hash b, b"


subsection‹Basic Properties of pubEK, pubSK, priEK and priSK›

lemma publicKey_eq_iff [iff]:
     "(publicKey b A = publicKey b' A') = (b=b'  A=A')"
by (blast dest: injective_publicKey)

lemma privateKey_eq_iff [iff]:
     "(invKey (publicKey b A) = invKey (publicKey b' A')) = (b=b'  A=A')"
by auto

lemma not_symKeys_publicKey [iff]: "publicKey b A  symKeys"
by (simp add: symKeys_def)

lemma not_symKeys_privateKey [iff]: "invKey (publicKey b A)  symKeys"
by (simp add: symKeys_def)

lemma symKeys_invKey_eq [simp]: "K  symKeys  invKey K = K"
by (simp add: symKeys_def)

lemma symKeys_invKey_iff [simp]: "(invKey K  symKeys) = (K  symKeys)"
by (unfold symKeys_def, auto)

text‹Can be slow (or even loop) as a simprule›
lemma symKeys_neq_imp_neq: "(K  symKeys)  (K'  symKeys)  K  K'"
by blast

text‹These alternatives to symKeys_neq_imp_neq› don't seem any better
in practice.›
lemma publicKey_neq_symKey: "K  symKeys  publicKey b A  K"
by blast

lemma symKey_neq_publicKey: "K  symKeys  K  publicKey b A"
by blast

lemma privateKey_neq_symKey: "K  symKeys  invKey (publicKey b A)  K"
by blast

lemma symKey_neq_privateKey: "K  symKeys  K  invKey (publicKey b A)"
by blast

lemma analz_symKeys_Decrypt:
     "[| Crypt K X  analz H;  K  symKeys;  Key K  analz H |]  
      ==> X  analz H"
by auto


subsection‹"Image" Equations That Hold for Injective Functions›

lemma invKey_image_eq [iff]: "(invKey x  invKey`A) = (xA)"
by auto

text‹holds because invKey is injective›
lemma publicKey_image_eq [iff]:
     "(publicKey b A  publicKey c ` AS) = (b=c  AAS)"
by auto

lemma privateKey_image_eq [iff]:
     "(invKey (publicKey b A)  invKey ` publicKey c ` AS) = (b=c  AAS)"
by auto

lemma privateKey_notin_image_publicKey [iff]:
     "invKey (publicKey b A)  publicKey c ` AS"
by auto

lemma publicKey_notin_image_privateKey [iff]:
     "publicKey b A  invKey ` publicKey c ` AS"
by auto

lemma keysFor_parts_initState [simp]: "keysFor (parts (initState C)) = {}"
apply (simp add: keysFor_def)
apply (induct_tac "C")
apply (auto intro: range_eqI)
done

text‹for proving new_keys_not_used›
lemma keysFor_parts_insert:
     "[| K  keysFor (parts (insert X H));  X  synth (analz H) |]  
      ==> K  keysFor (parts H) | Key (invKey K)  parts H"
by (force dest!: 
         parts_insert_subset_Un [THEN keysFor_mono, THEN [2] rev_subsetD]
         analz_subset_parts [THEN keysFor_mono, THEN [2] rev_subsetD] 
            intro: analz_into_parts)

lemma Crypt_imp_keysFor [intro]:
     "[|K  symKeys; Crypt K X  H|] ==> K  keysFor H"
by (drule Crypt_imp_invKey_keysFor, simp)

text‹Agents see their own private keys!›
lemma privateKey_in_initStateCA [iff]:
     "Key (invKey (publicKey b A))  initState A"
by (case_tac "A", auto)

text‹Agents see their own public keys!›
lemma publicKey_in_initStateCA [iff]: "Key (publicKey b A)  initState A"
by (case_tac "A", auto)

text‹RCA sees CAs' public keys!›
lemma pubK_CA_in_initState_RCA [iff]:
     "Key (publicKey b (CA i))  initState RCA"
by auto


text‹Spy knows all public keys›
lemma knows_Spy_pubEK_i [iff]: "Key (publicKey b A)  knows Spy evs"
apply (induct_tac "evs")
apply (simp_all add: imageI knows_Cons split: event.split)
done

declare knows_Spy_pubEK_i [THEN analz.Inj, iff]
                            (*needed????*)

text‹Spy sees private keys of bad agents! [and obviously public keys too]›
lemma knows_Spy_bad_privateKey [intro!]:
     "A  bad  Key (invKey (publicKey b A))  knows Spy evs"
by (rule initState_subset_knows [THEN subsetD], simp)


subsection‹Fresh Nonces for Possibility Theorems›

lemma Nonce_notin_initState [iff]: "Nonce N  parts (initState B)"
by (induct_tac "B", auto)

lemma Nonce_notin_used_empty [simp]: "Nonce N  used []"
by (simp add: used_Nil)

text‹In any trace, there is an upper bound N on the greatest nonce in use.›
lemma Nonce_supply_lemma: "N. n. Nn  Nonce n  used evs"
apply (induct_tac "evs")
apply (rule_tac x = 0 in exI)
apply (simp_all add: used_Cons split: event.split, safe)
apply (rule msg_Nonce_supply [THEN exE], blast elim!: add_leE)+
done

lemma Nonce_supply1: "N. Nonce N  used evs"
by (rule Nonce_supply_lemma [THEN exE], blast)

lemma Nonce_supply: "Nonce (SOME N. Nonce N  used evs)  used evs"
apply (rule Nonce_supply_lemma [THEN exE])
apply (rule someI, fast)
done


subsection‹Specialized Methods for Possibility Theorems›

ML
(*Tactic for possibility theorems*)
fun possibility_tac ctxt =
    REPEAT (*omit used_Says so that Nonces start from different traces!*)
    (ALLGOALS (simp_tac (ctxt delsimps [@{thm used_Says}, @{thm used_Notes}]))
     THEN
     REPEAT_FIRST (eq_assume_tac ORELSE' 
                   resolve_tac ctxt [refl, conjI, @{thm Nonce_supply}]))

(*For harder protocols (such as SET_CR!), where we have to set up some
  nonces and keys initially*)
fun basic_possibility_tac ctxt =
    REPEAT 
    (ALLGOALS (asm_simp_tac (ctxt setSolver safe_solver))
     THEN
     REPEAT_FIRST (resolve_tac ctxt [refl, conjI]))

method_setup possibility = Scan.succeed (SIMPLE_METHOD o possibility_tac)
    "for proving possibility theorems"

method_setup basic_possibility = Scan.succeed (SIMPLE_METHOD o basic_possibility_tac)
    "for proving possibility theorems"


subsection‹Specialized Rewriting for Theorems About termanalz and Image›

lemma insert_Key_singleton: "insert (Key K) H = Key ` {K}  H"
by blast

lemma insert_Key_image:
     "insert (Key K) (Key`KK  C) = Key ` (insert K KK)  C"
by blast

text‹Needed for DK_fresh_not_KeyCryptKey›
lemma publicKey_in_used [iff]: "Key (publicKey b A)  used evs"
by auto

lemma privateKey_in_used [iff]: "Key (invKey (publicKey b A))  used evs"
by (blast intro!: initState_into_used)

text‹Reverse the normal simplification of "image" to build up (not break down)
  the set of keys.  Based on analz_image_freshK_ss›, but simpler.›
lemmas analz_image_keys_simps =
       simp_thms mem_simps ― ‹these two allow its use with only:›
       image_insert [THEN sym] image_Un [THEN sym] 
       rangeI symKeys_neq_imp_neq
       insert_Key_singleton insert_Key_image Un_assoc [THEN sym]


(*General lemmas proved by Larry*)

subsection‹Controlled Unfolding of Abbreviations›

text‹A set is expanded only if a relation is applied to it›
lemma def_abbrev_simp_relation:
     "A = B  (A  X) = (B  X)   
                 (u = A) = (u = B)   
                 (A = u) = (B = u)"
by auto

text‹A set is expanded only if one of the given functions is applied to it›
lemma def_abbrev_simp_function:
     "A = B  
       parts (insert A X) = parts (insert B X)   
          analz (insert A X) = analz (insert B X)   
          keysFor (insert A X) = keysFor (insert B X)"
by auto

subsubsection‹Special Simplification Rules for termsignCert

text‹Avoids duplicating X and its components!›
lemma parts_insert_signCert:
     "parts (insert (signCert K X) H) =  
      insert X, Crypt K X (parts (insert (Crypt K X) H))"
by (simp add: signCert_def insert_commute [of X])

text‹Avoids a case split! [X is always available]›
lemma analz_insert_signCert:
     "analz (insert (signCert K X) H) =  
      insert X, Crypt K X (insert (Crypt K X) (analz (insert X H)))"
by (simp add: signCert_def insert_commute [of X])

lemma keysFor_insert_signCert: "keysFor (insert (signCert K X) H) = keysFor H"
by (simp add: signCert_def)

text‹Controlled rewrite rules for termsignCert, just the definitions
  of the others. Encryption primitives are just expanded, despite their huge
  redundancy!›
lemmas abbrev_simps [simp] =
    parts_insert_signCert analz_insert_signCert keysFor_insert_signCert
    sign_def     [THEN def_abbrev_simp_relation]
    sign_def     [THEN def_abbrev_simp_function]
    signCert_def [THEN def_abbrev_simp_relation]
    signCert_def [THEN def_abbrev_simp_function]
    certC_def    [THEN def_abbrev_simp_relation]
    certC_def    [THEN def_abbrev_simp_function]
    cert_def     [THEN def_abbrev_simp_relation]
    cert_def     [THEN def_abbrev_simp_function]
    EXcrypt_def  [THEN def_abbrev_simp_relation]
    EXcrypt_def  [THEN def_abbrev_simp_function]
    EXHcrypt_def [THEN def_abbrev_simp_relation]
    EXHcrypt_def [THEN def_abbrev_simp_function]
    Enc_def      [THEN def_abbrev_simp_relation]
    Enc_def      [THEN def_abbrev_simp_function]
    EncB_def     [THEN def_abbrev_simp_relation]
    EncB_def     [THEN def_abbrev_simp_function]


subsubsection‹Elimination Rules for Controlled Rewriting›

lemma Enc_partsE: 
     "!!R. [|Enc SK K EK M  parts H;  
             [|Crypt K (sign SK M)  parts H;  
               Crypt EK (Key K)  parts H|] ==> R|]  
           ==> R"

by (unfold Enc_def, blast)

lemma EncB_partsE: 
     "!!R. [|EncB SK K EK M b  parts H;  
             [|Crypt K (sign SK M, Hash b)  parts H;  
               Crypt EK (Key K)  parts H;  
               b  parts H|] ==> R|]  
           ==> R"
by (unfold EncB_def Enc_def, blast)

lemma EXcrypt_partsE: 
     "!!R. [|EXcrypt K EK M m  parts H;  
             [|Crypt K M, Hash m  parts H;  
               Crypt EK Key K, m  parts H|] ==> R|]  
           ==> R"
by (unfold EXcrypt_def, blast)


subsection‹Lemmas to Simplify Expressions Involving termanalz

lemma analz_knows_absorb:
     "Key K  analz (knows Spy evs)  
      ==> analz (Key ` (insert K H)  knows Spy evs) =  
          analz (Key ` H  knows Spy evs)"
by (simp add: analz_insert_eq Un_upper2 [THEN analz_mono, THEN subsetD])

lemma analz_knows_absorb2:
     "Key K  analz (knows Spy evs)  
      ==> analz (Key ` (insert X (insert K H))  knows Spy evs) =  
          analz (Key ` (insert X H)  knows Spy evs)"
apply (subst insert_commute)
apply (erule analz_knows_absorb)
done

lemma analz_insert_subset_eq:
     "[|X  analz (knows Spy evs);  knows Spy evs  H|]  
      ==> analz (insert X H) = analz H"
apply (rule analz_insert_eq)
apply (blast intro: analz_mono [THEN [2] rev_subsetD])
done

lemmas analz_insert_simps = 
         analz_insert_subset_eq Un_upper2
         subset_insertI [THEN [2] subset_trans] 


subsection‹Freshness Lemmas›

lemma in_parts_Says_imp_used:
     "[|Key K  parts {X}; Says A B X  set evs|] ==> Key K  used evs"
by (blast intro: parts_trans dest!: Says_imp_knows_Spy [THEN parts.Inj])

text‹A useful rewrite rule with termanalz_image_keys_simps
lemma Crypt_notin_image_Key: "Crypt K X  Key ` KK"
by auto

lemma fresh_notin_analz_knows_Spy:
     "Key K  used evs  Key K  analz (knows Spy evs)"
by (auto dest: analz_into_parts)

end