430 likes | 534 Views
Analyzing Security Protocols Using SPIN. Mathieu Thibault-Marois 5049388. Background. SPIN. Why SPIN Non- determinism is built into the language Provide exhaustive state- space search tools and options Search Modes Depth -first Breadth -first Safety Deadlocks Assertions
E N D
Analyzing Security Protocols Using SPIN Mathieu Thibault-Marois 5049388
SPIN • Why SPIN • Non-determinismisbuiltinto the language • Provide exhaustive state-spacesearchtools and options • Search Modes • Depth-first • Breadth-first • Safety • Deadlocks • Assertions • Liveness • Never claims • Compression algorithms
SPIN – Compression Algorithms • Memory requirementdominated by state storage • 3 modes of execution • Byte Masking • Fastexecution speed • High memory requirements • DCOLLAPSE • Medium executionspeed • Medium memory requirements • DMA • Slow execution speed • Low memory requirements
SPIN – Byte Masking [1] • Identify byte values in state-vector that are known to constant values • Ex.: Padding bytes, channel content for rendez-vous channels, etc. • Only store non-masked bytes • Static • Default execution mode for SPIN
SPIN: DCOLLAPSE [1] • Recursive Index Method • Based on the observation thatcomplexity stems from non-deteminism of processexecutions • Global state-vectoriscombination of all local states • Storingcomplete description for all local state-vectoriswasteful • State-vectorisrecursively split to smaller components • 2 levels of indirection in SPIN • State of all global variables and all message channels • State of each active processwithits local variables • No major change to the standard hash-table storagerequired • Allow components thatoccursfrequently to be store only once
SPIN: DMA [2] • Replace Hash-table by deterministicfinite state recognizer. • Interrogaterecognizerinstead of lookingthrough hash-table • Built on the fly • Update recognizerwhen new state is to beadded to set of reached states. • Update procedurepreserveminimality • Greaterrun-time requirement as a trade-off for reduction of memory requirement.
SPIN: Compression Comparison • Scenario 1 [1]: • Scenario 2 [2]:
SPIN: D_Step • D_Step • Stands for « DeterministicSteps » • Cannotcontainstatementswhichmay block • Useful to reducecomplexity as itremoves all intermediatesteps • Need to watch out for certain cases • Whatis the value of a after the following block: d_step { if ::a = 1; ::a = 2; fi }
Needham-Schroeder Protocol [3] • Proposed in 1978 • Consist of two communication protocols: • Symmetric Key Protocol • Goal is to establish a session key betweentwoentities • Public Key Protocol • Goal is to providemutualauthentication to twoentities • Attackdiscoveredon the public key protocol in 1995 by Gavin Lowe • Note: An attack on the symmetricprotocolwasalsodiscovered in 1981. • Problem: • 17 years gap between invention and attackdiscovery
Public Key Protocol [3] • Entities: • Initiator(A), Receiver(B), Trusted Server (S) • Assumptions • Nonces are not guessable and are not identical • Intruder cannot decrypt messages without the corresponding key • Protocol Run:
Lowe’s Attack [4] • Add an Intruder (I) which can do anything that do not break the preceding assumptions • Attack: • Result • B believes it is talking with A but is talking with I • I knows both NA and NB
Fixing Lowe’s Attack [4] • Modify Message #6: • Trying the attack with the new message: • A will not reply to this message as A can see by decrypting the message that I is sending a message intercepted from B by looking at the 3rd field. …
Test System Specification • Core i5-2500k @ 4.00Ghz • 8.0GB RAM • Windows 7 64bits Professional • SPIN configuration • -DMEMLIM=8192 • Set memory limit to 8192MB • -O2 • 2nd optimization level for GCC • -DXUSAFE • Do not verify channel assertions (exclusive read/write assess) • -DSAFETY • Do not check liveness • -DNOCLAIM • Do not user a never claim or LTL property
Design: Initiator proctype Initiator() { Encrypted Message; /* Message {Data1,Data2}_Key */ if /* Randomly select a partner */ ::PartnerA = B; ::PartnerA = I; fi; d_step /* A -> S:{A,PartnerA} { Message.data1 = A; Message.data2 = PartnerA; Message.key = 0; } network ! S, Message; network ? A, Message; /* Expecting Message from S with public key for PartnerA */ (Message.key == KSS) && (Message.data2 == PartnerA); PartnerKeyA = Message.data1; d_step /* A -> PartnerA:{NA,A}_PartnerKeyA */ { Message.data1 = NA; Message.data2 = A; Message.key = PartnerKeyA; } network ! PartnerA, Message;
Design: Initiator network ? A, Message; /* Expecting Message encrypted with KPA containing */ /* NA with Nonce for the partner */ (Message.key == KPA) && (Message.data1 == NA); PartnerNonceA = Message.data2; d_step /* A -> PartnerA:{PartnerNonceA,0}_PartnerKeyA */ { Message.data1 = PartnerNonceA; Message.data2 = 0; Message.key = PartnerKeyA; } network ! PartnerA, Message; doneA = true; /* A has now completed the protocol and is in session */ /* with PartnerA */ }
Design: Receiver proctype Receiver() { Encrypted Message; /* Message {Data1,Data2}_Key */ network ? B, Message; /* Expecting message from initiator encrypted with (Message.key == KPB); /* KPB containing partner identity and nonce */ PartnerB = Message.data2; PartnerNonceB = Message.data1; d_step /* B -> S:{B,PartnerB} { Message.data1 = B; Message.data2 = PartnerB ; Message.key = 0; } network ! S, Message; network ? B, Message; /* Expecting Message from S with public key for PartnerB */ (Message.key == KSS) && (Message.data2 == PartnerB); PartnerKeyB = Message.data1; d_step /* B -> PartnerB:{PartnerNonceB,NB}_PartnerKeyB { Message.data1 = PartnerNonceB; Message.data2 = NB; Message.key = PartnerKeyB; } network ! PartnerB, Message; network ? B, Message; /* Expecting message encrypted with KPB and containing NB*/ (Message.key == KPB) && (Message.data1 == NB); doneB = true; /* B has now completed the protocol and should be */ /*in session with PartnerB */ }
Design: Server proctype Server() { mtype target; Encrypted Message; /*{Data1,Data2}_Key*/ do ::network ? S, Message;/* Server expect message of format {Requesting,Requested} atomic{ if ::(Message.data1 == A && Message.data2 == B) -> d_step{target = A; Message.data1 = KPB; Message.data2 = B; Message.key = KSS;} ::(Message.data1 == A && Message.data2 == A) -> d_step{target = A; Message.data1 = KPA; Message.data2 = A; Message.key = KSS;} ::(Message.data1 == A && Message.data2 == I) -> d_step{target = A; Message.data1 = KPI; Message.data2 = I; Message.key = KSS;} ::(Message.data1 == B && Message.data2 == B) -> d_step{target = B; Message.data1 = KPB; Message.data2 = B; Message.key = KSS;} ::(Message.data1 == B && Message.data2 == A) -> d_step{target = B; Message.data1 = KPA; Message.data2 = A; Message.key = KSS;} ::(Message.data1 == B && Message.data2 == I) -> d_step{target = B; Message.data1 = KPI; Message.data2 = I; Message.key = KSS;} ::(Message.data1 == I && Message.data2 == B) -> d_step{target = I; Message.data1 = KPB; Message.data2 = B; Message.key = KSS;} ::(Message.data1 == I && Message.data2 == A) -> d_step{target = I; Message.data1 = KPA; Message.data2 = A; Message.key = KSS;} ::(Message.data1 == I && Message.data2 == I) -> d_step{target = I; Message.data1 = KPI; Message.data2 = I; Message.key = KSS;} ::else-> gotoskipSending fi; } network ! target, Message;/*S -> RequestingEntity:{KeyRequested,Requested}_KSS*/ skipSending: od }
Secrecy Property • Problem: • Need to define what is the “secret” that the protocol should keep • Need to find a way to describe that the secret has been lost • Assertion: • Verified only when both the initiator and the receiver have completed the protocol run • Verifies that 2 situation are always true • If Partner of A is B, then Partner of B is A • If A selects B as a partner, then they must be partners at the end together • If Partner of A is I, then Partner of B is also I • If A select I as a partner, then it is possible that I is in session with both A and B without violating the protocol. • Code: ::(doneA == true && doneB == true) -> assert((PartnerA == B && PartnerB == A) || (PartnerA == I && PartnerB == I));
Knowledgeable Intruder • Goal • Show that the attack works • Limitation • Useless to assess the feasibility of using SPIN to detect attacks on protocols as the attack already knows the attack • Code: proctypeUselessIntruder() { Encrypted Message; /* Message structure: */ /*mtype Data1 */ /*mtype Data2 */ /* mtype key */ do ::network ? I,Message; /*Read messages sent to intruder */ if ::(Message.key == KPI) -> /*If the key correspond*/ Message.key = KPB; /*Use B’s public key to re-encrypt the message*/ network ! B,Message; /*Forward message to B*/ ::else -> skip; fi; od; }
Knowledgeable Intruder • Search statistics: • 60 bytes state-vector • Depth Reached: 59 • States: 71 • Search Time: 0.015 seconds • Error Trail
Replaying Intruder • Goal • Assess complexity of an intruder that replay messages • Capabilities • Change encryption key of messages encrypted with KSS or KPI • Replay messages immediately • Can forward messages to any target • Can drop messages • Limitations • Intruder cannot change content of messages • Intruder cannot replay messages later on • Assumes only a replay attack
Replaying Intruder proctypeReplayIntruder() { Encrypted Message; /* Message structure: */ /*mtype Data1 */ /*mtype Data2 */ /* mtype key */ do ::network ? _,Message; /*Read any messages*/ if /*if the key is known, allow to re-encrypt*/ ::(Message.key == KPI) || (Message.key == KSS) -> if ::Message.key = KPA; /*encrypt with A public key*/ ::Message.key = KPB; /*encrypt with B public key*/ ::Message.key = KPI; /*encrypt with I public key*/ ::else -> skip; /*leave alone*/ fi; ::else -> skip; /*otherwise can’t change key*/ fi; if ::network ! A, Message; /*send to A*/ ::network ! B, Message; /*send to B*/ ::network ! S, Message; /*send to C*/ ::skip; /*do not send anything*/ fi; od; } • Code:
Replaying Intruder • Search statistics: • 60 bytes state-vector • Depth Reached: 66 • States: 543 • Search Time: 0.015 seconds • Error Trail
Replaying Intruder with Memory • Goal • Extend capabilities of previous intruder model • Assess complexity growth associated with storing messages • Capabilities • Same as before plus • Can also replay messages later • Limitations • Same as before plus • Limited memory capacity (in number of message stored)
Replaying Intruder with Memory proctypeMemoryReplayIntruder() { #define n 7 /* Number of memory slots for stored messages*/ Encrypted Message; /* Message structure: */ /*mtype Data1 */ /*mtype Data2 */ /* mtype key */ Encrypted stored[n]; /*Stored messages*/ byte index = 0; /*Write index for stored messages*/ byte readIndex = 0; /*Read index for stored messages*/ boolstoredFull = false; /*Indicates at least the buffer is full*/ /*means that all location contain messages*/ do ::network ? _,Message -> /*Receive ANY message*/ d_step /* Store the message*/ { stored[index].data1 = Message.data1; stored[index].data2 = Message.data2; stored[index].key = Message.key; } index = (index + 1); if /*First time the buffer is filled, set the flag that*/ /*all positions contain valid messages*/ ::(index == 10 && storedFull == false) -> storedFull = true; ::else -> skip; fi; index = index % n; • Code:
Replaying Intruder with Memory ::((storedFull == false && index > 0) /*If the buffer isn`t full but some messages are stored*/ || (storedFull == true)) -> /*or if the buffer is full*/ readIndex = 0; /*Generate a random index to a valid stored*/ /*message*/ do ::(storedFull == false && (readIndex+1) < index) -> readIndex = (readIndex + 1) % n; ::(storedFull == true) -> readIndex = (readIndex + 1) % n; ::break; od; atomic{ /*Get the stored message at the index specified*/ Message.data1 = stored[readIndex].data1; Message.data2 = stored[readIndex].data2; Message.key = stored[readIndex].key; } if /*If the stored message can be decrypted*/ /*then the intruder is enable to change the key and reencrypt*/ ::(Message.key == KPI) || (Message.key == KSS) -> if ::Message.key = KPA; ::Message.key = KPB; ::Message.key = KPI; ::else -> skip; fi; ::else -> skip; fi; if /*Select a random entity to send the message to*/ ::network ! A,Message; ::network ! B, Message; ::network ! S, Message; fi; od; /*Repeat indefinitely*/ }
Replaying Intruder with Memory • Search statistics: • Number of states: • Search Time: DMA DCOLLAPSE
Message Builder Intruder • Goal • Test feasibility of allowing intruder to build random messages from its knowledge • Capabilities • Build any random message of the following format {Data1,Data2}_key. • Randomly select a target • Can encrypt messages with any of the available public keys • Can intercept all messages on the network and decrypt those for which the key is known • Can forward or drop messages • Limitations • Only one format of messages allowed.
Message Builder Intruder :: atomic /*Build a random message to send*/ { if /*Choose target of the message*/ ::target = A; ::target = B; ::target = S; fi; if /*Choose information for the first slot*/ ::intercepted.data1 = A; ::intercepted.data1 = B; ::intercepted.data1 = I; ::intercepted.data1 = S; ::intercepted.data1 = KPA; ::intercepted.data1 = KPB; ::intercepted.data1 = KPI; ::(knowledge[0].known == true) -> intercepted.data1 = NA; ::(knowledge[1].known == true) -> intercepted.data1 = NB; ::intercepted.data1 = NI; fi;
Message Builder Intruder if /*Choose Information for the second slot*/ ::intercepted.data2 = A; ::intercepted.data2 = B; ::intercepted.data2 = I; ::intercepted.data2 = S; ::intercepted.data2 = KPA; ::intercepted.data2 = KPB; ::intercepted.data2 = KPI; ::(knowledge[0].known == true) -> intercepted.data2 = NA; ::(knowledge[1].known == true) -> intercepted.data2 = NB; ::intercepted.data2 = NI; ::intercepted.data2 = 0; fi; if /*Choose key for encryption*/ ::intercepted.key = KPI; ::intercepted.key = KPA; ::intercepted.key = KPB; ::intercepted.key = 0; fi; }
Message Builder Intruder • Search statistics: • 68 bytes state-vector • Depth Reached: 999 • States: 17 042 715 000 • Search Time: 265 000 seconds • Error trail very long and full of wasted messages between intruder and server 3 days !
Intelligent Message Builder • Goal • Reduce complexity of the message builder intruder by removing useless messages (messages that could not possibly be part of a protocol exchange) • Limitations • Can only send to A and B, no longer to S • Data1 field is limited to entities (not S), keys and nonces • Data2 field is limited to entities (not S), nonces or empty • Keys are limited to KPA and KPB • Messages encrypted with KPI are useless to anyone except I • Unencrypted messages sent to the server are trivial • Same as before for the rest
Intelligent Message Builder :: atomic /*Build a random message to send*/ { if /*Choose target of the message*/ ::target = A; ::target = B; fi; if /*Choose information for the first slot*/ ::intercepted.data1 = A; ::intercepted.data1 = B; ::intercepted.data1 = I; ::intercepted.data1 = KPA; ::intercepted.data1 = KPB; ::intercepted.data1 = KPI; ::(knowledge[0].known == true) -> intercepted.data1 = NA; ::(knowledge[1].known == true) -> intercepted.data1 = NB; ::intercepted.data1 = NI; fi; if /*Choose Information for the second slot*/ ::intercepted.data2 = A; ::intercepted.data2 = B; ::intercepted.data2 = I; ::(knowledge[0].known == true) -> intercepted.data2 = NA; ::(knowledge[1].known == true) -> intercepted.data2 = NB; ::intercepted.data2 = NI; ::intercepted.data2 = 0; fi; if /*Choose key for encryption*/ ::intercepted.key = KPA; ::intercepted.key = KPB; fi; }
Intelligent Message Builder • Search statistics: • 68 bytes state-vector • Depth Reached: 75 • States: 3 968 571 • Search Time: 8.31 seconds • Error trail:
Mixing up everything so far… • Goal • Mix Replaying capacity with memory capacity with message building capacity and assess complexity • Limitations and features • Same as all pieces presented that compose it.
Replay/MessageBuilder/Memory • Search statistics (n=3): • 84 bytes state-vector • Depth Reached: 685 • States: 679 196 240 • Search Time: 6710 seconds • Error trail:
Implementing Lowe’s Fix • Remember the message that needs to be replaced: • Require change to the structure of the message, now requires 3 data slots: • {Data1,Data2,Data3}_Key • B now sends the following message • {PartnerNonceB,NB,B}_PartnerKeyB • A verifies this new 3rd data slot only for that single message: • (Message.key == KPA) && (Message.data1 == NA) && (Message.data3 == PartnerA); • Intruder changes: • Need to read 3rd data slot when intercepting messages • Need to store 3rd data slot in memory along with Data1 and Data2 • Need to generate data for 3rd slot in the message builder • Server changes: • Set Data3 to 0 before sending
Running the Intruder again • Intruder • Message builder, Replay and with memory. • Goal • Find a vulnerability in the protocol. Ran for 42 hours and stopped due to out of memory error using DMA…
Conclusion • Design facilitated by inclusion of non-determinism in language • Defining secrecy property properly can be tricky • Search-time explodes as system gets more complicated • Must be careful when making compromises to reduce complexity • Even with compression algorithms, memory is a problem • Take into account the difference between finding an attack, and proving there are none…