(**************************************************************
 *                                                            *
 * This file is modified from ProVerif 2.00.                  *
 *                                                            *
 * ProVerif 2.00 is by                                        *
 *  Bruno Blanchet, Vincent Cheval, and Marc Sylvestre        *
 *  Copyright (C) INRIA, CNRS 2000-2018                       *
 *                                                            *
 * The authors of the changes since ProVerif 2.00 are left    *
 * anonymous for submission to IEEE Security and Privacy 2021 *
 *                                                            *
 **************************************************************)

(*

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details (in file LICENSE).

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

*)
(* 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[])).
