tls13.mx raw
1 // Copyright 2024 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 tls13 implements the TLS 1.3 Key Schedule as specified in RFC 8446,
6 // Section 7.1 and allowed by FIPS 140-3 IG 2.4.B Resolution 7.
7 package tls13
8
9 import (
10 "crypto/internal/fips140/hkdf"
11 "crypto/internal/fips140deps/byteorder"
12 "hash"
13 )
14
15 // We don't set the service indicator in this package but we delegate that to
16 // the underlying functions because the TLS 1.3 KDF does not have a standard of
17 // its own.
18
19 // ExpandLabel implements HKDF-Expand-Label from RFC 8446, Section 7.1.
20 func ExpandLabel[H hash.Hash](hash func() H, secret []byte, label []byte, context []byte, length int) []byte {
21 if len("tls13 ")+len(label) > 255 || len(context) > 255 {
22 // It should be impossible for this to panic: labels are fixed strings,
23 // and context is either a fixed-length computed hash, or parsed from a
24 // field which has the same length limitation.
25 //
26 // Another reasonable approach might be to return a randomized slice if
27 // we encounter an error, which would break the connection, but avoid
28 // panicking. This would perhaps be safer but significantly more
29 // confusing to users.
30 panic("tls13: label or context too long")
31 }
32 hkdfLabel := []byte{:0:2+1+len("tls13 ")+len(label)+1+len(context)}
33 hkdfLabel = byteorder.BEAppendUint16(hkdfLabel, uint16(length))
34 hkdfLabel = append(hkdfLabel, byte(len("tls13 ")+len(label)))
35 hkdfLabel = append(hkdfLabel, "tls13 "...)
36 hkdfLabel = append(hkdfLabel, label...)
37 hkdfLabel = append(hkdfLabel, byte(len(context)))
38 hkdfLabel = append(hkdfLabel, context...)
39 return hkdf.Expand(hash, secret, hkdfLabel, length)
40 }
41
42 func extract[H hash.Hash](hash func() H, newSecret, currentSecret []byte) []byte {
43 if newSecret == nil {
44 newSecret = []byte{:hash().Size()}
45 }
46 return hkdf.Extract(hash, newSecret, currentSecret)
47 }
48
49 func deriveSecret[H hash.Hash](hash func() H, secret []byte, label []byte, transcript hash.Hash) []byte {
50 if transcript == nil {
51 transcript = hash()
52 }
53 return ExpandLabel(hash, secret, label, transcript.Sum(nil), transcript.Size())
54 }
55
56 var (
57 resumptionBinderLabel = []byte("res binder")
58 clientEarlyTrafficLabel = []byte("c e traffic")
59 clientHandshakeTrafficLabel = []byte("c hs traffic")
60 serverHandshakeTrafficLabel = []byte("s hs traffic")
61 clientApplicationTrafficLabel = []byte("c ap traffic")
62 serverApplicationTrafficLabel = []byte("s ap traffic")
63 earlyExporterLabel = []byte("e exp master")
64 exporterLabel = []byte("exp master")
65 resumptionLabel = []byte("res master")
66 )
67
68 type EarlySecret struct {
69 secret []byte
70 hash func() hash.Hash
71 }
72
73 func NewEarlySecret[H hash.Hash](h func() H, psk []byte) *EarlySecret {
74 return &EarlySecret{
75 secret: extract(h, psk, nil),
76 hash: func() hash.Hash { return h() },
77 }
78 }
79
80 func (s *EarlySecret) ResumptionBinderKey() []byte {
81 return deriveSecret(s.hash, s.secret, resumptionBinderLabel, nil)
82 }
83
84 // ClientEarlyTrafficSecret derives the client_early_traffic_secret from the
85 // early secret and the transcript up to the ClientHello.
86 func (s *EarlySecret) ClientEarlyTrafficSecret(transcript hash.Hash) []byte {
87 return deriveSecret(s.hash, s.secret, clientEarlyTrafficLabel, transcript)
88 }
89
90 type HandshakeSecret struct {
91 secret []byte
92 hash func() hash.Hash
93 }
94
95 func (s *EarlySecret) HandshakeSecret(sharedSecret []byte) *HandshakeSecret {
96 derived := deriveSecret(s.hash, s.secret, []byte("derived"), nil)
97 return &HandshakeSecret{
98 secret: extract(s.hash, sharedSecret, derived),
99 hash: s.hash,
100 }
101 }
102
103 // ClientHandshakeTrafficSecret derives the client_handshake_traffic_secret from
104 // the handshake secret and the transcript up to the ServerHello.
105 func (s *HandshakeSecret) ClientHandshakeTrafficSecret(transcript hash.Hash) []byte {
106 return deriveSecret(s.hash, s.secret, clientHandshakeTrafficLabel, transcript)
107 }
108
109 // ServerHandshakeTrafficSecret derives the server_handshake_traffic_secret from
110 // the handshake secret and the transcript up to the ServerHello.
111 func (s *HandshakeSecret) ServerHandshakeTrafficSecret(transcript hash.Hash) []byte {
112 return deriveSecret(s.hash, s.secret, serverHandshakeTrafficLabel, transcript)
113 }
114
115 type MasterSecret struct {
116 secret []byte
117 hash func() hash.Hash
118 }
119
120 func (s *HandshakeSecret) MasterSecret() *MasterSecret {
121 derived := deriveSecret(s.hash, s.secret, []byte("derived"), nil)
122 return &MasterSecret{
123 secret: extract(s.hash, nil, derived),
124 hash: s.hash,
125 }
126 }
127
128 // ClientApplicationTrafficSecret derives the client_application_traffic_secret_0
129 // from the master secret and the transcript up to the server Finished.
130 func (s *MasterSecret) ClientApplicationTrafficSecret(transcript hash.Hash) []byte {
131 return deriveSecret(s.hash, s.secret, clientApplicationTrafficLabel, transcript)
132 }
133
134 // ServerApplicationTrafficSecret derives the server_application_traffic_secret_0
135 // from the master secret and the transcript up to the server Finished.
136 func (s *MasterSecret) ServerApplicationTrafficSecret(transcript hash.Hash) []byte {
137 return deriveSecret(s.hash, s.secret, serverApplicationTrafficLabel, transcript)
138 }
139
140 // ResumptionMasterSecret derives the resumption_master_secret from the master secret
141 // and the transcript up to the client Finished.
142 func (s *MasterSecret) ResumptionMasterSecret(transcript hash.Hash) []byte {
143 return deriveSecret(s.hash, s.secret, resumptionLabel, transcript)
144 }
145
146 type ExporterMasterSecret struct {
147 secret []byte
148 hash func() hash.Hash
149 }
150
151 // ExporterMasterSecret derives the exporter_master_secret from the master secret
152 // and the transcript up to the server Finished.
153 func (s *MasterSecret) ExporterMasterSecret(transcript hash.Hash) *ExporterMasterSecret {
154 return &ExporterMasterSecret{
155 secret: deriveSecret(s.hash, s.secret, exporterLabel, transcript),
156 hash: s.hash,
157 }
158 }
159
160 // EarlyExporterMasterSecret derives the exporter_master_secret from the early secret
161 // and the transcript up to the ClientHello.
162 func (s *EarlySecret) EarlyExporterMasterSecret(transcript hash.Hash) *ExporterMasterSecret {
163 return &ExporterMasterSecret{
164 secret: deriveSecret(s.hash, s.secret, earlyExporterLabel, transcript),
165 hash: s.hash,
166 }
167 }
168
169 func (s *ExporterMasterSecret) Exporter(label []byte, context []byte, length int) []byte {
170 secret := deriveSecret(s.hash, s.secret, label, nil)
171 h := s.hash()
172 h.Write(context)
173 return ExpandLabel(s.hash, secret, []byte("exporter"), h.Sum(nil), length)
174 }
175
176 func TestingOnlyExporterSecret(s *ExporterMasterSecret) []byte {
177 return s.secret
178 }
179