FormalProof/proverif/RogueAS.pv

177 lines
5.0 KiB
Plaintext
Raw Normal View History

(*
* Formal definition to verify the Fenrir protocol.
* to be used with ProVerif
*
* Here we check the security of the connection between client
* and service in the case of a compromised authentication server
*)
(*
* ==============
* Type definition
* ==============
*)
type pubKey. (* public key for asymmetric key encryption *)
type privKey. (* private key for asymmetric key encryption *)
type sKey. (* symmetric key *)
type nonce. (* just a nonce *)
const cs: channel. (* simulates service-fenrir channel for authentication *)
(* various stuff that should remain private *)
const prS: privKey [private]. (* service private key *)
free csKey: sKey [private].
free shared: sKey [private].
(*
* ==============
* Function definition
* ==============
*)
(* key to bitstring conversion *)
fun fromKey(sKey) : bitstring.
reduc forall a : sKey; toKey(fromKey(a)) = a.
(* symmetric key encription *)
fun sEnc(bitstring, sKey): bitstring. (* encrypt with symmetric key *)
reduc forall c: bitstring, k: sKey; sDec(sEnc(c,k),k) = c. (* decrypt with symmetric key *)
(* public key definition *)
fun genPub(privKey): pubKey. (* public keys are generated from private ones *)
(* public key signing *)
fun sign(bitstring, privKey): bitstring.
reduc forall c: bitstring, k: privKey; ver(c, sign(c, k), genPub(k)) = true. (* verify signature *)
(* some key exchange based on public keys *)
fun exchange(privKey, pubKey) : sKey.
equation forall p1 : privKey, p2 : privKey; exchange(p1, genPub(p2)) = exchange(p2, genPub(p1)).
(* hash used by OTP, sKey based *)
fun hash(sKey) : sKey.
(* xor function *)
(* note: this xor function doe not handle associativity as proverif would loop,
* so we pay attention to use it in a way that does not require associativity
*)
fun xor(sKey, sKey) : sKey.
reduc forall a : sKey, b : sKey; unxor(xor(a, b), b) = a.
reduc forall a : sKey, b : sKey; unxor2(xor(a, b), a) = b. (* created for proverif, not used for simplicity *)
(*
* ==============
* Events -- used for correlation
* ==============
*)
event clientConnect(sKey).
event serviceConnect(sKey).
(* rekeying algorithm *)
let client_rekey (key: sKey, chan: channel, pb : pubKey) =
new rekey_p1: privKey;
new rekey_n1: nonce;
out (chan, sEnc((rekey_n1, genPub(rekey_p1)), key));
in (chan, enc: bitstring);
let (=rekey_n1, srv_eph : pubKey, signed : bitstring) = sDec(enc, key) in
if ver((rekey_n1, srv_eph), signed, pb) then
let (new_Key) = exchange(rekey_p1, srv_eph) in
out (chan, sEnc((shared, shared), new_Key)) (* test secrecy *)
.
let server_rekey (key: sKey, chan: channel, pr : privKey) =
new rekey_s_p: privKey;
in (chan, enc: bitstring);
let (client_n1: nonce, client_p: pubKey) = sDec (enc, key) in
out (chan, sEnc((client_n1, genPub(rekey_s_p), sign((client_n1, genPub(rekey_s_p)), pr)), key));
let (new_Key) = exchange(rekey_s_p, client_p) in
in (chan, enc2: bitstring);
let (=shared, =shared) = sDec(enc2, new_Key)
.
(* test the connection between the service and client. Assume that the authentication server
* has been compromised. *)
let service_shared() =
let xored = xor(csKey, shared) in
out (cs, xored);
in (cs, enc : bitstring);
let data = sDec(enc, csKey) in
if data = fromKey(shared) then
event clientConnect(csKey);
server_rekey(csKey, cs, prS).
let client_shared(pbS: pubKey) =
in (cs, xored : sKey);
let xorKey = unxor(xored, shared) in
event serviceConnect(xorKey);
out (cs, sEnc(fromKey(shared), xorKey)); (* test 'shared' secrecy *)
client_rekey(xorKey, cs, pbS).
(* assume that the client and service have not yet setup a shared secret *)
(* DATA is the secret data *)
let service_no_shared() =
in (cs, pbC : pubKey);
let shared2 = exchange(prS, pbC) in
let xored = xor(csKey, shared2) in
out (cs, xored);
in (cs, enc : bitstring);
let data = sDec(enc, csKey) in
if data = fromKey(shared) then
event clientConnect(csKey);
server_rekey(csKey, cs, prS).
let client_no_shared(pbS: pubKey) =
new prC : privKey;
out (cs, genPub(prC));
let shared2 = exchange(prC, pbS) in
in (cs, xored : sKey);
let xorKey = unxor(xored, shared2) in
event serviceConnect(xorKey);
out (cs, sEnc(fromKey(shared), xorKey)); (* test 'shared' secrecy *)
client_rekey(xorKey, cs, pbS).
(* assume that the client and service have not yet setup a shared secret *)
(* DATA is the secret data *)
(*
* Event correlation:
*)
query k : sKey; event(clientConnect(k)) ==> event(serviceConnect(k)).
(*
* ==============
* What should be secret?
* ==============
*)
query attacker(shared). (* client-service shared key. *)
query attacker(csKey). (* client-service key. *)
(*
* ==============
* Run the verification
* ==============
*)
(* make it easy to deactivate single parts, like the 2-RTT login, which has unproven events problems *)
process
(!service_no_shared()) | (!client_no_shared(genPub(prS)))
| phase 1; (!service_shared()) | (!client_shared(genPub(prS)))