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