520 likes | 672 Views
Verification of Security Protocols. Sandro Etalle etalle@cs.utwente.nl. Outline. Day 1: Practice Using the tool we developed in Twente Day 2: Theory the constraint-solving algorithm. Schema of Day 1. A couple of words on Security Protocols How to specify a protocol
E N D
Verification of Security Protocols Sandro Etalle etalle@cs.utwente.nl
Outline • Day 1: Practice • Using the tool we developed in Twente • Day 2: Theory • the constraint-solving algorithm
Schema of Day 1 • A couple of words on Security Protocols • 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 0 What are security protocols anyway?
Security Protocols • Use symmetric or public key cryptography. • May achieve • Confidentiality. • Authentication. • For assigning responsibility. • For giving credit. • Non-Repudiation. • …. • Difficult to do right!
The same, old example: Needham-Schroeder A->B : [A,Na]*pk(B) B->A : [Na,Nb]*pk(A) A->B : [Nb]*pk(B) • Notation • msg*k: asymmetric encryption • Na, Nb: nonces • A, B: Agents (Alice and Bob) • pk(A): public key of A
Goals of NS A->B : [A,Na]*pk(B) B->A : [Na,Nb]*pk(A) A->B : [Nb]*pk(B) • Exchange two secrets • can be used to form a key • Authentication
A->B : [A,Na]*pk(B) B->A : [Na,Nb]*pk(A) A->B : [Nb]*pk(B) A -> I: [A,Na]*pk(I) I(A) -> B:[A,Na]*pk(B) B-> A:[Na,Nb]*pk(A) A->I : [Nb]*pk(I) I(A)->B : [Nb]*pk(B) Secrecy (Na and Nb are disclosed) Authentication B “thinks” he is talking to A, while he is talking to I I is the intruder. What can go wrong
Finding Flaws is not Easy • Protocol dates: 1978. • Flaw found in 1995. • Difficult to do “by hand” • One can use • Belief logics (e.g. BAN logic). • Theorem Proving. • Model Checking and alike.
The Model Checking Approach • Basic idea: • Model the protocol (finite!). • Model the intruder (Dolev-Yao intruder). • Can intercept & learn messages. • Can forge new messages using his knowledge. • Problems (source of infiniteness) • Forging new messages (can be fixed). • Number of parallel sessions.
Two Aspects of Authentication • Authentication can be used: • To assign responsibility. • a message is supported by someone • To assign credit.
Example A -> B: [A,B,[K,A,B,T]*sk(A)] A -> B: [A,B,[M]*K-1] (2) T: timestamp K, K-1: asymmetric key pair • sk(A): secret key of A • When A sends (2) we can assume he takes responsibility for it • Should we give her credit as well?
Not suitable for giving Credit A -> C: [A,B,[K,A,B,T]*sk(A)] C -> B: [C,B,[K,C,B,T]*sk(C)] A -> C: [A,B,[M]*K-1] (2) C -> B: [C,B,[M]*K-1] (2) • C could fake himself in between. • and get the credit • It is a man-in-the-middle attack.
Another Example A -> B: [A,K]*pk(B) A -> B: [M1]*K (2) B -> A: [M2]*K (3) • Can we assign responsibility/credit to A for M1? • Can we assign responsibility/credit to B for M2?
Another Example A -> B: [A,K]*pk(B) A -> B: [M1]*K (2) B -> B: [M2]*K (3) • B can assign credit to A for M1. • because A included his name in (1). • No responsibility, though: anyone could have generated message 1. • A can hold B responsible for M2. • But A could have faked (3) so it would be difficult for A to prove that B “did it”. • Not really suitable for credit…
Part 1 Using CoProVe
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([B]), %forget about this one for a moment 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
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 Notationinitiator(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))]