proving computational security of c programs using vcc (and f7)

20
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)

Upload: brian

Post on 22-Feb-2016

42 views

Category:

Documents


0 download

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

TRANSCRIPT

Page 1: Proving Computational Security of C Programs using VCC (and F7)

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)

Page 2: Proving Computational Security of C Programs using VCC (and F7)

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

Page 3: Proving Computational Security of C Programs using VCC (and F7)

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.]…

Page 4: Proving Computational Security of C Programs using VCC (and F7)

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

Page 5: Proving Computational Security of C Programs using VCC (and F7)

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

Page 6: Proving Computational Security of C Programs using VCC (and F7)

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

Page 7: Proving Computational Security of C Programs using VCC (and F7)

THE METHOD

Page 8: Proving Computational Security of C Programs using VCC (and F7)

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…

Page 9: Proving Computational Security of C Programs using VCC (and F7)

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

Page 10: Proving Computational Security of C Programs using VCC (and F7)

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≲

Page 11: Proving Computational Security of C Programs using VCC (and F7)

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

Page 12: Proving Computational Security of C Programs using VCC (and F7)

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

Page 13: Proving Computational Security of C Programs using VCC (and F7)

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

Page 14: Proving Computational Security of C Programs using VCC (and F7)

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≲

≈𝜀

Page 15: Proving Computational Security of C Programs using VCC (and F7)

SIMULATION AS A CONTRACTDefining and Proving

Page 16: Proving Computational Security of C Programs using VCC (and F7)

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)

Page 17: Proving Computational Security of C Programs using VCC (and F7)

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)));

Page 18: Proving Computational Security of C Programs using VCC (and F7)

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)));

Page 19: Proving Computational Security of C Programs using VCC (and F7)

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?

Page 20: Proving Computational Security of C Programs using VCC (and F7)

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