Permalink
Cannot retrieve contributors at this time
(* | |
* Copyright 2015 INRIA and Microsoft Corporation | |
* | |
* Licensed under the Apache License, Version 2.0 (the "License"); | |
* you may not use this file except in compliance with the License. | |
* You may obtain a copy of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, software | |
* distributed under the License is distributed on an "AS IS" BASIS, | |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
* See the License for the specific language governing permissions and | |
* limitations under the License. | |
*) | |
module TLSConstants | |
(* Identifiers and sizes for the TLS crypto algorithms | |
This file also declares those that are assumed to be strong | |
(such assumption are on both the algorithms and their implementation) *) | |
(* remark: this file is part of the public API; it could expose less internal details | |
of TLS; strength assumptions could also be grouped elsewhere. *) | |
open Bytes | |
open Error | |
open TLSError | |
(** Some algorithms depend on the TLS protocol version *) | |
type PreProtocolVersion = | |
| SSL_3p0 | |
| TLS_1p0 | |
| TLS_1p1 | |
| TLS_1p2 | |
predicate IsProtocolVersion of PreProtocolVersion | |
definition | |
!p. IsProtocolVersion(p) | |
<=> (p = SSL_3p0 \/ p = TLS_1p0 \/ p = TLS_1p1 \/ p = TLS_1p2) | |
type ProtocolVersion = p:PreProtocolVersion{ IsProtocolVersion(p) } | |
(** Not abstract, but meant to be used only by crypto modules and CipherSuites *) | |
type blockCipher = | |
| TDES_EDE | |
| AES_128 | |
| AES_256 | |
type encAlg = | |
| CBC_Stale of blockCipher (* old style, using prior last block as IV *) | |
| CBC_Fresh of blockCipher (* new style, fresh IV for every fragment *) | |
| Stream_RC4_128 | |
predicate IND_CPA of encAlg (* strong algorithms for the IND-CPA encryption game *) | |
//#begin-cipherAssert | |
// some reasonable cryptographic assumptions if you believe that you are sufficiently | |
// protected against timing attacks (see: http://www.isg.rhul.ac.uk/tls/Lucky13.html ) | |
// assume(IND_CPA(CBC_Fresh(AES_128))) | |
// assume(IND_CPA(CBC_Fresh(AES_256))) | |
// some unreasonable cryptographic assumptions: | |
// assume(IND_CPA(Stream_RC4_128)) (see: http://vnhacker.blogspot.co.uk/2011/09/beast.html ) | |
// assume(IND_CPA(CBC_Stale(AES_256))) (see: http://www.isg.rhul.ac.uk/tls/ ) | |
//#end-cipherAssert | |
(** Algorithms for the MAC module *) | |
type hashAlg = | |
| NULL | |
| MD5SHA1 | |
| MD5 | |
| SHA | |
| SHA256 | |
| SHA384 | |
type macAlg = | |
| MA_HMAC of hashAlg | |
| MA_SSLKHASH of hashAlg | |
predicate INT_CMA_M of macAlg (* Strong algorithms for the INT-CMA forgery game *) | |
// some reasonable cryptogaphic assumptions: | |
assume INT_CMA_M(MA_HMAC(SHA256)) //used in MAC | |
assume INT_CMA_M(MA_HMAC(SHA)) | |
// assume(INT_CMA_M(MA_HMAC(SHA384))) | |
// some unreasonable assumption | |
// assume(INT_CMA_M(MD5)) | |
(** Signing algorithms for the Sig module *) | |
type sigAlg = | |
| SA_RSA | |
| SA_DSA | |
| SA_ECDSA | |
type sigHashAlg = sigAlg * hashAlg | |
predicate INT_CMA_S of sigAlg * hashAlg * hashAlg list | |
// INT_CMA_S(s,h,hs) indicates that signing hashes using (s,h) is INT-CMA, | |
// even if we also use the key to sign hashes using (s,h') where h' in hs | |
// | |
// some reasonable cryptographic assumptions: | |
// assume(INT_CMA_S(SA_DSA,SHA,[SHA])) | |
// assume(INT_CMA_S(SA_ECDSA,SHA,[SHA])) | |
(** algorithms for the record protocol *) | |
type aeadAlg = | |
| AES_128_GCM | |
| AES_256_GCM | |
type aeAlg = // for specification of INT_CTXT predicate | |
| MACOnly of macAlg | |
| MtE of encAlg * macAlg | |
| AEAD of aeadAlg * macAlg // macAlg is for the PRF | |
predicate INT_CTXT of ProtocolVersion * aeAlg | |
// some reasonable assumptions: | |
// assume INT_CTXT(TLS_1p2,MtE(CBC_Fresh(AES_128),MA_HMAC(SHA256))) | |
// This follows from Paterson et al. | |
// assume !e,m. PRF(m) /\ SPRP(e) => INT_CTXT(TLS_1p2,MtE(CBC_Fresh(e),m)) | |
predicate StrongAEAlg of ProtocolVersion * aeAlg | |
definition !pv,ae. StrongAEAlg(pv,ae) <=> | |
(?e,m. ae = MtE(e,m) /\ | |
IND_CPA(e) /\ | |
INT_CMA_M(m) /\ | |
INT_CTXT(pv,ae) ) | |
ask !ae,m,pv. ae=MACOnly(m) => not StrongAEAlg(pv,ae) | |
(** algorithms for the Handshake *) | |
// all these kex have server auth & optional client auth, | |
// except for anon which has none of them | |
type kexAlg = | |
| RSA // --> client-generated pms encrypted using server's public key | |
| DH_DSS // <-- Certificate(DSA containing g^y); --> g^x then pms = g^xy | |
| DH_RSA // idem with an RSA cert | |
| DHE_DSS // <-- Certificate(DSA); ServerKeyExchange({Cr,Sr,p,g,g^y}signed); --> g^x then pms = g^xy | |
| DHE_RSA // idem with an RSA cert | |
| ECDHE_RSA | |
| ECDHE_ECDSA | |
| DH_anon // --> g^x ; <-- g^y then pms = g^xy ; secure only against passive adversaries | |
predicate PRF of ProtocolVersion * macAlg | |
predicate KEF_DH of ProtocolVersion * macAlg | |
predicate KEF_RSA of ProtocolVersion * macAlg | |
// In the crypto'14 paper, these are global assumptions. | |
// In our code, we have some extra key agility: | |
// we get StrongHS for the rest even if one of them is false. | |
(* With F7, we need to declare both logical functions for lengths, constants, etc | |
and their concrete F# implementations, typechecked against these logical functions. *) | |
function val SigAlgBytes: sigAlg -> cbytes | |
private definition | |
(SigAlgBytes(SA_RSA) = [|1uy|]) /\ | |
(SigAlgBytes(SA_DSA) = [|2uy|]) /\ | |
(SigAlgBytes(SA_ECDSA) = [|3uy|]) | |
val sigAlgBytes: s:sigAlg -> b:bytes{B(b)=SigAlgBytes(s)} | |
val parseSigAlg: b:bytes -> (s:sigAlg{B(b)=SigAlgBytes(s)}) Result | |
function val HashAlgBytes: hashAlg -> cbytes | |
definition | |
HashAlgBytes(MD5) = [|1uy|] /\ | |
HashAlgBytes(SHA) = [|2uy|] /\ | |
HashAlgBytes(SHA256) = [|4uy|] /\ | |
HashAlgBytes(SHA384) = [|5uy|] | |
val hashAlgBytes: h:hashAlg -> b:bytes{B(b)=HashAlgBytes(h)} | |
val parseHashAlg: b:bytes -> (h:hashAlg{B(b)=HashAlgBytes(h)}) Result | |
function val EncKeySize: encAlg -> nat | |
assume !x. EncKeySize(x) >= 0 | |
private definition EncKeySize(Stream_RC4_128) = 16 | |
private definition EncKeySize(CBC_Stale(TDES_EDE)) = 24 | |
private definition EncKeySize(CBC_Stale(AES_128)) = 16 | |
private definition EncKeySize(CBC_Stale(AES_256)) = 32 | |
private definition EncKeySize(CBC_Fresh(TDES_EDE)) = 24 | |
private definition EncKeySize(CBC_Fresh(AES_128)) = 16 | |
private definition EncKeySize(CBC_Fresh(AES_256)) = 32 | |
val encKeySize: a:encAlg -> l:nat{l=EncKeySize(a)} | |
function val BlockSize: blockCipher -> nat | |
assume !x. BlockSize(x) > 0 | |
private definition BlockSize(TDES_EDE) = 8 | |
private definition BlockSize(AES_128) = 16 | |
private definition BlockSize(AES_256) = 16 | |
val blockSize: a:blockCipher -> l:nat {l=BlockSize(a)} | |
(* unused for now: | |
function val EncAlgBlockSize: encAlg -> nat | |
assume !x. EncAlgBlockSize(x) >= 0 | |
private definition !b. EncAlgBlockSize(CBC_Stale(b)) = BlockSize(b) | |
private definition !b. EncAlgBlockSize(CBC_Fresh(b)) = BlockSize(b) | |
private definition EncAlgBlockSize(Stream_RC4_128) = 0 | |
*) | |
function val AEADKeySize: aeadAlg -> nat | |
assume !x. AEADKeySize(x) >= 0 | |
private definition AEADKeySize(AES_128_GCM) = 16 | |
private definition AEADKeySize(AES_256_GCM) = 32 | |
val aeadKeySize: a:aeadAlg -> n:nat{n=AEADKeySize(a)} | |
function val AEADIVSize: aeadAlg -> nat | |
assume !x. AEADIVSize(x) >= 0 | |
private definition AEADIVSize(AES_128_GCM) = 4 | |
private definition AEADIVSize(AES_256_GCM) = 4 | |
val aeadIVSize: a:aeadAlg -> n:nat{n=AEADIVSize(a)} | |
function val AEADRecordIVSize: aeadAlg -> nat | |
assume !x. AEADRecordIVSize(x) >= 0 | |
private definition AEADRecordIVSize(AES_128_GCM) = 8 | |
private definition AEADRecordIVSize(AES_256_GCM) = 8 | |
val aeadRecordIVSize: a:aeadAlg -> n:nat{n = AEADRecordIVSize(a)} | |
function val AEADTagSize: aeadAlg -> nat | |
assume !x. AEADTagSize(x) >= 0 | |
private definition AEADTagSize(AES_128_GCM) = 16 | |
private definition AEADTagSize(AES_256_GCM) = 16 | |
val aeadTagSize: a:aeadAlg -> n:nat{n = AEADTagSize(a)} | |
// In TLS, hashes and MAC keys & tags have the same size, depending on hashAlg. | |
function val HashSize: hashAlg -> nat | |
private assume !x. HashSize(x) >= 0 | |
private definition HashSize(MD5 ) = 16 | |
private definition HashSize(SHA ) = 20 | |
private definition HashSize(SHA256 ) = 32 | |
private definition HashSize(SHA384 ) = 48 | |
private definition HashSize(MD5SHA1) = 36 | |
val hashSize: a:hashAlg -> l:nat{l=HashSize(a)} | |
function val MacKeySize: macAlg -> nat | |
assume !x. MacKeySize(x) >= 0 | |
definition !a. MacKeySize(MA_HMAC(a)) = HashSize(a) | |
definition !a. MacKeySize(MA_SSLKHASH(a)) = HashSize(a) | |
val macKeySize: a:macAlg -> l:nat{l=MacKeySize(a)} | |
function val MacSize: macAlg -> nat | |
assume !x. MacSize(x) >= 0 | |
// It seems to be a common practice to make the MAC tag the | |
// same size as the MAC key, as both affect the security level. | |
// We use the MacSize predicate for extra clarity. | |
definition !x. MacSize(x) = MacKeySize(x) | |
val macSize: a:macAlg -> l:nat{l=MacSize(a)} | |
(* ------------------------------------------------------------------------ *) | |
(* Key parameters *) | |
type dsaparams = { p : bytes; q : bytes; g : bytes; } | |
type skeyparams = | |
| SK_RSA of bytes * bytes (* modulus x exponent *) | |
| SK_DSA of bytes * dsaparams | |
type pkeyparams = | |
| PK_RSA of bytes * bytes | |
| PK_DSA of bytes * dsaparams | |
val sigalg_of_skeyparams: skeyparams -> sigAlg | |
val sigalg_of_pkeyparams: pkeyparams -> sigAlg | |
(*** Following RFC5246 A.5 *) | |
private type SCSVsuite = | |
| TLS_EMPTY_RENEGOTIATION_INFO_SCSV | |
type cipherAlg = // internal; used only in ciphersuite definition | |
| RC4_128 | |
| TDES_EDE_CBC | |
| AES_128_CBC | |
| AES_256_CBC | |
type csAuthEncAlg = // internal; used only in ciphersuite definition | |
| CS_MtE of cipherAlg * hashAlg | |
| CS_AEAD of aeadAlg * hashAlg | |
type cipherSuite = // internal; kept abstract in the .fsi | |
| NullCipherSuite | |
| CipherSuite of kexAlg * csAuthEncAlg | |
| OnlyMACCipherSuite of kexAlg * hashAlg | |
| SCSV of SCSVsuite | |
type cipherSuites = cipherSuite list | |
(** Compression *) | |
// By design, we entirely disable TLS-level compression | |
// see e.g. traffic analyses & CRIME attacks | |
type PreCompression = | |
| NullCompression | |
predicate IsCompression of PreCompression | |
definition !c. IsCompression(c) <=> (c = NullCompression) | |
predicate IsCompressions of PreCompression list | |
definition IsCompressions([]) | |
definition !c,cs. IsCompression(c) /\ IsCompressions(cs) => IsCompressions(c::cs) | |
type Compression = c:PreCompression{IsCompression(c)} | |
function val CompressionBytes: Compression -> cbytes | |
definition CompressionBytes(NullCompression) = [| 0uy |] | |
predicate ContainsCompressions of Compression list * Compression list | |
function val CompressionsBytes: Compression list -> cbytes | |
definition CompressionsBytes([]) = [||] | |
definition !h,t. CompressionsBytes(h::t) = CompressionBytes(h) @| CompressionsBytes(t) | |
(* unused for now: | |
private assume !cl. ContainsCompressions(cl,cl) /\ | |
(!cl. ContainsCompressions(cl,[])) /\ | |
(!h,t,cl. ContainsCompressions(t,cl) => ContainsCompressions(h::t,cl)) /\ | |
(!h,t,h',t'. ContainsCompressions(t,t') => ContainsCompressions(h::t,h'::t')) | |
*) | |
val compressionBytes: c:Compression -> b:bytes{CompressionBytes(c) = B(b)} | |
val compressionMethodsBytes: cl:Compression list -> b:bytes{B(b) = CompressionsBytes(cl)} | |
val parseCompression: b:bytes -> (c:Compression{B(b)=CompressionBytes(c)}) Result | |
val parseCompressions: b:bytes -> cl:Compression list | |
// our server currently ignores any compression-methods proposal | |
(** Versions *) | |
function val VersionBytes: ProtocolVersion -> b:cbytes | |
assume !p. BLength(VersionBytes(p)) = 2 | |
private assume VersionBytes(SSL_3p0) = [| 3uy; 0uy |] | |
private assume VersionBytes(TLS_1p0) = [| 3uy; 1uy |] | |
private assume VersionBytes(TLS_1p1) = [| 3uy; 2uy |] | |
private assume VersionBytes(TLS_1p2) = [| 3uy; 3uy |] | |
ask !v,v'. IsProtocolVersion(v) /\ IsProtocolVersion(v') => | |
VersionBytes(v) = VersionBytes(v') => v = v' | |
ask !v. IsProtocolVersion(v) => BLength(VersionBytes(v)) = 2 | |
val versionBytes: pv:ProtocolVersion -> b:bytes{ Length(b) = 2 /\ B(b) = VersionBytes(pv) } | |
val parseVersion: b:bytes{Length(b) = 2} -> (pv:ProtocolVersion{ B(b)= VersionBytes(pv)}) Result | |
val minPV: a:ProtocolVersion -> b:ProtocolVersion -> c:ProtocolVersion | |
val geqPV: a:ProtocolVersion -> b:ProtocolVersion -> r:bool | |
val somePV: a: ProtocolVersion -> b:ProtocolVersion option {b = Some(a)} | |
predicate val IsNullCiphersuite: cipherSuite -> bool | |
private definition !x. IsNullCiphersuite(x) <=> x = NullCipherSuite | |
val nullCipherSuite: c:cipherSuite{IsNullCiphersuite(c)} | |
val isNullCipherSuite: c:cipherSuite -> r:bool{r=true <=> IsNullCiphersuite(c)} | |
predicate val IsSCSVCiphersuite: cipherSuite -> bool | |
private definition !x. IsSCSVCiphersuite(x) <=> ?z. x = SCSV(z) | |
val isAnonCipherSuite: cipherSuite -> bool | |
val isDHCipherSuite: cipherSuite -> bool | |
val isDHECipherSuite: cipherSuite -> bool | |
val isECDHECipherSuite: cipherSuite -> bool | |
val isRSACipherSuite: cipherSuite -> bool | |
val isOnlyMACCipherSuite: cipherSuite -> bool | |
val contains_TLS_EMPTY_RENEGOTIATION_INFO_SCSV: cipherSuites -> bool | |
val verifyDataLen_of_ciphersuite: cipherSuite -> nat | |
function val CiphersuitePrfMacAlg: cipherSuite -> macAlg | |
private definition | |
(!a,b,c. CiphersuitePrfMacAlg( CipherSuite ( a , CS_MtE ( b , c )) ) = MA_HMAC(SHA256) ) /\ | |
(!a,b, hAlg. CiphersuitePrfMacAlg( CipherSuite ( a , CS_AEAD ( b , hAlg )) ) = MA_HMAC(hAlg) ) /\ | |
(!a, hAlg. CiphersuitePrfMacAlg( OnlyMACCipherSuite (a, hAlg) ) = MA_HMAC(SHA256) ) | |
val prfMacAlg_of_ciphersuite: cs:cipherSuite -> ma:macAlg { ma=CiphersuitePrfMacAlg(cs) } | |
val verifyDataHashAlg_of_ciphersuite: cs:cipherSuite -> hashAlg | |
val sessionHashAlg: ProtocolVersion -> cipherSuite -> hashAlg | |
// we rely on these labels being pairwise distinct to justify domain separation | |
// (but the corresponding refinements are ignored by F7) | |
type prflabel = b:bytes { b=Utf8("master secret") \/ b=Utf8("extended master secret") \/ b=Utf8("key expansion") } | |
val extract_label: l:prflabel {l=Utf8("master secret")} | |
val extended_extract_label: l:prflabel {l=Utf8("extended master secret")} | |
val kdf_label: l:prflabel {l=Utf8("key expansion")} | |
// We need descriptors for the algorithm keyed by PMS and MS (named "PRF" in TLS) | |
// Given pv and cs, and except for SSL3, | |
// the same algorithm is used for extraction, key derivation, and verifyData | |
// | |
// Specified here rather than in TLSPRF as these algorithm names are used in indexes | |
type prePrfAlg = | |
| PRF_SSL3_nested // MD5(SHA1(...)) for extraction and keygen | |
| PRF_SSL3_concat // MD5 @| SHA1 for VerifyData tags | |
| PRF_TLS_1p01 of prflabel // MD5 xor SHA1 | |
| PRF_TLS_1p2 of prflabel * macAlg // typically SHA256 but may depend on CS | |
type kefAlg = pa:prePrfAlg | |
{ | |
pa=PRF_SSL3_nested \/ | |
pa=PRF_TLS_1p01(extract_label) \/ | |
pa=PRF_TLS_1p01(extended_extract_label) \/ | |
(?ma. pa=PRF_TLS_1p2(extract_label,ma)) \/ | |
(?ma. pa=PRF_TLS_1p2(extended_extract_label,ma)) } | |
type kdfAlg = pa:prePrfAlg | |
{ | |
pa=PRF_SSL3_nested \/ | |
pa=PRF_TLS_1p01(kdf_label) \/ | |
(?ma. pa=PRF_TLS_1p2(kdf_label,ma))} | |
type vdAlg = ProtocolVersion * cipherSuite | |
function val TLSMACAlg: hashAlg * ProtocolVersion -> macAlg | |
function val TLSENCAlg: cipherAlg * ProtocolVersion -> encAlg | |
private definition !mac. TLSMACAlg(mac,SSL_3p0) = MA_SSLKHASH(mac) | |
private definition !mac. TLSMACAlg(mac,TLS_1p0) = MA_HMAC(mac) | |
private definition !mac. TLSMACAlg(mac,TLS_1p1) = MA_HMAC(mac) | |
private definition !mac. TLSMACAlg(mac,TLS_1p2) = MA_HMAC(mac) | |
private definition !pv. TLSENCAlg(RC4_128,pv) = Stream_RC4_128 | |
private definition TLSENCAlg(AES_128_CBC, SSL_3p0) = CBC_Stale(AES_128) | |
private definition TLSENCAlg(AES_128_CBC, TLS_1p0) = CBC_Stale(AES_128) | |
private definition TLSENCAlg(AES_128_CBC, TLS_1p1) = CBC_Fresh(AES_128) | |
private definition TLSENCAlg(AES_128_CBC, TLS_1p2) = CBC_Fresh(AES_128) | |
private definition TLSENCAlg(AES_256_CBC, SSL_3p0) = CBC_Stale(AES_256) | |
private definition TLSENCAlg(AES_256_CBC, TLS_1p0) = CBC_Stale(AES_256) | |
private definition TLSENCAlg(AES_256_CBC, TLS_1p1) = CBC_Fresh(AES_256) | |
private definition TLSENCAlg(AES_256_CBC, TLS_1p2) = CBC_Fresh(AES_256) | |
private definition TLSENCAlg(TDES_EDE_CBC,SSL_3p0) = CBC_Stale(TDES_EDE) | |
private definition TLSENCAlg(TDES_EDE_CBC,TLS_1p0) = CBC_Stale(TDES_EDE) | |
private definition TLSENCAlg(TDES_EDE_CBC,TLS_1p1) = CBC_Fresh(TDES_EDE) | |
private definition TLSENCAlg(TDES_EDE_CBC,TLS_1p2) = CBC_Fresh(TDES_EDE) | |
function val CipherSuiteSigAlg: cipherSuite -> sigAlg | |
private definition | |
(!a. CipherSuiteSigAlg(CipherSuite(DHE_DSS, a)) = SA_DSA) /\ | |
(!a. CipherSuiteSigAlg(CipherSuite(DHE_RSA, a)) = SA_RSA) /\ | |
(!a. CipherSuiteSigAlg(CipherSuite(DH_DSS, a)) = SA_DSA) /\ | |
(!a. CipherSuiteSigAlg(CipherSuite(DH_RSA, a)) = SA_RSA) /\ | |
(!a. CipherSuiteSigAlg(CipherSuite(RSA, a)) = SA_RSA) /\ | |
(!a. CipherSuiteSigAlg(OnlyMACCipherSuite(RSA, a)) = SA_RSA) | |
function val CipherSuiteSigHashAlg: cipherSuite -> sigHashAlg | |
function val CipherSuiteMACAlg: cipherSuite * ProtocolVersion -> macAlg | |
function val CipherSuiteENCAlg: cipherSuite * ProtocolVersion -> encAlg | |
function val CipherSuiteAuthEncAlg: cipherSuite * ProtocolVersion -> aeAlg | |
private definition !kex,mac,pv. | |
CipherSuiteAuthEncAlg(OnlyMACCipherSuite(kex,mac),pv) = MACOnly(TLSMACAlg(mac,pv)) | |
function val CipherSuiteKEXAlg: cipherSuite -> kexAlg | |
private definition !kex,ae. | |
CipherSuiteKEXAlg(CipherSuite(kex,ae)) = kex | |
private definition !kex,mac,pv. | |
CipherSuiteAuthEncAlg(OnlyMACCipherSuite(kex,mac),pv) = MACOnly(TLSMACAlg(mac,pv)) | |
private definition !kex,enc,mac,pv. | |
CipherSuiteAuthEncAlg(CipherSuite(kex,CS_MtE(enc,mac)),pv) = MtE(TLSENCAlg(enc,pv),TLSMACAlg(mac,pv)) | |
private definition !kex,ae,prf,pv. | |
CipherSuiteAuthEncAlg(CipherSuite(kex,CS_AEAD(ae,prf)),pv) = AEAD(ae,TLSMACAlg(prf,pv)) | |
function val AEMacAlg: aeAlg -> macAlg | |
definition !mac. AEMacAlg(MACOnly(mac)) = mac | |
definition !mac,enc. AEMacAlg(MtE(enc,mac)) = mac | |
function val AEEncAlg: aeAlg -> encAlg | |
definition !enc,mac. AEEncAlg(MtE(enc,mac)) = enc | |
definition !cs,pv. CipherSuiteMACAlg(cs,pv) = AEMacAlg(CipherSuiteAuthEncAlg(cs,pv)) | |
definition !cs,pv. CipherSuiteENCAlg(cs,pv) = AEEncAlg(CipherSuiteAuthEncAlg(cs,pv)) | |
ask !cs,pv,mac. CipherSuiteAuthEncAlg(cs,pv) = MACOnly(mac) => CipherSuiteMACAlg(cs,pv) = mac | |
ask !cs,pv,mac,enc. CipherSuiteAuthEncAlg(cs,pv) = MtE(enc,mac) => CipherSuiteMACAlg(cs,pv) = mac | |
ask !cs,pv,mac,enc. CipherSuiteAuthEncAlg(cs,pv) = MtE(enc,mac) => CipherSuiteENCAlg(cs,pv) = enc | |
private val tlsEncAlg: c:cipherAlg -> pv:ProtocolVersion -> e:encAlg{e = TLSENCAlg(c,pv)} | |
private val tlsMacAlg: c:hashAlg -> pv:ProtocolVersion -> e:macAlg{e = TLSMACAlg(c,pv)} | |
val mk_aeAlg: cs:cipherSuite -> pv:ProtocolVersion -> a:aeAlg{a = CipherSuiteAuthEncAlg(cs,pv)} | |
val encAlg_of_aeAlg: a:aeAlg -> e:encAlg{e=AEEncAlg(a)} | |
val macAlg_of_aeAlg: a:aeAlg -> m:macAlg{m=AEMacAlg(a)} | |
val macAlg_of_ciphersuite: cs:cipherSuite -> pv:ProtocolVersion -> h:macAlg{h = CipherSuiteMACAlg(cs,pv)} | |
val encAlg_of_ciphersuite: cs:cipherSuite -> pv:ProtocolVersion -> c:encAlg{c = CipherSuiteENCAlg(cs,pv)} | |
val sigAlg_of_ciphersuite: cs:cipherSuite -> s:sigAlg{s = CipherSuiteSigAlg(cs)} | |
function val CipherSuiteBytes: cipherSuite -> cbytes | |
private assume | |
CipherSuiteBytes(NullCipherSuite) = [| 0x00uy; 0x00uy |] | |
/\ CipherSuiteBytes(OnlyMACCipherSuite (RSA, MD5)) = [| 0x00uy; 0x01uy |] | |
/\ CipherSuiteBytes(OnlyMACCipherSuite (RSA, SHA)) = [| 0x00uy; 0x02uy |] | |
/\ CipherSuiteBytes(OnlyMACCipherSuite (RSA, SHA256)) = [| 0x00uy; 0x3Buy |] | |
/\ CipherSuiteBytes(CipherSuite (RSA, CS_MtE (RC4_128, MD5))) = [| 0x00uy; 0x04uy |] | |
/\ CipherSuiteBytes(CipherSuite (RSA, CS_MtE (RC4_128, SHA))) = [| 0x00uy; 0x05uy |] | |
/\ CipherSuiteBytes(CipherSuite (RSA, CS_MtE (TDES_EDE_CBC, SHA))) = [| 0x00uy; 0x0Auy |] | |
/\ CipherSuiteBytes(CipherSuite (RSA, CS_MtE (AES_128_CBC, SHA))) = [| 0x00uy; 0x2Fuy |] | |
/\ CipherSuiteBytes(CipherSuite (RSA, CS_MtE (AES_256_CBC, SHA))) = [| 0x00uy; 0x35uy |] | |
/\ CipherSuiteBytes(CipherSuite (RSA, CS_MtE (AES_128_CBC, SHA256))) = [| 0x00uy; 0x3Cuy |] | |
/\ CipherSuiteBytes(CipherSuite (RSA, CS_MtE (AES_256_CBC, SHA256))) = [| 0x00uy; 0x3Duy |] | |
/\ CipherSuiteBytes(CipherSuite (DH_DSS, CS_MtE (TDES_EDE_CBC, SHA))) = [| 0x00uy; 0x0Duy |] | |
/\ CipherSuiteBytes(CipherSuite (DH_RSA, CS_MtE (TDES_EDE_CBC, SHA))) = [| 0x00uy; 0x10uy |] | |
/\ CipherSuiteBytes(CipherSuite (DHE_DSS, CS_MtE (TDES_EDE_CBC, SHA))) = [| 0x00uy; 0x13uy |] | |
/\ CipherSuiteBytes(CipherSuite (DHE_RSA, CS_MtE (TDES_EDE_CBC, SHA))) = [| 0x00uy; 0x16uy |] | |
/\ CipherSuiteBytes(CipherSuite (DH_DSS, CS_MtE (AES_128_CBC, SHA))) = [| 0x00uy; 0x30uy |] | |
/\ CipherSuiteBytes(CipherSuite (DH_RSA, CS_MtE (AES_128_CBC, SHA))) = [| 0x00uy; 0x31uy |] | |
/\ CipherSuiteBytes(CipherSuite (DHE_DSS, CS_MtE (AES_128_CBC, SHA))) = [| 0x00uy; 0x32uy |] | |
/\ CipherSuiteBytes(CipherSuite (DHE_RSA, CS_MtE (AES_128_CBC, SHA))) = [| 0x00uy; 0x33uy |] | |
/\ CipherSuiteBytes(CipherSuite (DH_DSS, CS_MtE (AES_256_CBC, SHA))) = [| 0x00uy; 0x36uy |] | |
/\ CipherSuiteBytes(CipherSuite (DH_RSA, CS_MtE (AES_256_CBC, SHA))) = [| 0x00uy; 0x37uy |] | |
/\ CipherSuiteBytes(CipherSuite (DHE_DSS, CS_MtE (AES_256_CBC, SHA))) = [| 0x00uy; 0x38uy |] | |
/\ CipherSuiteBytes(CipherSuite (DHE_RSA, CS_MtE (AES_256_CBC, SHA))) = [| 0x00uy; 0x39uy |] | |
/\ CipherSuiteBytes(CipherSuite (DH_DSS, CS_MtE (AES_128_CBC, SHA256))) = [| 0x00uy; 0x3Euy |] | |
/\ CipherSuiteBytes(CipherSuite (DH_RSA, CS_MtE (AES_128_CBC, SHA256))) = [| 0x00uy; 0x3Fuy |] | |
/\ CipherSuiteBytes(CipherSuite (DHE_DSS, CS_MtE (AES_128_CBC, SHA256))) = [| 0x00uy; 0x40uy |] | |
/\ CipherSuiteBytes(CipherSuite (DHE_RSA, CS_MtE (AES_128_CBC, SHA256))) = [| 0x00uy; 0x67uy |] | |
/\ CipherSuiteBytes(CipherSuite (DH_DSS, CS_MtE (AES_256_CBC, SHA256))) = [| 0x00uy; 0x68uy |] | |
/\ CipherSuiteBytes(CipherSuite (DH_RSA, CS_MtE (AES_256_CBC, SHA256))) = [| 0x00uy; 0x69uy |] | |
/\ CipherSuiteBytes(CipherSuite (DHE_DSS, CS_MtE (AES_256_CBC, SHA256))) = [| 0x00uy; 0x6Auy |] | |
/\ CipherSuiteBytes(CipherSuite (DHE_RSA, CS_MtE (AES_256_CBC, SHA256))) = [| 0x00uy; 0x6Buy |] | |
/\ CipherSuiteBytes(CipherSuite (DH_anon, CS_MtE (RC4_128, MD5))) = [| 0x00uy; 0x18uy |] | |
/\ CipherSuiteBytes(CipherSuite (DH_anon, CS_MtE (TDES_EDE_CBC, SHA))) = [| 0x00uy; 0x1Buy |] | |
/\ CipherSuiteBytes(CipherSuite (DH_anon, CS_MtE (AES_128_CBC, SHA))) = [| 0x00uy; 0x34uy |] | |
/\ CipherSuiteBytes(CipherSuite (DH_anon, CS_MtE (AES_256_CBC, SHA))) = [| 0x00uy; 0x3Auy |] | |
/\ CipherSuiteBytes(CipherSuite (DH_anon, CS_MtE (AES_128_CBC, SHA256))) = [| 0x00uy; 0x6Cuy |] | |
/\ CipherSuiteBytes(CipherSuite (DH_anon, CS_MtE (AES_256_CBC, SHA256))) = [| 0x00uy; 0x6Duy |] | |
/\ CipherSuiteBytes(CipherSuite (RSA, CS_AEAD(AES_128_GCM, SHA256))) = [| 0x00uy; 0x9Cuy |] | |
/\ CipherSuiteBytes(CipherSuite (RSA, CS_AEAD(AES_256_GCM, SHA384))) = [| 0x00uy; 0x9Duy |] | |
/\ CipherSuiteBytes(CipherSuite (DHE_RSA, CS_AEAD(AES_128_GCM, SHA256))) = [| 0x00uy; 0x9Euy |] | |
/\ CipherSuiteBytes(CipherSuite (DHE_RSA, CS_AEAD(AES_256_GCM, SHA384))) = [| 0x00uy; 0x9Fuy |] | |
/\ CipherSuiteBytes(CipherSuite (DH_RSA, CS_AEAD(AES_128_GCM, SHA256))) = [| 0x00uy; 0xA0uy |] | |
/\ CipherSuiteBytes(CipherSuite (DH_RSA, CS_AEAD(AES_256_GCM, SHA384))) = [| 0x00uy; 0xA1uy |] | |
/\ CipherSuiteBytes(CipherSuite (DHE_DSS, CS_AEAD(AES_128_GCM, SHA256))) = [| 0x00uy; 0xA2uy |] | |
/\ CipherSuiteBytes(CipherSuite (DHE_DSS, CS_AEAD(AES_256_GCM, SHA384))) = [| 0x00uy; 0xA3uy |] | |
/\ CipherSuiteBytes(CipherSuite (DH_DSS, CS_AEAD(AES_128_GCM, SHA256))) = [| 0x00uy; 0xA4uy |] | |
/\ CipherSuiteBytes(CipherSuite (DH_DSS, CS_AEAD(AES_256_GCM, SHA384))) = [| 0x00uy; 0xA5uy |] | |
/\ CipherSuiteBytes(CipherSuite (DH_anon, CS_AEAD(AES_128_GCM, SHA256))) = [| 0x00uy; 0xA6uy |] | |
/\ CipherSuiteBytes(CipherSuite (DH_anon, CS_AEAD(AES_256_GCM, SHA384))) = [| 0x00uy; 0xA7uy |] | |
/\ CipherSuiteBytes(SCSV (TLS_EMPTY_RENEGOTIATION_INFO_SCSV)) = [| 0x00uy; 0xFFuy |] | |
function val CipherSuitesBytes: cipherSuites -> cbytes | |
private definition | |
(CipherSuitesBytes([]) = [||]) /\ | |
(!h,t. CipherSuitesBytes(h::t) = CipherSuiteBytes(h) @| CipherSuitesBytes(t)) | |
private val consCipherSuites: cs:cipherSuite -> css:cipherSuites -> css':cipherSuites{css' = cs::css} | |
val cipherSuiteBytes: c:cipherSuite -> b:bytes{Length(b)=2 /\ B(b) = CipherSuiteBytes(c)} | |
val parseCipherSuite: b:bytes{Length(b)=2} -> (c:cipherSuite{B(b) = CipherSuiteBytes(c)}) Result | |
// this parsing function may fail if b has the wrong length, | |
// or if we were strict on unknown ciphersuites | |
val parseCipherSuites: b:bytes -> (css:cipherSuites) Result | |
// Similarly to compression methods we do not guarantee anything about the parsing of ciphersuites at the server | |
// As invalid bytes are ignored B(b) = CipherSuitesBytes(css) may not hold. | |
val cipherSuitesBytes: css:cipherSuites -> b:bytes {B(b) = CipherSuitesBytes(css)} | |
val mkIntTriple: (nat * nat * nat) -> (nat * nat * nat) | |
(* This type is not used for verification, just to run the | |
implementation and let the client refer to concrete ciphersuites *) | |
type cipherSuiteName = | |
| TLS_NULL_WITH_NULL_NULL | |
| TLS_RSA_WITH_NULL_MD5 | |
| TLS_RSA_WITH_NULL_SHA | |
| TLS_RSA_WITH_NULL_SHA256 | |
| TLS_RSA_WITH_RC4_128_MD5 | |
| TLS_RSA_WITH_RC4_128_SHA | |
| TLS_RSA_WITH_3DES_EDE_CBC_SHA | |
| TLS_RSA_WITH_AES_128_CBC_SHA | |
| TLS_RSA_WITH_AES_256_CBC_SHA | |
| TLS_RSA_WITH_AES_128_CBC_SHA256 | |
| TLS_RSA_WITH_AES_256_CBC_SHA256 | |
| TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA | |
| TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA | |
| TLS_DHE_DSS_WITH_AES_128_CBC_SHA | |
| TLS_DHE_RSA_WITH_AES_128_CBC_SHA | |
| TLS_DHE_DSS_WITH_AES_256_CBC_SHA | |
| TLS_DHE_RSA_WITH_AES_256_CBC_SHA | |
| TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 | |
| TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 | |
| TLS_DHE_DSS_WITH_AES_256_CBC_SHA256 | |
| TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 | |
| TLS_ECDHE_RSA_WITH_RC4_128_SHA | |
| TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA | |
| TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA | |
| TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 | |
| TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA | |
| TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 | |
| TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 | |
| TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 | |
| TLS_DH_anon_WITH_RC4_128_MD5 | |
| TLS_DH_anon_WITH_3DES_EDE_CBC_SHA | |
| TLS_DH_anon_WITH_AES_128_CBC_SHA | |
| TLS_DH_anon_WITH_AES_256_CBC_SHA | |
| TLS_DH_anon_WITH_AES_128_CBC_SHA256 | |
| TLS_DH_anon_WITH_AES_256_CBC_SHA256 | |
| TLS_RSA_WITH_AES_128_GCM_SHA256 | |
| TLS_RSA_WITH_AES_256_GCM_SHA384 | |
| TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 | |
| TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 | |
| TLS_DH_RSA_WITH_AES_128_GCM_SHA256 | |
| TLS_DH_RSA_WITH_AES_256_GCM_SHA384 | |
| TLS_DHE_DSS_WITH_AES_128_GCM_SHA256 | |
| TLS_DHE_DSS_WITH_AES_256_GCM_SHA384 | |
| TLS_DH_DSS_WITH_AES_128_GCM_SHA256 | |
| TLS_DH_DSS_WITH_AES_256_GCM_SHA384 | |
| TLS_DH_anon_WITH_AES_128_GCM_SHA256 | |
| TLS_DH_anon_WITH_AES_256_GCM_SHA384 | |
val cipherSuite_of_name: cipherSuiteName -> cipherSuite | |
val cipherSuites_of_nameList: cipherSuiteName list -> cipherSuites | |
val name_of_cipherSuite: cipherSuite -> cipherSuiteName Result | |
val names_of_cipherSuites: cipherSuites -> (cipherSuiteName list) Result | |
type preContentType = | |
| Change_cipher_spec | |
| Alert | |
| Handshake | |
| Application_data | |
type ContentType = ct:preContentType | |
{ct = Change_cipher_spec \/ ct = Alert \/ | |
ct = Handshake \/ ct = Application_data} | |
// to be relocated to some other library | |
val bytes_of_seq: sn:nat -> b:bytes{Length(b) = 8 /\ b = IntBytes(8,sn)} | |
val seq_of_bytes: b:bytes{Length(b)=8} -> sn:nat{b = IntBytes(8,sn)} | |
function val CTBytes: ContentType -> cbytes | |
assume !c. BLength(CTBytes(c)) = 1 | |
private definition CTBytes(Change_cipher_spec) = [|20uy|] | |
private definition CTBytes(Alert) = [|21uy|] | |
private definition CTBytes(Handshake) = [|22uy|] | |
private definition CTBytes(Application_data) = [|23uy|] | |
val ctBytes: ct:ContentType -> b:bytes{B(b)=CTBytes(ct)} | |
val parseCT: b:bytes {Length(b)=1} -> (ct:ContentType{B(b)=CTBytes(ct)}) Result | |
val ctToString: ContentType -> string | |
// binary format for length-prefixed bytes; | |
// the integer is the length of the prefix (1, 2, 3 or 4 for TLS) | |
function val VLBytes: (nat * cbytes) -> cbytes | |
definition !i,b. VLBytes(i,b) = B(IntBytes(i,BLength(b))) @| b | |
ask !i,b,b'. VLBytes(i,b) = VLBytes(i,b') => b = b' | |
val vlbytes: l:nat -> b:bytes -> r:bytes {B(r)=VLBytes(l,B(b))} | |
val vlsplit: | |
l:nat{l<=8} -> b:bytes{Length(b)>=l} -> | |
( b1:bytes * b2:bytes {B(b) = VLBytes(l,B(b1)) @| B(b2)}) Result | |
val vlparse: | |
l:nat{l<=8} -> b:bytes{Length(b)>=l} -> | |
( r:bytes { B(b) = VLBytes(l,B(r)) }) Result | |
// nice to have, not used so far. F7 needs a little help. | |
// | |
// ask !i,b. BLength(VLBytes(i,b)) = BLength(B(IntBytes(i,BLength(b))) @| b) | |
// ask !i,b. BLength(B(IntBytes(i,BLength(b))) @| b) = BLength(B(IntBytes(i,BLength(b)))) + BLength(b) | |
// ask !i,b. BLength(B(IntBytes(i,BLength(b)))) + BLength(b) = Length(IntBytes(i,BLength(b))) + BLength(b) | |
// ask !i,b. Length(IntBytes(i,BLength(b))) + BLength(b) = i + BLength(b) | |
ask !i,b. BLength(B(IntBytes(i,BLength(b))) @| b) = i + BLength(b) | |
ask !i,b. BLength(VLBytes(i,b)) = i + BLength(b) | |
// relies on associativity | |
theorem !i,b1,b2,c1,c2. | |
i >= 0 => | |
(VLBytes(i,b1) @| b2 = VLBytes(i,c1) @| c2) => (b1 = c1 /\ b2 = c2) | |
// cert-type parsing / formatting | |
type certType = | |
| RSA_sign | |
| DSA_sign | |
| RSA_fixed_dh | |
| DSA_fixed_dh | |
function val CertTypeBytes: certType -> cbytes | |
private definition CertTypeBytes(RSA_sign) = [|1uy|] | |
private definition CertTypeBytes(DSA_sign) = [|2uy|] | |
private definition CertTypeBytes(RSA_fixed_dh) = [|3uy|] | |
private definition CertTypeBytes(DSA_fixed_dh) = [|4uy|] | |
val certTypeBytes: ct:certType -> b:bytes {B(b)=CertTypeBytes(ct)} | |
val parseCertType: b:bytes -> (ct:certType {B(b)=CertTypeBytes(ct)}) Result | |
function val CertTypesBytes: certType list -> cbytes | |
private definition !h,t. | |
CertTypesBytes([]) = [||] /\ | |
CertTypesBytes(h::t) = CertTypeBytes(h) @| CertTypesBytes(t) | |
val certificateTypeListBytes: ctl:certType list -> | |
b:bytes{B(b)=CertTypesBytes(ctl)} | |
val parseCertificateTypeList: b:bytes -> | |
ctl:certType list{ | |
} | |
function val DefaultCertTypes: bool * cipherSuite -> certType list | |
private definition | |
(!cs. CipherSuiteSigAlg(cs) = SA_DSA => DefaultCertTypes(false,cs) = [DSA_fixed_dh]) /\ | |
(!cs. CipherSuiteSigAlg(cs) = SA_DSA => DefaultCertTypes(true ,cs) = [DSA_sign]) /\ | |
(!cs. CipherSuiteSigAlg(cs) = SA_RSA => DefaultCertTypes(false,cs) = [RSA_fixed_dh]) /\ | |
(!cs. CipherSuiteSigAlg(cs) = SA_RSA => DefaultCertTypes(true ,cs) = [RSA_sign]) | |
val defaultCertTypes: sign:bool -> cs:cipherSuite -> ctl:certType list{ctl=DefaultCertTypes(sign,cs)} | |
function val DistinguishedNameListBytes: string list -> cbytes | |
definition DistinguishedNameListBytes([]) = [||] | |
definition !h,t. DistinguishedNameListBytes(h::t) = VLBytes(2,B(Utf8(h))) @| DistinguishedNameListBytes(t) | |
function val DistinguishedNamesBytes: string list -> cbytes | |
private definition !l. DistinguishedNamesBytes(l) = VLBytes(2,DistinguishedNameListBytes(l)) | |
val distinguishedNameListBytes: n:string list -> b:bytes{B(b)=DistinguishedNameListBytes(n)} | |
val parseDistinguishedNameList: b:bytes -> s:string list -> | |
(res:string list{ | |
}) Result |