free c.
(* 

A -> B : A, N_A
B -> S : B, N_B, { A, N_A }_Kbs
S -> A : N_B, { B, K_ab, N_A }_Kas, { A, K_ab, N_B }_Kbs
A -> B : { A, K_ab, N_B }_Kbs, { N_B }_Kab

Full agreement is wrong (the adversary can arrange so that A does not see
{ A, K_ab, N_B }_Kbs).

No agreement on N_A, but agreement on N_B and on the session key K_ab.

Attack of Syverson for evinj:endAparam(x) ==> evinj:beginAparam(x).
*)

(* Table of host names/keys shared with the server 
   The constructor host maps keys to host names.
   The private destructor getkey maps host names to keys.

   The adversary can create any number of dishonest participants
   by generating a fresh key k and computing host(k) to get the 
   corresponding identity.
 *)

fun host/1.
private reduc getkey(host(x)) = x.

(* Shared key cryptography *)

fun encrypt/2.
reduc decrypt(encrypt(x,y),y) = x.

(* Secrecy assumptions *)

not kas.

(* honestParticipants is a private channel on which we send the name of
   the honest participants; we use this information to test whether
   a participant is honest *)
private free honestParticipants.

private free secretA, secretB.
query attacker:kab[a = host(kas); b = host(kas)].

(* Role of the initiator with identity A and key kas shared with S *)

let processInitiator =
	new Na; 
	out(c, (A, Na)); 
	in(c, (nb, m1, m2));
        let (b, kab, na2) = decrypt(m1, kas) in
	event beginBparam(b);
	event beginBkey(b, A, nb, kab);
        if na2 = Na then 
        out(c, (m2, encrypt(nb, kab)));
	(* OK protocol finished 
	   If the interlocutor is honest, execute the events endAparam
           and send a test message to check that the key kab is secret *)
	in(honestParticipants, =b);
	event endAparam(A);
	out(c, encrypt(secretA, kab)).

(* Role of the responder with identity A and key kas shared with S *)
                         
let processResponder =
	in(c, (a, na)); 
	event beginAparam(a);
        new Nb; 
	out(c, (A, Nb, encrypt((a, na), kas)));
	in(c, (m3, m4));
        let (=a, kab, =Nb) = decrypt(m3, kas) in
        if Nb = decrypt(m4, kab) then
	(* OK protocol finished 
           If the interlocutor is honest, execute the events endBparam
           and endBkey, and send a test message to check that the key kab 
	   is secret *)
	in(honestParticipants, =a);
	event endBparam(A);
	event endBkey(A, a, Nb, kab);
	out(c, encrypt(secretB, kab)). 

(* Server *)

let processS = 
	in(c, (b, nb, m5));
	let kbs2 = getkey(b) in
        let (a, na) = decrypt(m5,kbs2) in
        let kas2 = getkey(a) in
        new kab;
	out(c, (nb, encrypt((b, kab, na), kas2), encrypt((a, kab, nb), kbs2))).

(* Start process *)

process
(* First replication: create an unbounded number of honest principals *) 
( 
    !
    (* Create a principal of key kas shared with S and identity A *)
    new kas; let A = host(kas) in 
    (
       (* The attacker knows the host names (but not the secret keys) *)
       out(c, A) |
       (* This principal is honest: we send its name on channel
          "honestParticipants" to record that fact *)
       (!out(honestParticipants, A)) | 
       (* Launch an unbounded number of sessions of the initiator A *)
       (!processInitiator) | 
       (* Launch an unbounded number of sessions of the responder A *)
       (!processResponder)
    )
)
|
(* Launch an unbounded number of sessions of the server *)
(!processS)

(* EXPECTPV
RESULT not attacker:kab_2[a_1 = host(kas[!1 = v]),m5 = v_1,nb_1 = v_2,b_1 = host(kas[!1 = v_3]),!1 = v_4] is true.
0.020s (user 0.012s + system 0.008s), max rss 8848K
END *)
