410 likes | 535 Views
Constraint Logic Programming for Verifying Security Protocols. Sandro Etalle Ricardo Corin University of Twente. Outline. Day 1: Practice Using the tool we developed in Twente Day 2: Theory the constraint-solving algorithm. Schema of Day 1. How to specify a protocol
E N D
Constraint Logic Programming for Verifying Security Protocols Sandro Etalle Ricardo Corin University of Twente
Outline • Day 1: Practice • Using the tool we developed in Twente • Day 2: Theory • the constraint-solving algorithm
Schema of Day 1 • How to specify a protocol • How to specify a particular session • How to find security and authentication flaws • Interpreting the result of the tool
Part 1 How to specify a protocol
Preliminaries: Prolog’s notation • variables: begin with uppercase or with _ • Na,Nb,A,B, _a are variables • a,na,nb,b are non-variable terms • variable are terms • Complex terms can be built using predicate (function) symbols: • pk(b) is a non-variable term (pk is a function symbol) • pk(B) • Nb*pk(B) is the same as *(Nb,pk(B)): * is an infix-operator. • send(Nb*pk(B))
Learning by example: the Needham-Schroeder A->B : [A,Na]*pk(B) B->A : [Na,Nb]*pk(A) A->B : [Nb]*pk(B) • Notation • [t1,t2]: pairing (these are lists in PROLOG) • msg*k: asymmetric encryption • Conventions • Na, Nb: nonces • A, B: Agents (Alice and Bob) • pk(A): public key of A
Roles A->B : [A,Na]*pk(B) B->A : [Na,Nb]*pk(A) A->B : [Nb]*pk(B) • Here we have 2 ROLES • one INITIATOR (A) • one RESPONDER (B) • A role is specified as a sequence of EVENTS
Events • events are actions, two kind: • send(t) • recv(t) • t is a term (a message) • the crucial part of a role is a list of his actions: [recv([A,B]), send([A,Na]*pk(B)), recv([Na,Nb]*pk(A)), send(Nb*pk(B))] • [t1,…,tn]: is a list in Prolog
Specifying a Role • Fixed (abstract) notation: name(Variables) = [Actions]. • E.g. initiator(A,B,Na,Nb) = [ send([A,Na]*pk(B)), recv([Na,Nb]*pk(A)), send(Nb*pk(B))]. • The tool notation is different! • compiler notation vs abstract notation (this one)
The Responder • How does the responder look like? • Just exchange “send” and “recv” responder(A,B,Na,Nb) = [ recv([A,Na]*pk(B)), send([Na,Nb]*pk(A)), recv(Nb*pk(B))]). • Any name is good (not only “responder) • Notice ALL THESE VARIABLES! • names & nonces are not fixed • roles are parametric
Summarizing: • We specified the roles of NS: initiator(A,B,Na, Nb), responder(A,B,Na,Nb) • We still have to specify how our session looks like • how many initiators & how many responders • NB: a recent result by Comon-Lundh & Cortier states that 2 agents are sufficient (but give no limit on the number of sessions) • The names of the agents • are there agents playing both as initiator and responders? • We need to define a scenario
Part 2 How to specify a particular session
System Scenarios • Protocol roles provide ‘templates’ • Set up a finite scenario for verification • choose roles participating in the session • instantiate the variables of the roles • Instantiation: used for: • Say who is playing which role • Introduce fresh nonces
System Scenarios cont’d A->B : [A,Na]*pk(B) B->A : [Na,Nb]*pk(A) A->B : [Nb]*pk(B) • A possible scenario: • s1 = {initiator(a,B,na,Nb), responder(A,b,Na,nb)} • one INITIATOR A played by agent a • one RESPONDER B played by agent b
Variables & non-variables • Consider the scenario • {initiator(a,B,na,Nb), responder(A,b,Na,nb)} • Variables indicate parameters that may assume any value (their value is not known at the start). • For instance, the initiator here does not know in advance the name of the responder. • Fresh nonces = new terms (ground terms that don’t occur elsewhere ).
More System Scenarios for NS • {initiator(a,b,na,nb), responder(a,b,na,nb)} • the ‘honest’ scenario (but unrealistic) • {initiator(a,B,na,Nb), responder(A,b,Na,nb)} • may not communicate with each other • {initiator(a,b,na,nb), responder(A,B,Na,Nb)} • a may also play the responder role • {initiator(a,b,na,nb), responder(c,d,nc,nd)} • no communication!
The network model • Network - intruder: Dolev-Yao. Scenario Agent Role Role Role Role Role send(t) recv(t) Network/Intruder
Constraint Store • knowledge (K) • the intruder’s knowledge: the set of intercepted messages • constraint store: {msg_1:K_1, …, msg_n:K_n} • msg_1, … , msg_n: messages (terms) • K_1, …, K_n: knowledges (set of messages) • Is satisfiable: each msg_i is generable using K_i.
Overview of the Verification Algorithm • A step of the verification algorithm: • choose an event e from a role of S • Two cases: • e = send(t) • t is added to the intruder’s knowledge • e = recv(t) • add constraint t:K to the constraint store • if constraint store is solvable, proceed • otherwise, stop
Part 3 Using the tool in practice How to find security and authentication flaws
Finding Secrecy flaws • What is a secrecy flaw? • To check if na remains secret, one just has to add to the scenario the singleton role [recv(na)] • na remains secret <=> the intruder cannot output it! • in practice we define a special role • secrecy(X) = [recv(X)].
Finding Authentication Flaws • More complex than checking secrecy. • What is an authentication flaw? • Various definitions. • Basically: an input event recv(t) without corresponding preceding output event send(t). • Can be checked by e.g., running the responder strand without an initiator role. • We are working on it.
From abstract notation to implementation notation • Abstract notation role_name(Var1,…,VarN) = [Events]. • Concrete notation role_name(Var1,...,VarN,[Events]). Abstract Notation initiator(A,B,Na,Nb) = [ send([A,Na]*pk(B)), recv([Na,Nb]*pk(A)), send(Nb*pk(B)) ]). % Implementation Notation initiator(A,B,Na,Nb,[ send([A,Na]*pk(B)), recv([Na,Nb]*pk(A)), send(Nb*pk(B)) ]).
Specification of NS % Initiator role initiator(A,B,Na,Nb,[ send([A,Na]*pk(B)), recv([Na,Nb]*pk(A)), send(Nb*pk(B)) ]). % Responder role responder(A,B,Na,Nb,[ recv([A,Na]*pk(B)), send([Na,Nb]*pk(A)), recv(Nb*pk(B)) ]). % Standard secrecy-checking role secrecy(X,[recv(X)]).
Scenarios in Practice scenario([ [name_1,Var_1], ..., [name_n,Var_n] ] ) :- role_1(...,Var_1), ... role_n(...,Var_n).
What do we achieve with this scenario? For Instance scenario([ [alice,Init1], [bob,Resp1], [sec,Secr1] ] ) :- initiator(a,B,na,Nb,Init1), responder(a,b,Na,nb,Resp1), secrecy(nb, Secr1).
Last Details (1):Initial intruder knowledge & has_to_finish % Set up the initial intruder knowledge initial_intruder_knowledge([a,b,e]). % specify which roles we want to force to % finish (only sec in this example) has_to_finish([sec]).
The Origination assumption • Roles are ‘parametric’, i.e. may contain variables • We have to avoid sending out uninstantiated variables (only the intruder may do so). • We must satisfy the origination assumption: • Any variable should appear for the first time in a recv event • So, we add events of the form recv(X), where appropriate
Specification of NS with O.A. scenario([[alice,Init1], [bob,Resp1], [sec,Secr1]]) :- initiator(a,B,na,Nb,Init1), responder(a,b,Na,nb,Resp1), secrecy(nb, Secr1). % Initiator role initiator(A,B,Na,Nb,[ recv(B), send([A,Na]*pk(B)), recv([Na,Nb]*pk(A)), send(Nb*pk(B)) ]). % Responder role responder(A,B,Na,Nb,[ recv([A,Na]*pk(B)), send([Na,Nb]*pk(A)), recv(Nb*pk(B)) ]).
Last steps before execution… • Decide whether we want Prolog stop at first solution it finds, or iterate and show them all. • Click on Verify
The Results • For each run, the tool visualizes: • which events of a role could not be completed (nb: the tools tries to complete each role, but this is sometimes impossible) • the complete run.
Examples of Results (1) SOLUTION FOUND State: [[alice,[]],[bob,[recv(nb * pk(b))]],[sec,[]]] . . . alice finished sec finished! bob did not finish
Examples of Results (2) SOLUTION FOUND State: [[a,[]],[b,[recv(nb * pk(b))]],[sec,[]]] Trace: [a,send([a,na] * pk(e))] [b,recv([a,na] * pk(b))] [b,send([na,nb] * pk(a))] [a,recv([na,nb] * pk(a))] [a,send(nb * pk(e))] [sec,recv(nb)]
What if we try another scenario? • scenario([ • [alice1,Init1], • [alice2,Init2], • [bob,Resp1], • [sec,Secr1] • ] • ) :- • initiator(a,b,na,Nb,Init1), • initiator(b,A,na,Nb,Init1), • responder(a,b,Na,nb,Resp1), • secrecy(nb, Secr1). • TRY THIS!
Exercise 1: Modify NS as Lowe proposed A->B : [A,Na]*pk(B) B->A : [Na,Nb,B]*pk(A) A->B : [Nb]*pk(B) • To do • implement the roles • Try bigger scenarios, with at least two parallel sessions • Find Millen’s type flaw attack
Looking for authentication flaws in Needham-Schroeder • Consider (again) the scenario: • No secrecy check this time. • But, if B is notb, and the responder role finishes, we have an authentication attack! {initiator(a,B,na,Nb), responder(a,b,Na,nb)}
Looking for authentication flaws in Needham-Schroeder cont’d • We only have to specify has_to_finish to b: has_to_finish([b]). • And verify again…
Results: the first reported trace SOLUTION FOUND State: [[a,[]],[b,[]]] Trace: [a,send([a,na] * pk(b))] [b,recv([a,na] * pk(b))] [b,send([na,nb] * pk(a))] [a,recv([na,nb] * pk(a))] [a,send(nb * pk(b))] [b,recv(nb * pk(b))] • This is a normal run • This is a correct trace. To find a flaw we must look for B not instantiated to b!
Results: the right trace SOLUTION FOUND State: [[a,[]],[b,[]]] Trace: [a,send([a,na] * pk(e))] [b,recv([a,na] * pk(b))] [b,send([na,nb] * pk(a))] [a,recv([na,nb] * pk(a))] [a,send(nb * pk(e))] [b,recv(nb * pk(b))]
Another protocol: Yahalom A->B : A,Na B->S : [A, Na,Nb]+Kbs S->A : [B, Kab, Na, Nb]+Kas, [A,Kab]+Kbs A->B : [A, Kab]+Kbs, [Nb]+Kab • [t]+k: symmetric encryption • Kxs: shared key between x and s • Na, Nb: nonces • Goal: establish a secret session key Kab • Incorrect (see Clark and Jacob library)
Exercise for home • For the yahalom protocol: • Encode the protocol • Verify the protocol: try many scenarios • Could you find any flaw? • Model leakage of Nb (i.e., B sends Nb in plain at some point) • Verify again the protocol: could you find any flaw? • Compare this attack to the one described by Clark & Jacob • 2. Try the other protocols listed in the online tool. • http://130.89.144.15/cgi-bin/show.cgi • www.cs.utwente.nl/~etalle