Refinement Types for Secure Implementations
Total Page:16
File Type:pdf, Size:1020Kb
Refinement Types for Secure Implementations Jesper Bengtson Karthikeyan Bhargavan Uppsala University Microsoft Research Cedric´ Fournet Andrew D. Gordon Microsoft Research Microsoft Research Sergio Maffeis Imperial College London Revision of November 2010 Technical Report MSR–TR–2008–118 Microsoft Research Roger Needham Building 7 J.J. Thomson Avenue Cambridge, CB3 0FB United Kingdom Refinement Types for Secure Implementations Jesper Bengtson Karthikeyan Bhargavan Cedric´ Fournet Andrew D. Gordon Uppsala University Microsoft Research Microsoft Research Microsoft Research Sergio Maffeis Imperial College London Abstract minimize the gap between executable and verified code. # We present the design and implementation of a typechecker for They automatically extract models from F code and, af- verifying security properties of the source code of cryptographic ter applying various program transformations, pass them to protocols and access control mechanisms. The underlying type ProVerif, a cryptographic analyzer [Blanchet, 2001, Abadi theory is a l-calculus equipped with refinement types for express- and Blanchet, 2005]. Their approach yields verified secu- ing pre- and post-conditions within first-order logic. We derive rity for very detailed models, but also demands considerable formal cryptographic primitives and represent active adversaries care in programming, in order to control the complexity of within the type theory. Well-typed programs enjoy assertion-based global cryptographic analysis for giant protocols. Even if security properties, with respect to a realistic threat model includ- ProVerif scales up remarkably well in practice, beyond a ing key compromise. The implementation amounts to an enhanced few message exchanges, or a few hundred lines of F#, veri- typechecker for the general purpose functional language F#; type- checking generates verification conditions that are passed to an fication becomes long (up to a few days) and unpredictable SMT solver. We describe a series of checked examples. This is (with trivial code changes leading to divergence). the first tool to verify authentication properties of cryptographic protocols by typechecking their source code. Cryptographic Verification meets Program Verification In parallel with the development of specialist tools for cryp- 1 Introduction tography, verification tools in general are also making rapid progress, and can deal with much larger programs [see for The goal of this work is to verify the security of imple- example Flanagan et al., 2002, Filliatreˆ and Marche´, 2004, mentation code by typing. Here we are concerned particu- Barnett et al., 2005,R egis-Gianas´ and Pottier, 2008]. To larly with authentication and authorization properties. verify the security of programs with some cryptography, we We develop an extended typechecker for code written would like to combine both kinds of tools. However, this in F# (a variant of ML) [Syme et al., 2007] and annotated integration is delicate: the underlying assumptions of cryp- with refinement types that embed logical formulas. We use tographic models to account for active adversaries typically these dependent types to specify access-control and crypto- differ from those made for general-purpose program veri- graphic properties, as well as desired security goals. Type- fication. On the other hand, modern applications involve checking then ensures that the code is secure. a large amount of (non-cryptographic) code and extensive We evaluate our approach on code implementing autho- libraries, sometimes already verified; we’d rather benefit rization decisions and on reference implementations of se- from this effort. curity protocols. Our typechecker verifies security proper- ties for a realistic threat model that includes a symbolic at- Authorization by Typing Logic is now a well established tacker, in the style of Dolev and Yao[1983], who is able tool for expressing and reasoning about authorization poli- to create arbitrarily many principals, create arbitrarily many cies. Although many systems rely on dynamic authorization instances of each protocol roles, send and receive network engines that evaluate logical queries against local stores of traffic, and compromise arbitrarily many principals. facts and rules, it is sometimes possible to enforce policies statically. Thus, Fournet et al.[2007a,b] treat policy en- Verifying Cryptographic Implementations In earlier forcement as a type discipline; they develop their approach work, Bhargavan et al.[2008b] advocate the crypto- for typed p-calculi, supplemented with cryptographic prim- graphic verification of reference implementations of pro- itives. Relying on a “says” modality in the logic, they also tocols, rather than their handwritten models, in order to account for partial trust (in logic specification) in the face of This is the November 2010 revision of technical report MSR-TR-2008-118, which ap- peared first in September 2008. An abridged, preliminary version appears in the pro- ceedings of the 21st IEEE Computer Security Foundations Symposium (CSF 2008). partial compromise (in their implementations). The present is safe when no assertion can ever fail at run time. By anno- work is an attempt to develop, apply, and evaluate this ap- tating programs with suitable formulas, we formalize secu- proach for a general-purpose programming language. rity properties, such as authentication and authorization, as expression safety. # Outline of the Implementation Our prototype tool, Our F code is written in a functional style, so pre- and named F7, takes as input module interfaces (similar to F# post-conditions concern data values and events represented module interfaces but with extended types) and module im- by logical formulas; our type system does not (and need not plementations (in plain F#). It typechecks implementations for our purposes) directly support reasoning about mutable against interfaces, and also generates plain F# interfaces by state, such as heap-allocated structures. erasure. Using the F# compiler, generated interfaces and verified implementations can then be compiled as usual. Contributions First, we formalize our approach within Our tool performs typechecking and partial type infer- a typed concurrent l-calculus. We develop a type system ence, relying on an external theorem prover for discharging with refinement types that carry logical formulas, building the logical conditions generated by typing. We currently use on standard techniques for dependent types, and establish plain first-order logic (rather than an authorization-specific its soundness. logic) and delegate its proofs to Z3 [de Moura and Bjørner, Second, we adapt our type system to account for active 2008], a solver for Satisfiability Modulo Theories (SMT). (untyped) adversaries, by extending subtyping so that all Thus, in comparison with previous work, we still rely on an values manipulated by the adversary can be given a spe- external prover, but this prover is being developed for gen- cial universal type (Un). Our calculus has no built-in cryp- eral program verification, not for cryptography; also, we use tographic primitives. Instead, we show how a wide range this prover locally, to discharge proof obligations at various of cryptographic primitives can be symbolically coded (and program locations, rather than rely on a global translation typed) in the calculus, using a seal abstraction [Morris, to a cryptographic model. 1973, Sumii and Pierce, 2007]. The corresponding robust Reflecting our assumptions on cryptography and other safety properties then follow as a corollary of type safety. system libraries, some modules have two implementations: Third, experimentally, we implement our approach as an a symbolic implementation used for extended typing and extension of F#, and develop a new typechecker (with par- symbolic execution, and a concrete implementation used tial type inference) based on Z3 (a fast, incomplete, first- for plain typing and distributed execution. We have ac- order logic prover). cess to a collection of F# test programs already analyzed us- ing dual implementations of cryptography [Bhargavan et al., Fourth, we evaluate our approach on a series of program- 2008b], so we can compare our new approach to prior work ming examples, involving authentication and authorization on model extraction to ProVerif. Unlike ProVerif, type- properties of protocols and applications; this indicates that checking requires annotations that include pre- and post- our use of refinement types is an interesting alternative to conditions. On the other hand, these annotations can ex- global verification tools for cryptography, especially for the press general authorization policies, and their use makes verification of executable reference implementations. typechecking more compositional and predictable than the global analysis performed by ProVerif. Moreover, type- Contents The paper is organized as follows. Section2 checking succeeds even on code involving recursion and presents our core language with refinement types, and il- complex data structures. lustrates it by programming access control policies. Sec- tion3 adds typed support for cryptography, using an en- Outline of the Theory We justify our extended type- coding based on seals, and illustrates it by implementing checker by developing a formal type theory for a core of F#: MAC-based authentication protocols. Section4 describes a concurrent call-by-value l-calculus named RCF. our type system and its main properties. Sections5 and6 To represent pre- and post-conditions, our