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