created at 2021-04-12
Basics
PRF를 통한 forward secrecy.
Certificate를 통한 authentication.
Encrypt ALPN(e.g. http/2) data
Handshake/Record/… Layers
Where is TLS?
Before TLS, Server create CSR
- A -> Certificate Authority
CSR(Certificate Signing Request) : A’s pub_key + identity + sign(A’s priv_key,(A’s pub_key, identity))
- Certificate Authority -> A
check A’s sign and sign with Certificate Authority’s priv_key
A’s Certificate : CSR + sign(Certificate Authority’s priv_key, content1)
- A -> B
with A’s Certificate
- B
verify A’s Certificate with Certificate Authority’s pub_key
Man in the Middle can not replace A’s pub_key with their pub_key.
[CSR]
- Country Name, State or Province Name, Locality Name, Organization, Organization Unit, Common Name
Server CA
[CSR]CSR data + public key + Server's algorithm + sign
-------->
verify
<-------- [Certificate] CSR + CA public key + CA's algorithm + CA's sign
TLS Handshake Protocol
TLS 1.2v Initial Handshake
Client Server
[ClientHello]:"TLS versions, random number, cipher suites, ALPNs(http/2), session Ticket or ID(0 length)"
(empty SessionTicket extension)-------->
[ServerHello]:"TLS version, Server's random number, cipher suite, compression method, session Ticket or ID(0 length)"
[Certificate]*:"RSA public key"
[ServerKeyExchange]*:"DHE Server's public key"
[CertificateRequest]* (if it is needed)
<-------- [ServerHelloDone]*:"empty"
[Certificate]* (if it is needed, in here we only describe one way)
[ClientKeyExchange]:"DHE Client's public key, Client's random number"
[CertificateVerify]* (if it is needed)
caculate pre_master_secret: combine(Client's private key, Server's public key), this is symmetric key = 1024/2048 bits
generate master_secret: (TLS 1.2 use HMAC): PRF(pre_master_secret + "master secret" + ClientHello.random + ServerHello.random) 48 bytes
ChangeCipherSpec:(Tell Server that just from now on, every msg will be encrypted)
[Finished]:"master_secret, HASH([ClientHello] ~ [Finished]), string('finished')"
-------->
verify Client's [Finished], if hash and keys driven from master_secret are correct, NewSessionTicket starts
[NewSessionTicket]:"HASH(Client's [Finished], Server's [Finished])"
This
message MUST NOT be sent if the server did not include a
SessionTicket extension in the ServerHello
[ChangeCipherSpec]:(Tell Client that just from now on, every msg will be encrypted)
<-------- [Finished]:"master_secret, HASH([ServerHello]~[Finished])"
Application Data <-------> Application Data
TLS 1.3v Handshake RFC#8446
Client Server
Key ^ ClientHello
Exch | + key_share* send A,g,p: A = g^a (mod p)
| + signature_algorithms*
| + psk_key_exchange_modes*
v + pre_shared_key* -------->
ServerHello ^ Key
+ key_share* | Exch send B: B = g^b (mod p), driven Pre-Shard-Key(PSK) = A^b (mod p)
+ pre_shared_key* v
{EncryptedExtensions} ^ Server send Encrypted message m'=GCM(Key=K,IV=Client's random + Server's random, M=Extensions from Client)
{CertificateRequest*} v Params
{Certificate*} ^ Server's pub_key, sign, CAs' pub_key, signs
{CertificateVerify*} | Auth sign(RSA priv_key, handshake context+certificate)
{Finished} v send HMAC(all handshake)
<-------- [Application Data*]
driven Pre-Shard-Key(PSK) = B^a (mod p)
^ {Certificate*}
Auth | {CertificateVerify*}
v {Finished} send HMAC(all handshake)
-------->
[Application Data] <-------> [Application Data]
+ Indicates noteworthy extensions sent in the
previously noted message.
* Indicates optional or situation-dependent
messages/extensions that are not always sent.
{} Indicates messages protected using key PSK :
[] Indicates messages protected using key Kn : HKDF
derived from [[sender](https://datatracker.ietf.org/doc/html/rfc8446#ref-sender)]_application_traffic_secret_N.
TLS 1.3v PSK->Master Secret 도출과정
0
|
v
PSK -> HKDF-Extract = Early Secret
|
+-----> Derive-Secret(., "ext binder" | "res binder", "")
| = binder_key
|
+-----> Derive-Secret(., "c e traffic", ClientHello)
| = client_early_traffic_secret
|
+-----> Derive-Secret(., "e exp master", ClientHello)
| = early_exporter_master_secret
v
Derive-Secret(., "derived", "")
|
v
(EC)DHE -> HKDF-Extract = Handshake Secret
|
+-----> Derive-Secret(., "c hs traffic",
| ClientHello...ServerHello)
| = client_handshake_traffic_secret
|
+-----> Derive-Secret(., "s hs traffic",
| ClientHello...ServerHello)
| = server_handshake_traffic_secret
v
Derive-Secret(., "derived", "")
|
v
0 -> HKDF-Extract = Master Secret
|
+-----> Derive-Secret(., "c ap traffic",
| ClientHello...server Finished)
| = client_application_traffic_secret_0
|
+-----> Derive-Secret(., "s ap traffic",
| ClientHello...server Finished)
| = server_application_traffic_secret_0
|
+-----> Derive-Secret(., "exp master",
| ClientHello...server Finished)
| = exporter_master_secret
|
+-----> Derive-Secret(., "res master",
ClientHello...client Finished)
= resumption_master_secret
After TLS Full Handshake
Client Server
<-------- [NewSessionTicket] 다중 티켓 가능
struct {
uint32 ticket_lifetime;
uint32 ticket_age_add;
opaque ticket_nonce<0..255>; Unique
opaque ticket<1..2^16-1>; PSK identity: we can self-encryption or else(we simply verify ticket with clients extensions)
Extension extensions<0..2^16-2>;
} NewSessionTicket;
Resumption with PSK identity(ticket)
Client Server
Subsequent Handshake:
ClientHello
+ key_share*
+ pre_shared_key -------->
ServerHello
+ pre_shared_key
+ key_share*
{EncryptedExtensions}
{Finished}
<-------- [Application Data*]
{Finished} -------->
[Application Data] <-------> [Application Data]
0-RTT Data
When clients and servers share a PSK, TLS 1.3 allows clients to send data on the first flight.
Client’s encrypted Application Data is not forward secret!!!(변경되지 않음)
Client Server
ClientHello
+ early_data
+ key_share*
+ psk_key_exchange_modes
+ pre_shared_key
(Application Data*) -------->
ServerHello
+ pre_shared_key
+ key_share*
{EncryptedExtensions}
+ early_data*
{Finished}
<-------- [Application Data*]
(EndOfEarlyData)
{Finished} -------->
[Application Data] <-------> [Application Data]
() Indicates messages protected using keys
derived from a client_early_traffic_secret.
Structures
Structure of [ClientHello] message 1.3v:
uint16 ProtocolVersion;
opaque Random[32];
uint8 CipherSuite[2]; /* Cryptographic suite selector */
struct {
ProtocolVersion legacy_version = 0x0303; /* TLS v1.2 */
Random random;
opaque legacy_session_id<0..32>;
CipherSuite cipher_suites<2..2^16-2>;
opaque legacy_compression_methods<1..2^8-1>;
Extension extensions<8..2^16-1>;
} ClientHello;
Structure of [ServerHello] message 1.3v:
struct {
ProtocolVersion legacy_version = 0x0303; /* TLS v1.2 */
Random random; /* 32 bytes! */
opaque legacy_session_id_echo<0..32>;
CipherSuite cipher_suite;
uint8 legacy_compression_method = 0;
Extension extensions<6..2^16-1>;
} ServerHello;
struct {
ExtensionType extension_type;
opaque extension_data<0..2^16-1>;
} Extension;
enum {
server_name(0), /* [RFC 6066](https://datatracker.ietf.org/doc/html/rfc6066) */
max_fragment_length(1), /* [RFC 6066](https://datatracker.ietf.org/doc/html/rfc6066) */
status_request(5), /* [RFC 6066](https://datatracker.ietf.org/doc/html/rfc6066) */
supported_groups(10), /* [RFC 8422](https://datatracker.ietf.org/doc/html/rfc8422), 7919 */
signature_algorithms(13), /* [RFC 8446](https://datatracker.ietf.org/doc/html/rfc8446) */
use_srtp(14), /* [RFC 5764](https://datatracker.ietf.org/doc/html/rfc5764) */
heartbeat(15), /* [RFC 6520](https://datatracker.ietf.org/doc/html/rfc6520) */
application_layer_protocol_negotiation(16), /* [RFC 7301](https://datatracker.ietf.org/doc/html/rfc7301) */
signed_certificate_timestamp(18), /* [RFC 6962](https://datatracker.ietf.org/doc/html/rfc6962) */
client_certificate_type(19), /* [RFC 7250](https://datatracker.ietf.org/doc/html/rfc7250) */
server_certificate_type(20), /* [RFC 7250](https://datatracker.ietf.org/doc/html/rfc7250) */
padding(21), /* [RFC 7685](https://datatracker.ietf.org/doc/html/rfc7685) */
pre_shared_key(41), /* [RFC 8446](https://datatracker.ietf.org/doc/html/rfc8446) */
early_data(42), /* [RFC 8446](https://datatracker.ietf.org/doc/html/rfc8446) */
supported_versions(43), /* [RFC 8446](https://datatracker.ietf.org/doc/html/rfc8446) */
cookie(44), /* [RFC 8446](https://datatracker.ietf.org/doc/html/rfc8446) */
psk_key_exchange_modes(45), /* [RFC 8446](https://datatracker.ietf.org/doc/html/rfc8446) */
certificate_authorities(47), /* [RFC 8446](https://datatracker.ietf.org/doc/html/rfc8446) */
oid_filters(48), /* [RFC 8446](https://datatracker.ietf.org/doc/html/rfc8446) */
post_handshake_auth(49), /* [RFC 8446](https://datatracker.ietf.org/doc/html/rfc8446) */
signature_algorithms_cert(50), /* [RFC 8446](https://datatracker.ietf.org/doc/html/rfc8446) */
key_share(51), /* [RFC 8446](https://datatracker.ietf.org/doc/html/rfc8446) */
(65535)
} ExtensionType;
Structure of [ServerKeyExchange] message:
struct {
select (KeyExchangeAlgorithm) {
case dh_anon:
ServerDHParams params;
case dhe_dss:
/* 우리는 DHE_RSA 사용할 것임. */
case dhe_rsa:
ServerDHParams params; <- have (Y, g, p) Y = g^a (mod p)
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](https://datatracker.ietf.org/doc/html/rfc5246#ref-TLSECC)] */
};
} ServerKeyExchange;
[ClientKeyExchange]
struct {
select (KeyExchangeAlgorithm) {
case rsa:
EncryptedPreMasterSecret;
case dhe_dss:
case dhe_rsa:
case dh_dss:
case dh_rsa:
case dh_anon:
ClientDiffieHellmanPublic; <- have (Z) Z = g^b (mod p)
} exchange_keys;
} ClientKeyExchange;
implementations of master_secret generation in Golang with RFC#5246 Section 5 and RFC#2104
- Here, A(0) = seed = concatenate(Server’s random number, Client’s random number)
- pHash = HMAC(pre_master_secret, A(0)) + HMAC(pre_master_secret, A(1)) + HMAC(pre_master_secret, A(2)) + … (where + indicates concatenation.)
- master_secret = pHash
As public key operation(e.g. RSA) takes such computational resource of server, TLS provides session ID for shortcut
TLS Record Protocol
TLS record protocol is a separate sub-protocol which is used to actually encrypt and transmit upper level protocol data such as HTTP
In Picture
[Chain Of Trust with Certificate Authority] root -> intermediate -> leaf
from TECHSCHOOL
For TLS_AES256_GCM_SHA384,
- SHA384 algorithm hashing handshake data+verification data in 384 bits.
- 384 into 3 blocks(128 bits), and with GCM encryption algorithms Server generate last GMAC(TAG) that also encrypt AEAD.
- Thus Server MAC = TAG from GCM
After Initial handshakes Client receive PSK(Pre-Shared Key) identity, i.e. token.
In Server, they store like this
Client’s PSK —- ticket1, ticket2, ticket3, ticket4, …
And later when Client want to handshake with Server again, send ([ticket1, ticket2, …], client’s DHE pub_key)
Server inspect whether Client’s tickets are expired(failed to provide forward secrecy). If failed, full-handshake start with Client.