(* Otway Rees protocol.
   Version of Otway Rees, Operating Systems Review Vol 21 no 1, p 8-10, 1987 

A -> B: (C, A, B, { Na, C, A, B }_kA)
B -> S: (C, A, B, { Na, C, A, B }_kA, { Nb, C, A, B }_kB)
S -> B: (C, { Na, k }_kA, { Nb, k }_kB)
B -> A: (C, { Na, k }_kA)

*)

free c: channel.

type key.
type host.
type nonce.

(* Probabilistic shared key encryption *)

type sseed.
fun internal_encrypt(bitstring,key,sseed): bitstring.
reduc forall x: bitstring, y: key, r: sseed; decrypt(internal_encrypt(x,y,r),y) = x.
letfun encrypt(x: bitstring, y: key) = new r: sseed; internal_encrypt(x,y,r).

(* Secrecy assumptions *)

not attacker(new Kas).
not attacker(new Kbs).

(* 2 honest host names A and B *)

free A, B: host.

(* the table host names/keys 
   The key table consists of pairs 
   (host, key shared between the host and the server) *)
table keys(host, key).

(* Queries *)

free secretA, secretB: bitstring [private].
noninterf secretA.
noninterf secretB.
noninterf secretA, secretB.

(* Role of the initiator with identity xA and key kA shared with S *)

let processInitiator =
        (* The attacker starts the initiator by choosing identity xA,
	   and its interlocutor xB0.
	   We check that xA is honest (i.e. is A or B)
	   and get its corresponding key.
	*)
        in(c, (xA: host, xB0: host));
	if xA = A || xA = B then
	get keys(=xA, kA) in
	(* Real start of the role *)
	new C: nonce; 
	new Na: nonce;
        out(c, (C, xA, xB0, encrypt((Na, C, xA, xB0), kA)));
	in(c, (=C, m2: bitstring));
	let (=Na, k: key) = decrypt(m2, kA) in
	(* OK *)
	if xB0 = A || xB0 = B then 
	out(c, encrypt(secretA, k)).

(* Role of the responder with identity xB and key kB shared with S *)

let processResponder =
        (* The attacker starts the responder by choosing identity xB.
	   We check that xB is honest (i.e. is A or B)
	   and get its corresponding key. *)
        in(c, xB: host);
	if xB = A || xB = B then
	get keys(=xB, kB) in
	(* Real start of the role *)
	in(c, (C1: nonce, xA1: host, =xB, m2: bitstring));
	new Nb: nonce;
	out(c, (C1, xA1, xB, m2, encrypt((Nb, C1, xA1, xB), kB)));
	in(c, (=C1, m3: bitstring, m4: bitstring));
	let (=Nb, k: key) = decrypt(m4, kB) in
	out(c, (C1, m3));
	(* OK *)
	if xA1 = A || xA1 = B then
	out(c, encrypt(secretB, k)).

(* Server *)

let processS = 
        in(c, (C1: nonce, xA1: host, xB1: host, m2: bitstring, m3: bitstring));
    	get keys(=xA1, kA1) in
	get keys(=xB1, kB1) in
	let (Na1: nonce, =C1, =xA1, =xB1) = decrypt(m2, kA1) in
	let (Nb1: nonce, =C1, =xA1, =xB1) = decrypt(m3, kB1) in
	new k: key;
        out(c, (C1, encrypt((Na1, k), kA1), 
                    encrypt((Nb1, k), kB1))).


(* Key registration *)

let processK =
        in(c, (h: host, k: key));
        if h <> A && h <> B then insert keys(h,k).

(* Start process *)

process
	new Kas: key; new Kbs: key;
	insert keys(A, Kas);
	insert keys(B, Kbs);
	(
          (* Launch an unbounded number of sessions of the initiator *)
          (!processInitiator) | 
          (* Launch an unbounded number of sessions of the responder *)
          (!processResponder) |
          (* Launch an unbounded number of sessions of the server *)
          (!processS) |
          (* Key registration process *)
	  (!processK)
        )


(* EXPECTPV
RESULT Non-interference secretA is true.
RESULT Non-interference secretB is true.
RESULT Non-interference secretA, secretB is true.
0.704s (user 0.628s + system 0.076s), max rss 13664K
END *)
