1
2
3
4
5 package tls
6
7 import (
8 "bytes"
9 "crypto/internal/hpke"
10 "errors"
11 "fmt"
12 "slices"
13 "strings"
14
15 "golang.org/x/crypto/cryptobyte"
16 )
17
18
19
20
21 var sortedSupportedAEADs []uint16
22
23 func init() {
24 for aeadID := range hpke.SupportedAEADs {
25 sortedSupportedAEADs = append(sortedSupportedAEADs, aeadID)
26 }
27 slices.Sort(sortedSupportedAEADs)
28 }
29
30 type echCipher struct {
31 KDFID uint16
32 AEADID uint16
33 }
34
35 type echExtension struct {
36 Type uint16
37 Data []byte
38 }
39
40 type echConfig struct {
41 raw []byte
42
43 Version uint16
44 Length uint16
45
46 ConfigID uint8
47 KemID uint16
48 PublicKey []byte
49 SymmetricCipherSuite []echCipher
50
51 MaxNameLength uint8
52 PublicName []byte
53 Extensions []echExtension
54 }
55
56 var errMalformedECHConfig = errors.New("tls: malformed ECHConfigList")
57
58 func parseECHConfig(enc []byte) (skip bool, ec echConfig, err error) {
59 s := cryptobyte.String(enc)
60 ec.raw = []byte(enc)
61 if !s.ReadUint16(&ec.Version) {
62 return false, echConfig{}, errMalformedECHConfig
63 }
64 if !s.ReadUint16(&ec.Length) {
65 return false, echConfig{}, errMalformedECHConfig
66 }
67 if len(ec.raw) < int(ec.Length)+4 {
68 return false, echConfig{}, errMalformedECHConfig
69 }
70 ec.raw = ec.raw[:ec.Length+4]
71 if ec.Version != extensionEncryptedClientHello {
72 s.Skip(int(ec.Length))
73 return true, echConfig{}, nil
74 }
75 if !s.ReadUint8(&ec.ConfigID) {
76 return false, echConfig{}, errMalformedECHConfig
77 }
78 if !s.ReadUint16(&ec.KemID) {
79 return false, echConfig{}, errMalformedECHConfig
80 }
81 if !readUint16LengthPrefixed(&s, &ec.PublicKey) {
82 return false, echConfig{}, errMalformedECHConfig
83 }
84 var cipherSuites cryptobyte.String
85 if !s.ReadUint16LengthPrefixed(&cipherSuites) {
86 return false, echConfig{}, errMalformedECHConfig
87 }
88 for !cipherSuites.Empty() {
89 var c echCipher
90 if !cipherSuites.ReadUint16(&c.KDFID) {
91 return false, echConfig{}, errMalformedECHConfig
92 }
93 if !cipherSuites.ReadUint16(&c.AEADID) {
94 return false, echConfig{}, errMalformedECHConfig
95 }
96 ec.SymmetricCipherSuite = append(ec.SymmetricCipherSuite, c)
97 }
98 if !s.ReadUint8(&ec.MaxNameLength) {
99 return false, echConfig{}, errMalformedECHConfig
100 }
101 var publicName cryptobyte.String
102 if !s.ReadUint8LengthPrefixed(&publicName) {
103 return false, echConfig{}, errMalformedECHConfig
104 }
105 ec.PublicName = publicName
106 var extensions cryptobyte.String
107 if !s.ReadUint16LengthPrefixed(&extensions) {
108 return false, echConfig{}, errMalformedECHConfig
109 }
110 for !extensions.Empty() {
111 var e echExtension
112 if !extensions.ReadUint16(&e.Type) {
113 return false, echConfig{}, errMalformedECHConfig
114 }
115 if !extensions.ReadUint16LengthPrefixed((*cryptobyte.String)(&e.Data)) {
116 return false, echConfig{}, errMalformedECHConfig
117 }
118 ec.Extensions = append(ec.Extensions, e)
119 }
120
121 return false, ec, nil
122 }
123
124
125
126
127 func parseECHConfigList(data []byte) ([]echConfig, error) {
128 s := cryptobyte.String(data)
129 var length uint16
130 if !s.ReadUint16(&length) {
131 return nil, errMalformedECHConfig
132 }
133 if length != uint16(len(data)-2) {
134 return nil, errMalformedECHConfig
135 }
136 var configs []echConfig
137 for len(s) > 0 {
138 if len(s) < 4 {
139 return nil, errors.New("tls: malformed ECHConfig")
140 }
141 configLen := uint16(s[2])<<8 | uint16(s[3])
142 skip, ec, err := parseECHConfig(s)
143 if err != nil {
144 return nil, err
145 }
146 s = s[configLen+4:]
147 if !skip {
148 configs = append(configs, ec)
149 }
150 }
151 return configs, nil
152 }
153
154 func pickECHConfig(list []echConfig) *echConfig {
155 for _, ec := range list {
156 if _, ok := hpke.SupportedKEMs[ec.KemID]; !ok {
157 continue
158 }
159 var validSCS bool
160 for _, cs := range ec.SymmetricCipherSuite {
161 if _, ok := hpke.SupportedAEADs[cs.AEADID]; !ok {
162 continue
163 }
164 if _, ok := hpke.SupportedKDFs[cs.KDFID]; !ok {
165 continue
166 }
167 validSCS = true
168 break
169 }
170 if !validSCS {
171 continue
172 }
173 if !validDNSName(string(ec.PublicName)) {
174 continue
175 }
176 var unsupportedExt bool
177 for _, ext := range ec.Extensions {
178
179
180
181 if ext.Type&uint16(1<<15) != 0 {
182 unsupportedExt = true
183 }
184 }
185 if unsupportedExt {
186 continue
187 }
188 return &ec
189 }
190 return nil
191 }
192
193 func pickECHCipherSuite(suites []echCipher) (echCipher, error) {
194 for _, s := range suites {
195
196
197
198 if _, ok := hpke.SupportedAEADs[s.AEADID]; !ok {
199 continue
200 }
201 if _, ok := hpke.SupportedKDFs[s.KDFID]; !ok {
202 continue
203 }
204 return s, nil
205 }
206 return echCipher{}, errors.New("tls: no supported symmetric ciphersuites for ECH")
207 }
208
209 func encodeInnerClientHello(inner *clientHelloMsg, maxNameLength int) ([]byte, error) {
210 h, err := inner.marshalMsg(true)
211 if err != nil {
212 return nil, err
213 }
214 h = h[4:]
215
216 var paddingLen int
217 if inner.serverName != "" {
218 paddingLen = max(0, maxNameLength-len(inner.serverName))
219 } else {
220 paddingLen = maxNameLength + 9
221 }
222 paddingLen = 31 - ((len(h) + paddingLen - 1) % 32)
223
224 return append(h, make([]byte, paddingLen)...), nil
225 }
226
227 func skipUint8LengthPrefixed(s *cryptobyte.String) bool {
228 var skip uint8
229 if !s.ReadUint8(&skip) {
230 return false
231 }
232 return s.Skip(int(skip))
233 }
234
235 func skipUint16LengthPrefixed(s *cryptobyte.String) bool {
236 var skip uint16
237 if !s.ReadUint16(&skip) {
238 return false
239 }
240 return s.Skip(int(skip))
241 }
242
243 type rawExtension struct {
244 extType uint16
245 data []byte
246 }
247
248 func extractRawExtensions(hello *clientHelloMsg) ([]rawExtension, error) {
249 s := cryptobyte.String(hello.original)
250 if !s.Skip(4+2+32) ||
251 !skipUint8LengthPrefixed(&s) ||
252 !skipUint16LengthPrefixed(&s) ||
253 !skipUint8LengthPrefixed(&s) {
254 return nil, errors.New("tls: malformed outer client hello")
255 }
256 var rawExtensions []rawExtension
257 var extensions cryptobyte.String
258 if !s.ReadUint16LengthPrefixed(&extensions) {
259 return nil, errors.New("tls: malformed outer client hello")
260 }
261
262 for !extensions.Empty() {
263 var extension uint16
264 var extData cryptobyte.String
265 if !extensions.ReadUint16(&extension) ||
266 !extensions.ReadUint16LengthPrefixed(&extData) {
267 return nil, errors.New("tls: invalid inner client hello")
268 }
269 rawExtensions = append(rawExtensions, rawExtension{extension, extData})
270 }
271 return rawExtensions, nil
272 }
273
274 func decodeInnerClientHello(outer *clientHelloMsg, encoded []byte) (*clientHelloMsg, error) {
275
276
277
278
279
280
281
282
283 innerReader := cryptobyte.String(encoded)
284 var versionAndRandom, sessionID, cipherSuites, compressionMethods []byte
285 var extensions cryptobyte.String
286 if !innerReader.ReadBytes(&versionAndRandom, 2+32) ||
287 !readUint8LengthPrefixed(&innerReader, &sessionID) ||
288 len(sessionID) != 0 ||
289 !readUint16LengthPrefixed(&innerReader, &cipherSuites) ||
290 !readUint8LengthPrefixed(&innerReader, &compressionMethods) ||
291 !innerReader.ReadUint16LengthPrefixed(&extensions) {
292 return nil, errors.New("tls: invalid inner client hello")
293 }
294
295
296
297
298 for _, p := range innerReader {
299 if p != 0 {
300 return nil, errors.New("tls: invalid inner client hello")
301 }
302 }
303
304 rawOuterExts, err := extractRawExtensions(outer)
305 if err != nil {
306 return nil, err
307 }
308
309 recon := cryptobyte.NewBuilder(nil)
310 recon.AddUint8(typeClientHello)
311 recon.AddUint24LengthPrefixed(func(recon *cryptobyte.Builder) {
312 recon.AddBytes(versionAndRandom)
313 recon.AddUint8LengthPrefixed(func(recon *cryptobyte.Builder) {
314 recon.AddBytes(outer.sessionId)
315 })
316 recon.AddUint16LengthPrefixed(func(recon *cryptobyte.Builder) {
317 recon.AddBytes(cipherSuites)
318 })
319 recon.AddUint8LengthPrefixed(func(recon *cryptobyte.Builder) {
320 recon.AddBytes(compressionMethods)
321 })
322 recon.AddUint16LengthPrefixed(func(recon *cryptobyte.Builder) {
323 for !extensions.Empty() {
324 var extension uint16
325 var extData cryptobyte.String
326 if !extensions.ReadUint16(&extension) ||
327 !extensions.ReadUint16LengthPrefixed(&extData) {
328 recon.SetError(errors.New("tls: invalid inner client hello"))
329 return
330 }
331 if extension == extensionECHOuterExtensions {
332 if !extData.ReadUint8LengthPrefixed(&extData) {
333 recon.SetError(errors.New("tls: invalid inner client hello"))
334 return
335 }
336 var i int
337 for !extData.Empty() {
338 var extType uint16
339 if !extData.ReadUint16(&extType) {
340 recon.SetError(errors.New("tls: invalid inner client hello"))
341 return
342 }
343 if extType == extensionEncryptedClientHello {
344 recon.SetError(errors.New("tls: invalid outer extensions"))
345 return
346 }
347 for ; i <= len(rawOuterExts); i++ {
348 if i == len(rawOuterExts) {
349 recon.SetError(errors.New("tls: invalid outer extensions"))
350 return
351 }
352 if rawOuterExts[i].extType == extType {
353 break
354 }
355 }
356 recon.AddUint16(rawOuterExts[i].extType)
357 recon.AddUint16LengthPrefixed(func(recon *cryptobyte.Builder) {
358 recon.AddBytes(rawOuterExts[i].data)
359 })
360 }
361 } else {
362 recon.AddUint16(extension)
363 recon.AddUint16LengthPrefixed(func(recon *cryptobyte.Builder) {
364 recon.AddBytes(extData)
365 })
366 }
367 }
368 })
369 })
370
371 reconBytes, err := recon.Bytes()
372 if err != nil {
373 return nil, err
374 }
375 inner := &clientHelloMsg{}
376 if !inner.unmarshal(reconBytes) {
377 return nil, errors.New("tls: invalid reconstructed inner client hello")
378 }
379
380 if !bytes.Equal(inner.encryptedClientHello, []byte{uint8(innerECHExt)}) {
381 return nil, errInvalidECHExt
382 }
383
384 hasTLS13 := false
385 for _, v := range inner.supportedVersions {
386
387
388
389
390
391 if v&0x0F0F == 0x0A0A && v&0xff == v>>8 {
392 continue
393 }
394
395
396 if v == VersionTLS13 {
397 hasTLS13 = true
398 } else if v < VersionTLS13 {
399
400 return nil, errors.New("tls: client sent encrypted_client_hello extension with unsupported versions")
401 }
402 }
403
404 if !hasTLS13 {
405 return nil, errors.New("tls: client sent encrypted_client_hello extension but did not offer TLS 1.3")
406 }
407
408 return inner, nil
409 }
410
411 func decryptECHPayload(context *hpke.Receipient, hello, payload []byte) ([]byte, error) {
412 outerAAD := bytes.Replace(hello[4:], payload, make([]byte, len(payload)), 1)
413 return context.Open(outerAAD, payload)
414 }
415
416 func generateOuterECHExt(id uint8, kdfID, aeadID uint16, encodedKey []byte, payload []byte) ([]byte, error) {
417 var b cryptobyte.Builder
418 b.AddUint8(0)
419 b.AddUint16(kdfID)
420 b.AddUint16(aeadID)
421 b.AddUint8(id)
422 b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { b.AddBytes(encodedKey) })
423 b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { b.AddBytes(payload) })
424 return b.Bytes()
425 }
426
427 func computeAndUpdateOuterECHExtension(outer, inner *clientHelloMsg, ech *echClientContext, useKey bool) error {
428 var encapKey []byte
429 if useKey {
430 encapKey = ech.encapsulatedKey
431 }
432 encodedInner, err := encodeInnerClientHello(inner, int(ech.config.MaxNameLength))
433 if err != nil {
434 return err
435 }
436
437
438
439 encryptedLen := len(encodedInner) + 16
440 outer.encryptedClientHello, err = generateOuterECHExt(ech.config.ConfigID, ech.kdfID, ech.aeadID, encapKey, make([]byte, encryptedLen))
441 if err != nil {
442 return err
443 }
444 serializedOuter, err := outer.marshal()
445 if err != nil {
446 return err
447 }
448 serializedOuter = serializedOuter[4:]
449 encryptedInner, err := ech.hpkeContext.Seal(serializedOuter, encodedInner)
450 if err != nil {
451 return err
452 }
453 outer.encryptedClientHello, err = generateOuterECHExt(ech.config.ConfigID, ech.kdfID, ech.aeadID, encapKey, encryptedInner)
454 if err != nil {
455 return err
456 }
457 return nil
458 }
459
460
461
462
463
464 func validDNSName(name string) bool {
465 if len(name) > 253 {
466 return false
467 }
468 labels := strings.Split(name, ".")
469 if len(labels) <= 1 {
470 return false
471 }
472 for _, l := range labels {
473 labelLen := len(l)
474 if labelLen == 0 {
475 return false
476 }
477 for i, r := range l {
478 if r == '-' && (i == 0 || i == labelLen-1) {
479 return false
480 }
481 if (r < '0' || r > '9') && (r < 'a' || r > 'z') && (r < 'A' || r > 'Z') && r != '-' {
482 return false
483 }
484 }
485 }
486 return true
487 }
488
489
490
491
492
493
494
495 type ECHRejectionError struct {
496 RetryConfigList []byte
497 }
498
499 func (e *ECHRejectionError) Error() string {
500 return "tls: server rejected ECH"
501 }
502
503 var errMalformedECHExt = errors.New("tls: malformed encrypted_client_hello extension")
504 var errInvalidECHExt = errors.New("tls: client sent invalid encrypted_client_hello extension")
505
506 type echExtType uint8
507
508 const (
509 innerECHExt echExtType = 1
510 outerECHExt echExtType = 0
511 )
512
513 func parseECHExt(ext []byte) (echType echExtType, cs echCipher, configID uint8, encap []byte, payload []byte, err error) {
514 data := make([]byte, len(ext))
515 copy(data, ext)
516 s := cryptobyte.String(data)
517 var echInt uint8
518 if !s.ReadUint8(&echInt) {
519 err = errMalformedECHExt
520 return
521 }
522 echType = echExtType(echInt)
523 if echType == innerECHExt {
524 if !s.Empty() {
525 err = errMalformedECHExt
526 return
527 }
528 return echType, cs, 0, nil, nil, nil
529 }
530 if echType != outerECHExt {
531 err = errInvalidECHExt
532 return
533 }
534 if !s.ReadUint16(&cs.KDFID) {
535 err = errMalformedECHExt
536 return
537 }
538 if !s.ReadUint16(&cs.AEADID) {
539 err = errMalformedECHExt
540 return
541 }
542 if !s.ReadUint8(&configID) {
543 err = errMalformedECHExt
544 return
545 }
546 if !readUint16LengthPrefixed(&s, &encap) {
547 err = errMalformedECHExt
548 return
549 }
550 if !readUint16LengthPrefixed(&s, &payload) {
551 err = errMalformedECHExt
552 return
553 }
554
555
556
557 return echType, cs, configID, bytes.Clone(encap), bytes.Clone(payload), nil
558 }
559
560 func marshalEncryptedClientHelloConfigList(configs []EncryptedClientHelloKey) ([]byte, error) {
561 builder := cryptobyte.NewBuilder(nil)
562 builder.AddUint16LengthPrefixed(func(builder *cryptobyte.Builder) {
563 for _, c := range configs {
564 builder.AddBytes(c.Config)
565 }
566 })
567 return builder.Bytes()
568 }
569
570 func (c *Conn) processECHClientHello(outer *clientHelloMsg) (*clientHelloMsg, *echServerContext, error) {
571 echType, echCiphersuite, configID, encap, payload, err := parseECHExt(outer.encryptedClientHello)
572 if err != nil {
573 if errors.Is(err, errInvalidECHExt) {
574 c.sendAlert(alertIllegalParameter)
575 } else {
576 c.sendAlert(alertDecodeError)
577 }
578
579 return nil, nil, errInvalidECHExt
580 }
581
582 if echType == innerECHExt {
583 return outer, &echServerContext{inner: true}, nil
584 }
585
586 if len(c.config.EncryptedClientHelloKeys) == 0 {
587 return outer, nil, nil
588 }
589
590 for _, echKey := range c.config.EncryptedClientHelloKeys {
591 skip, config, err := parseECHConfig(echKey.Config)
592 if err != nil || skip {
593 c.sendAlert(alertInternalError)
594 return nil, nil, fmt.Errorf("tls: invalid EncryptedClientHelloKeys Config: %s", err)
595 }
596 if skip {
597 continue
598 }
599 echPriv, err := hpke.ParseHPKEPrivateKey(config.KemID, echKey.PrivateKey)
600 if err != nil {
601 c.sendAlert(alertInternalError)
602 return nil, nil, fmt.Errorf("tls: invalid EncryptedClientHelloKeys PrivateKey: %s", err)
603 }
604 info := append([]byte("tls ech\x00"), echKey.Config...)
605 hpkeContext, err := hpke.SetupReceipient(hpke.DHKEM_X25519_HKDF_SHA256, echCiphersuite.KDFID, echCiphersuite.AEADID, echPriv, info, encap)
606 if err != nil {
607
608 continue
609 }
610
611 encodedInner, err := decryptECHPayload(hpkeContext, outer.original, payload)
612 if err != nil {
613
614 continue
615 }
616
617
618
619
620
621
622
623 echInner, err := decodeInnerClientHello(outer, encodedInner)
624 if err != nil {
625 c.sendAlert(alertIllegalParameter)
626 return nil, nil, errInvalidECHExt
627 }
628
629 c.echAccepted = true
630
631 return echInner, &echServerContext{
632 hpkeContext: hpkeContext,
633 configID: configID,
634 ciphersuite: echCiphersuite,
635 }, nil
636 }
637
638 return outer, nil, nil
639 }
640
641 func buildRetryConfigList(keys []EncryptedClientHelloKey) ([]byte, error) {
642 var atLeastOneRetryConfig bool
643 var retryBuilder cryptobyte.Builder
644 retryBuilder.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
645 for _, c := range keys {
646 if !c.SendAsRetry {
647 continue
648 }
649 atLeastOneRetryConfig = true
650 b.AddBytes(c.Config)
651 }
652 })
653 if !atLeastOneRetryConfig {
654 return nil, nil
655 }
656 return retryBuilder.Bytes()
657 }
658
View as plain text