(* Needham Shroeder public key protocol.
   Original version, with a flaw discovered by Lowe *)

pred c(any_type) [decompData, elimVar].

type skey.
type pkey.
type host.
type key.
type nonce.

fun host(skey):host.
fun sign(bitstring,skey):bitstring.
fun pk(skey):pkey.
fun encrypt(bitstring,pkey):bitstring.

name secret:bitstring.
name sS:skey.
name sA:skey.
name sB:skey.
name k:skey.
name Na:nonce.
name Nb:nonce.

query c(secret[]).

not c(sS[]).
not c(sA[]).
not c(sB[]).
(* not c(Na[pk(sB[])]). *)

clauses

(* The attacker *)

forall x:bitstring, y:skey; c(x) & c(y) -> c(sign(x,y));
forall x:bitstring, y:skey; c(sign(x,y)) -> c(x);
forall x:skey, m:bitstring; c(x) & c(encrypt(m,pk(x))) -> c(m);
forall x:skey; c(x) -> c(pk(x));
forall x:bitstring, y:pkey; c(x) & c(y) -> c(encrypt(x,y));
forall x:skey; c(host(x));

(* The protocol *)
(* Initialisation *)

c(pk(sA[]));
c(pk(sB[]));
c(pk(sS[]));

(* A *)

forall x:host, pkx:pkey; c(sign((pkx, x), sS[])) -> c(encrypt((Na[pkx], host(sA[])), pkx));
forall x:host, y:nonce, pkx:pkey; c(sign((pkx, x), sS[])) & c(encrypt((Na[pkx], y), pk(sA[])))
   -> c(encrypt((y,k[x]), pkx));

(* B *)

forall x:nonce, a:host, pka:pkey; c(encrypt((x,a), pk(sB[]))) & c(sign((pka, a), sS[])) -> c(encrypt((x, Nb[x,a]), pka));
forall x:nonce, pka:pkey, z:skey; c(encrypt((x,host(sA[])), pk(sB[]))) & c(sign((pka, host(sA[])), sS[])) & c(encrypt((Nb[x, host(sA[])], z), pk(sB[])))
   -> c(encrypt(secret[], pk(z)));

(* server *)

forall s1:skey, s2:skey; c((host(s1),host(s2))) -> c(sign((pk(s2), host(s2)), sS[])).
