verification of security protocols secrecy and authentication in proverif april 23, 2012

35
Verification of Security Protocols Secrecy and Authentication in ProVerif April 23, 2012

Upload: cole-want

Post on 16-Dec-2015

226 views

Category:

Documents


3 download

TRANSCRIPT

Verification of Security Protocols

Secrecy and Authenticationin ProVerif

April 23, 2012

PAGE 2

Try yourself (1)

• A wants to send a secret message m to B •

A B: {|{|msg,m|}skA|}pkB

• B expects m to be secret. Is it true?

• Model in ProVerif:- A/B- Initializer- Compromised

• Find an attack and fix the protocol

PAGE 3

free net, msg, spy.private free initialInitiatorData, initialResponderData.(* The cryptographic constructors. *)fun pencrypt/2. (* public key encryption *)fun sign/2. (* digital signing *)fun enc/1. (* extracts encryption key from a key-pair *)fun dec/1. (* extracts decryption key from a key-pair *)private fun pubkeypair/1.private fun signkeypair/1.(* The cryptographic destructors. *)reduc pdecrypt(pencrypt(x,enc(y)),dec(y)) = x.reduc unsign(sign(x,enc(y)),dec(y)) = x.reduc pubkey(agent) = enc(pubkeypair(agent)).reduc unsignkey(agent) = dec(signkeypair(agent)).(* The queries. *)query attacker: flagA.query attacker: flagB.

Encoding (1)

A B: {|{|msg,m|}skA|}pkB

PAGE 4

(* Initiator process *)let initiator = in(initialInitiatorData,(a,sa)); (* initial data*) !in(net, b); (* get responder's name*) if a<>b then let pb = pubkey(b) in new m; (if b<>spy then new flagA; out(m,flagA)) | let signed = sign((msg,m),sa) in out(net, (a, b, pencrypt(signed,pb))).(* Responder process. *)let responder = in(initialResponderData, (b,db)); in(net, (a,=b,encrypted)); let va = unsignkey(a) in let signed = pdecrypt(encrypted,db) in let (=msg,m) = unsign(signed,va) in if a<>spy then new flagB; out(m,flagB).

Encoding (2)

A B: {|{|msg,m|}skA|}pkB

Notice again that we are sending flagA on the “secret channel” given by m. And that there is a “if b <> spy” conditional before. This is because we are checking for internal attacker (and since the spy is an internal, she can always get hold of m).

PAGE 5

(* Initializer process – initial data are sent over a trusted channel *)let initializer = new agent in (* generate agent name *) let pkp = pubkeypair(agent) in (* compute public encryption keypair *) let skp = signkeypair(agent) in (* compute signing keypair *) out(initialInitiatorData, (agent,enc(skp))); (*launch initiator role*) out(initialResponderData, (agent,dec(pkp))); (*launch responder role*) out(net, (agent, enc(pkp), dec(skp))). (* publish the public data *)

(* The compromised agent. *)let compromised = let pkp = pubkeypair(spy) in (* compute public encryption keypair *) let skp = signkeypair(spy) in (* compute signing keypair *) out(net, (pkp,skp)). (* publish the keypairs to model compromise *)

(* The system. *)process !initiator | !responder | compromised | !initializer

Encoding (3)

A B: {|{|msg,m|}skA|}pkB

PAGE 6

• AttackA M: {|{|msg,m|}skA|}pkM

M(A) B: {|{|msg,m|}skA|}pkB

• The fixA B: {|{|pkB,msg,m|}skA|}pkB

Attack / Fix

PAGE 7

Try yourself (2)

• Consider the following protocol (pkB is the public key of B):A B: AB A: NA B: {s;N}pkB

• B expects that s is a secret that he shares with A• Model this protocol in ProVerif: express B's secrecy expectation as a

conditional secrecy assertion• Is the conditional secrecy of s guaranteed in the internal threat

model? If not, write down the attack trace and fix the protocol

PAGE 8

free net,spy.private free initialInitiatorData, initialResponderData.

(* The cryptographic constructors. *)fun pencrypt/2. (* public key encryption *)fun sign/2. (* digital signing *)fun enc/1. (* extracts encryption key from a key-pair *)fun dec/1. (* extracts decryption key from a key-pair *)

(* The cryptographic destructors. *)reduc pdecrypt(pencrypt(x,enc(y)),dec(y)) = x.reduc unsign(sign(x,enc(y)),dec(y)) = x.

(* A constructor that maps agents to their secret keypairs. *)private fun pubkeypair/1.private fun signkeypair/1.

Encoding (1)A B: AB A: NA B: {s;N}pkB

PAGE 9

reduc pubkey(agent) = enc(pubkeypair(agent)).(* unsignkey/1. *)reduc unsignkey(agent) = dec(signkeypair(agent)).

(* The queries. *)query attacker: s.query attacker: flagA.query attacker: flagB.

let initializer = new agent; let pkp = pubkeypair(agent) in let skp = signkeypair(agent) in out(initialInitiatorData, (agent,enc(skp))); out(initialResponderData, (agent,dec(pkp))); out(net, (agent, enc(pkp), dec(skp))).

Encoding (2)A B: AB A: NA B: {s;N}pkB

PAGE 10

let initiator = in(initialInitiatorData, (a,sa)); in(net, (b,encb,unsb)); if a<>b then if encb = pubkey(b) then new s; (if b <> spy then new flagA; out(s,flagA)) | out(net,a); in(net,n); out(net,(pencrypt(s,n),encb)).

let responder = in(initialResponderData, (b,db)); in(net,a); if a<>b then new n; out(net,n); in(net, (encrypted)); let (s,=n) = pdecrypt(encrypted,db) in if a <> spy then new flagB; out(s,flagB).

Encoding (3)A B: AB A: NA B: {s;N}pkB

This is put in parallel, but we could also put this in sequence with the rest (I think).

PAGE 11

let compromised = let pkp = pubkeypair(spy) in let skp = signkeypair(spy) in out(net, (pkp,skp)).

process !initiator | !responder | compromised | !initializer

Encoding (4)A B: AB A: NA B: {s;N}pkB

PAGE 12

• AttackM(A) B: AB M(A): NM(A) B: {|s;N|}pkB

• Secrecy s? NO! (spy)• Secrecy flagA? NO!• Secrecy flagB? NO!

• Solution A B: {|{|s;B;N|}skA|}pkB

Attack / Fix

A B: AB A: NA B: {|{|s;B;N|}skA|}pkB

A B: AB A: NA B: {s;N}pkB

There are other solutions, but we have to aim at the most simple solution possible (also in the exam, don’t start putting encryption everywhere).

PAGE 13

let initiator = [...] if a<>b then if encb = pubkey(b) then new s; (if b <> spy then new flagA; out(s,flagA)) | out(net,a); in(net,n); out(net,

(pencrypt(sign((s,b,N),sa),encb))).

let responder = [...] in(net, (signedencrypted)); let signed = pdecrypt(signedencrypted,db) in let (s,=b,=N) = unsign(signed, unsignkey(a)) in if a <> spy then new flagB; out(s,flagB).

Exercise 4: secrecy?

Secrecy s? NO! (spy!)Secrecy flagA? YES!Secrecy flagB? YES!

A B: AB A: NA B: {|{|s;B;N|}skA|}pkB

PAGE 14

Try yourself (3)

• Consider the following protocol, with kA a symmetric key shared by A and server S, and kB a symmetric key shared by B and S:

A B : (A;B;{Na;B}kA)

B S : (A;B;{Na;B}kA;{Nb;B}kB)

S B : ({Na;k}kA;{Nb;k}kB)

B A : ({Na;k}kA)

• Model this protocol in ProVerif• At the end of the protocol, A and B should be able to communicate

secretly by using the newly established key k: study the strong secrecy of k and fix the protocol if necessary

• Note that there are only 3 agents

PAGE 15

fun encrypt/2.reduc decrypt(encrypt(m,k),k) = m.fun host/1.private reduc getkey(host(x)) = x.

free c.private free secretA, secretB.private free k.noninterf k.

let processA = in(c, hostB0); new Na; out(c, (hostA, hostB0, encrypt((Na, hostB0), kA)));

in(c, (m2));let (=Na, k) = decrypt(m2, kA) in if hostB0 = hostB then

out(c, encrypt(secretA, k)).

Encoding (1)A B: (A;B;{Na;B}kA)B S: (A;B;{Na;B}kA;{Nb;B}kB)S B: ({Na;k}kA;{Nb;k}kB)B A: ({Na;k}kA)

PAGE 16

let processB = in(c, (hostA1, =hostB, m2));new Nb;out(c, (hostA1, hostB, m2, encrypt((Nb, hostB), kB)));in(c, (m3, m4));let (=Nb, k) = decrypt(m4, kB) in

out(c, (m3)); if hostA1 = hostA then out(c, encrypt(secretB, k)).

let processS = in(c, (hostA1, hostB1, m2, m3)); let (Na1, =hostB1) = decrypt(m2, getkey(hostA1)) in

let (Nb1, =hostB1) = decrypt(m3, getkey(hostB1)) in out(c, (encrypt((Na1, k), getkey(hostA1)), encrypt((Nb1, k), getkey(hostB1)))).

Encoding (2)A B: (A;B;{Na;B}kA)B S: (A;B;{Na;B}kA;{Nb;B}kB)S B: ({Na;k}kA;{Nb;k}kB)B A: ({Na;k}kA)

PAGE 17

process new kA; new kB; let hostA = host(kA) in let hostB = host(kB) in out(c, hostA); out(c, hostB); ((!processA) | (!processB) | (!processS))

Encoding (3)

Noninterf? NO! The attacker can impersonate A and get k

A B: (A;B;{Na;A;B}kA)B S: (A;B;{Na;A;B}kA;{Nb;B}kB)S B: ({Na;k}kA;{Nb;k}kB)B A: ({Na;k}kA)

A B: (A;B;{Na;B}kA)B S: (A;B;{Na;B}kA;{Nb;B}kB)S B: ({Na;k}kA;{Nb;k}kB)B A: ({Na;k}kA)

PAGE 18

Noninterf? YES!

noninterf secretA, secretB.

let processA = [...] out(c, (hostA, hostB0, encrypt((Na, hostA, hostB0), kA)));

[...]

let processB = [...]

out(c, (hostA1, hostB, m2, encrypt((Nb, hostA1, hostB), kB)));[...]

let processS = in(c, (hostA1, hostB1, m2, m3)); let (Na1, =hostA1, =hostB1) = decrypt(m2, getkey(hostA1)) in

let (Nb1, =hostA1, =hostB1) = decrypt(m3, getkey(hostB1)) in new k;

[...]

Encoding (4)

A B: (A;B;{Na;A;B}kA)B S: (A;B;{Na;A;B}kA;{Nb;B}kB)S B: ({Na;k}kA;{Nb;k}kB)B A: ({Na;k}kA)

PAGE 19

• Queries (properties you want to verify) must be declared in the declaration section

• Today we study:- Secrecy: queries if the attacker can obtain M

− query attacker : M- Many-one correspondence: queries if event M is always preceded by event N

− query ev: M ==> ev: N (∀ parameters)- One-one correspondence: queries if event M is always preceded by event N,

and every trace contains at least as many N-events as M-events− query evinj: M ==> evinj: N

Queries

PAGE 20

query ev: endSend(x,y,z) ==>ev: beginSend(x,y,z).

=

query (∀ x,y,z) (ev:endSend(x,y,z) ==>ev: beginSend(x,y,z)).

Authentication and correspondence properties

PAGE 21

B A: {|B;n;m1|}pkA

A B: {|B;n;m2|}skA

• Does A authenticates to B?=

• Goal: if one of the parties thinks that the exchange (A;B;m1;m2) happened, then this exchange should have indeed started sometime in the past

Example: a simple authentication protocol

PAGE 22

free c, A, B.private free skA, skB.fun pk/1.fun enc/2.fun sign/2.reduc dec(enc(x,pk(y)),y) = x.reduc check(sign(x,y),pk(y)) = x.

query ev:end(w,x,(y,z)) ==> ev:begin(w,x,(y,z)).

let initiatorB = new nB; new m1B; out(c,enc((B,nB,m1B),pk(skA))); in(c,x); let (=B,=nB,m2)=check(x,pk(skA)) in event end(A,B,(m1B,m2)).

Example: a simple authentication protocol

B A: {|B;n;m1|}pkA

A B: {|B;n;m2|}skA

PAGE 23

let responderA =in(c,x);let (=B,nonce,m1)=dec(x,skA) in

new m2A; event begin(A,B,(m1,m2A)); out(c,sign((B,nonce,m2A),skA)).

process out(c,pk(skA)); out(c,pk(skB)); (!responderA | !initiatorB)

Example: a simple authentication protocol

B A: {|B;n;m1|}pkA

A B: {|B;n;m2|}skA

Check this out. Having “=B” in the let means that A knows B;s name beforehand, which is in general an assumption we CANNOT make.

PAGE 24

• Answer: ev: end(w,x,(y,z)) ==>

ev: begin(w,x,(y,z)) is false.

• Attack:B A: {|B;n;m1|}pkA

A M: {|B;n;m2|}skA

M knows n (B, m2)

M A: {|B;n;mm|}pkA

A B: {|B;n;m2|}skA

Example: a simple authentication protocol

B A: {|B;n;m1|}pkA

A B: {|B;n;m2|}skA

PAGE 25

B A: {|B;n;m1|}pkA

A B: {|B;n;m1;m2|}skA

• Now the same attack is not possible:B A: {|B;n;m1|}pkA

A M: {|B;n;m1;m2|}skA

M knows n (B, m2)

M A: {|B;n;mm|}pkA

A B: {|B;n;mm;m2|}skA

Example: a simple authentication protocol - Fixed

PAGE 26

• We want to include a compromised agent called spy, publishing the spy’s secrets

• We need to use conditional end-events:

... (if a<>spy then event endSend(a,b,m)) | ...

instead of

... event endSend(a,b,m); ...

• Why? The latter is trivially violated for a=spy.

Modeling internal threats

PAGE 27

Other ProVerif features

• A public key certificate is a pair of an agent name A and her public key pA digitally signed by the key ca of a trusted certificate authority.

• In ProVerif: sign((A; pA); ca)

PAGE 28

• ProVerif allows to insert phase separators into processes:...; phase n; ...where n is a positive integer

• The phase separator indicates that the process now enters phase n

• When a process starts running, it is in phase 0

• When a process enters the next phase, all processes that have not yet reached the end of the previous phase are discarded

• In that sense, one can understand the phase separators as global synchronization commands

Other ProVerif features

PAGE 29

• You can query for standard secrecy up to the end of a certain phase:

query attacker: x phase n.

• This queries if x remains secret up to the end of phase n.• The query is violated if an attacker can get x before the process has

started executing phase n+1.

Other ProVerif features

PAGE 30

Other ProVerif features

• Non-interference allows us to reason about the secrecy of guessable messages that are meant to be kept secret.- Example: Electronic votes. These are easily guessable, because in a typical

election there is only a small number of candidates.• Standard secrecy is often appropriate for reasoning about messages

that are virtually impossible to guess.- Example: Cryptographic session keys.

• Somewhat in between are weak secrets. These are impossible to guess online, but offline attacks are possible.- Example: Passwords.- An offline attack works by first collecting some data online and then running a

computationally intensive analysis offline.- Example: Searching a dictionary for likely passwords.- Query in ProVerif: weaksecret w.

PAGE 31

Other ProVerif features

• ProVerif can soundly verify testing equivalence (observational equivalence).

• ProVerif verification of testing equivalence is incomplete.- This incompleteness does show in practice (much more often than the

incompleteness for standard secrecy and correspondence assertions).• To query for testing equivalence of two processes, you need to

express the two processes “as one”. ProVerif choice-construct tells ProVerif the spots where the two processes differ:

• M,N Msg ::= ... | choice[M,N] | ...∈- fst(P): process obtained from P by replacing every occurrence of choice[M,N] by

M- snd(P): process obtained from P by replacing every occurrence of choice[M,N]

by N- ProVerif tries to prove fst(P) snd(P).≃

PAGE 32

• In principle, you can query for observational equivalence of arbitrary processes P and Q using the choice construct:

R = if choice[m,n] = m then P else Q

Then fst(R)≃snd(R) iff P≃Q

• However, ProVerif is usually unable to verify fst(R)≃snd(R) due to its incompleteness

Other ProVerif features

PAGE 33

fun hash/1.free net.process new n; out(net, choice[n, hash(n)]).

• This asks ProVerif to prove:new n; out(net, n)≃new n; out(net, hash(n)).

• ProVerif succeeds on this.• Intuitively, this equivalence holds, because to an observer both n

and hash(n) look completely arbitrary.

Other ProVerif features

PAGE 34

free net,n,m.

process out(net, choice[n,m]); out(net, choice[m,n])

• This asks ProVerif to prove:out(net,n); out(net,m)≃out(net,m); out(net,n)

• These are not equivalent

Other ProVerif features

PAGE 35

Do it yourself

• Consider the following protocol:B A : nb;text1A: begin(A,B,nb)A B : pkA;A;{na;nb;text2}skA

B: end(A,B,nb)B: begin(B,A,na)B A : pkB;B;{na;text3}skB

A: end(B,A,na)- A public-key infrastructure is assumed: pkA, pkB are the public keys of A and B, respectively- skA, skB are the signing keys of A and B, respectively- text1,text2,text3 are publicly known messages

• Write a model of this protocol in ProVerif• Check whether the protocol correctly realizes mutual authentication between A

and B; fix it if needed