Upload
brian
View
42
Download
0
Tags:
Embed Size (px)
DESCRIPTION
Proving Computational Security of C Programs using VCC (and F7). FCC/ASA Harvard University - 28 th June 2012 F. Dupressoir (Open University & MSRC) C. Fournet (MSRC) A. Gordon (MSRC & University of Edinburgh). Cryptographic Code in C. - PowerPoint PPT Presentation
Citation preview
Proving Computational Security of C Programs using VCC (and F7)
FCC/ASAHarvard University - 28th June 2012
F. Dupressoir (Open University & MSRC)C. Fournet (MSRC)
A. Gordon (MSRC & University of Edinburgh)
Cryptographic Code in C
• The security of much criticalinfrastructure depends in part oncrypto code in C, yet vulnerabilitiescontinue to be found.
• Designers starting to appreciate reference implementations– eg, TCG: “It has taken years to achieve good TPM
interoperability”, need for “more precise language for describing TPM data structures and behaviors”
– New TPM standard will come with a reference implementation in C
Prior Tools for Cryptographic CodeTool Paper Lang. Symbolic/Computational
CSur Goubault-Larrecq & Parennes, 2005 C Symbolic
FS2PV/CV Bhargavan et al., 2005/2008 F# Symbolic/Computational
Pistachio Udrea et al., 2006 C - (compliance, unsound)
F7 Bhargavan et al., 2008 F# Symbolic
Aspier Chaki & Datta, 2009 C Symbolic
F7+CoSP Backes et al., 2010 F# Computationally Sound
CSec-Modex Aizatulin et al., 2011 C Computationally Sound (1-path)
F7 Fournet et al., 2011 F# Computational
VCC Dupressoir et al., 2011 C Symbolic (protocols)
VCC Polikarpova & Moskal, 2012 C Symbolic (stateful devices)
Küsters et al., 2012 Java- Computational
Csec-Modex Aizatulin et al., 2012 (draft) C Computational (1-path)
Also, [O’Shea], [Pironti, Sisto et al.], [Backes, Hritcu et al.], [Jürjens et al.]…
THE DEVICE
Create(1001<id0>14) = 0001Create(1000<id1>14) = 0002Export(02) = 00<template1>14<key1>16
Export(01) = FECreate(1001<id2>14) = FFEncrypt(01<plaintext0>16) = 00<ciphertext0>(16+16+20)
Unload(01) = 00<blob0>(16+16+16+20)
Clear(01) = 00Create(1001<id3>14) = 0001Decrypt(01<ciphertext0>(16+16+20)) = FBClear(03) = 00Load(<blob0>(16+16+16+20)) = 0003Decrypt(03<ciphertext0>(16+16+20)) = 00<plaintext0>16
The Device• Buffer to write in parameters and
read out results• Create: template → handle
– Uses a KDF• Import:
template * bytes → handle• Export:
handle → template * key• Clear: handle → unit• Unload: handle → bytes
– Uses Encrypt-then-MAC• Load: bytes → handle• Encrypt/Decrypt:
handle * bytes → bytes
Internal State
Slot 0
Template
Key
Slot N
Template
Key
Primary Seed Root Storage Key
Slot i
Template
Key
Input/Output Buffer
…
Security• Ideal Functionality-Based Assumptions
– Concrete KDF is indistinguishable from ideal PRF– Concrete (Encode-then-)Encrypt-then-MAC is indistinguishable from ideal
Authenticated Encryption• Ideal Functionality-Based Theorem:
Device is indistinguishable from an ideal functionality with the following features:– When the object involved is not sensitive, run the C code– Create samples a key and stores it in a table, marks an empty slot as taken,
stores the template, and returns the chosen index– Import/Export fail with “wrong attributes” error– Unload/Load, Encrypt/Decrypt encrypt zeroes; use a table– Clear marks the selected handle as empty
THE METHOD
Challenges
• Probabilistic C Programs– Tool usability, maintaining probabilistic features– Probabilistic VS under-specified behaviours
• Equivalence-Based Properties in C– F7: perfect secrecy approximated by parametricity– C: memory reused without being cleared
• Clear sets a bit to 0, but may not overwrite the slot• Slots shared by sensitive and public objects with variable size
– Fine-grained information-flow is hard for C• Stack pointer may depend on secret• Unspecified behaviours…
Total Functional Correctness andSpecification Security
• VCC can prove functional correctness– Soundly deals with unspecified behaviours– Can prove termination
• F7 can prove computational security• VCC and F7 have a coinciding core:– Pure inductive VCC specifications– First-order deterministic F7 expressions
• Probabilistic F7 modelled by derandomizing
The Method in a PictureIdeal F#
ImplementationConcrete F#
Implementation
Crypto𝑅𝑐 ⋅Device𝑅
Concrete C Implementation
Crypto𝑆𝑐 ⋅Device𝑆
Ideal C Implementation
Crypto𝑆𝑖 ⋅Device𝑆
F7
game-hopping≈𝜀
VCC
annotations≲Language
Reference(Pure)
System(Imperative)
CryptographyConcrete Ideal
VCC
annotations≲
Going Through the StepsIdeal F#
Implementation
Crypto𝑅𝑖 ⋅Device𝑅
Concrete F# Implementation
Crypto𝑅𝑐 ⋅Device𝑅
F7
game-hopping≈𝜀
• Type-checking the concrete code to prove that game switching steps can be applied ( is a concrete bound)– Unload/Load encryption (+ formatting) becomes ideal AE– KDF becomes 2 lazy-sampling RFs (sensitive/non-sensitive)– Encrypt/Decrypt encryption becomes ideal AE
• by inlining crypto primitives– More complex examples may need more complex proofs– See Cédric’s ideal interface for TLS
• secure by standard type-checking
Going Through the StepsConcrete F#
Implementation
Crypto𝑅𝑐 ⋅Device𝑅
Concrete C Implementation
Crypto𝑆𝑐 ⋅Device𝑆
VCC
annotations≲
• Assume that computes the same functions as – Observation function may need to be
fine-tuned to crypto and device code• Write VCC contracts expressing
observational equivalence– Observation function should fit the
adversary model• Fiddle with VCC until success– Some work for loops/recursion– Unexplored potential for modularity
Going Through the StepsIdeal F#
Implementation
Crypto𝑅𝑖 ⋅Device𝑅
Ideal C Implementation
Crypto𝑆𝑖 ⋅Device𝑆
VCC
annotations≲
• Do the same on the other side• Same contracts can be used:– VCC gives function-level abstraction– A single run of VCC proves both vertical sides
of the square• On observation functions– At adversary interface, capture everything the
adversary can do– Internally, can be very vague: any unspecified
behaviour causes verification failure at some levelif it flows into the final output
Going Through the StepsIdeal F#
Implementation
Crypto𝑅𝑖 ⋅Device𝑅
Concrete F# Implementation
Crypto𝑅𝑐 ⋅Device𝑅
Concrete C Implementation
Crypto𝑆𝑐 ⋅Device𝑆
Ideal C Implementation
F7
game-hopping≈𝜀
VCC
annotations≲
VCC
annotations≲
≈𝜀
SIMULATION AS A CONTRACTDefining and Proving
Assumptions
• Assume existence of reference KDF
void _(assume_correct) KDF(BYTE* t, UINT8 t_len, _(ghost \template tmpl) BYTE* s, UINT8 s_len, _(ghost \seed seed) BYTE* buf, UINT8* buf_len _(ghost out \key key)) _(decreases 0) // Termination _(maintains \thread_local_array(t, t_len)) // Memory Safety _(maintains \thread_local_array(s, s_len)) // Memory Safety _(ensures \mutable_array(buf, *buf_len)) // Memory Safety _(writes \array_range(buf,(size_t) keylength(tmpl)), buf_len) // Writes the buffer and the length // Simulation on inputs _(requires observeState(state) == refState) _(requires from_array(t,t_len) == tmpl && from_array(s, s_len) == seedRepr(seed)) // Simulation on outputs _(ensures observeState(state) == refState) _(ensures from_array(buf,*buf_len) == keyRepr(tmpl,key)) _(ensures \old(KDF_R(refState,tmpl,seed)) == (refState,key));
_(abstract (\kdfState*\key) KDF_R(\kdfState S, \bytes t, \seed s))In practice, slightly more verbose and distant from F7
• Assume the C implementation is equivalent(up to some observation)
Theorems
• Write reference implementation in VCC_(def (\state*\iobuffer) Create_R((\state*\iobuffer) in) { switch (unmarshal_Create_IN_R(snd(in))) { case None(): return (fst(in), cons(RC_UNMARSHAL, substring(snd(in),1,IOBLEN - 1)) }; case Some(tmpl): Return<(\state*\handle)> res = Create_cmd_R(fst(in),tmpl); switch (res) { case Error(rc): return (fst(in), cons(rc,substring(snd(in),1,IOBLEN - 1))); case Success(S,h): return (S, cons(RC_SUCCESS,cons(h,substring(snd(in),2,IOBLEN - 2))); } } })
• Prove the C implementation is equivalent(up to adversary observations)
void Create(void) _(decreases 0) // Termination _(writes \array_range(IOB,IOBLEN)) // Writes clause _(ensures \mutable_array(IOB,IOBLEN)) // Memory-safety _(maintains observe(store) == store.S) // State simulation invariant // Output simulation _(ensures \old(Create_R(store.S,from_array(IOB,IOBLEN))) == (store.S, from_array(IOB,IOBLEN)));
Theorems
• Translate reference implementation from F7let Create_R (S: state * buf: iobuffer): state * iobuffer = match (unmarshal_Create_IN_R(buf)) | None() -> (S, cons RC_UNMARSHAL (substring buf 1 (IOBLEN - 1))) | Some(tmpl) -> match Create_cmd_R S tmpl with | Error(rc) -> (S, cons rc (substring buf 1 (IOBLEN - 1))) | Success(S,h) -> (S, cons RC_SUCCESS (cons h (substring buf 2 (IOBLEN - 2))))
• Prove the C implementation is equivalent(up to adversary observation)
void Create(void) _(decreases 0) // Termination _(writes \array_range(IOB,IOBLEN)) // Writes clause _(ensures \mutable_array(IOB,IOBLEN)) // Memory-safety _(maintains observe(store) == store.S) // State simulation invariant // Output simulation _(ensures \old(Create_R(store.S,from_array(IOB,IOBLEN))) == (store.S, from_array(IOB,IOBLEN)));
Conclusion
• You can prove computational security of C programs using existing tools– And a lot of work: specification needs to be more
formal than just the C code• Improve C verification tools?– Add probabilities and relational contracts
• Politely ask for formal specifications?
Preliminary Conclusions on the TPM
• Need automation (F7 to VCC, memory safety)– Very tedious work, concerning generated code– Why not generate it from a formal description on which
security can be proved?• First convince ourselves that the proof would work:
several important bugs found and fixed– Agile object loading allowed modifying public part
• Adaptability of proof to other implementation choices is not obvious– Minor subsystems (slot/context allocation): easy– General (1.2 compatibility): major changes in formal spec