src/HOL/Auth/OtwayRees_Bad.ML
author paulson
Tue Nov 11 11:16:18 1997 +0100 (1997-11-11)
changeset 4198 c63639beeff1
parent 4091 771b1f6422a8
child 4422 21238c9d363e
permissions -rw-r--r--
Fixed spelling error
     1 (*  Title:      HOL/Auth/OtwayRees_Bad
     2     ID:         $Id$
     3     Author:     Lawrence C Paulson, Cambridge University Computer Laboratory
     4     Copyright   1996  University of Cambridge
     5 
     6 Inductive relation "otway" for the Otway-Rees protocol.
     7 
     8 The FAULTY version omitting encryption of Nonce NB, as suggested on page 247 of
     9   Burrows, Abadi and Needham.  A Logic of Authentication.
    10   Proc. Royal Soc. 426 (1989)
    11 
    12 This file illustrates the consequences of such errors.  We can still prove
    13 impressive-looking properties such as Spy_not_see_encrypted_key, yet the
    14 protocol is open to a middleperson attack.  Attempting to prove some key lemmas
    15 indicates the possibility of this attack.
    16 *)
    17 
    18 open OtwayRees_Bad;
    19 
    20 proof_timing:=true;
    21 HOL_quantifiers := false;
    22 
    23 
    24 (*A "possibility property": there are traces that reach the end*)
    25 goal thy 
    26  "!!A B. [| A ~= B; A ~= Server; B ~= Server |]   \
    27 \        ==> EX K. EX NA. EX evs: otway.          \
    28 \               Says B A {|Nonce NA, Crypt (shrK A) {|Nonce NA, Key K|}|} \
    29 \                 : set evs";
    30 by (REPEAT (resolve_tac [exI,bexI] 1));
    31 by (rtac (otway.Nil RS otway.OR1 RS otway.OR2 RS otway.OR3 RS otway.OR4) 2);
    32 by possibility_tac;
    33 result();
    34 
    35 
    36 (**** Inductive proofs about otway ****)
    37 
    38 (*Nobody sends themselves messages*)
    39 goal thy "!!evs. evs : otway ==> ALL A X. Says A A X ~: set evs";
    40 by (etac otway.induct 1);
    41 by (Auto_tac());
    42 qed_spec_mp "not_Says_to_self";
    43 Addsimps [not_Says_to_self];
    44 AddSEs   [not_Says_to_self RSN (2, rev_notE)];
    45 
    46 
    47 (** For reasoning about the encrypted portion of messages **)
    48 
    49 goal thy "!!evs. Says A' B {|N, Agent A, Agent B, X|} : set evs ==> \
    50 \                X : analz (spies evs)";
    51 by (blast_tac (claset() addSDs [Says_imp_spies RS analz.Inj]) 1);
    52 qed "OR2_analz_spies";
    53 
    54 goal thy "!!evs. Says S' B {|N, X, Crypt (shrK B) X'|} : set evs ==> \
    55 \                X : analz (spies evs)";
    56 by (blast_tac (claset() addSDs [Says_imp_spies RS analz.Inj]) 1);
    57 qed "OR4_analz_spies";
    58 
    59 goal thy "!!evs. Says Server B {|NA, X, Crypt K' {|NB,K|}|} : set evs \
    60 \                 ==> K : parts (spies evs)";
    61 by (blast_tac (claset() addSEs spies_partsEs) 1);
    62 qed "Oops_parts_spies";
    63 
    64 (*OR2_analz... and OR4_analz... let us treat those cases using the same 
    65   argument as for the Fake case.  This is possible for most, but not all,
    66   proofs: Fake does not invent new nonces (as in OR2), and of course Fake
    67   messages originate from the Spy. *)
    68 
    69 bind_thm ("OR2_parts_spies",
    70           OR2_analz_spies RS (impOfSubs analz_subset_parts));
    71 bind_thm ("OR4_parts_spies",
    72           OR4_analz_spies RS (impOfSubs analz_subset_parts));
    73 
    74 (*For proving the easier theorems about X ~: parts (spies evs).*)
    75 fun parts_induct_tac i = 
    76     etac otway.induct i			THEN 
    77     forward_tac [Oops_parts_spies] (i+6) THEN
    78     forward_tac [OR4_parts_spies]  (i+5) THEN
    79     forward_tac [OR2_parts_spies]  (i+3) THEN 
    80     prove_simple_subgoals_tac  i;
    81 
    82 
    83 (** Theorems of the form X ~: parts (spies evs) imply that NOBODY
    84     sends messages containing X! **)
    85 
    86 (*Spy never sees another agent's shared key! (unless it's bad at start)*)
    87 goal thy 
    88  "!!evs. evs : otway ==> (Key (shrK A) : parts (spies evs)) = (A : bad)";
    89 by (parts_induct_tac 1);
    90 by (Fake_parts_insert_tac 1);
    91 by (ALLGOALS Blast_tac);
    92 qed "Spy_see_shrK";
    93 Addsimps [Spy_see_shrK];
    94 
    95 goal thy 
    96  "!!evs. evs : otway ==> (Key (shrK A) : analz (spies evs)) = (A : bad)";
    97 by (auto_tac(claset() addDs [impOfSubs analz_subset_parts], simpset()));
    98 qed "Spy_analz_shrK";
    99 Addsimps [Spy_analz_shrK];
   100 
   101 goal thy  "!!A. [| Key (shrK A) : parts (spies evs); evs : otway |] ==> A:bad";
   102 by (blast_tac (claset() addDs [Spy_see_shrK]) 1);
   103 qed "Spy_see_shrK_D";
   104 
   105 bind_thm ("Spy_analz_shrK_D", analz_subset_parts RS subsetD RS Spy_see_shrK_D);
   106 AddSDs [Spy_see_shrK_D, Spy_analz_shrK_D];
   107 
   108 
   109 (*Nobody can have used non-existent keys!*)
   110 goal thy "!!evs. evs : otway ==>          \
   111 \         Key K ~: used evs --> K ~: keysFor (parts (spies evs))";
   112 by (parts_induct_tac 1);
   113 (*Fake*)
   114 by (best_tac
   115       (claset() addSDs [impOfSubs (parts_insert_subset_Un RS keysFor_mono)]
   116                addIs  [impOfSubs analz_subset_parts]
   117                addDs  [impOfSubs (analz_subset_parts RS keysFor_mono)]
   118                addss  (simpset())) 1);
   119 (*OR1-3*)
   120 by (ALLGOALS Blast_tac);
   121 qed_spec_mp "new_keys_not_used";
   122 
   123 bind_thm ("new_keys_not_analzd",
   124           [analz_subset_parts RS keysFor_mono,
   125            new_keys_not_used] MRS contra_subsetD);
   126 
   127 Addsimps [new_keys_not_used, new_keys_not_analzd];
   128 
   129 
   130 
   131 (*** Proofs involving analz ***)
   132 
   133 (*Describes the form of K and NA when the Server sends this message.  Also
   134   for Oops case.*)
   135 goal thy 
   136  "!!evs. [| Says Server B                                                 \
   137 \            {|NA, X, Crypt (shrK B) {|NB, Key K|}|} : set evs;           \
   138 \           evs : otway |]                                                \
   139 \     ==> K ~: range shrK & (EX i. NA = Nonce i) & (EX j. NB = Nonce j)";
   140 by (etac rev_mp 1);
   141 by (etac otway.induct 1);
   142 by (prove_simple_subgoals_tac 1);
   143 by (Blast_tac 1); 
   144 qed "Says_Server_message_form";
   145 
   146 
   147 (*For proofs involving analz.*)
   148 val analz_spies_tac = 
   149     dtac OR2_analz_spies 4 THEN 
   150     dtac OR4_analz_spies 6 THEN
   151     forward_tac [Says_Server_message_form] 7 THEN assume_tac 7 THEN 
   152     REPEAT ((eresolve_tac [exE, conjE] ORELSE' hyp_subst_tac) 7);
   153 
   154 
   155 (****
   156  The following is to prove theorems of the form
   157 
   158   Key K : analz (insert (Key KAB) (spies evs)) ==>
   159   Key K : analz (spies evs)
   160 
   161  A more general formula must be proved inductively.
   162 ****)
   163 
   164 
   165 (** Session keys are not used to encrypt other session keys **)
   166 
   167 (*The equality makes the induction hypothesis easier to apply*)
   168 goal thy  
   169  "!!evs. evs : otway ==>                                    \
   170 \  ALL K KK. KK <= Compl (range shrK) -->                   \
   171 \            (Key K : analz (Key``KK Un (spies evs))) =  \
   172 \            (K : KK | Key K : analz (spies evs))";
   173 by (etac otway.induct 1);
   174 by analz_spies_tac;
   175 by (REPEAT_FIRST (resolve_tac [allI, impI]));
   176 by (REPEAT_FIRST (rtac analz_image_freshK_lemma ));
   177 by (ALLGOALS (asm_simp_tac analz_image_freshK_ss));
   178 (*Fake*) 
   179 by (spy_analz_tac 2);
   180 (*Base*)
   181 by (Blast_tac 1);
   182 qed_spec_mp "analz_image_freshK";
   183 
   184 
   185 goal thy
   186  "!!evs. [| evs : otway;  KAB ~: range shrK |] ==>          \
   187 \        Key K : analz (insert (Key KAB) (spies evs)) =  \
   188 \        (K = KAB | Key K : analz (spies evs))";
   189 by (asm_simp_tac (analz_image_freshK_ss addsimps [analz_image_freshK]) 1);
   190 qed "analz_insert_freshK";
   191 
   192 
   193 (*** The Key K uniquely identifies the Server's  message. **)
   194 
   195 goal thy 
   196  "!!evs. evs : otway ==>                                                  \
   197 \   EX B' NA' NB' X'. ALL B NA NB X.                                      \
   198 \     Says Server B {|NA, X, Crypt (shrK B) {|NB, K|}|} : set evs -->     \
   199 \     B=B' & NA=NA' & NB=NB' & X=X'";
   200 by (etac otway.induct 1);
   201 by (ALLGOALS (asm_simp_tac (simpset() addsimps [all_conj_distrib])));
   202 by (ALLGOALS Clarify_tac);
   203 (*Remaining cases: OR3 and OR4*)
   204 by (ex_strip_tac 2);
   205 by (Blast_tac 2);
   206 by (expand_case_tac "K = ?y" 1);
   207 by (REPEAT (ares_tac [refl,exI,impI,conjI] 2));
   208 (*...we assume X is a recent message, and handle this case by contradiction*)
   209 by (blast_tac (claset() addSEs spies_partsEs
   210                       delrules [conjI]    (*no split-up to 4 subgoals*)) 1);
   211 val lemma = result();
   212 
   213 goal thy 
   214  "!!evs. [| Says Server B {|NA, X, Crypt (shrK B) {|NB, K|}|}   : set evs; \ 
   215 \           Says Server B' {|NA',X',Crypt (shrK B') {|NB',K|}|} : set evs; \
   216 \           evs : otway |] ==> X=X' & B=B' & NA=NA' & NB=NB'";
   217 by (prove_unique_tac lemma 1);
   218 qed "unique_session_keys";
   219 
   220 
   221 (*Crucial security property, but not itself enough to guarantee correctness!*)
   222 goal thy 
   223  "!!evs. [| A ~: bad;  B ~: bad;  evs : otway |]                    \
   224 \        ==> Says Server B                                            \
   225 \              {|NA, Crypt (shrK A) {|NA, Key K|},                    \
   226 \                Crypt (shrK B) {|NB, Key K|}|} : set evs -->         \
   227 \            Says B Spy {|NA, NB, Key K|} ~: set evs -->              \
   228 \            Key K ~: analz (spies evs)";
   229 by (etac otway.induct 1);
   230 by analz_spies_tac;
   231 by (ALLGOALS
   232     (asm_simp_tac (simpset() addcongs [conj_cong] 
   233                             addsimps [analz_insert_eq, analz_insert_freshK]
   234                             addsimps (pushes@expand_ifs))));
   235 (*Oops*)
   236 by (blast_tac (claset() addSDs [unique_session_keys]) 4);
   237 (*OR4*) 
   238 by (Blast_tac 3);
   239 (*OR3*)
   240 by (blast_tac (claset() addSEs spies_partsEs
   241                        addIs [impOfSubs analz_subset_parts]) 2);
   242 (*Fake*) 
   243 by (spy_analz_tac 1);
   244 val lemma = result() RS mp RS mp RSN(2,rev_notE);
   245 
   246 goal thy 
   247  "!!evs. [| Says Server B                                         \
   248 \            {|NA, Crypt (shrK A) {|NA, Key K|},                  \
   249 \                  Crypt (shrK B) {|NB, Key K|}|} : set evs;      \
   250 \           Says B Spy {|NA, NB, Key K|} ~: set evs;              \
   251 \           A ~: bad;  B ~: bad;  evs : otway |]                \
   252 \        ==> Key K ~: analz (spies evs)";
   253 by (forward_tac [Says_Server_message_form] 1 THEN assume_tac 1);
   254 by (blast_tac (claset() addSEs [lemma]) 1);
   255 qed "Spy_not_see_encrypted_key";
   256 
   257 
   258 (*** Attempting to prove stronger properties ***)
   259 
   260 (*Only OR1 can have caused such a part of a message to appear.
   261   I'm not sure why A ~= B premise is needed: OtwayRees.ML doesn't need it.
   262   Perhaps it's because OR2 has two similar-looking encrypted messages in
   263         this version.*)
   264 goal thy 
   265  "!!evs. [| A ~: bad;  A ~= B;  evs : otway |]                \
   266 \        ==> Crypt (shrK A) {|NA, Agent A, Agent B|} : parts (spies evs) --> \
   267 \            Says A B {|NA, Agent A, Agent B,                  \
   268 \                       Crypt (shrK A) {|NA, Agent A, Agent B|}|}  : set evs";
   269 by (parts_induct_tac 1);
   270 by (Fake_parts_insert_tac 1);
   271 by (Blast_tac 1);
   272 qed_spec_mp "Crypt_imp_OR1";
   273 
   274 
   275 (*Crucial property: If the encrypted message appears, and A has used NA
   276   to start a run, then it originated with the Server!*)
   277 (*Only it is FALSE.  Somebody could make a fake message to Server
   278           substituting some other nonce NA' for NB.*)
   279 goal thy 
   280  "!!evs. [| A ~: bad;  A ~= Spy;  evs : otway |]                    \
   281 \        ==> Crypt (shrK A) {|NA, Key K|} : parts (spies evs) --> \
   282 \            Says A B {|NA, Agent A, Agent B,                        \
   283 \                       Crypt (shrK A) {|NA, Agent A, Agent B|}|}    \
   284 \             : set evs -->                                          \
   285 \            (EX B NB. Says Server B                                 \
   286 \                 {|NA,                                              \
   287 \                   Crypt (shrK A) {|NA, Key K|},                    \
   288 \                   Crypt (shrK B) {|NB, Key K|}|}  : set evs)";
   289 by (parts_induct_tac 1);
   290 by (Fake_parts_insert_tac 1);
   291 (*OR1: it cannot be a new Nonce, contradiction.*)
   292 by (blast_tac (claset() addSIs [parts_insertI]
   293                        addSEs spies_partsEs) 1);
   294 (*OR3 and OR4*)
   295 by (ALLGOALS (asm_simp_tac (simpset() addsimps [ex_disj_distrib])));
   296 by (ALLGOALS Clarify_tac);
   297 (*OR4*)
   298 by (blast_tac (claset() addSIs [Crypt_imp_OR1]
   299                        addEs  spies_partsEs) 2);
   300 (*OR3*)  (** LEVEL 5 **)
   301 (*The hypotheses at this point suggest an attack in which nonce NB is used
   302   in two different roles:
   303           Says B' Server
   304            {|Nonce NA, Agent Aa, Agent A,
   305              Crypt (shrK Aa) {|Nonce NA, Agent Aa, Agent A|}, Nonce NB,
   306              Crypt (shrK A) {|Nonce NA, Agent Aa, Agent A|}|}
   307           : set evs3;
   308           Says A B
   309            {|Nonce NB, Agent A, Agent B,
   310              Crypt (shrK A) {|Nonce NB, Agent A, Agent B|}|}
   311           : set evs3;
   312 *)
   313 writeln "GIVE UP! on NA_Crypt_imp_Server_msg";
   314 
   315 
   316 (*Thus the key property A_can_trust probably fails too.*)