650 likes | 805 Views
Design, Analysis and Verification of Security Protocols. Ricardo Corin corin@cs.utwente.nl. Slides by Sandro Etalle and Ricardo Corin. Day 2. Using CoProVe. Preliminaries: Prolog’s notation. variables : begin with uppercase or with _ Na,Nb,A,B, _a are variables
E N D
Design, Analysis and Verification of Security Protocols Ricardo Corin corin@cs.utwente.nl Slides by Sandro Etalle and Ricardo Corin
Day 2 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))
Protocol Verification Roadmap • Pick a protocol and identify different roles • Specify protocol roles’ templates • Prepare a session using 2 • Add a security check to the session • Verify it • If attack, (try to) patch the protocol and go back to 1 • If no attack, go back to 3
The whole process for 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
Step 1: identify 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
Step 2: 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
Protocol Verification Roadmap • Pick a protocol and identify different roles • Specify protocol roles’ templates • Prepare a session using 2 • Add a security check to the session • Verify it • If attack, (try to) patch the protocol and go back to 1 • If no attack, go back to 3
Step 3: System Scenarios • Protocol roles provide ‘templates’ • Set up a session=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 • Remember: Uppercase is Var, Lowercase is constant
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!
Protocol Verification Roadmap • Pick a protocol and identify different roles • Specify protocol roles’ templates • Prepare a session using 2 • Add a security check to the session • Verify it • If attack, patch the protocol and go to 1 • If no attack, go to 3 Before moving on, let’s see a bit of theory...
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
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
What’s a security check? Pick a protocol and identify different roles Specify protocol roles’ templates Prepare a session using 2 Add a security check to the session We consider two security goals: Confidentiality and Authentication
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 without a corresponding 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)) ]).
The full specification of NS (Step 2) % 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)]).
The notation of Scenarios (Step 3+4) 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]).
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([A,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/~corin
Security Protocols & the Attacks • Otway-Rees • Secrecy+type-flaw attack • Kao-chow • replay-attack • Woo-Lam • authentication+type flaw attack • NSL (as bonus protocol) • auth+type-flaw attack
Otway-Rees Protocol 1. A->B : [M,A,B,[Na,M,A,B]+Kas] 2. B->S : [M,A,B,[Na,M,A,B]+Kas], [Nb,M,A,B]+Kbs 3. S->B : [M, [Na,Kab]+Kas, [Nb,Kab]+Kbs 4. B->A : [M,[Na,Kab]+Kas ] • Aim: key distribution using a trusted server. • Kab: short-term key. • Could be guessed. • Na and Nb serve as challenges.
Attack upon Otway-Rees a.1 A->e(B) : [M,A,B,[Na,M,A,B]+Kas] a.4 e(B)->A : [M,A,B,[Na,M,A,B]+Kas] • Type flaw attack • A takes [M,A,B] to be the key • The intruder just replies the first message. • It is an authentication flaw. • It is also a secrecy flaw (the intruder knows the key, now).
Otway-Rees in the tool initiator(A,B,Na,Nb,M,X,Kas,Kab,[ recv([A,B]), % for origination assumption send([M,A,B,[Na,M,A,B]+Kas]]), recv([M,[Na,Kab]+Kas]), send(X+Kab)]). % another way of checking secrecy responder(A,B,Na,Nb,M,X,Kas,Kab,[ %NOT RELEVANT recv([M,A,B,[Na,M,A,B]+Kas]), send([[M,A,B,[Na,M,A,B]+Kas], [Nb,M,A,B]+Kbs]), recv([[M,Na,Kab]+Kas, [Nb,Kab]+Kbs]), send([M,[Na,Kab]+Kas]), recv(X+Kab) ]).
Otway-Rees in the tool cont’d secrecy(N,[recv(N)]). server(A,B,Na,Nb,M,X,Kas,Kab,[ recv([[M,A,B,[Na,M,A,B]+Kas]]], [Nb,[M,[A,B]]]+Kbs]), send([[M,[Na,Kab]]+Kas, [Nb,Kab]+Kbs])]).
One initiator is enough. And the secrecy check. We could not check secrecy the “usual” way because Kab is not instantiated anywhere (it is given by the server). scenario([[sec1,St],[a,Sa1]]) :- initiator(a,b,na,Nb,m,x,kas,Kab,Sa1), secrecy(x, St). initial_intruder_knowledge([a,b,e]). has_to_finish([sec1]). Scenario
The Attack Output Trace: [a,recv([a,b])] [a,send([m,[a,[b,[na,[m,[a,b]]] + kas]]])] [a,recv([m,[na,[m,[a,b]]] + kas])] [a,send(x + [m,[a,b]])] [sec1,recv(x)]
Kao-Chow authentication Protocol 1. A->S : [A,B,Na] 2. S->B : [A,B,Na,Kab]+Kas,[A,B,Na,Kab]+Kbs, 3. B->A : [A,B,Na,Kab]+Kas,[Na+Kab,Nb] 4. A->B : Nb+Kab • Assumption: Kab is compromised
Attack upon Kao-Chow a.1 A->S : [A,B,Na] a.2 S->B : [A,B,Na,Kab]+Kas, [A,B,Na,Kab]+Kbs a.3 B->A : [A,B,Na,Kab]+Kas,[Na+Kab,Nb] a.4 A->B : Nb+Kab b.2 e(S)->B : [A,B,Na,Kab]+Kas,[A,B,Na,Kab]+Kbs b.3 B->e(A) : [A,B,Na,Kab]+Kas, [Na+Kab,Nb’] b.4 e(A)->B : Nb’+Kab
How it works • Two sessions. • First a normal session is carried out. • We assume the intruder “guesses” Kab. • This is something we have to implement manually. • In a second session, the intruder can impersonate both A and the server S.