// Copyright 2018 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 tlsimport ()// This file contains the functions necessary to compute the TLS 1.3 key// schedule. See RFC 8446, Section 7.const ( resumptionBinderLabel = "res binder" clientEarlyTrafficLabel = "c e traffic" clientHandshakeTrafficLabel = "c hs traffic" serverHandshakeTrafficLabel = "s hs traffic" clientApplicationTrafficLabel = "c ap traffic" serverApplicationTrafficLabel = "s ap traffic" exporterLabel = "exp master" resumptionLabel = "res master" trafficUpdateLabel = "traffic upd")// expandLabel implements HKDF-Expand-Label from RFC 8446, Section 7.1.func ( *cipherSuiteTLS13) ( []byte, string, []byte, int) []byte {varcryptobyte.Builder .AddUint16(uint16()) .AddUint8LengthPrefixed(func( *cryptobyte.Builder) { .AddBytes([]byte("tls13 ")) .AddBytes([]byte()) }) .AddUint8LengthPrefixed(func( *cryptobyte.Builder) { .AddBytes() }) , := .Bytes()if != nil {// Rather than calling BytesOrPanic, we explicitly handle this error, in // order to provide a reasonable error message. It should be basically // impossible for this to panic, and routing errors back through the // tree rooted in this function is quite painful. The labels are fixed // size, and the context is either a fixed-length computed hash, or // parsed from a field which has the same length limitation. As such, an // error here is likely to only be caused during development. // // NOTE: another reasonable approach here 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(fmt.Errorf("failed to construct HKDF label: %s", )) } := make([]byte, ) , := hkdf.Expand(.hash.New, , ).Read()if != nil || != {panic("tls: HKDF-Expand-Label invocation failed unexpectedly") }return}// deriveSecret implements Derive-Secret from RFC 8446, Section 7.1.func ( *cipherSuiteTLS13) ( []byte, string, hash.Hash) []byte {if == nil { = .hash.New() }return .expandLabel(, , .Sum(nil), .hash.Size())}// extract implements HKDF-Extract with the cipher suite hash.func ( *cipherSuiteTLS13) (, []byte) []byte {if == nil { = make([]byte, .hash.Size()) }returnhkdf.Extract(.hash.New, , )}// nextTrafficSecret generates the next traffic secret, given the current one,// according to RFC 8446, Section 7.2.func ( *cipherSuiteTLS13) ( []byte) []byte {return .expandLabel(, trafficUpdateLabel, nil, .hash.Size())}// trafficKey generates traffic keys according to RFC 8446, Section 7.3.func ( *cipherSuiteTLS13) ( []byte) (, []byte) { = .expandLabel(, "key", nil, .keyLen) = .expandLabel(, "iv", nil, aeadNonceLength)return}// finishedHash generates the Finished verify_data or PskBinderEntry according// to RFC 8446, Section 4.4.4. See sections 4.4 and 4.2.11.2 for the baseKey// selection.func ( *cipherSuiteTLS13) ( []byte, hash.Hash) []byte { := .expandLabel(, "finished", nil, .hash.Size()) := hmac.New(.hash.New, ) .Write(.Sum(nil))return .Sum(nil)}// exportKeyingMaterial implements RFC5705 exporters for TLS 1.3 according to// RFC 8446, Section 7.5.func ( *cipherSuiteTLS13) ( []byte, hash.Hash) func(string, []byte, int) ([]byte, error) { := .deriveSecret(, exporterLabel, )returnfunc( string, []byte, int) ([]byte, error) { := .deriveSecret(, , nil) := .hash.New() .Write()return .expandLabel(, "exporter", .Sum(nil), ), nil }}type keySharePrivateKeys struct { curveID CurveID ecdhe *ecdh.PrivateKey kyber *mlkem768.DecapsulationKey}// kyberDecapsulate implements decapsulation according to Kyber Round 3.func kyberDecapsulate( *mlkem768.DecapsulationKey, []byte) ([]byte, error) { , := mlkem768.Decapsulate(, )if != nil {returnnil, }returnkyberSharedSecret(, ), nil}// kyberEncapsulate implements encapsulation according to Kyber Round 3.func kyberEncapsulate( []byte) (, []byte, error) { , , = mlkem768.Encapsulate()if != nil {returnnil, nil, }return , kyberSharedSecret(, ), nil}func kyberSharedSecret(, []byte) []byte {// Package mlkem768 implements ML-KEM, which compared to Kyber removed a // final hashing step. Compute SHAKE-256(K || SHA3-256(c), 32) to match Kyber. // See https://words.filippo.io/mlkem768/#bonus-track-using-a-ml-kem-implementation-as-kyber-v3. := sha3.NewShake256() .Write() := sha3.Sum256() .Write([:]) := make([]byte, 32) .Read()return}const x25519PublicKeySize = 32// generateECDHEKey returns a PrivateKey that implements Diffie-Hellman// according to RFC 8446, Section 4.2.8.2.func generateECDHEKey( io.Reader, CurveID) (*ecdh.PrivateKey, error) { , := curveForCurveID()if ! {returnnil, errors.New("tls: internal error: unsupported curve") }return .GenerateKey()}func curveForCurveID( CurveID) (ecdh.Curve, bool) {switch {caseX25519:returnecdh.X25519(), truecaseCurveP256:returnecdh.P256(), truecaseCurveP384:returnecdh.P384(), truecaseCurveP521:returnecdh.P521(), truedefault:returnnil, false }}func curveIDForCurve( ecdh.Curve) (CurveID, bool) {switch {caseecdh.X25519():returnX25519, truecaseecdh.P256():returnCurveP256, truecaseecdh.P384():returnCurveP384, truecaseecdh.P521():returnCurveP521, truedefault:return0, false }}
The pages are generated with Goldsv0.7.0-preview. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds.