// Copyright 2024 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package tls13 implements the TLS 1.3 Key Schedule as specified in RFC 8446, // Section 7.1 and allowed by FIPS 140-3 IG 2.4.B Resolution 7.
package tls13 import ( ) // We don't set the service indicator in this package but we delegate that to // the underlying functions because the TLS 1.3 KDF does not have a standard of // its own. // ExpandLabel implements HKDF-Expand-Label from RFC 8446, Section 7.1. func [ fips140.Hash]( func() , []byte, string, []byte, int) []byte { if len("tls13 ")+len() > 255 || len() > 255 { // It should be impossible for this to panic: labels are fixed strings, // and context is either a fixed-length computed hash, or parsed from a // field which has the same length limitation. // // Another reasonable approach might be to return a randomized slice if // we encounter an error, which would break the connection, but avoid // panicking. This would perhaps be safer but significantly more // confusing to users. panic("tls13: label or context too long") } := make([]byte, 0, 2+1+len("tls13 ")+len()+1+len()) = byteorder.BEAppendUint16(, uint16()) = append(, byte(len("tls13 ")+len())) = append(, "tls13 "...) = append(, ...) = append(, byte(len())) = append(, ...) return hkdf.Expand(, , string(), ) } func extract[ fips140.Hash]( func() , , []byte) []byte { if == nil { = make([]byte, ().Size()) } return hkdf.Extract(, , ) } func deriveSecret[ fips140.Hash]( func() , []byte, string, fips140.Hash) []byte { if == nil { = () } return ExpandLabel(, , , .Sum(nil), .Size()) } const ( resumptionBinderLabel = "res binder" clientEarlyTrafficLabel = "c e traffic" clientHandshakeTrafficLabel = "c hs traffic" serverHandshakeTrafficLabel = "s hs traffic" clientApplicationTrafficLabel = "c ap traffic" serverApplicationTrafficLabel = "s ap traffic" earlyExporterLabel = "e exp master" exporterLabel = "exp master" resumptionLabel = "res master" ) type EarlySecret struct { secret []byte hash func() fips140.Hash } func [ fips140.Hash]( func() , []byte) *EarlySecret { return &EarlySecret{ secret: extract(, , nil), hash: func() fips140.Hash { return () }, } } func ( *EarlySecret) () []byte { return deriveSecret(.hash, .secret, resumptionBinderLabel, nil) } // ClientEarlyTrafficSecret derives the client_early_traffic_secret from the // early secret and the transcript up to the ClientHello. func ( *EarlySecret) ( fips140.Hash) []byte { return deriveSecret(.hash, .secret, clientEarlyTrafficLabel, ) } type HandshakeSecret struct { secret []byte hash func() fips140.Hash } func ( *EarlySecret) ( []byte) *HandshakeSecret { := deriveSecret(.hash, .secret, "derived", nil) return &HandshakeSecret{ secret: extract(.hash, , ), hash: .hash, } } // ClientHandshakeTrafficSecret derives the client_handshake_traffic_secret from // the handshake secret and the transcript up to the ServerHello. func ( *HandshakeSecret) ( fips140.Hash) []byte { return deriveSecret(.hash, .secret, clientHandshakeTrafficLabel, ) } // ServerHandshakeTrafficSecret derives the server_handshake_traffic_secret from // the handshake secret and the transcript up to the ServerHello. func ( *HandshakeSecret) ( fips140.Hash) []byte { return deriveSecret(.hash, .secret, serverHandshakeTrafficLabel, ) } type MasterSecret struct { secret []byte hash func() fips140.Hash } func ( *HandshakeSecret) () *MasterSecret { := deriveSecret(.hash, .secret, "derived", nil) return &MasterSecret{ secret: extract(.hash, nil, ), hash: .hash, } } // ClientApplicationTrafficSecret derives the client_application_traffic_secret_0 // from the master secret and the transcript up to the server Finished. func ( *MasterSecret) ( fips140.Hash) []byte { return deriveSecret(.hash, .secret, clientApplicationTrafficLabel, ) } // ServerApplicationTrafficSecret derives the server_application_traffic_secret_0 // from the master secret and the transcript up to the server Finished. func ( *MasterSecret) ( fips140.Hash) []byte { return deriveSecret(.hash, .secret, serverApplicationTrafficLabel, ) } // ResumptionMasterSecret derives the resumption_master_secret from the master secret // and the transcript up to the client Finished. func ( *MasterSecret) ( fips140.Hash) []byte { return deriveSecret(.hash, .secret, resumptionLabel, ) } type ExporterMasterSecret struct { secret []byte hash func() fips140.Hash } // ExporterMasterSecret derives the exporter_master_secret from the master secret // and the transcript up to the server Finished. func ( *MasterSecret) ( fips140.Hash) *ExporterMasterSecret { return &ExporterMasterSecret{ secret: deriveSecret(.hash, .secret, exporterLabel, ), hash: .hash, } } // EarlyExporterMasterSecret derives the exporter_master_secret from the early secret // and the transcript up to the ClientHello. func ( *EarlySecret) ( fips140.Hash) *ExporterMasterSecret { return &ExporterMasterSecret{ secret: deriveSecret(.hash, .secret, earlyExporterLabel, ), hash: .hash, } } func ( *ExporterMasterSecret) ( string, []byte, int) []byte { := deriveSecret(.hash, .secret, , nil) := .hash() .Write() return ExpandLabel(.hash, , "exporter", .Sum(nil), ) } func ( *ExporterMasterSecret) []byte { return .secret }