github.com/twelsh-aw/go/src@v0.0.0-20230516233729-a56fe86a7c81/crypto/tls/key_schedule.go (about) 1 // Copyright 2018 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package tls 6 7 import ( 8 "crypto/ecdh" 9 "crypto/hmac" 10 "errors" 11 "fmt" 12 "hash" 13 "io" 14 15 "golang.org/x/crypto/cryptobyte" 16 "golang.org/x/crypto/hkdf" 17 ) 18 19 // This file contains the functions necessary to compute the TLS 1.3 key 20 // schedule. See RFC 8446, Section 7. 21 22 const ( 23 resumptionBinderLabel = "res binder" 24 clientHandshakeTrafficLabel = "c hs traffic" 25 serverHandshakeTrafficLabel = "s hs traffic" 26 clientApplicationTrafficLabel = "c ap traffic" 27 serverApplicationTrafficLabel = "s ap traffic" 28 exporterLabel = "exp master" 29 resumptionLabel = "res master" 30 trafficUpdateLabel = "traffic upd" 31 ) 32 33 // expandLabel implements HKDF-Expand-Label from RFC 8446, Section 7.1. 34 func (c *cipherSuiteTLS13) expandLabel(secret []byte, label string, context []byte, length int) []byte { 35 var hkdfLabel cryptobyte.Builder 36 hkdfLabel.AddUint16(uint16(length)) 37 hkdfLabel.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) { 38 b.AddBytes([]byte("tls13 ")) 39 b.AddBytes([]byte(label)) 40 }) 41 hkdfLabel.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) { 42 b.AddBytes(context) 43 }) 44 hkdfLabelBytes, err := hkdfLabel.Bytes() 45 if err != nil { 46 // Rather than calling BytesOrPanic, we explicitly handle this error, in 47 // order to provide a reasonable error message. It should be basically 48 // impossible for this to panic, and routing errors back through the 49 // tree rooted in this function is quite painful. The labels are fixed 50 // size, and the context is either a fixed-length computed hash, or 51 // parsed from a field which has the same length limitation. As such, an 52 // error here is likely to only be caused during development. 53 // 54 // NOTE: another reasonable approach here might be to return a 55 // randomized slice if we encounter an error, which would break the 56 // connection, but avoid panicking. This would perhaps be safer but 57 // significantly more confusing to users. 58 panic(fmt.Errorf("failed to construct HKDF label: %s", err)) 59 } 60 out := make([]byte, length) 61 n, err := hkdf.Expand(c.hash.New, secret, hkdfLabelBytes).Read(out) 62 if err != nil || n != length { 63 panic("tls: HKDF-Expand-Label invocation failed unexpectedly") 64 } 65 return out 66 } 67 68 // deriveSecret implements Derive-Secret from RFC 8446, Section 7.1. 69 func (c *cipherSuiteTLS13) deriveSecret(secret []byte, label string, transcript hash.Hash) []byte { 70 if transcript == nil { 71 transcript = c.hash.New() 72 } 73 return c.expandLabel(secret, label, transcript.Sum(nil), c.hash.Size()) 74 } 75 76 // extract implements HKDF-Extract with the cipher suite hash. 77 func (c *cipherSuiteTLS13) extract(newSecret, currentSecret []byte) []byte { 78 if newSecret == nil { 79 newSecret = make([]byte, c.hash.Size()) 80 } 81 return hkdf.Extract(c.hash.New, newSecret, currentSecret) 82 } 83 84 // nextTrafficSecret generates the next traffic secret, given the current one, 85 // according to RFC 8446, Section 7.2. 86 func (c *cipherSuiteTLS13) nextTrafficSecret(trafficSecret []byte) []byte { 87 return c.expandLabel(trafficSecret, trafficUpdateLabel, nil, c.hash.Size()) 88 } 89 90 // trafficKey generates traffic keys according to RFC 8446, Section 7.3. 91 func (c *cipherSuiteTLS13) trafficKey(trafficSecret []byte) (key, iv []byte) { 92 key = c.expandLabel(trafficSecret, "key", nil, c.keyLen) 93 iv = c.expandLabel(trafficSecret, "iv", nil, aeadNonceLength) 94 return 95 } 96 97 // finishedHash generates the Finished verify_data or PskBinderEntry according 98 // to RFC 8446, Section 4.4.4. See sections 4.4 and 4.2.11.2 for the baseKey 99 // selection. 100 func (c *cipherSuiteTLS13) finishedHash(baseKey []byte, transcript hash.Hash) []byte { 101 finishedKey := c.expandLabel(baseKey, "finished", nil, c.hash.Size()) 102 verifyData := hmac.New(c.hash.New, finishedKey) 103 verifyData.Write(transcript.Sum(nil)) 104 return verifyData.Sum(nil) 105 } 106 107 // exportKeyingMaterial implements RFC5705 exporters for TLS 1.3 according to 108 // RFC 8446, Section 7.5. 109 func (c *cipherSuiteTLS13) exportKeyingMaterial(masterSecret []byte, transcript hash.Hash) func(string, []byte, int) ([]byte, error) { 110 expMasterSecret := c.deriveSecret(masterSecret, exporterLabel, transcript) 111 return func(label string, context []byte, length int) ([]byte, error) { 112 secret := c.deriveSecret(expMasterSecret, label, nil) 113 h := c.hash.New() 114 h.Write(context) 115 return c.expandLabel(secret, "exporter", h.Sum(nil), length), nil 116 } 117 } 118 119 // generateECDHEKey returns a PrivateKey that implements Diffie-Hellman 120 // according to RFC 8446, Section 4.2.8.2. 121 func generateECDHEKey(rand io.Reader, curveID CurveID) (*ecdh.PrivateKey, error) { 122 curve, ok := curveForCurveID(curveID) 123 if !ok { 124 return nil, errors.New("tls: internal error: unsupported curve") 125 } 126 127 return curve.GenerateKey(rand) 128 } 129 130 func curveForCurveID(id CurveID) (ecdh.Curve, bool) { 131 switch id { 132 case X25519: 133 return ecdh.X25519(), true 134 case CurveP256: 135 return ecdh.P256(), true 136 case CurveP384: 137 return ecdh.P384(), true 138 case CurveP521: 139 return ecdh.P521(), true 140 default: 141 return nil, false 142 } 143 } 144 145 func curveIDForCurve(curve ecdh.Curve) (CurveID, bool) { 146 switch curve { 147 case ecdh.X25519(): 148 return X25519, true 149 case ecdh.P256(): 150 return CurveP256, true 151 case ecdh.P384(): 152 return CurveP384, true 153 case ecdh.P521(): 154 return CurveP521, true 155 default: 156 return 0, false 157 } 158 }