src/HOL/Auth/NS_Public.ML
author paulson
Thu Jan 08 18:10:34 1998 +0100 (1998-01-08)
changeset 4537 4e835bd9fada
parent 4477 b3e5857d8d99
child 4556 e7a4683c0026
permissions -rw-r--r--
Expressed most Oops rules using Notes instead of Says, and other tidying
     1 (*  Title:      HOL/Auth/NS_Public
     2     ID:         $Id$
     3     Author:     Lawrence C Paulson, Cambridge University Computer Laboratory
     4     Copyright   1996  University of Cambridge
     5 
     6 Inductive relation "ns_public" for the Needham-Schroeder Public-Key protocol.
     7 Version incorporating Lowe's fix (inclusion of B's identify in round 2).
     8 
     9 This version is experimental.  It adds many more rules to the claset and even
    10 replaces Fake_parts_insert_tac by Blast_tac.
    11 *)
    12 
    13 open NS_Public;
    14 
    15 set proof_timing;
    16 HOL_quantifiers := false;
    17 
    18 AddEs spies_partsEs;
    19 AddDs [impOfSubs analz_subset_parts];
    20 AddDs [impOfSubs Fake_parts_insert];
    21 
    22 AddIffs [Spy_in_bad];
    23 
    24 (*A "possibility property": there are traces that reach the end*)
    25 goal thy 
    26  "!!A B. A ~= B ==> EX NB. EX evs: ns_public.               \
    27 \                     Says A B (Crypt (pubK B) (Nonce NB)) : set evs";
    28 by (REPEAT (resolve_tac [exI,bexI] 1));
    29 by (rtac (ns_public.Nil RS ns_public.NS1 RS ns_public.NS2 RS ns_public.NS3) 2);
    30 by possibility_tac;
    31 result();
    32 
    33 
    34 (**** Inductive proofs about ns_public ****)
    35 
    36 (*Nobody sends themselves messages*)
    37 goal thy "!!evs. evs : ns_public ==> ALL A X. Says A A X ~: set evs";
    38 by (etac ns_public.induct 1);
    39 by Auto_tac;
    40 qed_spec_mp "not_Says_to_self";
    41 Addsimps [not_Says_to_self];
    42 AddSEs   [not_Says_to_self RSN (2, rev_notE)];
    43 
    44 
    45 (*Induction for regularity theorems.  If induction formula has the form
    46    X ~: analz (spies evs) --> ... then it shortens the proof by discarding
    47    needless information about analz (insert X (spies evs))  *)
    48 fun parts_induct_tac i = 
    49     etac ns_public.induct i
    50     THEN 
    51     REPEAT (FIRSTGOAL analz_mono_contra_tac)
    52     THEN 
    53     prove_simple_subgoals_tac i;
    54 
    55 
    56 (** Theorems of the form X ~: parts (spies evs) imply that NOBODY
    57     sends messages containing X! **)
    58 
    59 (*Spy never sees another agent's private key! (unless it's bad at start)*)
    60 goal thy 
    61  "!!A. evs: ns_public ==> (Key (priK A) : parts (spies evs)) = (A : bad)";
    62 by (parts_induct_tac 1);
    63 by (Blast_tac 1);
    64 qed "Spy_see_priK";
    65 Addsimps [Spy_see_priK];
    66 
    67 goal thy 
    68  "!!A. evs: ns_public ==> (Key (priK A) : analz (spies evs)) = (A : bad)";
    69 by Auto_tac;
    70 qed "Spy_analz_priK";
    71 Addsimps [Spy_analz_priK];
    72 
    73 AddSDs [Spy_see_priK RSN (2, rev_iffD1), 
    74 	Spy_analz_priK RSN (2, rev_iffD1)];
    75 
    76 
    77 (**** Authenticity properties obtained from NS2 ****)
    78 
    79 (*It is impossible to re-use a nonce in both NS1 and NS2, provided the nonce
    80   is secret.  (Honest users generate fresh nonces.)*)
    81 goal thy 
    82  "!!evs. [| Crypt (pubK B) {|Nonce NA, Agent A|} : parts (spies evs); \
    83 \           Nonce NA ~: analz (spies evs);       \
    84 \           evs : ns_public |]                      \
    85 \ ==> Crypt (pubK C) {|NA', Nonce NA, Agent D|} ~: parts (spies evs)";
    86 by (etac rev_mp 1);
    87 by (etac rev_mp 1);
    88 by (parts_induct_tac 1);
    89 by (ALLGOALS Blast_tac);
    90 qed "no_nonce_NS1_NS2";
    91 
    92 (*Adding it to the claset slows down proofs...*)
    93 val nonce_NS1_NS2_E = no_nonce_NS1_NS2 RSN (2, rev_notE);
    94 
    95 
    96 (*Unicity for NS1: nonce NA identifies agents A and B*)
    97 goal thy 
    98  "!!evs. [| Nonce NA ~: analz (spies evs);  evs : ns_public |]      \
    99 \ ==> EX A' B'. ALL A B.                                            \
   100 \      Crypt (pubK B) {|Nonce NA, Agent A|} : parts (spies evs) --> \
   101 \      A=A' & B=B'";
   102 by (etac rev_mp 1);
   103 by (parts_induct_tac 1);
   104 by (ALLGOALS
   105     (asm_simp_tac (simpset() addsimps [all_conj_distrib,
   106 				       parts_insert_spies])));
   107 (*NS1*)
   108 by (expand_case_tac "NA = ?y" 2 THEN Blast_tac 2);
   109 (*Fake*)
   110 by (Clarify_tac 1);
   111 by (ex_strip_tac 1);
   112 by (Blast_tac 1);
   113 val lemma = result();
   114 
   115 goal thy 
   116  "!!evs. [| Crypt(pubK B)  {|Nonce NA, Agent A|}  : parts(spies evs); \
   117 \           Crypt(pubK B') {|Nonce NA, Agent A'|} : parts(spies evs); \
   118 \           Nonce NA ~: analz (spies evs);                            \
   119 \           evs : ns_public |]                                        \
   120 \        ==> A=A' & B=B'";
   121 by (prove_unique_tac lemma 1);
   122 qed "unique_NA";
   123 
   124 
   125 (*Tactic for proving secrecy theorems*)
   126 fun analz_induct_tac i = 
   127     etac ns_public.induct i   THEN
   128     ALLGOALS (asm_simp_tac (simpset() addsplits [expand_if]));
   129 
   130 
   131 (*Secrecy: Spy does not see the nonce sent in msg NS1 if A and B are secure*)
   132 goal thy 
   133  "!!evs. [| Says A B (Crypt(pubK B) {|Nonce NA, Agent A|}) : set evs;         \
   134 \           A ~: bad;  B ~: bad;  evs : ns_public |]                        \
   135 \        ==>  Nonce NA ~: analz (spies evs)";
   136 by (etac rev_mp 1);
   137 by (analz_induct_tac 1);
   138 (*NS3*)
   139 by (blast_tac (claset() addEs [nonce_NS1_NS2_E]) 4);
   140 (*NS2*)
   141 by (blast_tac (claset() addDs [unique_NA]) 3);
   142 (*NS1*)
   143 by (Blast_tac 2);
   144 (*Fake*)
   145 by (spy_analz_tac 1);
   146 qed "Spy_not_see_NA";
   147 
   148 
   149 (*Authentication for A: if she receives message 2 and has used NA
   150   to start a run, then B has sent message 2.*)
   151 goal thy 
   152  "!!evs. [| Says A B (Crypt (pubK B) {|Nonce NA, Agent A|}) : set evs;  \
   153 \           Says B' A (Crypt(pubK A) {|Nonce NA, Nonce NB, Agent B|})   \
   154 \             : set evs;                                                \
   155 \           A ~: bad;  B ~: bad;  evs : ns_public |]                  \
   156 \        ==> Says B A (Crypt(pubK A) {|Nonce NA, Nonce NB, Agent B|})   \
   157 \              : set evs";
   158 by (etac rev_mp 1);
   159 (*prepare induction over Crypt (pubK A) {|NA,NB,B|} : parts H*)
   160 by (etac (Says_imp_spies RS parts.Inj RS rev_mp) 1);
   161 by (etac ns_public.induct 1);
   162 by (ALLGOALS Asm_simp_tac);
   163 (*NS1*)
   164 by (Blast_tac 2);
   165 (*Fake*)
   166 by (blast_tac (claset() addDs [Spy_not_see_NA]) 1);
   167 qed "A_trusts_NS2";
   168 
   169 (*If the encrypted message appears then it originated with Alice in NS1*)
   170 goal thy 
   171  "!!evs. [| Crypt (pubK B) {|Nonce NA, Agent A|} : parts (spies evs); \
   172 \           Nonce NA ~: analz (spies evs);                 \
   173 \           evs : ns_public |]                             \
   174 \   ==> Says A B (Crypt (pubK B) {|Nonce NA, Agent A|}) : set evs";
   175 by (etac rev_mp 1);
   176 by (etac rev_mp 1);
   177 by (parts_induct_tac 1);
   178 by (Blast_tac 1);
   179 qed "B_trusts_NS1";
   180 
   181 
   182 
   183 (**** Authenticity properties obtained from NS2 ****)
   184 
   185 (*Unicity for NS2: nonce NB identifies nonce NA and agents A, B 
   186   [unicity of B makes Lowe's fix work]
   187   [proof closely follows that for unique_NA] *)
   188 goal thy 
   189  "!!evs. [| Nonce NB ~: analz (spies evs);  evs : ns_public |]            \
   190 \ ==> EX A' NA' B'. ALL A NA B.                                           \
   191 \      Crypt (pubK A) {|Nonce NA, Nonce NB, Agent B|} : parts (spies evs) \
   192 \         -->  A=A' & NA=NA' & B=B'";
   193 by (etac rev_mp 1);
   194 by (parts_induct_tac 1);
   195 by (ALLGOALS
   196     (asm_simp_tac (simpset() addsimps [all_conj_distrib, 
   197 				       parts_insert_spies])));
   198 (*NS2*)
   199 by (expand_case_tac "NB = ?y" 2 THEN Blast_tac 2);
   200 (*Fake*)
   201 by (Clarify_tac 1);
   202 by (ex_strip_tac 1);
   203 by (Blast_tac 1);
   204 val lemma = result();
   205 
   206 goal thy 
   207  "!!evs. [| Crypt(pubK A)  {|Nonce NA, Nonce NB, Agent B|}   \
   208 \             : parts(spies evs);                            \
   209 \           Crypt(pubK A') {|Nonce NA', Nonce NB, Agent B'|} \
   210 \             : parts(spies evs);                            \
   211 \           Nonce NB ~: analz (spies evs);                   \
   212 \           evs : ns_public |]                               \
   213 \        ==> A=A' & NA=NA' & B=B'";
   214 by (prove_unique_tac lemma 1);
   215 qed "unique_NB";
   216 
   217 AddDs [unique_NB];
   218 
   219 
   220 (*Secrecy: Spy does not see the nonce sent in msg NS2 if A and B are secure*)
   221 goal thy 
   222  "!!evs. [| Says B A (Crypt (pubK A) {|Nonce NA, Nonce NB, Agent B|}) \
   223 \             : set evs;                                              \
   224 \           A ~: bad;  B ~: bad;  evs : ns_public |]                \
   225 \ ==> Nonce NB ~: analz (spies evs)";
   226 by (etac rev_mp 1);
   227 by (analz_induct_tac 1);
   228 (*NS3*)
   229 by (Blast_tac 4);
   230 (*NS2: by freshness and unicity of NB*)
   231 by (blast_tac (claset() addEs [nonce_NS1_NS2_E]) 3);
   232 (*NS1*)
   233 by (Blast_tac 2);
   234 (*Fake*)
   235 by (spy_analz_tac 1);
   236 qed "Spy_not_see_NB";
   237 
   238 AddDs [Spy_not_see_NB];
   239 
   240 
   241 (*Authentication for B: if he receives message 3 and has used NB
   242   in message 2, then A has sent message 3.*)
   243 goal thy 
   244  "!!evs. [| Says B A  (Crypt (pubK A) {|Nonce NA, Nonce NB, Agent B|}) \
   245 \             : set evs;                                               \
   246 \           Says A' B (Crypt (pubK B) (Nonce NB)): set evs;            \
   247 \           A ~: bad;  B ~: bad;  evs : ns_public |]                   \
   248 \        ==> Says A B (Crypt (pubK B) (Nonce NB)) : set evs";
   249 by (etac rev_mp 1);
   250 (*prepare induction over Crypt (pubK B) NB : parts H*)
   251 by (etac (Says_imp_spies RS parts.Inj RS rev_mp) 1);
   252 by (parts_induct_tac 1);
   253 by (ALLGOALS Clarify_tac);
   254 by (ALLGOALS Blast_tac);
   255 qed "B_trusts_NS3";
   256 
   257 
   258 (**** Overall guarantee for B*)
   259 
   260 (*Matches only NS2, not NS1 (or NS3)*)
   261 val Says_imp_spies' = 
   262     read_instantiate [("X","Crypt ?K {|?XX,?YY,?ZZ|}")] Says_imp_spies;
   263 
   264 
   265 (*If B receives NS3 and the nonce NB agrees with the nonce he joined with
   266   NA, then A initiated the run using NA.  SAME proof as B_trusts_NS3!*)
   267 goal thy 
   268  "!!evs. [| Says B A  (Crypt (pubK A) {|Nonce NA, Nonce NB, Agent B|}) \
   269 \             : set evs;                                               \
   270 \           Says A' B (Crypt (pubK B) (Nonce NB)): set evs;            \
   271 \           A ~: bad;  B ~: bad;  evs : ns_public |]                 \
   272 \    ==> Says A B (Crypt (pubK B) {|Nonce NA, Agent A|}) : set evs";
   273 by (etac rev_mp 1);
   274 (*prepare induction over Crypt (pubK B) {|NB|} : parts H*)
   275 by (etac (Says_imp_spies RS parts.Inj RS rev_mp) 1);
   276 by (etac ns_public.induct 1);
   277 by (ALLGOALS Asm_simp_tac);
   278 by (ALLGOALS Clarify_tac);
   279 (*NS3 holds because NB determines A and NA*)
   280 by (ALLGOALS Blast_tac);
   281 qed "B_trusts_protocol";
   282