src/HOL/Auth/OtwayRees_Bad.ML
author nipkow
Tue Apr 08 10:48:42 1997 +0200 (1997-04-08)
changeset 2919 953a47dc0519
parent 2837 dee1c7f1f576
child 3102 4d01cdc119d2
permissions -rw-r--r--
Dep. on Provers/nat_transitive
     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 (*Weak liveness: 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_of_list 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_of_list 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_of_list evs ==> \
    50 \                X : analz (sees lost Spy evs)";
    51 by (fast_tac (!claset addSDs [Says_imp_sees_Spy RS analz.Inj]) 1);
    52 qed "OR2_analz_sees_Spy";
    53 
    54 goal thy "!!evs. Says S' B {|N, X, Crypt (shrK B) X'|} : set_of_list evs ==> \
    55 \                X : analz (sees lost Spy evs)";
    56 by (fast_tac (!claset addSDs [Says_imp_sees_Spy RS analz.Inj]) 1);
    57 qed "OR4_analz_sees_Spy";
    58 
    59 goal thy "!!evs. Says Server B {|NA, X, Crypt K' {|NB,K|}|} : set_of_list evs \
    60 \                 ==> K : parts (sees lost Spy evs)";
    61 by (fast_tac (!claset addSEs sees_Spy_partsEs) 1);
    62 qed "Oops_parts_sees_Spy";
    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_sees_Spy",
    70           OR2_analz_sees_Spy RS (impOfSubs analz_subset_parts));
    71 bind_thm ("OR4_parts_sees_Spy",
    72           OR4_analz_sees_Spy RS (impOfSubs analz_subset_parts));
    73 
    74 val parts_Fake_tac = 
    75     forward_tac [OR2_parts_sees_Spy] 4 THEN 
    76     forward_tac [OR4_parts_sees_Spy] 6 THEN
    77     forward_tac [Oops_parts_sees_Spy] 7;
    78 
    79 (*For proving the easier theorems about X ~: parts (sees lost Spy evs) *)
    80 fun parts_induct_tac i = SELECT_GOAL
    81     (DETERM (etac otway.induct 1 THEN parts_Fake_tac THEN
    82              (*Fake message*)
    83              TRY (best_tac (!claset addDs [impOfSubs analz_subset_parts,
    84                                            impOfSubs Fake_parts_insert]
    85                                     addss (!simpset)) 2)) THEN
    86      (*Base case*)
    87      fast_tac (!claset addss (!simpset)) 1 THEN
    88      ALLGOALS Asm_simp_tac) i;
    89 
    90 
    91 (** Theorems of the form X ~: parts (sees lost Spy evs) imply that NOBODY
    92     sends messages containing X! **)
    93 
    94 (*Spy never sees another agent's shared key! (unless it's lost at start)*)
    95 goal thy 
    96  "!!evs. evs : otway \
    97 \        ==> (Key (shrK A) : parts (sees lost Spy evs)) = (A : lost)";
    98 by (parts_induct_tac 1);
    99 by (Auto_tac());
   100 qed "Spy_see_shrK";
   101 Addsimps [Spy_see_shrK];
   102 
   103 goal thy 
   104  "!!evs. evs : otway \
   105 \        ==> (Key (shrK A) : analz (sees lost Spy evs)) = (A : lost)";
   106 by (auto_tac(!claset addDs [impOfSubs analz_subset_parts], !simpset));
   107 qed "Spy_analz_shrK";
   108 Addsimps [Spy_analz_shrK];
   109 
   110 goal thy  "!!A. [| Key (shrK A) : parts (sees lost Spy evs);       \
   111 \                  evs : otway |] ==> A:lost";
   112 by (fast_tac (!claset addDs [Spy_see_shrK]) 1);
   113 qed "Spy_see_shrK_D";
   114 
   115 bind_thm ("Spy_analz_shrK_D", analz_subset_parts RS subsetD RS Spy_see_shrK_D);
   116 AddSDs [Spy_see_shrK_D, Spy_analz_shrK_D];
   117 
   118 
   119 (*Nobody can have used non-existent keys!*)
   120 goal thy "!!evs. evs : otway ==>          \
   121 \         Key K ~: used evs --> K ~: keysFor (parts (sees lost Spy evs))";
   122 by (parts_induct_tac 1);
   123 (*Fake*)
   124 by (best_tac
   125       (!claset addIs [impOfSubs analz_subset_parts]
   126                addDs [impOfSubs (analz_subset_parts RS keysFor_mono),
   127                       impOfSubs (parts_insert_subset_Un RS keysFor_mono)]
   128                unsafe_addss (!simpset)) 1);
   129 (*OR1-3*)
   130 by (REPEAT (fast_tac (!claset addss (!simpset)) 1));
   131 qed_spec_mp "new_keys_not_used";
   132 
   133 bind_thm ("new_keys_not_analzd",
   134           [analz_subset_parts RS keysFor_mono,
   135            new_keys_not_used] MRS contra_subsetD);
   136 
   137 Addsimps [new_keys_not_used, new_keys_not_analzd];
   138 
   139 
   140 
   141 (*** Proofs involving analz ***)
   142 
   143 (*Describes the form of K and NA when the Server sends this message.  Also
   144   for Oops case.*)
   145 goal thy 
   146  "!!evs. [| Says Server B                                                 \
   147 \            {|NA, X, Crypt (shrK B) {|NB, Key K|}|} : set_of_list evs;   \
   148 \           evs : otway |]                                                \
   149 \     ==> K ~: range shrK & (EX i. NA = Nonce i) & (EX j. NB = Nonce j)";
   150 by (etac rev_mp 1);
   151 by (etac otway.induct 1);
   152 by (ALLGOALS (fast_tac (!claset addss (!simpset))));
   153 qed "Says_Server_message_form";
   154 
   155 
   156 (*For proofs involving analz.*)
   157 val analz_Fake_tac = 
   158     dtac OR2_analz_sees_Spy 4 THEN 
   159     dtac OR4_analz_sees_Spy 6 THEN
   160     forward_tac [Says_Server_message_form] 7 THEN assume_tac 7 THEN 
   161     REPEAT ((eresolve_tac [exE, conjE] ORELSE' hyp_subst_tac) 7);
   162 
   163 
   164 (****
   165  The following is to prove theorems of the form
   166 
   167   Key K : analz (insert (Key KAB) (sees lost Spy evs)) ==>
   168   Key K : analz (sees lost Spy evs)
   169 
   170  A more general formula must be proved inductively.
   171 ****)
   172 
   173 
   174 (** Session keys are not used to encrypt other session keys **)
   175 
   176 (*The equality makes the induction hypothesis easier to apply*)
   177 goal thy  
   178  "!!evs. evs : otway ==> \
   179 \  ALL K KK. KK <= Compl (range shrK) -->                      \
   180 \            (Key K : analz (Key``KK Un (sees lost Spy evs))) = \
   181 \            (K : KK | Key K : analz (sees lost Spy evs))";
   182 by (etac otway.induct 1);
   183 by analz_Fake_tac;
   184 by (REPEAT_FIRST (resolve_tac [allI, impI]));
   185 by (REPEAT_FIRST (rtac analz_image_freshK_lemma ));
   186 by (ALLGOALS (asm_simp_tac analz_image_freshK_ss));
   187 (*Base*)
   188 by (fast_tac (!claset addIs [image_eqI] addss (!simpset)) 1);
   189 (*Fake, OR2, OR4*) 
   190 by (REPEAT (spy_analz_tac 1));
   191 qed_spec_mp "analz_image_freshK";
   192 
   193 
   194 goal thy
   195  "!!evs. [| evs : otway;  KAB ~: range shrK |] ==>              \
   196 \        Key K : analz (insert (Key KAB) (sees lost Spy evs)) = \
   197 \        (K = KAB | Key K : analz (sees lost Spy evs))";
   198 by (asm_simp_tac (analz_image_freshK_ss addsimps [analz_image_freshK]) 1);
   199 qed "analz_insert_freshK";
   200 
   201 
   202 (*** The Key K uniquely identifies the Server's  message. **)
   203 
   204 goal thy 
   205  "!!evs. evs : otway ==>                                                      \
   206 \   EX B' NA' NB' X'. ALL B NA NB X.                                          \
   207 \     Says Server B {|NA, X, Crypt (shrK B) {|NB, K|}|} : set_of_list evs --> \
   208 \     B=B' & NA=NA' & NB=NB' & X=X'";
   209 by (etac otway.induct 1);
   210 by (ALLGOALS (asm_simp_tac (!simpset addsimps [all_conj_distrib])));
   211 by (Step_tac 1);
   212 (*Remaining cases: OR3 and OR4*)
   213 by (ex_strip_tac 2);
   214 by (Fast_tac 2);
   215 by (expand_case_tac "K = ?y" 1);
   216 by (REPEAT (ares_tac [refl,exI,impI,conjI] 2));
   217 (*...we assume X is a recent message, and handle this case by contradiction*)
   218 by (fast_tac (!claset addSEs sees_Spy_partsEs
   219                       delrules [conjI]    (*prevent split-up into 4 subgoals*)
   220                       addss (!simpset addsimps [parts_insertI])) 1);
   221 val lemma = result();
   222 
   223 goal thy 
   224  "!!evs. [| Says Server B {|NA, X, Crypt (shrK B) {|NB, K|}|}      \
   225 \            : set_of_list evs;                                    \ 
   226 \           Says Server B' {|NA',X',Crypt (shrK B') {|NB',K|}|}    \
   227 \            : set_of_list evs;                                    \
   228 \           evs : otway |] ==> X=X' & B=B' & NA=NA' & NB=NB'";
   229 by (prove_unique_tac lemma 1);
   230 qed "unique_session_keys";
   231 
   232 
   233 (*Crucial security property, but not itself enough to guarantee correctness!*)
   234 goal thy 
   235  "!!evs. [| A ~: lost;  B ~: lost;  evs : otway |]                    \
   236 \        ==> Says Server B                                            \
   237 \              {|NA, Crypt (shrK A) {|NA, Key K|},                    \
   238 \                Crypt (shrK B) {|NB, Key K|}|} : set_of_list evs --> \
   239 \            Says B Spy {|NA, NB, Key K|} ~: set_of_list evs -->      \
   240 \            Key K ~: analz (sees lost Spy evs)";
   241 by (etac otway.induct 1);
   242 by analz_Fake_tac;
   243 by (ALLGOALS
   244     (asm_simp_tac (!simpset addcongs [conj_cong] 
   245                             addsimps [not_parts_not_analz, analz_insert_freshK]
   246                             setloop split_tac [expand_if])));
   247 (*OR3*)
   248 by (fast_tac (!claset delrules [impCE]
   249                       addSEs sees_Spy_partsEs
   250                       addIs [impOfSubs analz_subset_parts]
   251                       addss (!simpset addsimps [parts_insert2])) 3);
   252 (*OR4, OR2, Fake*) 
   253 by (REPEAT_FIRST spy_analz_tac);
   254 (*Oops*) (** LEVEL 5 **)
   255 by (fast_tac (!claset delrules [disjE]
   256                       addDs [unique_session_keys] addss (!simpset)) 1);
   257 val lemma = result() RS mp RS mp RSN(2,rev_notE);
   258 
   259 goal thy 
   260  "!!evs. [| Says Server B                                                \
   261 \            {|NA, Crypt (shrK A) {|NA, Key K|},                         \
   262 \                  Crypt (shrK B) {|NB, Key K|}|} : set_of_list evs;     \
   263 \           Says B Spy {|NA, NB, Key K|} ~: set_of_list evs;             \
   264 \           A ~: lost;  B ~: lost;  evs : otway |]                \
   265 \        ==> Key K ~: analz (sees lost Spy evs)";
   266 by (forward_tac [Says_Server_message_form] 1 THEN assume_tac 1);
   267 by (fast_tac (!claset addSEs [lemma]) 1);
   268 qed "Spy_not_see_encrypted_key";
   269 
   270 
   271 (*** Attempting to prove stronger properties ***)
   272 
   273 (*Only OR1 can have caused such a part of a message to appear.
   274   I'm not sure why A ~= B premise is needed: OtwayRees.ML doesn't need it.
   275   Perhaps it's because OR2 has two similar-looking encrypted messages in
   276         this version.*)
   277 goal thy 
   278  "!!evs. [| A ~: lost;  A ~= B;  evs : otway |]                \
   279 \        ==> Crypt (shrK A) {|NA, Agent A, Agent B|}           \
   280 \             : parts (sees lost Spy evs) -->                  \
   281 \            Says A B {|NA, Agent A, Agent B,                  \
   282 \                       Crypt (shrK A) {|NA, Agent A, Agent B|}|}  \
   283 \             : set_of_list evs";
   284 by (parts_induct_tac 1);
   285 by (Fast_tac 1);
   286 qed_spec_mp "Crypt_imp_OR1";
   287 
   288 
   289 (*Crucial property: If the encrypted message appears, and A has used NA
   290   to start a run, then it originated with the Server!*)
   291 (*Only it is FALSE.  Somebody could make a fake message to Server
   292           substituting some other nonce NA' for NB.*)
   293 goal thy 
   294  "!!evs. [| A ~: lost;  A ~= Spy;  evs : otway |]                        \
   295 \        ==> Crypt (shrK A) {|NA, Key K|} : parts (sees lost Spy evs) --> \
   296 \            Says A B {|NA, Agent A, Agent B,                  \
   297 \                       Crypt (shrK A) {|NA, Agent A, Agent B|}|}  \
   298 \             : set_of_list evs -->                            \
   299 \            (EX B NB. Says Server B                           \
   300 \                 {|NA,                                        \
   301 \                   Crypt (shrK A) {|NA, Key K|},              \
   302 \                   Crypt (shrK B) {|NB, Key K|}|}             \
   303 \                   : set_of_list evs)";
   304 by (parts_induct_tac 1);
   305 (*OR1: it cannot be a new Nonce, contradiction.*)
   306 by (fast_tac (!claset addSIs [parts_insertI]
   307                       addSEs sees_Spy_partsEs
   308                       addss (!simpset)) 1);
   309 (*OR4*)
   310 by (REPEAT (Safe_step_tac 2));
   311 by (REPEAT (best_tac (!claset addSDs [parts_cut]) 3));
   312 by (fast_tac (!claset addSIs [Crypt_imp_OR1]
   313                       addEs  sees_Spy_partsEs) 2);
   314 (*OR3*)  (** LEVEL 5 **)
   315 by (ALLGOALS (asm_simp_tac (!simpset addsimps [ex_disj_distrib])));
   316 by (step_tac (!claset delrules [disjCI, impCE]) 1);
   317 (*The hypotheses at this point suggest an attack in which nonce NA is used
   318   in two different roles:
   319           Says B' Server
   320            {|Nonce NAa, Agent Aa, Agent A,
   321              Crypt (shrK Aa) {|Nonce NAa, Agent Aa, Agent A|}, Nonce NA,
   322              Crypt (shrK A) {|Nonce NAa, Agent Aa, Agent A|}|}
   323           : set_of_list evsa;
   324           Says A B
   325            {|Nonce NA, Agent A, Agent B,
   326              Crypt (shrK A) {|Nonce NA, Agent A, Agent B|}|}
   327           : set_of_list evsa 
   328 *)
   329 writeln "GIVE UP! on NA_Crypt_imp_Server_msg";
   330 
   331 
   332 (*Thus the key property A_can_trust probably fails too.*)