1 / 27

The EverCrypt Verified Library

EverCrypt is a comprehensive and verifiable library that optimizes for different platforms, architectures, and algorithms on the fly. It aims to provide a high-performance and secure software stack for real-world applications.

wixom
Download Presentation

The EverCrypt Verified Library

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. The EverCrypt Verified Library MicrosoftResearch CMU: B. Parno, A. Fromherz INRIA: K. Bhargavan, B. Beurdouche, M. Polubelova MSR-Cambridge: A. Delignat-Lavaud, C. Fournet, J. Choi, S. Zanella MSR-Redmond: C. Hawblitzel, J. Protzenko, T. Ramananandro, N. Swamy MSR-Bangalore: A. Rastogi Rosario: G. Martinez

  2. Verifying cryptography • An essential pursuit in the quest for a secure software stack (e.g. TLS) • Many successes: Fiat, VST, CryptoLine, Cryptol/SAW, Vale, HACL*/Low* • However: Real-world applications want a high-performance library that optimizes for separate platforms, architectures, and can seamlessly pick the best algorithm on the fly. (see Linux/ZINC, OpenSSL, etc.)

  3. The features of an ideal library (programmer) • Usable: preferably in C or ASM, not “exotic” languages • Comprehensive: one algorithm per processor generation / bitsize • Auto-configurable: best algorithm picked automatically • Deep integration: ASM, e.g. for the multiplication, C, e.g. for the rest • Abstraction: clients deal with a unified API for each family

  4. The features of an ideal library (researcher) • Verifiable: written in a language amenable to verification • Programmer productivity: share as much code as possible / agile • Auto-configurable: doesn’t blue-screen with “missing instruction” • Deep integration: each implementation verifies against the same spec • Abstraction: clients need not know any implementation details We are aiming for a comprehensive verification result without compromising performance.

  5. EverCrypt mediates between (possibly verified) clients and different implementations C client miTLS Merkle tree clients EverCrypt (C) agile, multiplexing library HACL* (C) Vale (ASM) cryptographic providers • Agility: same code, multiple algorithms (e.g. hash) • Multiplexing: same algorithm, multiple implementations (e.g. SHA2_256) • Abstraction: clients verify against a single spec and an abstract footprint

  6. Challenges in verification (an outline) 1. Vale vs Low*: reconciling different memory models & abstractions 2. HACL*: high-level, generic combinators vs. low-level code 3. EverCrypt: hide multiplexing and layer agile abstractions for clients

  7. Vale vs Low*

  8. Vale: a deep embedding of assembly semantics in F* • Memory model maps addresses to bytes • Refinements of the memory model to adopt structured views (e.g. nat64) • Small, trusted interop interface generator ensures ABI and calling conventions are respected

  9. Low*: a shallow embedding of a (curated) C subset in F* • Memory model: a region-based, structured memory model (à la CompCert); each allocation unit (array) has a type & layout • Libraries: a series of models for machine integers, arrays (stack & heap), low-level data structures, system functions • Language subset: no closures, limited higher-order, etc. • Limitations: not the full power of C, e.g. can’t take address of a field • Motto: high-level proofs for low-level code – the user retains the full expressive power of F* for proofs

  10. The Low*/Vale boundary • A map from the Low* memory model to the Vale one (and vice-versa) • A library of views that capture the layout of arrays • The trusted wrapper (auto-generated) sets up the initial register state • A combinator captures that a Vale procedure (mem -> mem) can “morally” be executed with a suitable effect when in Low* • Extra proof obligations related to byte sequences vs words, endianness, etc.

  11. Meta-programming HACL*

  12. Abstract, agile specifications • One key challenge in SMT-backed software verification: the context • Introducing abstractions is essential, even at the level of the specs Spec.SHA2.fsti val compress:a:sha_alg -> state a -> bytes -> state a implements Spec.SHA2.fst • Agile specifications limit code duplication! • Abstract specifications tame context proliferation This maximizes spec compactness

  13. Testable specifications • Specs are easy to get wrong (e.g. endianness, typo in constants) • Specifications are not Low*, but can be compiled to OCaml for tests Spec.SHA2.fsti Spec.Test.Hash.fst Spec.SHA2.fst val compress:a:sha_alg -> state a -> bytes -> state a

  14. Implementing abstract, agile (!) specifications • We are adamant about separating specifications from implementations • The friend mechanism of F* provides language support for that is specified by Spec.SHA2.fsti Impl.SHA2.fsti implements implements abstraction Impl.SHA2.fst Spec.SHA2.fst friends val compress:a:sha_alg -> state a -> array u8 -> Stack unit

  15. A first layer of partial evaluation This is not Low*:Reason: val compress:a:sha_alg -> state a -> array u8 -> Stack unit let state a = function | SHA2_224 | SHA2_256 -> array u32 | SHA2_384 | SHA2_512 -> array u64 This could be compiled as a union. However, this is not idiomatic.Instead, we rely on partial evaluation: let compress_224 = compress SHA2_224let compress_256 = compress SHA2_256 let compress_384 = compress SHA2_384 let compress_512 = compress SHA2_512

  16. Higher-order combinators • It is frequent to combine core operations to generate a construction (counter-mode, hash, etc.) Example: • Given any (abstract)compression function, one can define a Merkle-Damgård construction • Construction: folding the core compression function over multiple blocks of input data • We do not want to write this n times...

  17. An example of a higher-order combinator // Write once; this is not Low*noextractinline_for_extractionlet mk_compress_blocks (a: hash_alg) (compress: compress_st a) (s: state a) (input: blocks) (n: u32 { length input = block_size a * n }) =C.Loops.for 0ul n (fun i -> compress s (Buffer.sub input (i * block_size a) (block_size a))) // Specialize many times; now this is Low*let compress_blocks_224 = mk_compress_blocks SHA2_224 compress_224...let compress_md5 = mk_compress_blocks MD5 compress_md5...

  18. Meta-programming is pervasive • We use it for a given algorithm (SHA2) • We use it for constructions (Merkle-Damgard) • We will reuse combinators later on at the level of EverCrypt • More higher-order combinators, e.g. noextractinline_for_extractionlet mk_hash (a: hash_alg) (init: init_st a) (compress_blocks: compress_blocks_st a) (compress_last: compress_last_st a) (extract: extract_st a)= ...

  19. No state abstraction in HACL* After partially evaluating everything, we get: • a library of pure C functions • all monomorphic and Low* • higher-order combinators (not extracted) • transparent state for each algorithm

  20. EverCrypt = Vale + HACL*

  21. State abstraction for algorithmic agility • EverCrypthides its internal state, offering callers an abstract footprint • Modifying a disjoint memory location preserves footprint and invariant • Internally, a tagged union implements algorithmic agility let compress_blocks (s: multiplexed_state) (b: array u8) (n: u32) = match s with | SHA2_256 s -> ... | MD5 s -> ... | ...

  22. Connecting Vale and HACL* for implementation multiplexing let multiplexed_compress_blocks_sha2_256 (s: state SHA2_256) (blocks: array u8) (n: u32)= if StaticConfig.has_vale && AutoConfig.has_shaext () then Vale.Interop.SHA2.compress_256 s blocks n else Hacl.SHA2.compress_256 s blocks nThis uses static and dynamic configuration (more on that in a couple slides). • On the Low* side:extern void Vale_Interop_SHA2_compress256(uint32_t *s, uint8_t *blocks, uint32_t n) • On the Vale side: .text .global Vale_Interop_SHA2_compress256 Vale_Interop_SHA2_compress256: reconciled at link-time!

  23. Reusing combinators • Since all the cryptographic constructions that need compress_blocks are higher-order combinators, EverCrypt can mix and match • For instance, instead of:let hash_sha2_256 =mk_hash init_sha2_256 compress_blocks_sha2_256 compress_last_sha2_256 ...we can use:let hash_sha2_256 =mk_hash init_sha2_256 multiplexed_compress_blocks_sha2_256 compress_last_sha2_256 ... • Each operation can now be multiplexed at any level in the stack

  24. Preserving specifications • From the client’s perspective, the algorithmic specification remains the same • It is now agile between all algorithms from a given family • The specification abstraction ensures no context pollution occurs • The library can serve as a foundation for higher-level constructions

  25. Feature detection EverCrypt relies on two flavors of feature detection: • static configurations allow disabling one provider entirely (e.g. Vale), meaning entire branches are partially evaluated and eliminated (no symbols) • dynamic configurations detect the presence of CPU features at run-time and allow switching at run-time between Vale, HACL*, or others The dynamic configuration needs the CPUID instruction; this is implemented in Vale.

  26. Building higher-level constructions Using EverCrypt as a foundation, one can build advanced functionalities, such as: • HMAC • HKDF • Merkle Trees Each functionality can offer a new layer of abstraction to further shield its clients from large contexts.Relying on EverCrypt, HMAC is naturally agile and multiplexing.

  27. Conclusion • Three core tenets: agility, multiplexing, abstraction • Connection at proof-time and run-time of two different languages • New motto: high-level proofs for high-level code that partially evaluates to low-level • Usable and used already: by both C clients (Firefox, Linux, Windows, ...) and verified Low* clients (Merkle trees, MPFR re-implementation...) Roadmap: • Performance: encouraging, in-progress • Eventually, all of: SHA2, SHA3 (+ SHA1, MD5), Argon, Blake2, P256, Chacha20, Salsa20, Poly1305 (32+64), Curve25519, Ed25519, AES-GCM, AES-CBC, HMAC, HKDF

More Related