RFC 5246
The Transport Layer Security (TLS) Protocol Version 1.2
RFC 5246: The Transport Layer Security (TLS) Protocol Version 1.2 ๐
okay so this is the big TLS 1.2 spec, and it's giving main character energy ๐ Here's the tea:
- Authors: T. Dierks (Independent) and E. Rescorla (RTFM, Inc.)
- Category: Standards Track
- Date: August 2008
- Obsoletes: RFCs 3268, 4346, and 4366
- Updates: RFC 4492
Status of This Memo ๐
This doc is an Internet standards track protocol for the Internet community, and it's literally asking for discussion and suggestions for improvements ๐ฌ For the standardization state and status of this protocol, check the current edition of the "Internet Official Protocol Standards" (STD 1). Distribution of this memo is unlimited ๐
Abstract โจ
This doc specifies Version 1.2 of the Transport Layer Security (TLS) protocol. TLS gives communications security over the Internet ๐ It lets client/server apps talk in a way that's designed to prevent eavesdropping, tampering, or message forgery. No drama allowed ๐
Table of Contents ๐
1. Introduction ....................................................4
1.1. Requirements Terminology ...................................5
1.2. Major Differences from TLS 1.1 .............................5
2. Goals ...........................................................6
3. Goals of This Document ..........................................7
4. Presentation Language ...........................................7
4.1. Basic Block Size ...........................................7
4.2. Miscellaneous ..............................................8
4.3. Vectors ....................................................8
4.4. Numbers ....................................................9
4.5. Enumerateds ................................................9
4.6. Constructed Types .........................................10
4.6.1. Variants ...........................................10
4.7. Cryptographic Attributes ..................................12
4.8. Constants .................................................14
5. HMAC and the Pseudorandom Function .............................14
6. The TLS Record Protocol ........................................15
6.1. Connection States .........................................16
6.2. Record Layer ..............................................19
6.2.1. Fragmentation ......................................19
6.2.2. Record Compression and Decompression ...............20
6.2.3. Record Payload Protection ..........................21
6.2.3.1. Null or Standard Stream Cipher ............22
6.2.3.2. CBC Block Cipher ..........................22
6.2.3.3. AEAD Ciphers ..............................24
6.3. Key Calculation ...........................................25
7. The TLS Handshaking Protocols ..................................26
7.1. Change Cipher Spec Protocol ...............................27
7.2. Alert Protocol ............................................28
7.2.1. Closure Alerts .....................................29
7.2.2. Error Alerts .......................................30
7.3. Handshake Protocol Overview ...............................33
7.4. Handshake Protocol ........................................37
7.4.1. Hello Messages .....................................38
7.4.1.1. Hello Request .............................38
7.4.1.2. Client Hello ..............................39
7.4.1.3. Server Hello ..............................42
7.4.1.4. Hello Extensions ..........................44
7.4.1.4.1. Signature Algorithms ...........45
7.4.2. Server Certificate .................................47
7.4.3. Server Key Exchange Message ........................50
7.4.4. Certificate Request ................................53
7.4.5. Server Hello Done ..................................55
7.4.6. Client Certificate .................................55
7.4.7. Client Key Exchange Message ........................57
7.4.7.1. RSA-Encrypted Premaster Secret Message ....58
7.4.7.2. Client Diffie-Hellman Public Value ........61
7.4.8. Certificate Verify .................................62
7.4.9. Finished ...........................................63
8. Cryptographic Computations .....................................64
8.1. Computing the Master Secret ...............................64
8.1.1. RSA ................................................65
8.1.2. Diffie-Hellman .....................................65
9. Mandatory Cipher Suites ........................................65
10. Application Data Protocol .....................................65
11. Security Considerations .......................................65
12. IANA Considerations ...........................................65
Appendix A. Protocol Data Structures and Constant Values ..........68
A.1. Record Layer ..............................................68
A.2. Change Cipher Specs Message ...............................69
A.3. Alert Messages ............................................69
A.4. Handshake Protocol ........................................70
A.4.1. Hello Messages .....................................71
A.4.2. Server Authentication and Key Exchange Messages ....72
A.4.3. Client Authentication and Key Exchange Messages ....74
A.4.4. Handshake Finalization Message .....................74
A.5. The Cipher Suite ..........................................75
A.6. The Security Parameters ...................................77
A.7. Changes to RFC 4492 .......................................78
Appendix B. Glossary ..............................................78
Appendix C. Cipher Suite Definitions ..............................83
Appendix D. Implementation Notes ..................................85
D.1. Random Number Generation and Seeding ......................85
D.2. Certificates and Authentication ...........................85
D.3. Cipher Suites .............................................85
D.4. Implementation Pitfalls ...................................85
Appendix E. Backward Compatibility ................................87
E.1. Compatibility with TLS 1.0/1.1 and SSL 3.0 ................87
E.2. Compatibility with SSL 2.0 ................................88
E.3. Avoiding Man-in-the-Middle Version Rollback ...............90
Appendix F. Security Analysis .....................................91
F.1. Handshake Protocol ........................................91
F.1.1. Authentication and Key Exchange ....................91
F.1.1.1. Anonymous Key Exchange ....................91
F.1.1.2. RSA Key Exchange and Authentication .......92
F.1.1.3. Diffie-Hellman Key Exchange with
Authentication ............................92
F.1.2. Version Rollback Attacks ...........................93
F.1.3. Detecting Attacks Against the Handshake Protocol ...94
F.1.4. Resuming Sessions ..................................94
F.2. Protecting Application Data ...............................94
F.3. Explicit IVs ..............................................95
F.4. Security of Composite Cipher Modes ........................95
F.5. Denial of Service .........................................96
F.6. Final Notes ...............................................96
Normative References ..............................................97
Informative References ............................................98
Working Group Information ........................................101
Contributors .....................................................101
1. Introduction โจ
okay so the big goal of TLS is to give privacy and data integrity between two communicating apps ๐ซถ It's built out of two layers: the TLS Record Protocol and the TLS Handshake Protocol. Down at the bottom, sitting on top of some reliable transport protocol (e.g., TCP [TCP]), is the TLS Record Protocol. It gives the connection two basic properties:
- The connection is private ๐ Symmetric cryptography handles the data encryption (e.g., AES [AES], RC4 [SCH], etc.). The keys for that encryption get generated uniquely for each connection, based on a secret that was negotiated by another protocol (like the TLS Handshake Protocol). The Record Protocol can also be used without encryption, which is lowkey wild.
- The connection is reliable ๐ฏ Message transport comes with a message integrity check that uses a keyed MAC. Secure hash functions (e.g., SHA-1, etc.) are used for the MAC computations. The Record Protocol can operate without a MAC, but it's generally only used that way while another protocol is using the Record Protocol as a transport for negotiating security parameters.
The TLS Record Protocol is used to wrap up various higher-level protocols ๐ One of those wrapped protocols is the TLS Handshake Protocol, which lets the server and client authenticate each other and negotiate an encryption algorithm and cryptographic keys before the application protocol sends or receives its first byte of data. The TLS Handshake Protocol gives the connection three basic properties:
- The peer's identity can be authenticated using asymmetric, or public key, cryptography (e.g., RSA [RSA], DSA [DSS], etc.) ๐ชช This authentication can be made optional, but it's generally required for at least one of the peers.
- The negotiation of a shared secret is secure. The negotiated secret is unavailable to eavesdroppers, and for any authenticated connection the secret cannot be obtained, even by an attacker who can place himself in the middle of the connection ๐ โโ๏ธ
- The negotiation is reliable. No attacker can modify the negotiation communication without being detected by the parties to the communication ๐จ
One advantage of TLS is that it's application protocol independent ๐ฆ Higher-level protocols can layer on top of TLS transparently. The TLS standard, however, doesn't specify how protocols add security with TLS. The decisions on how to start TLS handshaking and how to interpret the authentication certificates that get exchanged are left to the judgment of the designers and implementors of the protocols that run on top of TLS ๐ง
1.1. Requirements Terminology ๐
ngl this part is so important. The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this doc are to be read as described in RFC 2119 [REQ] ๐
1.2. Major Differences from TLS 1.1 โจ
okay so this doc is a glow-up of TLS 1.1 [TLS1.1] ๐ the big vibe is more flexibility, especially when it comes to negotiating crypto algorithms. here's the tea:
- the MD5/SHA-1 combo in the pseudorandom function (PRF) got replaced with PRFs that each cipher suite specifies ๐ซถ every cipher suite in this doc uses P_SHA256.
- the MD5/SHA-1 combo in the digitally-signed element got swapped for a single hash. signed elements now have a field that explicitly says which hash algorithm was used ๐ฅ
- the client and server got a serious cleanup for telling each other which hash and signature algorithms they'll accept ๐ ngl this also loosens some of the rules on signature and hash algorithms from earlier TLS versions.
- authenticated encryption with additional data modes are now supported โจ
- TLS Extensions and AES Cipher Suites got merged in from [TLSEXT] and [TLSAES] ๐ฆ
- EncryptedPreMasterSecret version numbers get checked more tightly ๐
- a bunch of requirements got tightened up ๐
- verify_data length now depends on the cipher suite (the default is still 12) ๐ธ
- the Bleichenbacher/Klima attack defenses got a cleaner description ๐ง
- alerts MUST now be sent in many cases ๐ญ this one's a big deal
- after a certificate_request, if no certificates are available, clients now MUST send an empty certificate list ๐
TLS_RSA_WITH_AES_128_CBC_SHAis now the mandatory-to-implement cipher suite ๐- HMAC-SHA256 cipher suites were added ๐
- the IDEA and DES cipher suites got removed ๐ they're deprecated now and will be documented in a separate document
- support for the SSLv2 backward-compatible hello is now a MAY, not a SHOULD, and sending it is a SHOULD NOT ๐ฅบ support will probably become a SHOULD NOT in the future
- the presentation language got limited "fall-through" so multiple case arms can share the same encoding ๐
- there's a brand new Implementation Pitfalls section ๐ซง
- the usual clarifications and editorial polish, obviously ๐
2. Goals ๐
okay so the TLS goals, ranked by priority, are:
- Cryptographic security: TLS should be used to establish a secure connection between two parties. ๐
- Interoperability: independent programmers should be able to build applications using TLS that successfully exchange cryptographic parameters without knowing one another's code ๐ซถ
- Extensibility: TLS gives you a framework where new public key and bulk encryption methods can be plugged in as needed โจ this also does two sub-goals: it avoids needing a brand-new protocol (which could bring in fresh weaknesses ๐ฌ) and it means you don't have to implement a whole new security library ๐ง
- Relative efficiency: crypto ops are super CPU-heavy, especially public key stuff ๐ฅ so TLS has an optional session caching scheme to cut down on how many connections have to be set up from scratch ๐ธ and care was taken to reduce network activity too ๐ฆ
3. Goals of This Document ๐
this doc and TLS itself are based on the SSL 3.0 Protocol Specification as published by Netscape ๐ the differences from SSL 3.0 aren't dramatic, but they're big enough that the various TLS and SSL 3.0 versions don't interoperate (though each protocol has a way for an implementation to back down to older versions ๐).
this doc is mainly for people implementing the protocol and for people doing cryptographic analysis of it ๐ฉโ๐ป the spec was written with those two groups in mind, so lots of the algorithm-dependent data structures and rules live in the body of the text instead of an appendix, which makes them way easier to find ๐
this doc doesn't cover service or interface definitions ๐ โโ๏ธ it does cover select policy areas where they're needed for solid security ๐
4. Presentation Language ๐ง
this doc is all about formatting data in an external representation ๐ we're using a super basic, kinda casually defined presentation syntax. it draws from a few sources. it looks like the C programming language and XDR [XDR] in its syntax, but it's risky to push the parallels too far ๐ this presentation language is only for documenting TLS. it has no general use beyond that ๐ซถ
4.1. Basic Block Size ๐งฉ
all data items are explicitly specified ๐ the basic data block size is one byte (that's 8 bits). multi-byte data items are concatenations of bytes, read from left to right and from top to bottom. from the byte stream, a multi-byte item (a numeric in the example) gets formed, using C notation, like this:
value = (byte[0] << 8*(n-1)) | (byte[1] << 8*(n-2)) |
... | byte[n-1];
this byte ordering for multi-byte values is the commonplace network byte order, aka big-endian format ๐ธ
4.2. Miscellaneous โจ
comments start with /* and end with */ ๐ฌ
optional components get wrapped in double brackets, [[ ]] ๐
single-byte entities holding uninterpreted data are type opaque ๐ซง
4.3. Vectors ๐ฆ
a vector (a single-dimensional array) is a stream of homogeneous data elements ๐ the size of a vector can be set at documentation time or left unspecified until runtime. either way, the length counts bytes, not elements ๐ here's the syntax for defining a new type, T', that's a fixed-length vector of type T:
T T'[n];
T' takes up n bytes in the data stream, where n is a multiple of the size of T ๐ง the vector's length doesn't get included in the encoded stream.
in this example, Datum is three consecutive bytes the protocol doesn't interpret, and Data is three consecutive Datum, which eats up nine bytes total ๐
opaque Datum[3]; /* three uninterpreted bytes */
Datum Data[9]; /* 3 consecutive 3 byte vectors */
variable-length vectors are defined by specifying an inclusive range of legal lengths, using the <floor..ceiling> notation ๐ when they're encoded, the actual length goes before the vector's contents in the byte stream. the length field is as many bytes as needed to hold the vector's specified maximum (ceiling) length. a variable-length vector whose actual length field is zero is called an empty vector ๐ซถ
T T'<floor..ceiling>;
in this example, mandatory is a vector that has to hold between 300 and 400 bytes of type opaque. it can never be empty ๐ญ its length field is two bytes, a uint16, which is enough to represent 400 (see Section 4.4). longer, on the other hand, can represent up to 800 bytes of data, or 400 uint16 elements, and it can be empty ๐ฆ its encoding includes a two-byte actual length field stuck on the front of the vector. the length of an encoded vector must be an even multiple of the length of a single element. for example, a 17-byte vector of uint16 would be illegal ๐ โโ๏ธ
opaque mandatory<300..400>;
/* length field is 2 bytes, cannot be empty */
uint16 longer<0..800>;
/* zero to 400 16-bit unsigned integers */
4.4. Numbers ๐ข
the basic numeric data type is an unsigned byte (uint8). all the bigger numeric types are built from fixed-length series of bytes concatenated as described in Section 4.1, and they're also unsigned ๐ these predefined numeric types exist:
uint8 uint16[2];
uint8 uint24[3];
uint8 uint32[4];
uint8 uint64[8];
every value here and everywhere else in the spec is stored in network byte (big-endian) order. for example, the uint32 represented by the hex bytes 01 02 03 04 is the same as the decimal value 16909060 ๐งฎ
sometimes (like with DH parameters) you have to represent integers as opaque vectors ๐ซง in those cases they're represented as unsigned integers, which means leading zero octets aren't required even when the most significant bit is set ๐ธ
4.5. Enumerateds ๐
there's an extra sparse data type called enum ๐ a field of type enum can only take the values declared in its definition. every definition is its own type, so only enumerateds of the same type can be assigned or compared ๐ every element of an enumerated must be assigned a value, like in this example. the elements aren't ordered, so they can get any unique value, in any order ๐งฉ
enum { e1(v1), e2(v2), ... , en(vn) [[, (n)]] } Te;
an enumerated takes up as much space in the byte stream as its maximal defined ordinal value would. this definition uses one byte for fields of type Color ๐
enum { red(3), blue(5), white(7) } Color;
you can optionally give a value without its tag to force the width without defining a superfluous element ๐ฆ
in this one, Taste eats two bytes in the data stream but can only be 1, 2, or 4 ๐
enum { sweet(1), sour(2), bitter(4), (32000) } Taste;
the names of an enumeration's elements are scoped inside the defined type. in the first example, a fully qualified reference to the second element would be Color.blue. that qualification isn't required when the assignment target is well specified ๐
Color color = Color.blue; /* overspecified, legal */
Color color = blue; /* correct, type implicit */
for enumerateds that never get converted to an external representation, the numerical info can be left out ๐ซถ
enum { low, medium, high } Amount;
4.6. Constructed Types ๐งฑ
you can build structure types out of primitive types for convenience โจ each specification declares a new, unique type. the definition syntax is a lot like C's ๐
struct {
T1 f1;
T2 f2;
...
Tn fn;
} [[T]];
fields inside a structure can be qualified with the type's name, kinda like enumerateds. for example, T.f2 refers to the second field of the previous declaration ๐ธ structure definitions can also be embedded ๐ช
4.6.1. Variants ๐
okay so structures can have variants ๐ based on some knowledge the environment already has. the selector has to be an enumerated type that lists the possible variants the structure defines. there must be a case arm for every element of the enumeration declared in the select. case arms get limited fall-through: if two case arms come right after each other with no fields in between, then they both contain the same fields. so in the example below, "orange" and "banana" both contain V2. this is a new piece of syntax in TLS 1.2 โจ
the body of the variant structure can be given a label for reference. how the variant actually gets picked at runtime is not prescribed by the presentation language ๐
struct {
T1 f1;
T2 f2;
....
Tn fn;
select (E) {
case e1: Te1;
case e2: Te2;
case e3: case e4: Te3;
....
case en: Ten;
} [[fv]];
} [[Tv]];
for example:
enum { apple, orange, banana } VariantTag;
struct {
uint16 number;
opaque string<0..10>; /* variable length */
} V1;
struct {
uint32 number;
opaque string[10]; /* fixed length */
} V2;
struct {
select (VariantTag) { /* value of selector is implicit */
case apple:
V1; /* VariantBody, tag = apple */
case orange:
case banana:
V2; /* VariantBody, tag = orange or banana */
} variant_body; /* optional label on variant */
} VariantRecord;
4.7. Cryptographic Attributes ๐ฆ
okay this part is giving cryptography main character energy ๐ฅ there are five cryptographic operations: digital signing, stream cipher encryption, block cipher encryption, authenticated encryption with additional data (AEAD) encryption, and public key encryption. they get labeled digitally-signed, stream-ciphered, block-ciphered, aead-ciphered, and public-key-encrypted, in that order. to say how a field gets its crypto processing, you put the right keyword in front of the field's type spec. the cryptographic keys are implied by the current session state (see Section 6.1) ๐
a digitally-signed element gets encoded as a struct called DigitallySigned:
struct {
SignatureAndHashAlgorithm algorithm;
opaque signature<0..2^16-1>;
} DigitallySigned;
the algorithm field says which algorithm got used (see Section 7.4.1.4.1 for the definition of this field). the algorithm field is new, so this is a change from earlier versions ๐ the signature is a digital signature made with those algorithms over the contents of the element. the contents themselves never show up on the wire, they just get calculated. the length of the signature depends on the signing algorithm and key.
in RSA signing, the opaque vector holds the signature made with the RSASSA-PKCS1-v1_5 signature scheme defined in [PKCS1]. as [PKCS1] talks about, the DigestInfo MUST be DER-encoded [X680] [X690]. for hash algorithms without parameters (which includes SHA-1), the DigestInfo.AlgorithmIdentifier.parameters field MUST be NULL, but implementations MUST accept both without parameters and with NULL parameters ๐ซถ earlier versions of TLS used a different RSA signature scheme that didn't include a DigestInfo encoding, so keep that in mind ๐
in DSA, the 20 bytes of the SHA-1 hash get run straight through the Digital Signing Algorithm with no extra hashing. this makes two values, r and s. the DSA signature is an opaque vector, same as above, and its contents are the DER encoding of:
Dss-Sig-Value ::= SEQUENCE {
r INTEGER,
s INTEGER
}
Note: in current terminology, DSA is the Digital Signature Algorithm and DSS is the NIST standard. in the original SSL and TLS specs, "DSS" was used for everything. this document uses "DSA" for the algorithm, "DSS" for the standard, and it keeps using "DSS" in the code point definitions for historical continuity ๐ฅน
in stream cipher encryption, the plaintext gets exclusive-ORed with an identical amount of output generated from a cryptographically secure keyed pseudorandom number generator ๐ธ
in block cipher encryption, every block of plaintext encrypts to a block of ciphertext. all block cipher encryption is done in CBC (Cipher Block Chaining) mode, and every item that's block-ciphered has to be an exact multiple of the cipher block length ๐
in AEAD encryption, the plaintext is encrypted and integrity protected at the same time โจ the input can be any length, and aead-ciphered output is usually bigger than the input, because it has to fit the integrity check value.
in public key encryption, a public key algorithm encrypts data so that only the matching private key can decrypt it. a public-key-encrypted element gets encoded as an opaque vector <0..2^16-1>, where the length depends on the encryption algorithm and key.
RSA encryption is done with the RSAES-PKCS1-v1_5 encryption scheme defined in [PKCS1] ๐
here's an example:
stream-ciphered struct {
uint8 field1;
uint8 field2;
digitally-signed opaque {
uint8 field3<0..255>;
uint8 field4;
};
} UserType;
the contents of the inner struct (field3 and field4) are used as input for the signature/hash algorithm, and then the whole structure gets encrypted with a stream cipher ๐ the length of this structure, in bytes, works out to two bytes for field1 and field2, plus two bytes for the signature and hash algorithm, plus two bytes for the length of the signature, plus the length of the output of the signing algorithm. the signature length is known because the algorithm and key used for signing are known before this structure gets encoded or decoded ๐ง
4.8. Constants ๐
you can define typed constants for specification purposes by declaring a symbol of the type you want and assigning values to it.
under-specified types (opaque, variable-length vectors, and structures that contain opaque) can't be assigned values ๐ โโ๏ธ and no fields of a multi-element structure or vector can be left out.
for example:
struct {
uint8 f1;
uint8 f2;
} Example1;
Example1 ex1 = {1, 4}; /* assigns f1 = 1, f2 = 4 */
5. HMAC and the Pseudorandom Function ๐
okay the TLS record layer uses a keyed Message Authentication Code (MAC) to protect message integrity ๐ก๏ธ the cipher suites defined in this document use a construction called HMAC, described in [HMAC], which is built on top of a hash function. other cipher suites MAY define their own MAC constructions, if needed.
there's also a construction needed to expand secrets into blocks of data for key generation or validation. this pseudorandom function (PRF) takes a secret, a seed, and an identifying label as input, and it gives back output of any length ๐ฆ
in this section we define one PRF, based on HMAC. this PRF with the SHA-256 hash function is used for all cipher suites defined in this document, and in TLS documents published before this one, whenever TLS 1.2 is negotiated. new cipher suites MUST explicitly specify a PRF and, in general, SHOULD use the TLS PRF with SHA-256 or a stronger standard hash function ๐ฅ
first up, we define a data expansion function, P_hash(secret, data), that uses one hash function to expand a secret and seed into any amount of output:
P_hash(secret, seed) = HMAC_hash(secret, A(1) + seed) +
HMAC_hash(secret, A(2) + seed) +
HMAC_hash(secret, A(3) + seed) + ...
where + means concatenation.
A() is defined as:
A(0) = seed
A(i) = HMAC_hash(secret, A(i-1))
P_hash can be iterated as many times as needed to make the amount of data you want ๐ฐ for example, if P_SHA256 is used to create 80 bytes of data, it has to be iterated three times (through A(3)), which creates 96 bytes of output. the last 16 bytes of the final iteration then get thrown away, leaving 80 bytes of output data.
TLS's PRF is created by applying P_hash to the secret like this:
PRF(secret, label, seed) = P_<hash>(secret, label + seed)
the label is an ASCII string. it should be included in the exact form it's given, without a length byte or a trailing null character ๐ง for example, the label "slithy toves" would be processed by hashing these bytes:
73 6C 69 74 68 79 20 74 6F 76 65 73
6. The TLS Record Protocol ๐ง
the TLS Record Protocol is a layered protocol ๐ at each layer, messages may include fields for length, description, and content. the Record Protocol takes messages to send, fragments the data into manageable blocks, optionally compresses it, applies a MAC, encrypts, and transmits the result. received data gets decrypted, verified, decompressed, and reassembled, and then delivered to higher-level clients.
four protocols use the record protocol in this document: the handshake protocol, the alert protocol, the change cipher spec protocol, and the application data protocol. to leave room for extending TLS, the record protocol can support additional record content types too. new record content type values get assigned by IANA in the TLS Content Type Registry, as described in Section 12 ๐
implementations MUST NOT send record types that aren't defined in this document unless some extension negotiated them. if a TLS implementation receives an unexpected record type, it MUST send an unexpected_message alert ๐จ
any protocol designed for use over TLS must be carefully designed to deal with every possible attack against it ๐ in practice, this means the protocol designer has to know what security properties TLS does and doesn't provide, and can't safely rely on the ones it doesn't.
one thing to note: the type and length of a record are not protected by encryption ๐ if that information is itself sensitive, application designers may want to take steps (padding, cover traffic) to minimize information leakage ๐
6.1. Connection States ๐
okay so a TLS connection state is basically the operating environment the TLS Record Protocol runs in ๐ It spells out the compression algorithm, the encryption algorithm, and the MAC algorithm, plus the parameters for all of them: the MAC key and the bulk encryption keys for each direction ๐ฆ Logically there are always four connection states hanging around: the current read and write states, and the pending read and write states โจ Every record gets processed under the current ones. The Handshake Protocol can set up the security parameters for the pending states, and the ChangeCipherSpec can pick either pending state to become current, in which case the old current one gets thrown out and replaced, and the pending one is reset to empty ๐ธ Making a state current before it has been initialized with security parameters is illegal, no exceptions ๐ โโ๏ธ And the very first current state says no encryption, no compression, and no MAC, which is honestly very chill ๐ซถ
The security parameters for a TLS connection read or write state get set by providing these values:
- connection end: whether this entity counts as the "client" or the "server" in this connection ๐
- PRF algorithm: the algorithm used to generate keys from the master secret (see Sections 5 and 6.3) ๐
- bulk encryption algorithm: the algorithm used for bulk encryption. This spec covers its key size, whether it's a block, stream, or AEAD cipher, the block size (if that applies), and the lengths of the explicit and implicit initialization vectors (or nonces) ๐ง
- MAC algorithm: the algorithm used for message authentication. This spec covers the size of the value the MAC algorithm returns ๐
- compression algorithm: the algorithm used for data compression. This spec must include all the info the algorithm needs to do compression ๐
- master secret: a 48-byte secret shared between the two peers in the connection ๐คซ
- client random: a 32-byte value provided by the client ๐ฒ
- server random: a 32-byte value provided by the server ๐ฒ
These parameters are defined in the presentation language like this:
enum { server, client } ConnectionEnd;
enum { tls_prf_sha256 } PRFAlgorithm;
enum { null, rc4, 3des, aes }
BulkCipherAlgorithm;
enum { stream, block, aead } CipherType;
enum { null, hmac_md5, hmac_sha1, hmac_sha256,
hmac_sha384, hmac_sha512} MACAlgorithm;
enum { null(0), (255) } CompressionMethod;
/* The algorithms specified in CompressionMethod, PRFAlgorithm,
BulkCipherAlgorithm, and MACAlgorithm may be added to. */
struct {
ConnectionEnd entity;
PRFAlgorithm prf_algorithm;
BulkCipherAlgorithm bulk_cipher_algorithm;
CipherType cipher_type;
uint8 enc_key_length;
uint8 block_length;
uint8 fixed_iv_length;
uint8 record_iv_length;
MACAlgorithm mac_algorithm;
uint8 mac_length;
uint8 mac_key_length;
CompressionMethod compression_algorithm;
opaque master_secret[48];
opaque client_random[32];
opaque server_random[32];
} SecurityParameters;
The record layer uses those security parameters to generate these six items (some ciphers don't need all of them, so for those they're just empty) ๐งฉ
client write MAC keyserver write MAC keyclient write encryption keyserver write encryption keyclient write IVserver write IV
The client write parameters are used by the server when it receives and processes records, and vice versa ๐ The algorithm for generating these items from the security parameters is in Section 6.3 ๐
Once the security parameters are set and the keys are generated, the connection states can be instantiated by making them the current states. These current states MUST be updated for each record processed. Each connection state has these elements:
- compression state: the current state of the compression algorithm ๐๏ธ
- cipher state: the current state of the encryption algorithm. This is the scheduled key for that connection. For stream ciphers, it also holds whatever state info the stream needs to keep encrypting or decrypting data ๐
- MAC key: the MAC key for this connection, as generated above ๐๏ธ
- sequence number: each connection state has a sequence number, tracked separately for read and write states. The sequence number MUST be set to zero whenever a connection state is made the active state. Sequence numbers are of type uint64 and may not exceed 2^64-1. Sequence numbers do not wrap. If a TLS implementation would need to wrap a sequence number, it must renegotiate instead. A sequence number gets incremented after each record: specifically, the first record transmitted under a particular connection state MUST use sequence number 0. ๐ขโจ
6.2. Record Layer ๐
The TLS record layer takes uninterpreted data from higher layers in non-empty blocks of any size ๐ง
6.2.1. Fragmentation ๐
The record layer chops information blocks into TLSPlaintext records, carrying data in chunks of 2^14 bytes or less ๐ฐ Client message boundaries are not preserved at the record layer (i.e., multiple client messages of the same ContentType MAY be coalesced into a single TLSPlaintext record, or a single message MAY be fragmented across several records) ๐
struct {
uint8 major;
uint8 minor;
} ProtocolVersion;
enum {
change_cipher_spec(20), alert(21), handshake(22),
application_data(23), (255)
} ContentType;
struct {
ContentType type;
ProtocolVersion version;
uint16 length;
opaque fragment[TLSPlaintext.length];
} TLSPlaintext;
- type: the higher-level protocol used to process the enclosed fragment ๐ง
- version: the version of the protocol being used. This document describes TLS Version 1.2, which uses the version { 3, 3 }. The version value 3.3 is historical, coming from the use of {3, 1} for TLS 1.0. (See Appendix A.1.) Note that a client supporting multiple TLS versions may not know which version will be used until it receives the ServerHello. See Appendix E for discussion about what record layer version number should be used for ClientHello. ๐ฐ๏ธ
- length: the length (in bytes) of the following TLSPlaintext.fragment. The length MUST NOT exceed 2^14. ๐
- fragment: the application data. This data is transparent and treated as an independent block to be handled by the higher-level protocol named in the type field ๐ซง
Implementations MUST NOT send zero-length fragments of Handshake, Alert, or ChangeCipherSpec content types. Zero-length fragments of Application data MAY be sent, since they can be potentially useful as a traffic analysis countermeasure ๐ต๏ธโโ๏ธ
Note: Data of different TLS record layer content types MAY be interleaved. Application data generally has lower precedence for transmission than other content types. However, records MUST be delivered to the network in the same order as they are protected by the record layer. Recipients MUST receive and process interleaved application layer traffic during handshakes subsequent to the first one on a connection. ๐
6.2.2. Record Compression and Decompression ๐๏ธ
All records are compressed using the compression algorithm defined in the current session state. There's always an active compression algorithm, but at first it's defined as CompressionMethod.null ๐ซ The compression algorithm turns a TLSPlaintext structure into a TLSCompressed structure. Compression functions get initialized with default state info whenever a connection state becomes active. [RFC3749] describes compression algorithms for TLS ๐
Compression must be lossless and may not increase the content length by more than 1024 bytes. If the decompression function encounters a TLSCompressed.fragment that would decompress to a length over 2^14 bytes, it MUST report a fatal decompression failure error. ๐จ
struct {
ContentType type; /* same as TLSPlaintext.type */
ProtocolVersion version;/* same as TLSPlaintext.version */
uint16 length;
opaque fragment[TLSCompressed.length];
} TLSCompressed;
- length: the length (in bytes) of the following TLSCompressed.fragment. The length MUST NOT exceed 2^14 + 1024. ๐
- fragment: the compressed form of TLSPlaintext.fragment ๐ญ
Note: A CompressionMethod.null operation is an identity operation; no fields are altered. ๐ช
Implementation note: Decompression functions are responsible for making sure messages can't cause internal buffer overflows. ๐ก๏ธ
6.2.3. Record Payload Protection ๐
The encryption and MAC functions turn a TLSCompressed structure into a TLSCiphertext, and the decryption functions reverse the process ๐ The MAC of the record also includes a sequence number, so missing, extra, or repeated messages are detectable ๐
struct {
ContentType type;
ProtocolVersion version;
uint16 length;
select (SecurityParameters.cipher_type) {
case stream: GenericStreamCipher;
case block: GenericBlockCipher;
case aead: GenericAEADCipher;
} fragment;
} TLSCiphertext;
- type: the type field is identical to TLSCompressed.type ๐ท๏ธ
- version: the version field is identical to TLSCompressed.version ๐ท๏ธ
- length: the length (in bytes) of the following TLSCiphertext.fragment. The length MUST NOT exceed 2^14 + 2048. ๐
- fragment: the encrypted form of TLSCompressed.fragment, with the MAC ๐
6.2.3.1. Null or Standard Stream Cipher โจ
okay bestie, stream ciphers (including BulkCipherAlgorithm.null, see Appendix A.6) are the ones that turn TLSCompressed.fragment structures into TLSCiphertext.fragment structures and back again ๐๐
stream-ciphered struct {
opaque content[TLSCompressed.length];
opaque MAC[SecurityParameters.mac_length];
} GenericStreamCipher;
the MAC gets computed like this ๐งฎ
MAC(MAC_write_key, seq_num +
TLSCompressed.type +
TLSCompressed.version +
TLSCompressed.length +
TLSCompressed.fragment);
where "+" just means concatenation ๐ซถ
seq_num: the sequence number for this record.MAC: the MAC algorithm specified bySecurityParameters.mac_algorithm.
the MAC is computed BEFORE encryption ๐ then the stream cipher encrypts the whole block, MAC included. for stream ciphers that don't use a synchronization vector (like RC4), the cipher state at the end of one record just carries straight over to the next packet ๐ธ and if the cipher suite is TLS_NULL_WITH_NULL_NULL, encryption is the identity operation. so the data isn't encrypted at all, and the MAC size is zero, which means no MAC is used ๐ for both null and stream ciphers,TLSCiphertext.lengthisTLSCompressed.lengthplusSecurityParameters.mac_length. literally that simple ๐
6.2.3.2. CBC Block Cipher
for block ciphers (like 3DES or AES), the encryption and MAC functions turn TLSCompressed.fragment structures into block TLSCiphertext.fragment structures and back ๐ง
struct {
opaque IV[SecurityParameters.record_iv_length];
block-ciphered struct {
opaque content[TLSCompressed.length];
opaque MAC[SecurityParameters.mac_length];
uint8 padding[GenericBlockCipher.padding_length];
uint8 padding_length;
};
} GenericBlockCipher;
the MAC is generated as described in Section 6.2.3.1 ๐
IV: The Initialization Vector (IV) SHOULD be chosen at random, and MUST be unpredictable. fun fact: before TLS 1.1 there was no IV field at all. the last ciphertext block of the previous record (the "CBC residue") got used as the IV instead. this got changed to stop the attacks described in [CBCATT] ๐ค for block ciphers, the IV length isSecurityParameters.record_iv_length, which is equal toSecurityParameters.block_size.padding: padding that gets added so the plaintext length is an integral multiple of the block cipher's block length ๐งฑ the padding MAY be any length up to 255 bytes, as long asTLSCiphertext.lengthends up being an integral multiple of the block length. longer-than-necessary padding might be wanted to frustrate attacks based on analysing the lengths of exchanged messages ๐ต๏ธโโ๏ธ each uint8 in the padding data vector MUST be filled with the padding length value. the receiver MUST check this padding and MUST use the bad_record_mac alert to indicate padding errors ๐จpadding_length: the padding length MUST be such that the total size of theGenericBlockCipherstructure is a multiple of the cipher's block length. legal values go from zero to 255, inclusive. this length tells you the size of the padding field, NOT counting the padding_length field itself ๐
the encrypted data length (TLSCiphertext.length) is one more than the sum of SecurityParameters.block_length, TLSCompressed.length, SecurityParameters.mac_length, and padding_length โจ
Example: if the block length is 8 bytes, the content length (TLSCompressed.length) is 61 bytes, and the MAC length is 20 bytes, then the length before padding is 82 bytes (this doesn't include the IV). so the padding length modulo 8 has to be 6 to make the total an even multiple of 8 bytes (the block length). the padding length can be 6, 14, 22, and so on, all the way up to 254. if the padding length is the minimum necessary, 6, the padding is 6 bytes, each one holding the value 6. so the last 8 octets of the GenericBlockCipher before block encryption look like this ๐
xx 06 06 06 06 06 06 06
where xx is the last octet of the MAC ๐ซ
Note: with block ciphers in CBC mode (Cipher Block Chaining), it is critical that the entire plaintext of the record be known before any ciphertext is transmitted. otherwise, the attacker can mount the attack described in [CBCATT] ๐ซ
Implementation note: Canvel et al. [CBCTIME] demonstrated a timing attack on CBC padding based on the time needed to compute the MAC ๐ฑ to defend against this, implementations MUST ensure that record processing time is essentially the same whether or not the padding is correct. in general, the best way is to compute the MAC even if the padding is incorrect, and only then reject the packet. for instance, if the pad looks incorrect, the implementation might assume a zero-length pad and then compute the MAC. this leaves a small timing channel, since MAC performance depends somewhat on the size of the data fragment, but it isn't believed to be big enough to be exploitable, thanks to the large block size of existing MACs and the small size of the timing signal ๐
6.2.3.3. AEAD Ciphers
for AEAD [AEAD] ciphers (like [CCM] or [GCM]), the AEAD function converts TLSCompressed.fragment structures into AEAD TLSCiphertext.fragment structures and back ๐
struct {
opaque nonce_explicit[SecurityParameters.record_iv_length];
aead-ciphered struct {
opaque content[TLSCompressed.length];
};
} GenericAEADCipher;
AEAD ciphers take a single key, a nonce, a plaintext, and "additional data" to include in the authentication check, as described in Section 2.1 of [AEAD] ๐ง the key is either the client_write_key or the server_write_key. no MAC key gets used here, so no MAC key, no problem ๐
each AEAD cipher suite MUST specify how the nonce given to the AEAD operation is constructed, and what the length of the GenericAEADCipher.nonce_explicit part is. in lots of cases it's a good idea to use the partially implicit nonce technique from Section 3.2.1 of [AEAD], with record_iv_length being the length of the explicit part ๐ in that case, the implicit part SHOULD be derived from key_block as client_write_iv and server_write_iv (as described in Section 6.3), and the explicit part goes into GenericAEADCipher.nonce_explicit.
the plaintext is the TLSCompressed.fragment ๐
the additional authenticated data, called additional_data, is defined like this ๐
additional_data = seq_num + TLSCompressed.type +
TLSCompressed.version + TLSCompressed.length;
where "+" means concatenation ๐ซถ
the aead_output is the ciphertext the AEAD encryption operation spits out. it's usually bigger than TLSCompressed.length, but by an amount that depends on the AEAD cipher. since some ciphers might bring padding along, the overhead could change with different TLSCompressed.length values ๐ each AEAD cipher MUST NOT produce an expansion of greater than 1024 bytes. symbolically:
AEADEncrypted = AEAD-Encrypt(write_key, nonce, plaintext,
additional_data)
to decrypt and verify, the cipher takes the key, the nonce, the "additional_data", and the AEADEncrypted value as input. the output is either the plaintext or an error saying decryption failed. there's no separate integrity check, so that's the whole deal ๐
TLSCompressed.fragment = AEAD-Decrypt(write_key, nonce,
AEADEncrypted,
additional_data)
if decryption fails, a fatal bad_record_mac alert MUST be generated. no vibes, just alarms ๐จ๐
6.3. Key Calculation ๐
the Record Protocol needs an algorithm to generate the keys the current connection state requires (see Appendix A.6), starting from the security parameters the handshake protocol hands over ๐ค
the master secret gets expanded into a sequence of secure bytes. that sequence is then split into a client write MAC key, a server write MAC key, a client write encryption key, and a server write encryption key. each one is generated from the byte sequence in exactly that order. unused values are empty. some AEAD ciphers may also need a client write IV and a server write IV (see Section 6.2.3.3) ๐งฉ
when keys and MAC keys are generated, the master secret is used as an entropy source ๐
to generate the key material, compute:
key_block = PRF(SecurityParameters.master_secret,
"key expansion",
SecurityParameters.server_random +
SecurityParameters.client_random);
keep going until enough output has been generated. then the key_block gets partitioned like this ๐ฐ
client_write_MAC_key[SecurityParameters.mac_key_length]
server_write_MAC_key[SecurityParameters.mac_key_length]
client_write_key[SecurityParameters.enc_key_length]
server_write_key[SecurityParameters.enc_key_length]
client_write_IV[SecurityParameters.fixed_iv_length]
server_write_IV[SecurityParameters.fixed_iv_length]
right now, client_write_IV and server_write_IV only get generated for implicit nonce techniques, as described in Section 3.2.1 of [AEAD] ๐
Implementation note: the currently defined cipher suite that needs the most material is AES_256_CBC_SHA256. it needs 2 x 32 byte keys and 2 x 32 byte MAC keys, for a total of 128 bytes of key material ๐ฆ
7. The TLS Handshaking Protocols ๐ค
okay this one's the big picture ๐ผ๏ธ TLS has three subprotocols. they let peers agree on security parameters for the record layer, authenticate themselves, instantiate the negotiated security parameters, and report error conditions to each other ๐
the Handshake Protocol is in charge of negotiating a session, which holds the following items:
- session identifier: an arbitrary byte sequence chosen by the server to identify an active or resumable session state ๐ชช
- peer certificate: the X509v3 [PKIX] certificate of the peer. this element of the state may be null ๐
- compression method: the algorithm used to compress data before encryption ๐๏ธ
- cipher spec: specifies the pseudorandom function (PRF) used to generate keying material, the bulk data encryption algorithm (like null, AES, etc.), and the MAC algorithm (like HMAC-SHA1). it also defines cryptographic attributes such as the mac_length. (see Appendix A.6 for the formal definition) ๐ง
- master secret: a 48-byte secret shared between the client and server ๐คซ
- is resumable: a flag saying whether the session can be used to initiate new connections ๐
these items are then used to create security parameters for the record layer to use when protecting application data ๐ก๏ธ many connections can be instantiated from the same session through the resumption feature of the TLS Handshake Protocol โจ
7.1. Change Cipher Spec Protocol ๐ฆ
okay so the change cipher spec protocol is literally just a signal for when we switch up our ciphering strategy ๐. it's a single message, and it gets encrypted and compressed under the current connection state, not the pending one ๐ . the whole message is one byte with the value 1 โจ
struct {
enum { change_cipher_spec(1), (255) } type;
} ChangeCipherSpec;
both the client and the server send the ChangeCipherSpec message to tell the other side that everything after it is protected under the newly negotiated CipherSpec and keys ๐. when it gets received, the receiver tells the record layer to immediately copy the read pending state into the read current state ๐ฅ. and right after sending it, the sender MUST instruct the record layer to make the write pending state the write active state ๐ค this is the moment everything officially switches over ๐
(See Section 6.1.) the ChangeCipherSpec message gets sent during the handshake, after the security parameters have been agreed upon, but before the verifying Finished message goes out ๐ค
Note: if a rehandshake happens while data is already flowing on a connection, the communicating parties may keep sending data with the old CipherSpec ๐ธ but once the ChangeCipherSpec has been sent, the new CipherSpec MUST be used ๐ฅ the first side to send ChangeCipherSpec doesn't know yet whether the other side has finished computing the new keying material (like if it has to do a time-consuming public key operation) ๐ so there's a little window where the recipient has to buffer the data, and that window MAY exist. in practice though, with modern machines it's likely to be pretty short โก
7.2. Alert Protocol ๐จ
one of the content types the TLS record layer supports is the alert type ๐ alert messages tell you how serious the message is (warning or fatal) and what the alert is about. alerts with a level of fatal cause the connection to terminate immediately ๐ other connections tied to the same session can keep going, but the session identifier MUST be invalidated, so that the failed session can't be used to set up new connections ๐ just like every other message, alert messages get encrypted and compressed based on the current connection state ๐ซถ
enum { warning(1), fatal(2), (255) } AlertLevel;
enum {
close_notify(0),
unexpected_message(10),
bad_record_mac(20),
decryption_failed_RESERVED(21),
record_overflow(22),
decompression_failure(30),
handshake_failure(40),
no_certificate_RESERVED(41),
bad_certificate(42),
unsupported_certificate(43),
certificate_revoked(44),
certificate_expired(45),
certificate_unknown(46),
illegal_parameter(47),
unknown_ca(48),
access_denied(49),
decode_error(50),
decrypt_error(51),
export_restriction_RESERVED(60),
protocol_version(70),
insufficient_security(71),
internal_error(80),
user_canceled(90),
no_renegotiation(100),
unsupported_extension(110),
(255)
} AlertDescription;
struct {
AlertLevel level;
AlertDescription description;
} Alert;
7.2.1. Closure Alerts ๐
the client and the server have to both know that the connection is ending, or else you get a truncation attack ๐ฑ either party is allowed to start the closing exchange ๐
close_notify: this one tells the recipient that the sender won't be sending any more messages on this connection. heads up, as of TLS 1.1, failing to close a connection properly no longer means the session can't be resumed ๐ง that's a change from TLS 1.0, made to match what implementations were already doing everywhere ๐
either party can start a close by sending a close_notify alert, and any data that shows up after a closure alert gets ignored ๐
unless some other fatal alert has already been sent, each party is required to send a close_notify alert before closing the write side of the connection ๐จ the other party MUST respond with its own close_notify alert and shut the connection down right away, throwing out any pending writes ๐๏ธ the initiator doesn't have to wait for that responding close_notify before closing the read side of the connection ๐
if the application protocol on top of TLS says that data can still travel over the underlying transport after the TLS connection closes, then the TLS implementation must receive the responding close_notify alert before it tells the application layer that the TLS connection has ended ๐ซถ but if the application protocol won't move any more data and is only going to close the underlying transport connection, then the implementation MAY choose to close the transport without waiting for the responding close_notify ๐ฆ nothing in this standard should be read as dictating how a TLS usage profile handles its data transport, including when connections get opened or closed ๐ธ
Note: it's assumed that closing a connection reliably delivers pending data before the transport gets destroyed ๐
7.2.2. Error Alerts ๐จโจ
Okay bestie, error handling in the TLS Handshake protocol is honestly so simple ๐ . When something goes wrong, the party that detects it sends a message to the other side. Once a fatal alert is sent or received, both parties immediately close the connection ๐ญ. Servers and clients MUST forget any session-identifiers, keys, and secrets tied to a failed connection ๐ฅ. So any connection terminated with a fatal alert MUST NOT be resumed. Dead connection, no comeback ๐.
Whenever an implementation runs into a condition defined as a fatal alert, it MUST send the appropriate alert before closing the connection ๐ซถ. For errors where no alert level is explicitly specified, the sending party MAY decide at its own discretion whether to treat it as fatal ๐ฆ. If you're sending an alert but plan to close the connection right after, it MUST go out at the fatal alert level ๐. No "eh, it's just a warning" vibes here, periodt.
Warning alerts are a different story ๐ธ. If one is sent and received, the connection can usually keep going normally. But if the receiving party decides not to proceed (like after getting a no_renegotiation alert it isn't willing to accept), it SHOULD send a fatal alert to terminate the connection ๐. The sender can't really know how the receiver will act, so warning alerts aren't super useful when the sender wants to keep going, and they're sometimes just left out โจ. For example, if a peer decides to accept an expired certificate (maybe after checking with the user) and wants to continue, it wouldn't generally send a certificate_expired alert ๐.
The following error alerts are defined ๐:
unexpected_message: An inappropriate message was received. This alert is always fatal and should never be observed in communication between proper implementations ๐.bad_record_mac: This alert is returned if a record is received with an incorrect MAC. This alert also MUST be returned if an alert is sent because aTLSCiphertextdecrypted in an invalid way: either it wasn't an even multiple of the block length, or its padding values, when checked, weren't correct. This message is always fatal and should never be observed in communication between proper implementations (except when messages were corrupted in the network) ๐ง.decryption_failed_RESERVED: This alert was used in some earlier versions of TLS, and may have permitted certain attacks against the CBC mode [CBCATT]. It MUST NOT be sent by compliant implementations ๐ซ.record_overflow: ATLSCiphertextrecord was received that had a length more than2^14+2048bytes, or a record decrypted to aTLSCompressedrecord with more than2^14+1024bytes. This message is always fatal and should never be observed in communication between proper implementations (except when messages were corrupted in the network) ๐ฆ.decompression_failure: The decompression function received improper input (e.g., data that would expand to excessive length). This message is always fatal and should never be observed in communication between proper implementations ๐๏ธ.handshake_failure: Reception of ahandshake_failurealert message indicates that the sender was unable to negotiate an acceptable set of security parameters given the options available. This is a fatal error ๐ค.no_certificate_RESERVED: This alert was used in SSLv3 but not any version of TLS. It MUST NOT be sent by compliant implementations ๐ซ.bad_certificate: A certificate was corrupt, contained signatures that did not verify correctly, etc. ๐.unsupported_certificate: A certificate was of an unsupported type ๐คทโโ๏ธ.certificate_revoked: A certificate was revoked by its signer โ.certificate_expired: A certificate has expired or is not currently valid โฐ.certificate_unknown: Some other (unspecified) issue arose in processing the certificate, rendering it unacceptable ๐.illegal_parameter: A field in the handshake was out of range or inconsistent with other fields. This message is always fatal ๐ท.unknown_ca: A valid certificate chain or partial chain was received, but the certificate was not accepted because the CA certificate could not be located or couldn't be matched with a known, trusted CA. This message is always fatal ๐ต๏ธโโ๏ธ.access_denied: A valid certificate was received, but when access control was applied, the sender decided not to proceed with negotiation. This message is always fatal ๐.decode_error: A message could not be decoded because some field was out of the specified range or the length of the message was incorrect. This message is always fatal and should never be observed in communication between proper implementations (except when messages were corrupted in the network) ๐งฉ.decrypt_error: A handshake cryptographic operation failed, including being unable to correctly verify a signature or validate a Finished message. This message is always fatal ๐.export_restriction_RESERVED: This alert was used in some earlier versions of TLS. It MUST NOT be sent by compliant implementations ๐ซ.protocol_version: The protocol version the client has attempted to negotiate is recognized but not supported. (For example, old protocol versions might be avoided for security reasons.) This message is always fatal ๐ฐ๏ธ.insufficient_security: Returned instead ofhandshake_failurewhen a negotiation has failed specifically because the server requires ciphers more secure than those supported by the client. This message is always fatal ๐.internal_error: An internal error unrelated to the peer or the correctness of the protocol (such as a memory allocation failure) makes it impossible to continue. This message is always fatal ๐ ๏ธ.user_canceled: This handshake is being canceled for some reason unrelated to a protocol failure. If the user cancels an operation after the handshake is complete, just closing the connection by sending aclose_notifyis more appropriate. This alert should be followed by aclose_notify. This message is generally a warning โ.no_renegotiation: Sent by the client in response to a hello request or by the server in response to a client hello after initial handshaking. Either of these would normally lead to renegotiation; when that is not appropriate, the recipient should respond with this alert. At that point, the original requester can decide whether to proceed with the connection. One case where this would be appropriate is where a server has spawned a process to satisfy a request; the process might receive security parameters (key length, authentication, etc.) at startup, and it might be difficult to communicate changes to these parameters after that point. This message is always a warning ๐ โโ๏ธ.unsupported_extension: sent by clients that receive an extended server hello containing an extension that they did not put in the corresponding client hello. This message is always fatal ๐งฉ.
New Alert values are assigned by IANA as described in Section 12 ๐.
7.3. Handshake Protocol Overview โจ
Okay bestie, so the cryptographic parameters of the session state come from the TLS Handshake Protocol, which runs on top of the TLS record layer ๐ง. When a client and server first start talking, they agree on a protocol version, pick their crypto algorithms, optionally authenticate each other, and use public-key encryption to generate shared secrets ๐.
The TLS Handshake Protocol has these steps, and it's giving organized ๐ :
- Exchange hello messages to agree on algorithms, exchange random values, and check for session resumption.
- Exchange the necessary cryptographic parameters so the client and server can agree on a premaster secret.
- Exchange certificates and cryptographic information so the client and server can authenticate themselves.
- Generate a master secret from the premaster secret and the exchanged random values.
- Provide security parameters to the record layer.
- Let the client and server verify that their peer calculated the same security parameters and that the handshake happened without tampering by an attacker.
โ ๏ธ Higher layers should not be overly reliant on whether TLS always negotiates the strongest possible connection between two peers, bestie. There are a bunch of ways a man-in-the-middle attacker can try to make two entities drop down to the least secure method they support ๐ญ. The protocol is designed to minimize this risk, but attacks are still possible. For example, an attacker could block access to the port a secure service runs on, or try to get the peers to negotiate an unauthenticated connection ๐. The fundamental rule is that higher levels must be cognizant of what their security requirements are and never transmit information over a channel less secure than what they require ๐ซถ. TLS is secure in that any cipher suite offers its promised level of security. If you negotiate 3DES with a 1024-bit RSA key exchange with a host whose certificate you have verified, you can expect to be that secure. โจ
Here's the handshake summary, and it's lowkey iconic ๐. The client sends a ClientHello message, and the server must respond with a ServerHello message, or else a fatal error occurs and the connection fails ๐. The ClientHello and ServerHello establish security enhancement capabilities between client and server. They set the following attributes: Protocol Version, Session ID, Cipher Suite, and Compression Method. Two random values are also generated and exchanged: ClientHello.random and ServerHello.random ๐.
The actual key exchange uses up to four messages: the server Certificate, the ServerKeyExchange, the client Certificate, and the ClientKeyExchange ๐ฆ. New key exchange methods can be created by specifying a format for these messages and defining how they're used so the client and server can agree on a shared secret. This secret MUST be quite long. Currently defined key exchange methods exchange secrets that range from 46 bytes upwards ๐ธ.
After the hello messages, the server sends its certificate in a Certificate message if it is going to be authenticated. A ServerKeyExchange message may also be sent if it's needed, for example if the server has no certificate, or if its certificate is for signing only ๐. If the server is authenticated, it may request a certificate from the client, if that fits the selected cipher suite. Next, the server sends the ServerHelloDone message to say the hello-message phase is complete, then it waits for a client response ๐ง. If the server sent a CertificateRequest message, the client MUST send the Certificate message. Then the ClientKeyExchange message is sent, and its content depends on the public key algorithm selected between the ClientHello and the ServerHello. If the client sent a certificate with signing ability, a digitally-signed CertificateVerify message is sent to explicitly prove possession of the private key in that certificate ๐ฅ.
Now the fun part ๐. The client sends a ChangeCipherSpec message and copies the pending Cipher Spec into the current Cipher Spec. It then immediately sends the Finished message under the new algorithms, keys, and secrets. The server responds with its own ChangeCipherSpec message, moves the pending Cipher Spec to current, and sends its Finished message under the new Cipher Spec. At this point the handshake is complete, and the client and server MAY begin exchanging application layer data ๐. Application data MUST NOT be sent before the first handshake is completed (before a cipher suite other than TLS_NULL_WITH_NULL_NULL is established) ๐ โโ๏ธ. (See the flow chart below.)
Client Server
ClientHello -------->
ServerHello
Certificate*
ServerKeyExchange*
CertificateRequest*
<-------- ServerHelloDone
Certificate*
ClientKeyExchange
CertificateVerify*
[ChangeCipherSpec]
Finished -------->
[ChangeCipherSpec]
<-------- Finished
Application Data <-------> Application Data
Figure 1. Message flow for a full handshake
* Indicates optional or situation-dependent messages that are not always sent. ๐
Note: To help avoid pipeline stalls, ChangeCipherSpec is an independent TLS protocol content type, and is not actually a TLS handshake message. ๐ง
When the client and server decide to resume a previous session or duplicate an existing one (instead of negotiating new security parameters), the message flow looks different ๐ฆ. The client sends a ClientHello using the Session ID of the session to be resumed. The server then checks its session cache for a match. If it finds one and the server is willing to re-establish the connection under that session state, it sends a ServerHello with the same Session ID value. At this point, both client and server MUST send ChangeCipherSpec messages and go straight to Finished messages. Once re-establishment is complete, the client and server MAY begin exchanging application layer data. (See the flow chart below.) If no Session ID match is found, the server generates a new session ID, and the TLS client and server do a full handshake instead ๐.
Client Server
ClientHello -------->
ServerHello
[ChangeCipherSpec]
<-------- Finished
[ChangeCipherSpec]
Finished -------->
Application Data <-------> Application Data
Figure 2. Message flow for an abbreviated handshake
The contents and significance of each message are covered in detail in the sections that follow ๐.
7.4. Handshake Protocol ๐ง
The TLS Handshake Protocol is one of the defined higher-level clients of the TLS Record Protocol ๐. It's used to negotiate the secure attributes of a session. Handshake messages are handed to the TLS record layer, where they get wrapped in one or more TLSPlaintext structures, which are processed and sent according to the current active session state ๐.
enum {
hello_request(0), client_hello(1), server_hello(2),
certificate(11), server_key_exchange (12),
certificate_request(13), server_hello_done(14),
certificate_verify(15), client_key_exchange(16),
finished(20), (255)
} HandshakeType;
struct {
HandshakeType msg_type; /* handshake type */
uint24 length; /* bytes in message */
select (HandshakeType) {
case hello_request: HelloRequest;
case client_hello: ClientHello;
case server_hello: ServerHello;
case certificate: Certificate;
case server_key_exchange: ServerKeyExchange;
case certificate_request: CertificateRequest;
case server_hello_done: ServerHelloDone;
case certificate_verify: CertificateVerify;
case client_key_exchange: ClientKeyExchange;
case finished: Finished;
} body;
} Handshake;
The handshake messages are presented below in the order they MUST be sent. Sending handshake messages in an unexpected order results in a fatal error ๐จ. Unneeded handshake messages can be left out, though ๐ธ. There's one exception to the ordering: the Certificate message is used twice in the handshake (from server to client, then from client to server), but it's only described in its first position ๐. The one message that isn't bound by these ordering rules is the HelloRequest message. It can be sent at any time, but it SHOULD be ignored by the client if it arrives in the middle of a handshake ๐.
New handshake message types are assigned by IANA as described in Section 12 ๐งพ.
7.4.1. Hello Messages ๐
The hello phase messages are used to exchange security enhancement capabilities between the client and server ๐ฆ. When a new session begins, the record layer's connection state encryption, hash, and compression algorithms are initialized to null. The current connection state is used for renegotiation messages โจ.
7.4.1.1. Hello Request
When this message will be sent: the server is allowed to send the HelloRequest ๐ at any time, so the client better stay ready. ๐ซถ
Meaning of this message: HelloRequest is basically a little ping that says "hey, start the negotiation over." ๐ฆ The client should send a ClientHello when it's convenient for it. This message isn't there to decide who's the client and who's the server, it just kicks off a fresh negotiation. โจ Servers SHOULD NOT send a HelloRequest right after the client first connects. Nope, that's the client's job, it sends the ClientHello first. ๐
The client will ignore this message if it's already in the middle of negotiating a session. ๐ It MAY also ignore it if it doesn't want to renegotiate, or if it's feeling extra, it can reply with a no_renegotiation alert. ๐ Handshake messages get transmission priority over application data, so the negotiation is expected to begin before more than a few records come in from the client. โก If the server sends a HelloRequest and never gets a ClientHello back, it may close the connection with a fatal alert. ๐
After the server sends a HelloRequest, it SHOULD NOT repeat the request until the handshake negotiation that follows is finished. ๐ธ
Structure of this message:
struct { } HelloRequest;
This message MUST NOT be included in the message hashes that are maintained throughout the handshake and used in the Finished messages and the certificate verify message. ๐ Keep it out of the hashes, bestie, no exceptions! ๐ญ
7.4.1.2. Client Hello
When this message will be sent: when a client first connects to a server, it is required to send the ClientHello as its very first message. ๐ The client can also send a ClientHello in response to a HelloRequest, or on its own whenever it wants to renegotiate the security parameters of an existing connection. ๐
Structure of this message: the ClientHello includes a random structure that gets used later in the protocol. ๐ฒ
struct {
uint32 gmt_unix_time;
opaque random_bytes[28];
} Random;
gmt_unix_time: this is the current time and date in standard UNIX 32-bit format (seconds since midnight starting Jan 1, 1970, UTC, ignoring leap seconds), according to the sender's internal clock. โฐ The basic TLS protocol doesn't require clocks to be set correctly, though higher-level or application protocols might add their own requirements. Also, for historical reasons the field is named with GMT, the predecessor of the current worldwide time base, UTC. ๐random_bytes: 28 bytes generated by a secure random number generator. ๐
The ClientHello includes a variable-length session identifier. If it isn't empty, the value identifies a session between the same client and server whose security parameters the client wants to reuse. ๐ฆ The identifier MAY come from an earlier connection, this connection, or another connection that's currently active. The second option is useful if the client only wants to refresh the random structures and derived values of a connection. The third option lets you set up several independent secure connections without doing the full handshake every time. โจ These independent connections can happen one after another or all at once. A SessionID becomes valid when the handshake that negotiated it finishes with the exchange of Finished messages. It sticks around until it gets removed, either because it aged out or because a fatal error happened on a connection tied to that session. ๐ง The actual contents of the SessionID are defined by the server.
opaque SessionID<0..32>;
Warning: Because the SessionID is sent without encryption or immediate MAC protection, servers MUST NOT place confidential information in session identifiers, and they must not let the contents of fake session identifiers cause any breach of security. ๐จ (Note that the content of the handshake as a whole, including the SessionID, is protected by the Finished messages exchanged at the end of the handshake. ๐ซถ)
The cipher suite list is passed from the client to the server in the ClientHello message. It contains the combinations of cryptographic algorithms the client supports, ordered by the client's preference, with its favorite first. ๐ Each cipher suite defines a key exchange algorithm, a bulk encryption algorithm (including the secret key length), a MAC algorithm, and a PRF. The server will pick one cipher suite. If none of the choices are acceptable, it returns a handshake failure alert and closes the connection. ๐ If the list contains cipher suites the server doesn't recognize, doesn't support, or doesn't want to use, the server MUST ignore those and process the rest as usual. ๐
uint8 CipherSuite[2]; /* Cryptographic suite selector */
The ClientHello also includes a list of compression algorithms the client supports, ordered by its preference. ๐
enum { null(0), (255) } CompressionMethod;
struct {
ProtocolVersion client_version;
Random random;
SessionID session_id;
CipherSuite cipher_suites<2..2^16-2>;
CompressionMethod compression_methods<1..2^8-1>;
select (extensions_present) {
case false:
struct {};
case true:
Extension extensions<0..2^16-1>;
};
} ClientHello;
TLS lets extensions follow the compression_methods field in an extensions block. You can tell whether extensions are there by checking whether any bytes come after compression_methods at the very end of the ClientHello. ๐ต๏ธ This way of detecting optional data is different from the normal TLS approach of using a variable-length field, but it's kept for compatibility with TLS from before extensions existed. ๐ฆ
client_version: the version of the TLS protocol the client wants to use for this session. This SHOULD be the latest (highest-valued) version the client supports. For this version of the specification, the version is 3.3 (see Appendix E for details about backward compatibility). ๐ซrandom: a random structure generated by the client. ๐ฒsession_id: the ID of a session the client wants to use for this connection. It's empty if no session_id is available, or if the client wants to generate new security parameters. ๐cipher_suites: a list of the cryptographic options the client supports, with its first preference first. If session_id isn't empty (which means the client is asking to resume a session), this vector MUST include at least the cipher_suite from that session. The values are defined in Appendix A.5. ๐compression_methods: a list of the compression methods the client supports, sorted by client preference. If session_id isn't empty (again, a resumption request), it MUST include the compression_method from that session. This vector MUST contain, and all implementations MUST support, CompressionMethod.null. That way, a client and server can always agree on a compression method. ๐คextensions: clients MAY request extended functionality from servers by sending data in the extensions field. The actual "Extension" format is defined in Section 7.4.1.4. ๐งฉ
If a client asks for extra functionality through extensions and the server doesn't supply it, the client MAY abort the handshake. ๐ โโ๏ธ A server MUST accept ClientHello messages both with and without the extensions field. And, like for every other message, it MUST check that the amount of data in the message exactly matches one of these formats. If it doesn't, it MUST send a fatal "decode_error" alert. ๐ซ
After sending the ClientHello, the client waits for a ServerHello message. Any handshake message the server sends back, except for a HelloRequest, is treated as a fatal error. ๐ฅ
7.4.1.3. Server Hello
When this message will be sent: the server sends this message in response to a ClientHello once it has found an acceptable set of algorithms. ๐ If it can't find a match, it responds with a handshake failure alert instead. ๐ฟ
Structure of this message:
struct {
ProtocolVersion server_version;
Random random;
SessionID session_id;
CipherSuite cipher_suite;
CompressionMethod compression_method;
select (extensions_present) {
case false:
struct {};
case true:
Extension extensions<0..2^16-1>;
};
} ServerHello;
You can tell whether extensions are present by checking whether any bytes follow the compression_method field at the very end of the ServerHello. ๐
server_version: this field contains the lower of the version the client suggested in the ClientHello and the highest version the server supports. For this version of the specification, the version is 3.3. (See Appendix E for details about backward compatibility.) โฌ๏ธrandom: this structure is generated by the server and MUST be independently generated from the ClientHello.random. ๐ฒ (No copying, babe!)session_id: this is the identity of the session that matches this connection. If the ClientHello.session_id was non-empty, the server looks in its session cache for a match. If it finds one and is willing to set up the new connection using that session state, it responds with the same value the client sent. That signals a resumed session and means the parties must go straight to the Finished messages. โฉ Otherwise, this field contains a different value that identifies the new session. The server MAY return an empty session_id to say the session won't be cached and therefore can't be resumed. ๐ซ If a session is resumed, it must be resumed using the same cipher suite it was originally negotiated with. There's no requirement that the server resume any session, even if it previously gave out a session_id, so no promises there. ๐ฅฒ Clients MUST be prepared to do a full negotiation, including negotiating new cipher suites, during any handshake. ๐ชcipher_suite: the single cipher suite the server picks from the list in ClientHello.cipher_suites. For resumed sessions, this field takes the value from the state of the session being resumed. ๐compression_method: the single compression algorithm the server picks from the list in ClientHello.compression_methods. For resumed sessions, this field takes the value from the resumed session state. ๐๏ธextensions: a list of extensions. Only extensions the client offered can show up in the server's list. ๐
7.4.1.4. Hello Extensions โจ
okay so extensions are basically little add-on boxes that ride along inside the Hello messages ๐ and the format is super simple bestie:
struct {
ExtensionType extension_type;
opaque extension_data<0..2^16-1>;
} Extension;
enum {
signature_algorithms(13), (65535)
} ExtensionType;
Here:
- "extension_type" tells you which extension it is ๐
- "extension_data" holds the info that's specific to that extension type ๐ฆ
The starter pack of extensions is defined in a companion document, [TLSEXT] ๐. And the list of extension types is kept by IANA, as described in Section 12 ๐ .
An extension type MUST NOT appear in the ServerHello unless that same extension type showed up in the matching ClientHello ๐. And if a client gets an extension type in the ServerHello that it did NOT ask for in its ClientHello, it MUST abort the handshake with an unsupported_extension fatal alert ๐. Not cute, not allowed.
Now here's the tea ๐: "server-oriented" extensions might show up in the future. For one of those (say, type x), the client would first have to send an extension of type x in its ClientHello with empty extension_data, just to say "hey, I can understand this type" ๐ง. Then the server can take it up on the offer. Iconic handshake energy ๐.
When there are multiple extensions of different types in the ClientHello or ServerHello, the extensions MAY appear in any order ๐. But there MUST NOT be more than one extension of the same type ๐ซ. One of each, periodt โจ.
Also, extensions can be sent both for a brand-new session and when you're requesting session resumption ๐. A client asking to resume doesn't generally know whether the server will say yes, so it SHOULD send the same extensions it would send if it weren't trying to resume ๐ซถ.
Every extension type's spec needs to explain what it does during a full handshake AND during session resumption ๐ฆ. Most current TLS extensions only matter when a session is being started: when an older session gets resumed, the server doesn't process these extensions in the Client Hello and doesn't include them in the Server Hello ๐ญ. Some extensions can do something different during resumption though, so keep an eye out ๐.
There are subtle (and not so subtle) interactions between new features and existing ones, and they can seriously weaken overall security ๐. So when you're designing new extensions, keep these in mind:
- Some cases where a server doesn't agree to an extension are error conditions, and some are just refusals to support particular features ๐ โโ๏ธ. In general, error alerts should be used for the former, and a field in the server extension response for the latter ๐.
- Extensions should, as far as possible, be designed to prevent any attack that forces use (or non-use) of a particular feature by messing with handshake messages ๐ก๏ธ. This applies whether or not the feature is believed to cause a security problem, no exceptions ๐ .
Often, including the extension fields in the inputs to the Finished message hashes will be enough ๐. But extreme care is needed when the extension changes the meaning of messages sent in the handshake phase ๐ฐ. Designers and implementors should know that until the handshake has been authenticated, active attackers can modify messages and insert, remove, or replace extensions ๐จ.
- It would be technically possible to use extensions to change major aspects of TLS's design, like cipher suite negotiation ๐. This is NOT recommended, and it would be more appropriate to define a new version of TLS instead ๐. Especially since the TLS handshake algorithms have specific protection against version rollback attacks based on the version number, and the possibility of version rollback should be a big consideration in any major design change ๐ฉ.
7.4.1.4.1. Signature Algorithms โจ
okay this one is the main character of extensions ๐. The client uses the "signature_algorithms" extension to tell the server which signature/hash algorithm pairs it's okay with being used in digital signatures ๐. The "extension_data" field of this extension contains a "supported_signature_algorithms" value ๐.
enum {
none(0), md5(1), sha1(2), sha224(3), sha256(4), sha384(5),
sha512(6), (255)
} HashAlgorithm;
enum { anonymous(0), rsa(1), dsa(2), ecdsa(3), (255) }
SignatureAlgorithm;
struct {
HashAlgorithm hash;
SignatureAlgorithm signature;
} SignatureAndHashAlgorithm;
SignatureAndHashAlgorithm
supported_signature_algorithms<2..2^16-2>;
Each SignatureAndHashAlgorithm value lists a single hash/signature pair the client is willing to verify ๐ฆ. The values are listed in descending order of preference ๐.
Note: because not every signature algorithm and hash algorithm may be accepted by an implementation (e.g., DSA with SHA-1, but not SHA-256), the algorithms are listed in pairs ๐ฅบ. That's why it's a pair situation, bestie ๐ .
Here's what each field means ๐:
- hash: this field indicates the hash algorithm that may be used ๐. The values mean support for unhashed data, MD5 [MD5], SHA-1, SHA-224, SHA-256, SHA-384, and SHA-512 [SHS], in that order ๐. The "none" value is there for future extensibility, in case of a signature algorithm that doesn't require hashing before signing ๐ฎ.
- signature: this field indicates the signature algorithm that may be used ๐๏ธ. The values mean anonymous signatures, RSASSA-PKCS1-v1_5 [PKCS1] and DSA [DSS], and ECDSA [ECDSA], respectively ๐. The "anonymous" value is meaningless in this context but is used in Section 7.4.3 ๐. It MUST NOT appear in this extension ๐ซ.
The semantics of this extension are kinda complicated ๐ตโ๐ซ, because the cipher suite indicates permissible signature algorithms but NOT hash algorithms ๐. Sections 7.4.2 and 7.4.3 describe the appropriate rules ๐.
If the client supports only the default hash and signature algorithms (listed in this section), it MAY omit the signature_algorithms extension โจ. But if the client does NOT support the default algorithms, or supports other hash and signature algorithms (and is willing to use them to verify messages sent by the server, i.e., server certificates and server key exchange), it MUST send the signature_algorithms extension, listing the algorithms it's willing to accept ๐ซถ.
If the client does not send the signature_algorithms extension, the server MUST do the following ๐:
- If the negotiated key exchange algorithm is one of (RSA, DHE_RSA, DH_RSA, RSA_PSK, ECDH_RSA, ECDHE_RSA), behave as if the client had sent the value {sha1,rsa} ๐ธ.
- If the negotiated key exchange algorithm is one of (DHE_DSS, DH_DSS), behave as if the client had sent the value {sha1,dsa} ๐ท.
- If the negotiated key exchange algorithm is one of (ECDH_ECDSA, ECDHE_ECDSA), behave as if the client had sent the value {sha1,ecdsa} ๐.
Note: this is a change from TLS 1.1, where there were no explicit rules, but as a practical matter one can assume that the peer supports MD5 and SHA-1 ๐ฐ๏ธ.
Note: this extension is not meaningful for TLS versions prior to 1.2 ๐ โโ๏ธ. Clients MUST NOT offer it if they are offering prior versions ๐ซ. However, even if clients do offer it, the rules specified in [TLSEXT] require servers to ignore extensions they do not understand ๐คทโโ๏ธ.
Servers MUST NOT send this extension ๐. TLS servers MUST support receiving this extension ๐.
When performing session resumption, this extension is NOT included in the Server Hello, and the server ignores the extension in the Client Hello (if present) ๐.
7.4.2. Server Certificate ๐โจ
When this message will be sent:
The server MUST send a Certificate message whenever the agreed-upon key exchange method uses certificates for authentication (this includes all key exchange methods defined in this document except DH_anon) ๐ . This message will always immediately follow the ServerHello message ๐.
Meaning of this message:
Okay so this message is how the server hands the client its certificate chain ๐. The certificate MUST be appropriate for the negotiated cipher suite's key exchange algorithm and any negotiated extensions ๐ง . Bestie, that's a whole vibe check ๐.
Structure of this message:
opaque ASN.1Cert<1..2^24-1>;
struct {
ASN.1Cert certificate_list<0..2^24-1>;
} Certificate;
certificate_list This is a sequence (chain) of certificates ๐. The sender's certificate MUST come first in the list ๐. Each following certificate MUST directly certify the one preceding it ๐ซถ. Because certificate validation requires that root keys be distributed independently, the self-signed certificate that specifies the root certificate authority MAY be omitted from the chain, under the assumption that the remote end must already possess it in order to validate it in any case ๐ธ. Lowkey iconic, ngl.
The same message type and structure will be used for the client's response to a certificate request message ๐ฆ. Note that a client MAY send no certificates if it does not have an appropriate certificate to send in response to the server's authentication request ๐. No cap, that's totally allowed.
Note: PKCS #7 [PKCS7] is not used as the format for the certificate vector because PKCS #6 [PKCS6] extended certificates are not used. Also, PKCS #7 defines a SET rather than a SEQUENCE, making the task of parsing the list more difficult ๐.
The following rules apply to the certificates sent by the server:
- The certificate type MUST be X.509v3, unless explicitly negotiated otherwise (e.g., [TLSPGP]) ๐.
- The end entity certificate's public key (and associated restrictions) MUST be compatible with the selected key exchange algorithm ๐. Here's the breakdown:
Key Exchange Alg. Certificate Key Type
RSA RSA public key; the certificate MUST allow the
RSA_PSK key to be used for encryption (the
keyEncipherment bit MUST be set if the key
usage extension is present).
Note: RSA_PSK is defined in [TLSPSK].
DHE_RSA RSA public key; the certificate MUST allow the
ECDHE_RSA key to be used for signing (the
digitalSignature bit MUST be set if the key
usage extension is present) with the signature
scheme and hash algorithm that will be employed
in the server key exchange message.
Note: ECDHE_RSA is defined in [TLSECC].
DHE_DSS DSA public key; the certificate MUST allow the
key to be used for signing with the hash
algorithm that will be employed in the server
key exchange message.
DH_DSS Diffie-Hellman public key; the keyAgreement bit
DH_RSA MUST be set if the key usage extension is
present.
ECDH_ECDSA ECDH-capable public key; the public key MUST
ECDH_RSA use a curve and point format supported by the
client, as described in [TLSECC].
ECDHE_ECDSA ECDSA-capable public key; the certificate MUST
allow the key to be used for signing with the
hash algorithm that will be employed in the
server key exchange message. The public key
MUST use a curve and point format supported by
the client, as described in [TLSECC].
- The "server_name" and "trusted_ca_keys" extensions [TLSEXT] are used to guide certificate selection ๐งญ.
If the client provided a "signature_algorithms" extension, then all certificates provided by the server MUST be signed by a hash/signature algorithm pair that appears in that extension ๐. Note that this implies that a certificate containing a key for one signature algorithm MAY be signed using a different signature algorithm (for instance, an RSA key signed with a DSA key) ๐ฆ. This is a departure from TLS 1.1, which required that the algorithms be the same ๐ฐ๏ธ. Note that this also implies that the DH_DSS, DH_RSA, ECDH_ECDSA, and ECDH_RSA key exchange algorithms do not restrict the algorithm used to sign the certificate. Fixed DH certificates MAY be signed with any hash/signature algorithm pair appearing in the extension. The names DH_DSS, DH_RSA, ECDH_ECDSA, and ECDH_RSA are historical ๐.
If the server has multiple certificates, it chooses one of them based on the above-mentioned criteria (in addition to other criteria, such as transport layer endpoint, local configuration and preferences, etc.) ๐ฏ. If the server has a single certificate, it SHOULD attempt to validate that it meets these criteria โจ.
Note that there are certificates that use algorithms and/or algorithm combinations that cannot be currently used with TLS. For example, a certificate with RSASSA-PSS signature key (id-RSASSA-PSS OID in SubjectPublicKeyInfo) cannot be used because TLS defines no corresponding signature algorithm ๐ โโ๏ธ.
As cipher suites that specify new key exchange methods are specified for the TLS protocol, they will imply the certificate format and the required encoded keying information ๐.
7.4.3. Server Key Exchange Message ๐๏ธ๐
When this message will be sent:
This message will be sent immediately after the server Certificate message (or the ServerHello message, if this is an anonymous negotiation) ๐ฌ.
The ServerKeyExchange message is sent by the server only when the server Certificate message (if sent) does not contain enough data to allow the client to exchange a premaster secret. This is true for the following key exchange methods:
DHE_DSS
DHE_RSA
DH_anon
It is not legal to send the ServerKeyExchange message for the following key exchange methods:
RSA
DH_DSS
DH_RSA
Other key exchange algorithms, such as those defined in [TLSECC], MUST specify whether the ServerKeyExchange message is sent or not; and if the message is sent, its contents ๐ง.
Meaning of this message:
This message conveys cryptographic information to allow the client to communicate the premaster secret: a Diffie-Hellman public key with which the client can complete a key exchange (with the result being the premaster secret) or a public key for some other algorithm ๐๐ธ.
Structure of this message:
enum { dhe_dss, dhe_rsa, dh_anon, rsa, dh_dss, dh_rsa
/* may be extended, e.g., for ECDH -- see [TLSECC] */
} KeyExchangeAlgorithm;
struct {
opaque dh_p<1..2^16-1>;
opaque dh_g<1..2^16-1>;
opaque dh_Ys<1..2^16-1>;
} ServerDHParams; /* Ephemeral DH parameters */
dh_p
The prime modulus used for the Diffie-Hellman operation.
dh_g
The generator used for the Diffie-Hellman operation.
dh_Ys
The server's Diffie-Hellman public value (g^X mod p).
struct {
select (KeyExchangeAlgorithm) {
case dh_anon:
ServerDHParams params;
case dhe_dss:
case dhe_rsa:
ServerDHParams params;
digitally-signed struct {
opaque client_random[32];
opaque server_random[32];
ServerDHParams params;
} signed_params;
case rsa:
case dh_dss:
case dh_rsa:
struct {} ;
/* message is omitted for rsa, dh_dss, and dh_rsa */
/* may be extended, e.g., for ECDH -- see [TLSECC] */
};
} ServerKeyExchange;
params
The server's key exchange parameters.
signed_params
For non-anonymous key exchanges, a signature over the server's
key exchange parameters.
If the client has offered the "signature_algorithms" extension, the signature algorithm and hash algorithm MUST be a pair listed in that extension ๐. Note that there is a possibility for inconsistencies here. For instance, the client might offer DHE_DSS key exchange but omit any DSA pairs from its "signature_algorithms" extension ๐ฌ. In order to negotiate correctly, the server MUST check any candidate cipher suites against the "signature_algorithms" extension before selecting them ๐. This is somewhat inelegant but is a compromise designed to minimize changes to the original cipher suite design ๐ซ .
In addition, the hash and signature algorithms MUST be compatible with the key in the server's end-entity certificate. RSA keys MAY be used with any permitted hash algorithm, subject to restrictions in the certificate, if any ๐.
Because DSA signatures do not contain any secure indication of hash algorithm, there is a risk of hash substitution if multiple hashes may be used with any key. Currently, DSA [DSS] may only be used with SHA-1. Future revisions of DSS [DSS-3] are expected to allow the use of other digest algorithms with DSA, as well as guidance as to which digest algorithms should be used with each key size. In addition, future revisions of [PKIX] may specify mechanisms for certificates to indicate which digest algorithms are to be used with DSA ๐จ๐.
As additional cipher suites are defined for TLS that include new key exchange algorithms, the server key exchange message will be sent if and only if the certificate type associated with the key exchange algorithm does not provide enough information for the client to exchange a premaster secret ๐.
7.4.4. Certificate Request ๐
When this message will be sent:
Okay bestie, so a non-anonymous server can optionally ask the client for a certificate ๐, but only if it actually makes sense for the cipher suite that got picked. If the server sends this, it comes right after the ServerKeyExchange message (if that one's being sent). If it's not, this message comes right after the server's Certificate message โจ.
Structure of this message:
enum {
rsa_sign(1), dss_sign(2), rsa_fixed_dh(3), dss_fixed_dh(4),
rsa_ephemeral_dh_RESERVED(5), dss_ephemeral_dh_RESERVED(6),
fortezza_dms_RESERVED(20), (255)
} ClientCertificateType;
opaque DistinguishedName<1..2^16-1>;
struct {
ClientCertificateType certificate_types<1..2^8-1>;
SignatureAndHashAlgorithm
supported_signature_algorithms<2^16-1>;
DistinguishedName certificate_authorities<0..2^16-1>;
} CertificateRequest;
certificate_types ๐ฆ This is a list of the certificate types that the client may offer.
rsa_sign a certificate containing an RSA key
dss_sign a certificate containing a DSA key
rsa_fixed_dh a certificate containing a static DH key.
dss_fixed_dh a certificate containing a static DH key
supported_signature_algorithms ๐ฅ This is a list of the hash/signature algorithm pairs that the server is able to verify, listed in descending order of preference.
certificate_authorities ๐ธ This is a list of the distinguished names [X501] of acceptable certificate_authorities, written in DER-encoded format. These distinguished names can point to a desired distinguished name for a root CA or for a subordinate CA. So this message can be used to describe known roots as well as a desired authorization space ๐. If the certificate_authorities list is empty, then the client MAY send any certificate of the appropriate ClientCertificateType, unless there's some external arrangement saying otherwise ๐ .
The way certificate_types and supported_signature_algorithms work together is kinda complicated, not gonna lie ๐. certificate_types has been around since SSLv3, but it was pretty underspecified. A lot of its job is now handled by supported_signature_algorithms. Here are the rules:
- Any certificates provided by the client MUST be signed using a hash/signature algorithm pair found in supported_signature_algorithms.
- The end-entity certificate provided by the client MUST contain a key that is compatible with certificate_types. If the key is a signature key, it MUST be usable with some hash/signature algorithm pair in supported_signature_algorithms.
- For historical reasons, some client certificate type names include the algorithm used to sign the certificate. For example, in earlier versions of TLS, rsa_fixed_dh meant a certificate signed with RSA and containing a static DH key. In TLS 1.2 this has been obsoleted by supported_signature_algorithms, so the certificate type no longer restricts the signing algorithm. For example, if the server sends the dss_fixed_dh certificate type and
{{sha1, dsa}, {sha1, rsa}}signature types, the client MAY reply with a certificate containing a static DH key, signed with RSA-SHA1. ๐ง
New ClientCertificateType values are assigned by IANA as described in Section 12. ๐
Note: Values listed as RESERVED may not be used. They were used in SSLv3.
Note: It is a fatal handshake_failure alert for an anonymous server to request client authentication. ๐
7.4.5. Server Hello Done ๐ซถ
When this message will be sent:
The ServerHelloDone message is sent by the server to say it's finished with the ServerHello and its associated messages. After sending this, the server waits for the client to respond โญ.
Meaning of this message:
This message means the server is done sending the messages needed for the key exchange, so the client can move on with its part of the key exchange ๐ธ.
Once the client gets ServerHelloDone, it SHOULD check that the server provided a valid certificate (if one was required) and that the server hello parameters are acceptable ๐.
Structure of this message:
struct { } ServerHelloDone;
7.4.6. Client Certificate ๐
When this message will be sent:
This is the first message the client can send after it gets a ServerHelloDone message. It's only sent if the server asked for a certificate. If the client doesn't have a suitable certificate, it MUST send a certificate message with no certificates in it. Basically the certificate_list structure has a length of zero ๐. If the client doesn't send any certificates, the server MAY, at its discretion, either continue the handshake without client authentication or respond with a fatal handshake_failure alert. Also, if some part of the certificate chain was unacceptable (for example, it wasn't signed by a known, trusted CA), the server MAY, at its discretion, either continue the handshake (treating the client as unauthenticated) or send a fatal alert ๐ค.
Client certificates are sent using the Certificate structure defined in Section 7.4.2. ๐
Meaning of this message:
This message gives the server the client's certificate chain. The server uses it when verifying the CertificateVerify message (when client authentication is based on signing) or when calculating the premaster secret (for non-ephemeral Diffie-Hellman) ๐. The certificate MUST be appropriate for the negotiated cipher suite's key exchange algorithm and for any negotiated extensions.
Here's the breakdown ๐:
- The certificate type MUST be X.509v3, unless it's explicitly negotiated otherwise (for example, [TLSPGP]).
- The end-entity certificate's public key (and its associated restrictions) has to be compatible with the certificate types listed in CertificateRequest:
Client Cert. Type Certificate Key Type
rsa_sign RSA public key; the certificate MUST allow the
key to be used for signing with the signature
scheme and hash algorithm that will be
employed in the certificate verify message.
dss_sign DSA public key; the certificate MUST allow the
key to be used for signing with the hash
algorithm that will be employed in the
certificate verify message.
ecdsa_sign ECDSA-capable public key; the certificate MUST
allow the key to be used for signing with the
hash algorithm that will be employed in the
certificate verify message; the public key
MUST use a curve and point format supported by
the server.
rsa_fixed_dh Diffie-Hellman public key; MUST use the same
dss_fixed_dh parameters as server's key.
rsa_fixed_ecdh ECDH-capable public key; MUST use the
ecdsa_fixed_ecdh same curve as the server's key, and MUST use a
point format supported by the server.
- If the certificate_authorities list in the certificate request message was non-empty, one of the certificates in the certificate chain SHOULD be issued by one of the listed CAs. ๐ฆ
- The certificates MUST be signed using an acceptable hash/signature algorithm pair, as described in Section 7.4.4. Heads up, this relaxes the constraints on certificate-signing algorithms that existed in earlier versions of TLS ๐.
As with the server certificate, note that some certificates use algorithms or algorithm combinations that can't currently be used with TLS ๐.
7.4.7. Client Key Exchange Message ๐
When this message will be sent:
The client ALWAYS sends this one ๐ . It MUST immediately follow the client certificate message, if that's sent. Otherwise, it MUST be the first message the client sends after it receives the ServerHelloDone message.
Hold on, I need to fix that. The original says this message is always sent by the client, and that's the part I'll keep exact: this message is always sent by the client. Everything else in this paragraph stays as written above ๐ซถ.
Meaning of this message:
With this message, the premaster secret gets set. That happens either by directly sending the RSA-encrypted secret, or by sending Diffie-Hellman parameters that let each side agree on the same premaster secret ๐.
When the client uses an ephemeral Diffie-Hellman exponent, this message contains the client's Diffie-Hellman public value. If the client is sending a certificate with a static DH exponent (that is, it's doing fixed_dh client authentication), then this message MUST be sent but MUST be empty ๐ฅบ.
Structure of this message:
The message you get depends on which key exchange method was selected. See Section 7.4.3 for the KeyExchangeAlgorithm definition ๐ง.
struct {
select (KeyExchangeAlgorithm) {
case rsa:
EncryptedPreMasterSecret;
case dhe_dss:
case dhe_rsa:
case dh_dss:
case dh_rsa:
case dh_anon:
ClientDiffieHellmanPublic;
} exchange_keys;
} ClientKeyExchange;
7.4.7.1. RSA-Encrypted Premaster Secret Message โจ
What this message is for ๐
Okay so this one's for when RSA is doing both the key agreement and the authentication. The client makes a 48-byte premaster secret, encrypts it with the public key from the server's certificate, and sends it off in an encrypted premaster secret message. Lowkey, this isn't a message on its own. It's a variant of the ClientKeyExchange message ๐ซถ
struct {
ProtocolVersion client_version;
opaque random[46];
} PreMasterSecret;
client_version
The latest (newest) version supported by the client. This is
used to detect version rollback attacks.
random
46 securely-generated random bytes.
struct {
public-key-encrypted PreMasterSecret pre_master_secret;
} EncryptedPreMasterSecret;
pre_master_secret
This random value is generated by the client and is used to
generate the master secret, as specified in Section 8.1.
The client_version is the newest version the client supports, and it's there so the server can catch version rollback attacks ๐ต๏ธโโ๏ธ The 46 random bytes have to be securely generated, no shortcuts bestie ๐
๐จ The version number inside the PreMasterSecret is the one the client offered in ClientHello.client_version, NOT the version that got negotiated for the connection. That's on purpose, it's how the rollback protection works! The tea is that some older implementations use the negotiated version instead, so if the server checks the version number, those clients might just... not interop ๐
Here's the big rule for clients ๐
Client implementations MUST always send the correct version number in PreMasterSecret. Servers have homework too: if ClientHello.client_version is TLS 1.1 or higher, server implementations MUST check the version number the way the note below describes. If it's TLS 1.0 or earlier, servers SHOULD check it, but they MAY have a configuration option to turn the check off. And if the check fails, the PreMasterSecret SHOULD be randomized like I'm about to show you ๐ฒ
๐ญ Okay so, the Bleichenbacher attack [BLEI] and the Klima et al. attack [KPR03] can be used against a TLS server that reveals whether a decrypted message is properly PKCS#1 formatted, contains a valid PreMasterSecret structure, or has the correct version number. Yikes, right? ๐ญ
As Klima [KPR03] describes, you can dodge these vulnerabilities by treating bad message blocks and/or mismatched version numbers the same way you'd treat correctly formatted RSA blocks. The steps go like this:
1. Generate a string R of 46 random bytes
2. Decrypt the message to recover the plaintext M
3. If the PKCS#1 padding is not correct, or the length of message
M is not exactly 48 bytes:
pre_master_secret = ClientHello.client_version || R
else If ClientHello.client_version <= TLS 1.0, and version
number check is explicitly disabled:
pre_master_secret = M
else:
pre_master_secret = ClientHello.client_version || M[2..47]
Note that explicitly building the pre_master_secret with ClientHello.client_version gives you an invalid master_secret if the client sent the wrong version in the original pre_master_secret. Plot twist ๐
There's also a second approach, where you treat a version number mismatch like a PKCS-1 formatting error and just fully randomize the premaster secret ๐ง
1. Generate a string R of 48 random bytes
2. Decrypt the message to recover the plaintext M
3. If the PKCS#1 padding is not correct, or the length of message
M is not exactly 48 bytes:
pre_master_secret = R
else If ClientHello.client_version <= TLS 1.0, and version
number check is explicitly disabled:
premaster secret = M
else If M[0..1] != ClientHello.client_version:
premaster secret = R
else:
premaster secret = M
No practical attacks against this one are known ๐ But Klima et al. [KPR03] do describe some theoretical attacks, so the first construction is the RECOMMENDED one. Iconic choice, no cap ๐
๐จ Whichever one you pick, a TLS server MUST NOT generate an alert if processing an RSA-encrypted premaster secret message fails, or if the version number isn't what was expected. It MUST continue the handshake with a randomly generated premaster secret instead. Logging the real cause of the failure can be useful for troubleshooting, BUT (and this is a big but ๐ญ) you have to be careful not to leak it to an attacker through things like timing, log files, or other channels.
Quick side quest ๐ฆ The RSAES-OAEP scheme from [PKCS1] is more secure against the Bleichenbacher attack. But for maximal compatibility with earlier versions of TLS, this spec uses RSAES-PKCS1-v1_5 instead. No variants of the Bleichenbacher attack are known to exist as long as you follow the recommendations above, so we're good โจ
Implementation note: the length bytes situation ๐
Public-key-encrypted data is represented as an opaque vector <0..2^16-1> (see Section 4.7). So the RSA-encrypted PreMasterSecret inside a ClientKeyExchange comes with two length bytes in front. Those bytes are technically redundant for RSA, since the EncryptedPreMasterSecret is the only thing in the ClientKeyExchange and its length can be figured out without them. The SSLv3 spec wasn't clear about how public-key-encrypted data should be encoded, so a lot of SSLv3 implementations skipped the length bytes and just put the RSA-encrypted data straight into the ClientKeyExchange message. Oops ๐
This spec requires the correct encoding of the EncryptedPreMasterSecret, length bytes and all. The catch is that this PDU won't work with many SSLv3 implementations. So anyone upgrading from SSLv3 MUST modify their implementation to generate and accept the correct encoding. If you want to be compatible with both SSLv3 and TLS, your implementation's behavior should depend on the protocol version ๐
Implementation note: timing attacks are real ๐ฐ๏ธ
It's now known that remote timing-based attacks on TLS are possible, at least when the client and server are on the same LAN. So implementations that use static RSA keys MUST use RSA blinding or some other anti-timing technique, as described in [TIMING]. Protect those keys, babe ๐
7.4.7.2. Client Diffie-Hellman Public Value ๐ธ
What this message is for ๐
This structure carries the client's Diffie-Hellman public value (Yc), but only if it wasn't already included in the client's certificate. How Yc gets encoded is decided by the enumerated PublicValueEncoding. Like the last one, this is a variant of the client key exchange message and not a message in itself ๐ง
enum { implicit, explicit } PublicValueEncoding;
implicit
If the client has sent a certificate which contains a suitable
Diffie-Hellman key (for fixed_dh client authentication), then
Yc is implicit and does not need to be sent again. In this
case, the client key exchange message will be sent, but it MUST
be empty.
explicit
Yc needs to be sent.
struct {
select (PublicValueEncoding) {
case implicit: struct { };
case explicit: opaque dh_Yc<1..2^16-1>;
} dh_public;
} ClientDiffieHellmanPublic;
dh_Yc
The client's Diffie-Hellman public value (Yc).
So here's the deal ๐โโ๏ธ If the client already sent a cert with a suitable Diffie-Hellman key (that's the fixed_dh client auth case), Yc is implicit and doesn't need to be sent again. The client key exchange message still goes out, but it MUST be empty. If Yc isn't covered by the cert, it's explicit, and it gets sent for real ๐
7.4.8. Certificate Verify ๐
When this message gets sent ๐๏ธ
This message gives explicit proof of a client certificate. It's only sent after a client certificate that has signing capability, which means every certificate except the ones with fixed Diffie-Hellman parameters. When it does get sent, it MUST immediately follow the client key exchange message ๐ซถ
struct {
digitally-signed struct {
opaque handshake_messages[handshake_messages_length];
}
} CertificateVerify;
Here's what handshake_messages means ๐ง It covers every handshake message sent or received, starting at client hello and stopping right before this message. It includes the type and length fields of the handshake messages, and it's the concatenation of all the Handshake structures (see Section 7.4) exchanged so far. Heads up: this means both sides have to either buffer the messages or keep running hashes for all the potential hash algorithms until the CertificateVerify is computed. Servers can cut down on that work by offering a restricted set of digest algorithms in the CertificateRequest message ๐
Now for the rules ๐ The hash and signature algorithms used in the signature MUST be one of the ones in the supported_signature_algorithms field of the CertificateRequest message. The hash and signature algorithms MUST also be compatible with the key in the client's end-entity certificate. RSA keys MAY be used with any permitted hash algorithm, subject to any restrictions in the certificate, if there are any ๐ฆ
๐จ Be careful with DSA! DSA signatures don't include any secure indication of which hash algorithm was used, so if you're allowed to use multiple hashes with one key, there's a risk of hash substitution. Right now, DSA [DSS] may only be used with SHA-1. Future revisions of DSS [DSS-3] are expected to allow other digest algorithms with DSA, plus guidance on which digests go with each key size. Future revisions of [PKIX] may also specify how certificates indicate which digest algorithms should be used with DSA. Stay tuned ๐
7.4.9. Finished โจ
okay so when it gets sent ๐: a Finished message is always sent right after a change cipher spec message, and its whole job is to check that the key exchange and authentication both worked ๐. It's super essential that the change cipher spec message shows up between the other handshake messages and the Finished one, so don't skip it ๐ .
What it means ๐ฆ: the Finished message is the very first thing protected with the algorithms, keys, and secrets that were just negotiated. Recipients of Finished messages MUST verify that the contents are correct, no cap. Once a side has sent its own Finished message and has received and validated its peer's, it can start sending and receiving application data over the connection ๐.
What it looks like ๐:
struct {
opaque verify_data[verify_data_length];
} Finished;
verify_data
PRF(master_secret, finished_label, Hash(handshake_messages))
[0..verify_data_length-1];
The pieces of that formula, explained:
- finished_label: messages sent by the client use the string "client finished", and messages sent by the server use the string "server finished" ๐ง
- Hash: this is a hash of the handshake messages. For the PRF defined in Section 5, the Hash MUST be the Hash that the PRF is built on. Any cipher suite that defines a different PRF MUST also define the Hash it uses for the Finished computation ๐
- verify_data_length: back in older TLS versions, verify_data was always 12 octets long. Now the length depends on the cipher suite. A cipher suite that doesn't explicitly say what verify_data_length is gets 12, and that covers every existing cipher suite. The encoding is the same as before ๐ธ. Future cipher suites MAY pick other lengths, but any such length MUST be at least 12 bytes ๐.
- handshake_messages: this is everything from all the messages in this handshake (leaving out any HelloRequest messages), up to but not including this message. It's only the handshake-layer data and doesn't include record layer headers. It's the concatenation of all the Handshake structures from Section 7.4 that have been exchanged so far ๐.
It is a fatal error if a Finished message is not preceded by a ChangeCipherSpec message at the appropriate point in the handshake. Don't let this one slide, bestie ๐จ.
Some more tea on the hashing: handshake_messages starts at ClientHello and runs up to, but not including, this Finished message. It can be different from the handshake_messages in Section 7.4.8, because it includes the CertificateVerify message (if one was sent) ๐. Also, the client's Finished and the server's Finished don't hash the same input, since whichever one goes second includes the one before it ๐ซถ.
Note: ChangeCipherSpec messages, alerts, and any other record types are not handshake messages, so they stay out of the hash computations. HelloRequest messages get left out of handshake hashes too ๐.
8. Cryptographic Computations ๐
okay so to start connection protection, the TLS Record Protocol needs a suite of algorithms, a master secret, and the client and server random values. The authentication, encryption, and MAC algorithms all come from the cipher_suite that the server picked and revealed in its ServerHello message. The compression algorithm gets negotiated in the hello messages, and so do the random values. The only thing left to do is calculate the master secret โจ.
8.1. Computing the Master Secret ๐
For every key exchange method, the same algorithm turns the pre_master_secret into the master_secret. The pre_master_secret should be deleted from memory once the master_secret has been computed ๐งน.
master_secret = PRF(pre_master_secret, "master secret",
ClientHello.random + ServerHello.random)
[0..47];
The master secret is always exactly 48 bytes long. The length of the premaster secret, though, changes depending on the key exchange method ๐ฆ.
8.1.1. RSA ๐
When RSA is used for server authentication and key exchange, the client generates a 48-byte pre_master_secret, encrypts it under the server's public key, and sends it to the server ๐จ. The server uses its private key to decrypt it. Then both parties turn the pre_master_secret into the master_secret, the same way as described above ๐ค.
8.1.2. Diffie-Hellman ๐ธ
A conventional Diffie-Hellman computation happens here. The negotiated key (Z) is used as the pre_master_secret, and then it gets converted into the master_secret, same as above. Leading bytes of Z that are all zero bits get stripped before Z is used as the pre_master_secret ๐ง.
Note: the Diffie-Hellman parameters come from the server, and they can be ephemeral or included in the server's certificate ๐ .
9. Mandatory Cipher Suites ๐
Unless some application profile standard says otherwise, a TLS-compliant application MUST implement the cipher suite TLS_RSA_WITH_AES_128_CBC_SHA (see Appendix A.5 for the definition) ๐.
10. Application Data Protocol ๐
Application data messages get carried by the record layer. They get fragmented, compressed, and encrypted based on the current connection state, and the record layer treats them as transparent data ๐ง.
11. Security Considerations ๐ฅ
Security issues are discussed throughout this memo, and you really need to pay attention, especially in Appendices D, E, and F ๐. Don't skim this part, bestie. It's serious business ๐ซถ.
12. IANA Considerations ๐
This document uses several registries that were first created in [TLS1.1]. IANA has updated them so they point at this document. The registries, along with their allocation policies (which haven't changed since [TLS1.1]), are listed below โจ.
- TLS ClientCertificateType Identifiers Registry: future values from 0-63 (decimal), inclusive, are assigned via Standards Action [RFC2434]. Values from 64-223 (decimal), inclusive, are assigned via Specification Required [RFC2434]. Values from 224-255 (decimal), inclusive, are reserved for Private Use [RFC2434] ๐.
- TLS Cipher Suite Registry: future values whose first byte is in the range 0-191 (decimal), inclusive, are assigned via Standards Action [RFC2434]. Values whose first byte is in the range 192-254 (decimal) are assigned via Specification Required [RFC2434]. Values whose first byte is 255 (decimal) are reserved for Private Use [RFC2434] ๐.
- This document defines several new HMAC-SHA256-based cipher suites. Their values (in Appendix A.5) got allocated from the TLS Cipher Suite registry ๐.
- TLS ContentType Registry: future values are allocated via Standards Action [RFC2434] ๐ฎ.
- TLS Alert Registry: future values are allocated via Standards Action [RFC2434] ๐จ.
- TLS HandshakeType Registry: future values are allocated via Standards Action [RFC2434] ๐ค.
This document also uses a registry that was originally created in [RFC4366]. IANA has updated it to reference this document. The registry, along with its allocation policy (unchanged from [RFC4366]), is listed below ๐ฆ:
- TLS ExtensionType Registry: future values are allocated via IETF Consensus [RFC2434]. IANA has updated this registry to include the signature_algorithms extension and its corresponding value (see Section 7.4.1.4) ๐ธ.
In addition, this document defines two new registries that IANA will maintain ๐:
- TLS SignatureAlgorithm Registry: the registry was initially populated with the values described in Section 7.4.1.4.1. Future values from 0-63 (decimal), inclusive, are assigned via Standards Action [RFC2434]. Values from 64-223 (decimal), inclusive, are assigned via Specification Required [RFC2434]. Values from 224-255 (decimal), inclusive, are reserved for Private Use [RFC2434] ๐ง.
- TLS HashAlgorithm Registry: the registry was initially populated with the values described in Section 7.4.1.4.1. Future values from 0-63 (decimal), inclusive, are assigned via Standards Action [RFC2434]. Values from 64-223 (decimal), inclusive, are assigned via Specification Required [RFC2434]. Values from 224-255 (decimal), inclusive, are reserved for Private Use [RFC2434] ๐.
This document also uses the TLS Compression Method Identifiers Registry, which is defined in [RFC3749]. IANA has allocated value 0 for the "null" compression method ๐.
Appendix A. Protocol Data Structures and Constant Values ๐
okay so this section describes the protocol types and constants ๐.
A.1. Record Layer ๐
struct {
uint8 major;
uint8 minor;
} ProtocolVersion;
ProtocolVersion version = { 3, 3 }; /* TLS v1.2*/
enum {
change_cipher_spec(20), alert(21), handshake(22),
application_data(23), (255)
} ContentType;
struct {
ContentType type;
ProtocolVersion version;
uint16 length;
opaque fragment[TLSPlaintext.length];
} TLSPlaintext;
struct {
ContentType type;
ProtocolVersion version;
uint16 length;
opaque fragment[TLSCompressed.length];
} TLSCompressed;
struct {
ContentType type;
ProtocolVersion version;
uint16 length;
select (SecurityParameters.cipher_type) {
case stream: GenericStreamCipher;
case block: GenericBlockCipher;
case aead: GenericAEADCipher;
} fragment;
} TLSCiphertext;
stream-ciphered struct {
opaque content[TLSCompressed.length];
opaque MAC[SecurityParameters.mac_length];
} GenericStreamCipher;
struct {
opaque IV[SecurityParameters.record_iv_length];
block-ciphered struct {
opaque content[TLSCompressed.length];
opaque MAC[SecurityParameters.mac_length];
uint8 padding[GenericBlockCipher.padding_length];
uint8 padding_length;
};
} GenericBlockCipher;
struct {
opaque nonce_explicit[SecurityParameters.record_iv_length];
aead-ciphered struct {
opaque content[TLSCompressed.length];
};
} GenericAEADCipher;
A.2. Change Cipher Specs Message ๐ฆ
struct {
enum { change_cipher_spec(1), (255) } type;
} ChangeCipherSpec;
A.3. Alert Messages ๐จ
enum { warning(1), fatal(2), (255) } AlertLevel;
enum {
close_notify(0),
unexpected_message(10),
bad_record_mac(20),
decryption_failed_RESERVED(21),
record_overflow(22),
decompression_failure(30),
handshake_failure(40),
no_certificate_RESERVED(41),
bad_certificate(42),
unsupported_certificate(43),
certificate_revoked(44),
certificate_expired(45),
certificate_unknown(46),
illegal_parameter(47),
unknown_ca(48),
access_denied(49),
decode_error(50),
decrypt_error(51),
export_restriction_RESERVED(60),
protocol_version(70),
insufficient_security(71),
internal_error(80),
user_canceled(90),
no_renegotiation(100),
unsupported_extension(110), /* new */
(255)
} AlertDescription;
struct {
AlertLevel level;
AlertDescription description;
} Alert;
A.4. Handshake Protocol โจ
Okay bestie, this is the part where the handshake messages get their official lineup ๐
Every message type gets a number, and then the big Handshake struct wraps whichever one you're sending. Literally the whole conversation is built out of these little packages ๐ฆ
enum {
hello_request(0), client_hello(1), server_hello(2),
certificate(11), server_key_exchange (12),
certificate_request(13), server_hello_done(14),
certificate_verify(15), client_key_exchange(16),
finished(20)
(255)
} HandshakeType;
struct {
HandshakeType msg_type;
uint24 length;
select (HandshakeType) {
case hello_request: HelloRequest;
case client_hello: ClientHello;
case server_hello: ServerHello;
case certificate: Certificate;
case server_key_exchange: ServerKeyExchange;
case certificate_request: CertificateRequest;
case server_hello_done: ServerHelloDone;
case certificate_verify: CertificateVerify;
case client_key_exchange: ClientKeyExchange;
case finished: Finished;
} body;
} Handshake;
A.4.1. Hello Messages ๐ธ
Here's the hello squad ๐ง The HelloRequest is totally empty, no body needed. Then Random is 4 bytes of time plus 28 bytes of random stuff, and the ClientHello and ServerHello both carry a version, a random, a session ID, and extensions if they're present. The client gets to offer a whole list of cipher suites and compression methods, while the server just picks one of each ๐ซถ
struct { } HelloRequest;
struct {
uint32 gmt_unix_time;
opaque random_bytes[28];
} Random;
opaque SessionID<0..32>;
uint8 CipherSuite[2];
enum { null(0), (255) } CompressionMethod;
struct {
ProtocolVersion client_version;
Random random;
SessionID session_id;
CipherSuite cipher_suites<2..2^16-2>;
CompressionMethod compression_methods<1..2^8-1>;
select (extensions_present) {
case false:
struct {};
case true:
Extension extensions<0..2^16-1>;
};
} ClientHello;
struct {
ProtocolVersion server_version;
Random random;
SessionID session_id;
CipherSuite cipher_suite;
CompressionMethod compression_method;
select (extensions_present) {
case false:
struct {};
case true:
Extension extensions<0..2^16-1>;
};
} ServerHello;
struct {
ExtensionType extension_type;
opaque extension_data<0..2^16-1>;
} Extension;
enum {
signature_algorithms(13), (65535)
} ExtensionType;
enum{
none(0), md5(1), sha1(2), sha224(3), sha256(4), sha384(5),
sha512(6), (255)
} HashAlgorithm;
enum {
anonymous(0), rsa(1), dsa(2), ecdsa(3), (255)
} SignatureAlgorithm;
struct {
HashAlgorithm hash;
SignatureAlgorithm signature;
} SignatureAndHashAlgorithm;
SignatureAndHashAlgorithm
supported_signature_algorithms<2..2^16-1>;
A.4.2. Server Authentication and Key Exchange Messages ๐ฅ
Now the server shows its receipts ๐ฅ The Certificate is a list of ASN.1 certs, the ServerKeyExchange changes shape depending on which key exchange algorithm is in play (and for some of them the message is just empty, literally omitted), and CertificateRequest is where the server asks the client for its cert. ServerHelloDone is the "okay, I'm done talking" message ๐
opaque ASN.1Cert<2^24-1>;
struct {
ASN.1Cert certificate_list<0..2^24-1>;
} Certificate;
enum { dhe_dss, dhe_rsa, dh_anon, rsa,dh_dss, dh_rsa
/* may be extended, e.g., for ECDH -- see [TLSECC] */
} KeyExchangeAlgorithm;
struct {
opaque dh_p<1..2^16-1>;
opaque dh_g<1..2^16-1>;
opaque dh_Ys<1..2^16-1>;
} ServerDHParams; /* Ephemeral DH parameters */
struct {
select (KeyExchangeAlgorithm) {
case dh_anon:
ServerDHParams params;
case dhe_dss:
case dhe_rsa:
ServerDHParams params;
digitally-signed struct {
opaque client_random[32];
opaque server_random[32];
ServerDHParams params;
} signed_params;
case rsa:
case dh_dss:
case dh_rsa:
struct {} ;
/* message is omitted for rsa, dh_dss, and dh_rsa */
/* may be extended, e.g., for ECDH -- see [TLSECC] */
} ServerKeyExchange;
enum {
rsa_sign(1), dss_sign(2), rsa_fixed_dh(3), dss_fixed_dh(4),
rsa_ephemeral_dh_RESERVED(5), dss_ephemeral_dh_RESERVED(6),
fortezza_dms_RESERVED(20),
(255)
} ClientCertificateType;
opaque DistinguishedName<1..2^16-1>;
struct {
ClientCertificateType certificate_types<1..2^8-1>;
DistinguishedName certificate_authorities<0..2^16-1>;
} CertificateRequest;
struct { } ServerHelloDone;
A.4.3. Client Authentication and Key Exchange Messages ๐ฆ
Time for the client to bring its side of the story ๐ฆ The ClientKeyExchange depends on the key exchange algorithm too: RSA gets an encrypted pre-master secret, and the Diffie-Hellman flavours send a public value. The PreMasterSecret is 48 bytes total (two bytes of version plus 46 random ones), and CertificateVerify is a signature over the handshake messages so far ๐
struct {
select (KeyExchangeAlgorithm) {
case rsa:
EncryptedPreMasterSecret;
case dhe_dss:
case dhe_rsa:
case dh_dss:
case dh_rsa:
case dh_anon:
ClientDiffieHellmanPublic;
} exchange_keys;
} ClientKeyExchange;
struct {
ProtocolVersion client_version;
opaque random[46];
} PreMasterSecret;
struct {
public-key-encrypted PreMasterSecret pre_master_secret;
} EncryptedPreMasterSecret;
enum { implicit, explicit } PublicValueEncoding;
struct {
select (PublicValueEncoding) {
case implicit: struct {};
case explicit: opaque DH_Yc<1..2^16-1>;
} dh_public;
} ClientDiffieHellmanPublic;
struct {
digitally-signed struct {
opaque handshake_messages[handshake_messages_length];
}
} CertificateVerify;
A.4.4. Handshake Finalization Message ๐
And finally, the Finished message: just a verify_data blob that proves the handshake went smoothly โจ It's the last little wave before the party starts ๐
struct {
opaque verify_data[verify_data_length];
} Finished;
A.5. The Cipher Suite ๐
Okay, the cipher suite list is literally the menu of security combos ๐ Each one gets a two-byte code, and some of them are NOT it, bestie ๐
The following values define the cipher suite codes used in the ClientHello and ServerHello messages.
A cipher suite defines a cipher specification supported in TLS Version 1.2.
TLS_NULL_WITH_NULL_NULL is specified and is the initial state of a TLS connection during the first handshake on that channel, but MUST NOT be negotiated, as it provides no more protection than an unsecured connection.
CipherSuite TLS_NULL_WITH_NULL_NULL = { 0x00,0x00 };
The following CipherSuite definitions require that the server provide an RSA certificate that can be used for key exchange. The server may request any signature-capable certificate in the certificate request message.
CipherSuite TLS_RSA_WITH_NULL_MD5 = { 0x00,0x01 };
CipherSuite TLS_RSA_WITH_NULL_SHA = { 0x00,0x02 };
CipherSuite TLS_RSA_WITH_NULL_SHA256 = { 0x00,0x3B };
CipherSuite TLS_RSA_WITH_RC4_128_MD5 = { 0x00,0x04 };
CipherSuite TLS_RSA_WITH_RC4_128_SHA = { 0x00,0x05 };
CipherSuite TLS_RSA_WITH_3DES_EDE_CBC_SHA = { 0x00,0x0A };
CipherSuite TLS_RSA_WITH_AES_128_CBC_SHA = { 0x00,0x2F };
CipherSuite TLS_RSA_WITH_AES_256_CBC_SHA = { 0x00,0x35 };
CipherSuite TLS_RSA_WITH_AES_128_CBC_SHA256 = { 0x00,0x3C };
CipherSuite TLS_RSA_WITH_AES_256_CBC_SHA256 = { 0x00,0x3D };
The following cipher suite definitions are used for server-authenticated (and optionally client-authenticated) Diffie-Hellman. DH denotes cipher suites in which the server's certificate contains the Diffie-Hellman parameters signed by the certificate authority (CA). DHE denotes ephemeral Diffie-Hellman, where the Diffie-Hellman parameters are signed by a signature-capable certificate, which has been signed by the CA. The signing algorithm used by the server is specified after the DHE component of the CipherSuite name. The server can request any signature-capable certificate from the client for client authentication, or it may request a Diffie-Hellman certificate. Any Diffie-Hellman certificate provided by the client must use the parameters (group and generator) described by the server.
CipherSuite TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA = { 0x00,0x0D };
CipherSuite TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA = { 0x00,0x10 };
CipherSuite TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA = { 0x00,0x13 };
CipherSuite TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA = { 0x00,0x16 };
CipherSuite TLS_DH_DSS_WITH_AES_128_CBC_SHA = { 0x00,0x30 };
CipherSuite TLS_DH_RSA_WITH_AES_128_CBC_SHA = { 0x00,0x31 };
CipherSuite TLS_DHE_DSS_WITH_AES_128_CBC_SHA = { 0x00,0x32 };
CipherSuite TLS_DHE_RSA_WITH_AES_128_CBC_SHA = { 0x00,0x33 };
CipherSuite TLS_DH_DSS_WITH_AES_256_CBC_SHA = { 0x00,0x36 };
CipherSuite TLS_DH_RSA_WITH_AES_256_CBC_SHA = { 0x00,0x37 };
CipherSuite TLS_DHE_DSS_WITH_AES_256_CBC_SHA = { 0x00,0x38 };
CipherSuite TLS_DHE_RSA_WITH_AES_256_CBC_SHA = { 0x00,0x39 };
CipherSuite TLS_DH_DSS_WITH_AES_128_CBC_SHA256 = { 0x00,0x3E };
CipherSuite TLS_DH_RSA_WITH_AES_128_CBC_SHA256 = { 0x00,0x3F };
CipherSuite TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 = { 0x00,0x40 };
CipherSuite TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 = { 0x00,0x67 };
CipherSuite TLS_DH_DSS_WITH_AES_256_CBC_SHA256 = { 0x00,0x68 };
CipherSuite TLS_DH_RSA_WITH_AES_256_CBC_SHA256 = { 0x00,0x69 };
CipherSuite TLS_DHE_DSS_WITH_AES_256_CBC_SHA256 = { 0x00,0x6A };
CipherSuite TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 = { 0x00,0x6B };
The following cipher suites are used for completely anonymous Diffie-Hellman communications in which neither party is authenticated. Note that this mode is vulnerable to man-in-the-middle attacks. Using this mode therefore is of limited use: These cipher suites MUST NOT be used by TLS 1.2 implementations unless the application layer has specifically requested to allow anonymous key exchange. (Anonymous key exchange may sometimes be acceptable, for example, to support opportunistic encryption when no set-up for authentication is in place, or when TLS is used as part of more complex security protocols that have other means to ensure authentication.)
โ ๏ธ Heads up: anonymous Diffie-Hellman has no identity check at all, so it's open to man-in-the-middle attacks. Only use it if the application layer has specifically asked for it, bestie ๐
CipherSuite TLS_DH_anon_WITH_RC4_128_MD5 = { 0x00,0x18 };
CipherSuite TLS_DH_anon_WITH_3DES_EDE_CBC_SHA = { 0x00,0x1B };
CipherSuite TLS_DH_anon_WITH_AES_128_CBC_SHA = { 0x00,0x34 };
CipherSuite TLS_DH_anon_WITH_AES_256_CBC_SHA = { 0x00,0x3A };
CipherSuite TLS_DH_anon_WITH_AES_128_CBC_SHA256 = { 0x00,0x6C };
CipherSuite TLS_DH_anon_WITH_AES_256_CBC_SHA256 = { 0x00,0x6D };
Note that using non-anonymous key exchange without actually verifying the key exchange is essentially equivalent to anonymous key exchange, and the same precautions apply. While non-anonymous key exchange will generally involve a higher computational and communicational cost than anonymous key exchange, it may be in the interest of interoperability not to disable non-anonymous key exchange when the application layer is allowing anonymous key exchange.
New cipher suite values have been assigned by IANA as described in Section 12.
Note: The cipher suite values { 0x00, 0x1C } and { 0x00, 0x1D } are reserved to avoid collision with Fortezza-based cipher suites in SSL 3.
A.6. The Security Parameters โจ
okay so these security parameters are worked out by the TLS Handshake Protocol and then handed over to the TLS record layer so it can set up a connection state ๐. here's what SecurityParameters holds:
enum { null(0), (255) } CompressionMethod;
enum { server, client } ConnectionEnd;
enum { tls_prf_sha256 } PRFAlgorithm;
enum { null, rc4, 3des, aes } BulkCipherAlgorithm;
enum { stream, block, aead } CipherType;
enum { null, hmac_md5, hmac_sha1, hmac_sha256, hmac_sha384,
hmac_sha512} MACAlgorithm;
/* Other values may be added to the algorithms specified in
CompressionMethod, PRFAlgorithm, BulkCipherAlgorithm, and
MACAlgorithm. */
struct {
ConnectionEnd entity;
PRFAlgorithm prf_algorithm;
BulkCipherAlgorithm bulk_cipher_algorithm;
CipherType cipher_type;
uint8 enc_key_length;
uint8 block_length;
uint8 fixed_iv_length;
uint8 record_iv_length;
MACAlgorithm mac_algorithm;
uint8 mac_length;
uint8 mac_key_length;
CompressionMethod compression_algorithm;
opaque master_secret[48];
opaque client_random[32];
opaque server_random[32];
} SecurityParameters;
A.7. Changes to RFC 4492 ๐ฆ
so RFC 4492 [TLSECC] is the one that brings Elliptic Curve cipher suites into TLS ๐. this document changes a few of the structures that RFC 4492 uses, so this section lays out the changes that people building both RFC 4492 and TLS 1.2 need to know about ๐. if you're doing TLS 1.2 but not RFC 4492, you can skip this part, bestie.
this document adds a "signature_algorithm" field to the digitally-signed element. it's how you tell which signature and digest algorithms were used to make a signature ๐ฅ. this also covers ECDSA signatures, so ECDSA can now be used with digest algorithms other than SHA-1 ๐, as long as that matches the certificate and any restrictions that future revisions of [PKIX] put in place.
as described in Sections 7.4.2 and 7.4.6, the rules for which signature algorithms can sign certificates are no longer locked to the cipher suite (when it's the server doing the signing) or to the ClientCertificateType (when it's the client). so the limits on the signing algorithm for certificates that Sections 2 and 3 of RFC 4492 set are relaxed too ๐ธ. the restrictions on the keys in the end-entity certificate are still there, same as in this document โจ.
Appendix B. Glossary ๐ง
okay the glossary is giving everything, so here it is in full ๐ .
Advanced Encryption Standard (AES) AES [AES] is a super popular symmetric encryption algorithm ๐. It's a block cipher that works with a 128-, 192-, or 256-bit key and a 16-byte block size. TLS only supports the 128- and 256-bit key sizes right now.
application protocol An application protocol is one that normally sits directly on top of the transport layer (e.g., TCP/IP) ๐. Examples are HTTP, TELNET, FTP, and SMTP.
asymmetric cipher See public key cryptography.
authenticated encryption with additional data (AEAD) A symmetric encryption algorithm that gives you confidentiality and message integrity at the same time ๐ฅ.
authentication Authentication is one entity figuring out who another entity is ๐ซถ.
block cipher A block cipher is an algorithm that works on plaintext in groups of bits, called blocks. 64 bits used to be a common block size, and 128 bits is one now ๐.
bulk cipher A symmetric encryption algorithm used to encrypt big piles of data ๐ฆ.
cipher block chaining (CBC) CBC is a mode where every plaintext block gets encrypted with a block cipher, but first it's exclusive-ORed with the previous ciphertext block (or, for the very first block, with the initialization vector). For decryption, every block gets decrypted first, and then it's exclusive-ORed with the previous ciphertext block (or IV) ๐ฆ.
certificate As part of the X.509 protocol (a.k.a. ISO Authentication framework), certificates get assigned by a trusted Certificate Authority. They give a strong binding between a party's identity (or some other attributes) and its public key ๐.
client The application entity that starts a TLS connection to a server ๐. That doesn't have to mean the client started the underlying transport connection. The main difference is that the server is generally authenticated, while the client is only optionally authenticated โจ.
client write key The key used to encrypt data the client writes ๐ธ.
client write MAC key The secret data used to authenticate data the client writes ๐.
connection A connection is a transport (in the OSI layering model) that gives a suitable type of service. For TLS, these are peer-to-peer relationships ๐ค. Connections are transient, and every connection is associated with one session ๐ฆ.
Data Encryption Standard DES [DES] is still very widely used as a symmetric encryption algorithm, even though it's considered rather weak now ๐ญ. DES is a block cipher with a 56-bit key and an 8-byte block size. Note that in TLS, for key generation purposes, DES is treated as having an 8-byte key length (64 bits), but it still only provides 56 bits of protection. (The low bit of each key byte is presumed to be set to produce odd parity in that key byte.) DES can also run in a mode [3DES] where three independent keys and three encryptions are used for each block of data. That uses 168 bits of key (24 bytes in the TLS key generation method) and gives the equivalent of 112 bits of security ๐.
Digital Signature Standard (DSS) DSS is a standard for digital signing, including the Digital Signing Algorithm. The National Institute of Standards and Technology approved it, and it's defined in NIST FIPS PUB 186-2, "Digital Signature Standard", published January 2000 by the U.S. Department of Commerce [DSS]. A significant update [DSS-3] has been drafted and was published in March 2006 ๐ง.
digital signatures Digital signatures use public key cryptography and one-way hash functions to make a signature of the data that can be authenticated, and that's hard to forge or repudiate ๐ .
handshake An initial negotiation between client and server that sets the parameters for their transactions ๐ค.
Initialization Vector (IV) When a block cipher is used in CBC mode, the initialization vector gets exclusive-ORed with the first plaintext block before encryption ๐.
Message Authentication Code (MAC) A MAC is a one-way hash computed from a message and some secret data. It's hard to forge without knowing the secret data, and its purpose is to detect whether the message has been altered ๐.
master secret Secure secret data used to generate encryption keys, MAC secrets, and IVs ๐๏ธ.
MD5 MD5 [MD5] is a hashing function that turns an arbitrarily long data stream into a fixed-size hash (16 bytes). Because of significant progress in cryptanalysis, at the time this document was published, MD5 no longer could be considered a 'secure' hashing function ๐ญ.
public key cryptography A class of cryptographic techniques that use two-key ciphers ๐. Messages encrypted with the public key can only be decrypted with the associated private key. Conversely, messages signed with the private key can be verified with the public key ๐.
one-way hash function A one-way transformation that turns an arbitrary amount of data into a fixed-length hash. It's computationally hard to reverse the transformation or to find collisions. MD5 and SHA are examples of one-way hash functions ๐ธ.
RC4 A stream cipher invented by Ron Rivest. A compatible cipher is described in [SCH] ๐ฆ.
RSA A very widely used public key algorithm that can be used for either encryption or digital signing [RSA] ๐.
server The server is the application entity that responds to requests for connections from clients. See also "client" ๐ฐ.
session A TLS session is an association between a client and a server ๐ซถ. Sessions are created by the handshake protocol, and they define a set of cryptographic security parameters that can be shared among multiple connections. They exist so you don't have to go through the expensive negotiation of new security parameters for every single connection โจ.
session identifier A session identifier is a value generated by a server that identifies a particular session ๐.
server write key The key used to encrypt data the server writes ๐ท.
server write MAC key The secret data used to authenticate data the server writes ๐.
SHA The Secure Hash Algorithm [SHS] is defined in FIPS PUB 180-2 and produces a 20-byte output. Note that all references to SHA (without a numerical suffix) actually use the modified SHA-1 algorithm ๐ง.
SHA-256 The 256-bit Secure Hash Algorithm is defined in FIPS PUB 180-2 and produces a 32-byte output ๐.
SSL Netscape's Secure Socket Layer protocol [SSL3]. TLS is based on SSL Version 3.0 ๐ผ.
stream cipher An encryption algorithm that turns a key into a cryptographically strong keystream, which is then exclusive-ORed with the plaintext ๐.
symmetric cipher See bulk cipher.
Transport Layer Security (TLS) This protocol, and also the Transport Layer Security working group of the Internet Engineering Task Force (IETF). See "Working Group Information" at the end of this document (see page 99) ๐.
Appendix C. Cipher Suite Definitions โจ
okay bestie, this is the cheat sheet ๐ธ Every cipher suite name is basically a little recipe: the key exchange, the cipher, and the MAC, all in one name. Here's the full menu ๐
Cipher Suite Key Cipher Mac
Exchange
TLS_NULL_WITH_NULL_NULL NULL NULL NULL
TLS_RSA_WITH_NULL_MD5 RSA NULL MD5
TLS_RSA_WITH_NULL_SHA RSA NULL SHA
TLS_RSA_WITH_NULL_SHA256 RSA NULL SHA256
TLS_RSA_WITH_RC4_128_MD5 RSA RC4_128 MD5
TLS_RSA_WITH_RC4_128_SHA RSA RC4_128 SHA
TLS_RSA_WITH_3DES_EDE_CBC_SHA RSA 3DES_EDE_CBC SHA
TLS_RSA_WITH_AES_128_CBC_SHA RSA AES_128_CBC SHA
TLS_RSA_WITH_AES_256_CBC_SHA RSA AES_256_CBC SHA
TLS_RSA_WITH_AES_128_CBC_SHA256 RSA AES_128_CBC SHA256
TLS_RSA_WITH_AES_256_CBC_SHA256 RSA AES_256_CBC SHA256
TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA DH_DSS 3DES_EDE_CBC SHA
TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA DH_RSA 3DES_EDE_CBC SHA
TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA DHE_DSS 3DES_EDE_CBC SHA
TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA DHE_RSA 3DES_EDE_CBC SHA
TLS_DH_anon_WITH_RC4_128_MD5 DH_anon RC4_128 MD5
TLS_DH_anon_WITH_3DES_EDE_CBC_SHA DH_anon 3DES_EDE_CBC SHA
TLS_DH_DSS_WITH_AES_128_CBC_SHA DH_DSS AES_128_CBC SHA
TLS_DH_RSA_WITH_AES_128_CBC_SHA DH_RSA AES_128_CBC SHA
TLS_DHE_DSS_WITH_AES_128_CBC_SHA DHE_DSS AES_128_CBC SHA
TLS_DHE_RSA_WITH_AES_128_CBC_SHA DHE_RSA AES_128_CBC SHA
TLS_DH_anon_WITH_AES_128_CBC_SHA DH_anon AES_128_CBC SHA
TLS_DH_DSS_WITH_AES_256_CBC_SHA DH_DSS AES_256_CBC SHA
TLS_DH_RSA_WITH_AES_256_CBC_SHA DH_RSA AES_256_CBC SHA
TLS_DHE_DSS_WITH_AES_256_CBC_SHA DHE_DSS AES_256_CBC SHA
TLS_DHE_RSA_WITH_AES_256_CBC_SHA DHE_RSA AES_256_CBC SHA
TLS_DH_anon_WITH_AES_256_CBC_SHA DH_anon AES_256_CBC SHA
TLS_DH_DSS_WITH_AES_128_CBC_SHA256 DH_DSS AES_128_CBC SHA256
TLS_DH_RSA_WITH_AES_128_CBC_SHA256 DH_RSA AES_128_CBC SHA256
TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 DHE_DSS AES_128_CBC SHA256
TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 DHE_RSA AES_128_CBC SHA256
TLS_DH_anon_WITH_AES_128_CBC_SHA256 DH_anon AES_128_CBC SHA256
TLS_DH_DSS_WITH_AES_256_CBC_SHA256 DH_DSS AES_256_CBC SHA256
TLS_DH_RSA_WITH_AES_256_CBC_SHA256 DH_RSA AES_256_CBC SHA256
TLS_DHE_DSS_WITH_AES_256_CBC_SHA256 DHE_DSS AES_256_CBC SHA256
TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 DHE_RSA AES_256_CBC SHA256
TLS_DH_anon_WITH_AES_256_CBC_SHA256 DH_anon AES_256_CBC SHA256
Next up are the cipher and MAC details ๐ The first table is the cipher side of things, and the second is the MAC side.
Key IV Block
Cipher Type Material Size Size
------------ ------ -------- ---- -----
NULL Stream 0 0 N/A
RC4_128 Stream 16 0 N/A
3DES_EDE_CBC Block 24 8 8
AES_128_CBC Block 16 16 16
AES_256_CBC Block 32 16 16
MAC Algorithm mac_length mac_key_length
-------- ----------- ---------- --------------
NULL N/A 0 0
MD5 HMAC-MD5 16 16
SHA HMAC-SHA1 20 20
SHA256 HMAC-SHA256 32 32
And here's what each column in those tables means ๐ง
- Type: tells you whether the cipher is a stream cipher or a block cipher running in CBC mode.
- Key Material: the number of bytes taken from the key_block that get used to generate the write keys.
- IV Size: how much data needs to be generated for the initialization vector. It's zero for stream ciphers, and for block ciphers it's equal to the block size (this is equal to
SecurityParameters.record_iv_length). - Block Size: how much data a block cipher encrypts in one chunk. A block cipher running in CBC mode can only encrypt an even multiple of its block size ๐ซถ
Appendix D. Implementation Notes ๐ฅ
okay so the TLS protocol literally cannot stop a bunch of common security mistakes on its own ๐ญ This section is a set of tips to help implementors not mess things up, bestie ๐
D.1. Random Number Generation and Seeding
TLS requires a cryptographically secure pseudorandom number generator (PRNG). Designing and seeding PRNGs needs real care โจ PRNGs built on secure hash operations, most notably SHA-1, are acceptable, but they can't give you more security than the size of the random number generator state ๐
To estimate how much seed material you're making, add up the number of bits of unpredictable information in each seed byte. For example, keystroke timing values from a PC compatible's 18.2 Hz timer give you 1 or 2 secure bits each, even though the counter value is 16 bits or more in total. So seeding a 128-bit PRNG would take roughly 100 of those timer values ๐
[RANDOM] provides guidance on the generation of random values ๐
D.2. Certificates and Authentication
Implementations are responsible for checking that certificates are intact, and they should generally support certificate revocation messages ๐ Certificates should always be verified to make sure they were properly signed by a trusted Certificate Authority (CA). Picking and adding trusted CAs should be done very carefully, and users should be able to view info about the certificate and the root CA ๐
D.3. Cipher Suites
TLS supports a huge range of key sizes and security levels, including some that give no security or just a tiny bit ๐ฌ A proper implementation will probably not support many cipher suites. For instance, anonymous Diffie-Hellman is strongly discouraged, because it can't stop man-in-the-middle attacks ๐จ Applications should also enforce minimum and maximum key sizes. For example, certificate chains with 512-bit RSA keys or signatures are not appropriate for high-security applications ๐ โโ๏ธ
D.4. Implementation Pitfalls
Real talk: some parts of earlier TLS specifications were hard to understand, and they caused a lot of interoperability and security problems ๐ญ A lot of those areas got clarified in this document, but this appendix is a short list of the most important things implementors need to watch out for ๐
TLS protocol issues:
- Do you correctly handle handshake messages that are fragmented across multiple TLS records (see Section 6.2.1)? What about corner cases like a ClientHello split into several small fragments? Do you fragment handshake messages that go over the maximum fragment size? Heads up, the certificate and certificate request handshake messages can be big enough to need fragmenting ๐งฉ
- Do you ignore the TLS record layer version number in all TLS records before ServerHello (see Appendix E.1)? ๐ค
- Do you handle TLS extensions in ClientHello correctly, including when the extensions field is left out completely? ๐
- Do you support renegotiation, both client-initiated and server-initiated? Renegotiation is an optional feature, but supporting it is highly recommended ๐ฆ
- When the server has asked for a client certificate but no suitable certificate is available, do you correctly send an empty Certificate message, instead of skipping the whole message (see Section 7.4.6)? ๐ฅน
Cryptographic details:
- In the RSA-encrypted Premaster Secret, do you correctly send and verify the version number? When you hit an error, do you keep going with the handshake to avoid the Bleichenbacher attack (see Section 7.4.7.1)? ๐ฅ
- What countermeasures are you using to prevent timing attacks against RSA decryption and signing operations (see Section 7.4.7.1)? ๐
- When verifying RSA signatures, do you accept both NULL and missing parameters (see Section 4.7)? Do you also check that the RSA padding doesn't have extra data after the hash value? [FI06] ๐ต๏ธโโ๏ธ
- When you're using Diffie-Hellman key exchange, do you correctly strip leading zero bytes from the negotiated key (see Section 8.1.2)? ๐งผ
- Does your TLS client check that the Diffie-Hellman parameters sent by the server are acceptable (see Section F.1.1.3)? ๐ง
- How do you generate unpredictable IVs for CBC mode ciphers (see Section 6.2.3.2)? ๐ฒ
- Do you accept long CBC mode padding (up to 255 bytes; see Section 6.2.3.2)? ๐
- How do you address CBC mode timing attacks (Section 6.2.3.2)? โฑ๏ธ
- Do you use a strong random number generator that is, most importantly, properly seeded (see Appendix D.1) for generating the premaster secret (for RSA key exchange), Diffie-Hellman private values, the DSA "k" parameter, and other security-critical values? ๐๐
Appendix E. Backward Compatibility ๐ธ
E.1. Compatibility with TLS 1.0/1.1 and SSL 3.0
Okay so there are a bunch of TLS versions (1.0, 1.1, 1.2, and whatever comes next ๐ฎ) plus SSL (2.0 and 3.0) ๐ญ, which means we need a way to agree on which one to use. Good news: TLS has version negotiation built right in ๐ , so the rest of the protocol doesn't have to stress about picking a version โจ
TLS 1.0, 1.1, and 1.2, plus SSL 3.0, are super similar and use compatible ClientHello messages, so supporting all of them is honestly not that hard ๐ซถ. Servers can also handle future TLS versions without drama, as long as the ClientHello format stays compatible and the client supports the highest version the server has ๐ฆ.
A TLS 1.2 client that wants to talk to older servers will send a normal TLS 1.2 ClientHello with { 3, 3 } (TLS 1.2) in ClientHello.client_version ๐. If the server doesn't support that version, it'll answer with a ServerHello carrying an older version number ๐ฅบ. If the client is cool with that version, the negotiation keeps going the way it should for whatever version got picked ๐.
If the version the server picked isn't supported by the client (or isn't acceptable), the client MUST send a protocol_version alert message and close the connection ๐
โโ๏ธ. That's a hard rule, no exceptions, bestie.
If a TLS server gets a ClientHello with a version number greater than the highest version it supports, it MUST reply according to the highest version the server supports ๐.
A TLS server can also get a ClientHello with a version number smaller than its highest supported version ๐. If the server wants to work with old clients, it goes with the highest version it supports that is not greater than ClientHello.client_version. For example, if the server supports TLS 1.0, 1.1, and 1.2, and client_version is TLS 1.0, the server will proceed with a TLS 1.0 ServerHello ๐ธ. If the server supports (or is willing to use) only versions greater than client_version, it MUST send a protocol_version alert message and close the connection. Not me being left on read ๐.
Whenever a client already knows the highest protocol version a server knows (like when it's resuming a session), it SHOULD start the connection in that native protocol โจ.
Note: some server implementations are known to do version negotiation incorrectly ๐. For example, there are buggy TLS 1.0 servers that just close the connection when the client offers a version newer than TLS 1.0. It's also known that some servers will refuse the connection if any TLS extensions are included in ClientHello. Interoperating with buggy servers like that is a complex topic beyond the scope of this document, and it may take multiple connection attempts from the client ๐ญ๐ง.
Earlier versions of the TLS spec weren't totally clear on what the record layer version number (TLSPlaintext.version) should contain when sending ClientHello (aka before everyone knows which protocol version is being used) ๐คทโโ๏ธ. So TLS servers that comply with this spec MUST accept any value {03,XX} as the record layer version number for ClientHello. Iconic of them ๐ซถ.
TLS clients that want to negotiate with older servers MAY send any value {03,XX} as the record layer version number ๐. Typical values would be {03,00}, the lowest version number the client supports, and the value of ClientHello.client_version. No single value will guarantee interoperability with all old servers, but that's a complex topic beyond the scope of this document ๐ฆ.
E.2. Compatibility with SSL 2.0
TLS 1.2 clients that want to support SSL 2.0 servers MUST send version 2.0 CLIENT-HELLO messages defined in [SSL2] ๐ง. The message MUST contain the same version number that would be used for an ordinary ClientHello, and MUST encode the supported TLS cipher suites in the CIPHER-SPECS-DATA field, as described below ๐.
Warning: ๐จ The ability to send version 2.0 CLIENT-HELLO messages is going to be phased out with all due haste ๐โโ๏ธ๐จ, since the newer ClientHello format has better ways to move to newer versions and negotiate extensions. TLS 1.2 clients SHOULD NOT support SSL 2.0. Literally let it go ๐ .
Even so, TLS servers that don't support SSL 2.0 MAY still accept version 2.0 CLIENT-HELLO messages ๐ธ. The message is shown below in enough detail for TLS server implementors, but the true definition is still [SSL2] ๐.
For negotiation purposes, a 2.0 CLIENT-HELLO is read the same way as a ClientHello with a "null" compression method and no extensions ๐ซถ. Also, this message MUST be sent directly on the wire, not wrapped as a TLS record โ ๏ธ. For calculating Finished and CertificateVerify, the msg_length field is NOT considered part of the handshake message ๐.
uint8 V2CipherSpec[3];
struct {
uint16 msg_length;
uint8 msg_type;
Version version;
uint16 cipher_spec_length;
uint16 session_id_length;
uint16 challenge_length;
V2CipherSpec cipher_specs[V2ClientHello.cipher_spec_length];
opaque session_id[V2ClientHello.session_id_length];
opaque challenge[V2ClientHello.challenge_length;
} V2ClientHello;
Here's the breakdown, bestie ๐ซถ:
msg_length: The highest bit MUST be 1, and the remaining bits hold the length of the following data in bytes ๐ข.msg_type: This field, together with the version field, identifies a version 2 ClientHello message ๐ชช. The value MUST be 1.version: Equal toClientHello.client_version๐.cipher_spec_length: This is the total length of thecipher_specsfield. It cannot be zero, and it MUST be a multiple of the V2CipherSpec length (3) ๐.session_id_length: This field MUST have a value of zero for a client that claims to support TLS 1.2 ๐ โโ๏ธ.challenge_length: The length in bytes of the client's challenge for the server to authenticate itself ๐. Historically, permissible values are between 16 and 32 bytes inclusive. When using the SSLv2 backward-compatible handshake, the client SHOULD use a 32-byte challenge ๐.cipher_specs: This is a list of all CipherSpecs the client is willing and able to use โจ. On top of the 2.0 cipher specs defined in [SSL2], this includes the TLS cipher suites normally sent inClientHello.cipher_suites, with each cipher suite prefixed by a zero byte. For example, the TLS cipher suite{0x00,0x0A}would be sent as{0x00,0x00,0x0A}๐ง.session_id: This field MUST be empty ๐ซ.challenge: Corresponds toClientHello.random๐ฒ. If the challenge length is less than 32, the TLS server will pad the data with leading (note: not trailing) zero bytes to make it 32 bytes long ๐.
Note: requests to resume a TLS session MUST use a TLS ClientHello, not the SSL 2.0 format ๐.
E.3. Avoiding Man-in-the-Middle Version Rollback
When TLS clients fall back to Version 2.0 compatibility mode, they MUST use special PKCS#1 block formatting ๐. This is done so that TLS servers will reject Version 2.0 sessions with TLS-capable clients. Protecting the downgrade path, periodt ๐ก๏ธ.
When a client negotiates SSL 2.0 but also supports TLS, it MUST set the right-hand (least-significant) 8 random bytes of the PKCS padding (not including the terminal null of the padding) for the RSA encryption of the ENCRYPTED-KEY-DATA field of the CLIENT-MASTER-KEY to 0x03 (the other padding bytes are random) ๐ฒ.
When a TLS-capable server negotiates SSL 2.0, it SHOULD check, after decrypting the ENCRYPTED-KEY-DATA field, that these 8 padding bytes are 0x03 ๐. If they aren't, the server SHOULD generate a random value for SECRET-KEY-DATA and keep going with the handshake, which will eventually fail since the keys won't match ๐. Note that reporting the error to the client could make the server vulnerable to the attacks described in [BLEI] ๐ฑ, so be careful, bestie.
Appendix F. Security Analysis ๐
The TLS protocol is designed to set up a secure connection between a client and a server communicating over an insecure channel ๐ฆ. This document makes several traditional assumptions, including that attackers have substantial computational resources and can't get secret information from sources outside the protocol ๐ต๏ธโโ๏ธ. Attackers are assumed to be able to capture, modify, delete, replay, and otherwise tamper with messages sent over the communication channel ๐. This appendix outlines how TLS was designed to resist a variety of attacks ๐ช.
F.1. Handshake Protocol
The handshake protocol is in charge of selecting a cipher spec and generating a master secret, which together make up the primary cryptographic parameters for a secure session ๐. The handshake protocol can also optionally authenticate parties who have certificates signed by a trusted certificate authority ๐ชช.
F.1.1. Authentication and Key Exchange
TLS supports three authentication modes: authentication of both parties, server authentication with an unauthenticated client, and total anonymity ๐. Whenever the server is authenticated, the channel is secure against man-in-the-middle attacks, but completely anonymous sessions are inherently vulnerable to such attacks ๐ฌ. Anonymous servers can't authenticate clients ๐ โโ๏ธ. If the server is authenticated, its certificate message must provide a valid certificate chain leading to an acceptable certificate authority ๐. Similarly, authenticated clients must supply an acceptable certificate to the server ๐ชช. Each party is responsible for verifying that the other's certificate is valid and hasn't expired or been revoked ๐.
The general goal of the key exchange process is to create a pre_master_secret that's known to the communicating parties and not to attackers ๐๏ธ. The pre_master_secret will be used to generate the master_secret (see Section 8.1) ๐. The master_secret is required to generate the Finished messages, encryption keys, and MAC keys (see Sections 7.4.9 and 6.3) โจ. By sending a correct Finished message, parties prove that they know the correct pre_master_secret, which is giving main character energy ๐.
F.1.1.1. Anonymous Key Exchange
Completely anonymous sessions can be set up using Diffie-Hellman for key exchange ๐งช. The server's public parameters are in the server key exchange message, and the client's are sent in the client key exchange message ๐จ. Eavesdroppers who don't know the private values should not be able to find the Diffie-Hellman result (aka the pre_master_secret) ๐.
Warning: โ ๏ธ Completely anonymous connections only protect against passive eavesdropping. Unless an independent tamper-proof channel is used to verify that the Finished messages weren't replaced by an attacker, server authentication is required in environments where active man-in-the-middle attacks are a concern ๐จ. Don't skip it, bestie ๐ซถ.
F.1.1.2. RSA Key Exchange and Authentication ๐
Okay so with RSA, key exchange and server authentication are combined, bestie ๐ The public key lives inside the server's certificate. ngl this is the scary part: if the server's static RSA key gets compromised, confidentiality is lost for all sessions protected under that static key ๐ If you want Perfect Forward Secrecy, you should use DHE cipher suites ๐ฆ Also, the damage from exposing a private key can be limited by changing your private key (and certificate) frequently. It's giving "rotate your secrets" energy ๐ซถ
After verifying the server's certificate, the client encrypts a pre_master_secret with the server's public key. If the server can decode the pre_master_secret and produce a correct Finished message, it proves it knows the private key matching the server certificate โจ
When RSA is used for key exchange, clients get authenticated through the certificate verify message (see Section 7.4.8) ๐ The client signs a value derived from all preceding handshake messages. Those include the server certificate, which binds the signature to the server, and ServerHello.random, which binds the signature to the current handshake process. Iconic ๐
F.1.1.3. Diffie-Hellman Key Exchange with Authentication ๐ธ
When Diffie-Hellman key exchange is used, the server can either supply a certificate containing fixed Diffie-Hellman parameters, or use the server key exchange message to send a set of temporary Diffie-Hellman parameters signed with a DSA or RSA certificate. The temporary parameters get hashed with the hello.random values before signing, so attackers can't replay old parameters ๐
Either way, the client can verify the certificate or signature to make sure the parameters belong to the server โ
If the client has a certificate with fixed Diffie-Hellman parameters, that certificate has everything needed to complete the key exchange. Note that in this case, the client and server will generate the same Diffie-Hellman result (aka pre_master_secret) every single time they communicate ๐ญ To keep the pre_master_secret from sticking around in memory any longer than necessary, convert it into the master_secret as soon as possible. Client Diffie-Hellman parameters must be compatible with the ones the server supplied, or the key exchange won't work.
If the client has a standard DSA or RSA certificate, or is unauthenticated, it sends a set of temporary parameters to the server in the client key exchange message. Then it can optionally use a certificate verify message to authenticate itself.
If the same DH keypair is going to be used for multiple handshakes, either because the client or server has a certificate with a fixed DH keypair or because the server is reusing DH keys, you need to take care to prevent small subgroup attacks. Implementations SHOULD follow the guidelines found in [SUBGROUP].
Small subgroup attacks are most easily avoided by using one of the DHE cipher suites and generating a fresh DH private key (X) for each handshake. If a suitable base (such as 2) is chosen, g^X mod p can be computed very quickly, so the performance cost is minimized. Using a fresh key for each handshake also provides Perfect Forward Secrecy, which is a whole mood ๐ฆ Implementations SHOULD generate a new X for each handshake when using DHE cipher suites.
Because TLS lets the server provide arbitrary DH groups, the client should verify that the DH group is of suitable size as defined by local policy. The client SHOULD also verify that the DH public exponent appears to be of adequate size. [KEYSIZ] provides a useful guide to the strength of various group sizes. The server MAY choose to assist the client by providing a known group, such as those defined in [IKEALG] or [MODP]. These can be verified by simple comparison ๐ง
F.1.2. Version Rollback Attacks ๐
Because TLS includes substantial improvements over SSL Version 2.0, attackers may try to make TLS-capable clients and servers fall back to Version 2.0. This attack can occur if (and only if) two TLS-capable parties use an SSL 2.0 handshake.
Although the solution using non-random PKCS #1 block type 2 message padding is inelegant, it provides a reasonably secure way for Version 3.0 servers to detect the attack. This solution is not secure against attackers who can brute-force the key and substitute a new ENCRYPTED-KEY-DATA message containing the same key (but with normal padding) before the application-specified wait threshold has expired. Altering the padding of the least-significant 8 bytes of the PKCS padding does not impact security for the size of the signed hashes and RSA key lengths used in the protocol, since this is essentially equivalent to increasing the input block size by 8 bytes.
F.1.3. Detecting Attacks Against the Handshake Protocol ๐ต๏ธ
An attacker might try to influence the handshake exchange to make the parties select different encryption algorithms than they would normally choose. Not me trying to sneak in and change the menu ๐
For this attack, an attacker must actively change one or more handshake messages. If this happens, the client and server will compute different values for the handshake message hashes. As a result, the parties won't accept each other's Finished messages. Without the master_secret, the attacker can't repair the Finished messages, so the attack gets discovered ๐จ
F.1.4. Resuming Sessions ๐
When a connection is established by resuming a session, new ClientHello.random and ServerHello.random values are hashed with the session's master_secret. As long as the master_secret hasn't been compromised, and the secure hash operations used to produce the encryption keys and MAC keys are secure, the connection should be secure and effectively independent from previous connections. Attackers can't use known encryption keys or MAC secrets to compromise the master_secret without breaking the secure hash operations. Main character energy ๐
Sessions can't be resumed unless both the client and server agree. If either party suspects that the session may have been compromised, or that certificates may have expired or been revoked, it should force a full handshake. An upper limit of 24 hours is suggested for session ID lifetimes, since an attacker who obtains a master_secret may be able to impersonate the compromised party until the corresponding session ID is retired. Applications that may run in relatively insecure environments should not write session IDs to stable storage ๐
F.2. Protecting Application Data ๐ก๏ธ
The master_secret is hashed with the ClientHello.random and ServerHello.random to produce unique data encryption keys and MAC secrets for each connection. Layers of protection, bestie ๐ง
Outgoing data is protected with a MAC before transmission. To prevent message replay or modification attacks, the MAC is computed from the MAC key, the sequence number, the message length, the message contents, and two fixed character strings. The message type field is necessary to ensure that messages intended for one TLS record layer client are not redirected to another. The sequence number ensures that attempts to delete or reorder messages will be detected. Since sequence numbers are 64 bits long, they should never overflow. Messages from one party can't be inserted into the other's output, since they use independent MAC keys. Similarly, the server write and client write keys are independent, so stream cipher keys are used only once ๐ฆ
If an attacker does break an encryption key, all messages encrypted with it can be read. Similarly, compromise of a MAC key can make message-modification attacks possible. Because MACs are also encrypted, message-alteration attacks generally require breaking the encryption algorithm as well as the MAC ๐ค
Note: MAC keys may be larger than encryption keys, so messages can remain tamper resistant even if encryption keys are broken. ๐ง
F.3. Explicit IVs ๐
[CBCATT] describes a chosen plaintext attack on TLS that depends on knowing the IV for a record. Previous versions of TLS [TLS1.0] used the CBC residue of the previous record as the IV, and therefore enabled this attack. This version uses an explicit IV in order to protect against this attack ๐
F.4. Security of Composite Cipher Modes ๐โจ
TLS secures transmitted application data via the use of symmetric encryption and authentication functions defined in the negotiated cipher suite. The objective is to protect both the integrity and confidentiality of the transmitted data from malicious actions by active attackers in the network. It turns out that the order in which encryption and authentication functions are applied to the data plays an important role in achieving this goal [ENCAUTH] ๐งฉ
The most robust method, called encrypt-then-authenticate, first applies encryption to the data and then applies a MAC to the ciphertext. This method ensures that the integrity and confidentiality goals are obtained with ANY pair of encryption and MAC functions, provided that the former is secure against chosen plaintext attacks and that the MAC is secure against chosen-message attacks. TLS uses another method, called authenticate-then-encrypt, in which a MAC is first computed on the plaintext, and then the concatenation of plaintext and MAC is encrypted. This method has been proven secure for CERTAIN combinations of encryption functions and MAC functions, but it is not guaranteed to be secure in general ๐ซฃ
In particular, it has been shown that there exist perfectly secure encryption functions (secure even in the information-theoretic sense) that, combined with any secure MAC function, fail to provide the confidentiality goal against an active attack. Therefore, new cipher suites and operation modes adopted into TLS need to be analyzed under the authenticate-then-encrypt method to verify that they achieve the stated integrity and confidentiality goals ๐
Currently, the security of the authenticate-then-encrypt method has been proven for some important cases. One is the case of stream ciphers in which a computationally unpredictable pad of the length of the message, plus the length of the MAC tag, is produced using a pseudorandom generator, and this pad is exclusive-ORed with the concatenation of plaintext and MAC tag. The other is the case of CBC mode using a secure block cipher. In this case, security can be shown if one applies one CBC encryption pass to the concatenation of plaintext and MAC, and uses a new, independent, and unpredictable IV for each new pair of plaintext and MAC. In versions of TLS prior to 1.1, CBC mode was used properly EXCEPT that it used a predictable IV in the form of the last block of the previous ciphertext. This made TLS open to chosen plaintext attacks. This version of the protocol is immune to those attacks ๐ For exact details on the encryption modes proven secure, see [ENCAUTH].
F.5. Denial of Service ๐ฅ
Okay so DoS attacks are a whole thing for TLS ๐. An attacker who opens a huge number of TCP connections can make a server burn through CPU doing RSA decryption ๐ฅ. Lowkey brutal. BUT since TLS is usually run over TCP, it's hard for the attacker to hide where they're really coming from, as long as the TCP stack uses proper TCP SYN randomization [SEQNUM] ๐.
Because TLS runs over TCP, it's also open to DoS attacks on individual connections ๐ญ. Attackers can forge RSTs to terminate connections, or forge partial TLS records to make a connection stall. A TCP-using protocol generally can't defend against this class of attack, so implementors or users who are worried about it should use IPsec AH [AH] or ESP [ESP] ๐ก๏ธ.
F.6. Final Notes ๐
For TLS to give you a secure connection, both the client and server systems, keys, and applications must be secure. On top of that, the implementation has to be free of security errors. Bestie, that's a lot ๐ญ.
The system is only as strong as the weakest key exchange and authentication algorithm it supports, and only trustworthy cryptographic functions should be used ๐. Short public keys and anonymous servers should be used with great caution ๐ โโ๏ธ. Implementations and users need to be careful about which certificates and certificate authorities they accept, because a dishonest certificate authority can do tremendous damage ๐.
Normative References ๐
These are the references the spec leans on hardest, so bookmark them ๐.
[AES] National Institute of Standards and Technology,
"Specification for the Advanced Encryption Standard (AES)"
FIPS 197. November 26, 2001.
[3DES] National Institute of Standards and Technology,
"Recommendation for the Triple Data Encryption Algorithm
(TDEA) Block Cipher", NIST Special Publication 800-67, May
2004.
[DSS] NIST FIPS PUB 186-2, "Digital Signature Standard",
National Institute of Standards and Technology, U.S.
Department of Commerce, 2000.
[HMAC] Krawczyk, H., Bellare, M., and R. Canetti, "HMAC: Keyed-
Hashing for Message Authentication", RFC 2104, February
1997.
[MD5] Rivest, R., "The MD5 Message-Digest Algorithm", RFC 1321,
April 1992.
[PKCS1] Jonsson, J. and B. Kaliski, "Public-Key Cryptography
Standards (PKCS) #1: RSA Cryptography Specifications
Version 2.1", RFC 3447, February 2003.
[PKIX] Housley, R., Polk, W., Ford, W., and D. Solo, "Internet
X.509 Public Key Infrastructure Certificate and
Certificate Revocation List (CRL) Profile", RFC 3280,
April 2002.
[SCH] B. Schneier. "Applied Cryptography: Protocols, Algorithms,
and Source Code in C, 2nd ed.", Published by John Wiley &
Sons, Inc. 1996.
[SHS] NIST FIPS PUB 180-2, "Secure Hash Standard", National
Institute of Standards and Technology, U.S. Department of
Commerce, August 2002.
[REQ] Bradner, S., "Key words for use in RFCs to Indicate
Requirement Levels", BCP 14, RFC 2119, March 1997.
[RFC2434] Narten, T. and H. Alvestrand, "Guidelines for Writing an
IANA Considerations Section in RFCs", BCP 26, RFC 2434,
October 1998.
[X680] ITU-T Recommendation X.680 (2002) | ISO/IEC 8824-1:2002,
Information technology - Abstract Syntax Notation One
(ASN.1): Specification of basic notation.
[X690] ITU-T Recommendation X.690 (2002) | ISO/IEC 8825-1:2002,
Information technology - ASN.1 encoding Rules:
Specification of Basic Encoding Rules (BER), Canonical
Encoding Rules (CER) and Distinguished Encoding Rules
(DER).
Informative References ๐ธ
These are the extra reading for when you want the deep cut ๐ง .
[AEAD] McGrew, D., "An Interface and Algorithms for Authenticated
Encryption", RFC 5116, January 2008.
[AH] Kent, S., "IP Authentication Header", RFC 4302, December
2005.
[BLEI] Bleichenbacher D., "Chosen Ciphertext Attacks against
Protocols Based on RSA Encryption Standard PKCS #1" in
Advances in Cryptology -- CRYPTO'98, LNCS vol. 1462,
pages: 1-12, 1998.
[CBCATT] Moeller, B., "Security of CBC Ciphersuites in SSL/TLS:
Problems and Countermeasures",
http://www.openssl.org/~bodo/tls-cbc.txt.
[CBCTIME] Canvel, B., Hiltgen, A., Vaudenay, S., and M. Vuagnoux,
"Password Interception in a SSL/TLS Channel", Advances in
Cryptology -- CRYPTO 2003, LNCS vol. 2729, 2003.
[CCM] "NIST Special Publication 800-38C: The CCM Mode for
Authentication and Confidentiality",
http://csrc.nist.gov/publications/nistpubs/800-38C/
SP800-38C.pdf
[DES] National Institute of Standards and Technology, "Data
Encryption Standard (DES)", FIPS PUB 46-3, October 1999.
[DSS-3] NIST FIPS PUB 186-3 Draft, "Digital Signature Standard",
National Institute of Standards and Technology, U.S.
Department of Commerce, 2006.
[ECDSA] American National Standards Institute, "Public Key
Cryptography for the Financial Services Industry: The
Elliptic Curve Digital Signature Algorithm (ECDSA)", ANS
X9.62-2005, November 2005.
[ENCAUTH] Krawczyk, H., "The Order of Encryption and Authentication
for Protecting Communications (Or: How Secure is SSL?)",
Crypto 2001.
[ESP] Kent, S., "IP Encapsulating Security Payload (ESP)", RFC
4303, December 2005.
[FI06] Hal Finney, "Bleichenbacher's RSA signature forgery based
on implementation error", ietf-openpgp@imc.org mailing
list, 27 August 2006, http://www.imc.org/ietf-openpgp/
mail-archive/msg14307.html.
[GCM] Dworkin, M., NIST Special Publication 800-38D,
"Recommendation for Block Cipher Modes of Operation:
Galois/Counter Mode (GCM) and GMAC", November 2007.
[IKEALG] Schiller, J., "Cryptographic Algorithms for Use in the
Internet Key Exchange Version 2 (IKEv2)", RFC 4307,
December 2005.
[KEYSIZ] Orman, H. and P. Hoffman, "Determining Strengths For
Public Keys Used For Exchanging Symmetric Keys", BCP 86,
RFC 3766, April 2004.
[KPR03] Klima, V., Pokorny, O., Rosa, T., "Attacking RSA-based
Sessions in SSL/TLS", http://eprint.iacr.org/2003/052/,
March 2003.
[MODP] Kivinen, T. and M. Kojo, "More Modular Exponential (MODP)
Diffie-Hellman groups for Internet Key Exchange (IKE)",
RFC 3526, May 2003.
[PKCS6] RSA Laboratories, "PKCS #6: RSA Extended Certificate
Syntax Standard", version 1.5, November 1993.
[PKCS7] RSA Laboratories, "PKCS #7: RSA Cryptographic Message
Syntax Standard", version 1.5, November 1993.
[RANDOM] Eastlake, D., 3rd, Schiller, J., and S. Crocker,
"Randomness Requirements for Security", BCP 106, RFC 4086,
June 2005.
[RFC3749] Hollenbeck, S., "Transport Layer Security Protocol
Compression Methods", RFC 3749, May 2004.
[RFC4366] Blake-Wilson, S., Nystrom, M., Hopwood, D., Mikkelsen, J.,
and T. Wright, "Transport Layer Security (TLS)
Extensions", RFC 4366, April 2006.
[RSA] R. Rivest, A. Shamir, and L. M. Adleman, "A Method for
Obtaining Digital Signatures and Public-Key
Cryptosystems", Communications of the ACM, v. 21, n. 2,
Feb 1978, pp. 120-126.
[SEQNUM] Bellovin, S., "Defending Against Sequence Number Attacks",
RFC 1948, May 1996.
[SSL2] Hickman, Kipp, "The SSL Protocol", Netscape Communications
Corp., Feb 9, 1995.
[SSL3] A. Freier, P. Karlton, and P. Kocher, "The SSL 3.0
Protocol", Netscape Communications Corp., Nov 18, 1996.
[SUBGROUP] Zuccherato, R., "Methods for Avoiding the "Small-Subgroup"
Attacks on the Diffie-Hellman Key Agreement Method for
S/MIME", RFC 2785, March 2000.
[TCP] Postel, J., "Transmission Control Protocol", STD 7, RFC
793, September 1981.
[TIMING] Boneh, D., Brumley, D., "Remote timing attacks are
practical", USENIX Security Symposium 2003.
[TLSAES] Chown, P., "Advanced Encryption Standard (AES)
Ciphersuites for Transport Layer Security (TLS)", RFC
3268, June 2002.
[TLSECC] Blake-Wilson, S., Bolyard, N., Gupta, V., Hawk, C., and B.
Moeller, "Elliptic Curve Cryptography (ECC) Cipher Suites
for Transport Layer Security (TLS)", RFC 4492, May 2006.
[TLSEXT] Eastlake, D., 3rd, "Transport Layer Security (TLS)
Extensions: Extension Definitions", Work in Progress,
February 2008.
[TLSPGP] Mavrogiannopoulos, N., "Using OpenPGP Keys for Transport
Layer Security (TLS) Authentication", RFC 5081, November
2007.
[TLSPSK] Eronen, P., Ed., and H. Tschofenig, Ed., "Pre-Shared Key
Ciphersuites for Transport Layer Security (TLS)", RFC
4279, December 2005.
[TLS1.0] Dierks, T. and C. Allen, "The TLS Protocol Version 1.0",
RFC 2246, January 1999.
[TLS1.1] Dierks, T. and E. Rescorla, "The Transport Layer Security
(TLS) Protocol Version 1.1", RFC 4346, April 2006.
[X501] ITU-T Recommendation X.501: Information Technology - Open
Systems Interconnection - The Directory: Models, 1993.
[XDR] Eisler, M., Ed., "XDR: External Data Representation
Standard", STD 67, RFC 4506, May 2006.
Working Group Information ๐
Want to talk TLS with the crew? The discussion list for the IETF TLS working group is at the e-mail address <tls@ietf.org>. Info about the group, and how to subscribe to the list, is here:
<https://www1.ietf.org/mailman/listinfo/tls>
Archives of the list live here:
<http://www.ietf.org/mail-archive/web/tls/current/index.html>
Contributors ๐ง
Huge thanks to everyone who helped build this. The people below all contributed to TLS ๐ซถ.
Christopher Allen (co-editor of TLS 1.0)
Alacrity Ventures
ChristopherA@AlacrityManagement.com
Martin Abadi
University of California, Santa Cruz
abadi@cs.ucsc.edu
Steven M. Bellovin
Columbia University
smb@cs.columbia.edu
Simon Blake-Wilson
BCI
sblakewilson@bcisse.com
Ran Canetti
IBM
canetti@watson.ibm.com
Pete Chown
Skygate Technology Ltd
pc@skygate.co.uk
Taher Elgamal
taher@securify.com
Securify
Pasi Eronen
pasi.eronen@nokia.com
Nokia
Anil Gangolli
anil@busybuddha.org
Kipp Hickman
Alfred Hoenes
David Hopwood
Independent Consultant
david.hopwood@blueyonder.co.uk
Phil Karlton (co-author of SSLv3)
Paul Kocher (co-author of SSLv3)
Cryptography Research
paul@cryptography.com
Hugo Krawczyk
IBM
hugo@ee.technion.ac.il
Jan Mikkelsen
Transactionware
janm@transactionware.com
Magnus Nystrom
RSA Security
magnus@rsasecurity.com
Robert Relyea
Netscape Communications
relyea@netscape.com
Jim Roskind
Netscape Communications
jar@netscape.com
Michael Sabin
Dan Simon
Microsoft, Inc.
dansimon@microsoft.com
Tom Weinstein
Tim Wright
Vodafone
timothy.wright@vodafone.com
Editors' Addresses ๐ฆ
These are the editors who wrangled this whole spec ๐.
Tim Dierks
Independent
EMail: tim@dierks.org
Eric Rescorla
RTFM, Inc.
EMail: ekr@rtfm.com
Full Copyright Statement ๐
Okay bestie, the legal stuff at the end! ๐ Copyright (C) The IETF Trust (2008) ๐ฆ. This document is covered by the rights, licenses, and restrictions in BCP 78, and outside of those, the authors keep all their rights โจ.
THIS DOCUMENT AND THE INFORMATION CONTAINED HEREIN ARE PROVIDED ON AN "AS IS" BASIS AND THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY, THE IETF TRUST AND THE INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
Translation: it's all provided as-is, and nobody is promising it won't step on anyone's toes or that it's perfect for every purpose ๐.
Intellectual Property ๐
Okay so the IETF is NOT taking a side on whether any patents or other IP rights cover the tech in this doc, or whether you can get a license for it ๐. It also hasn't done any independent digging to find out what rights might exist โจ. If you want the rules on RFC rights, check out BCP 78 and BCP 79 ๐.
If you're curious about IPR disclosures that were sent to the IETF Secretariat, or about licenses people promised to make available, or about attempts to get a general license for implementers or users, you can check the IETF on-line IPR repository at http://www.ietf.org/ipr ๐ซถ.
And if you think you spotted a copyright, patent, patent application, or other proprietary right that could cover tech you'd need to implement this standard, the IETF wants to hear about it! ๐ฃ Just send the info to ietf-ipr@ietf.org ๐.
๐ฆ where this page comes from
- ietf: rfc5246 2008-08
- ๐ girlified by claude-haiku-5-5 on : a language model's rewrite of the original, under its terms