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, errors.New("tls: client sent invalid encrypted_client_hello extension")
382 }
383
384 if len(inner.supportedVersions) != 1 || (len(inner.supportedVersions) >= 1 && inner.supportedVersions[0] != VersionTLS13) {
385 return nil, errors.New("tls: client sent encrypted_client_hello extension and offered incompatible versions")
386 }
387
388 return inner, nil
389 }
390
391 func decryptECHPayload(context *hpke.Receipient, hello, payload []byte) ([]byte, error) {
392 outerAAD := bytes.Replace(hello[4:], payload, make([]byte, len(payload)), 1)
393 return context.Open(outerAAD, payload)
394 }
395
396 func generateOuterECHExt(id uint8, kdfID, aeadID uint16, encodedKey []byte, payload []byte) ([]byte, error) {
397 var b cryptobyte.Builder
398 b.AddUint8(0)
399 b.AddUint16(kdfID)
400 b.AddUint16(aeadID)
401 b.AddUint8(id)
402 b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { b.AddBytes(encodedKey) })
403 b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { b.AddBytes(payload) })
404 return b.Bytes()
405 }
406
407 func computeAndUpdateOuterECHExtension(outer, inner *clientHelloMsg, ech *echClientContext, useKey bool) error {
408 var encapKey []byte
409 if useKey {
410 encapKey = ech.encapsulatedKey
411 }
412 encodedInner, err := encodeInnerClientHello(inner, int(ech.config.MaxNameLength))
413 if err != nil {
414 return err
415 }
416
417
418
419 encryptedLen := len(encodedInner) + 16
420 outer.encryptedClientHello, err = generateOuterECHExt(ech.config.ConfigID, ech.kdfID, ech.aeadID, encapKey, make([]byte, encryptedLen))
421 if err != nil {
422 return err
423 }
424 serializedOuter, err := outer.marshal()
425 if err != nil {
426 return err
427 }
428 serializedOuter = serializedOuter[4:]
429 encryptedInner, err := ech.hpkeContext.Seal(serializedOuter, encodedInner)
430 if err != nil {
431 return err
432 }
433 outer.encryptedClientHello, err = generateOuterECHExt(ech.config.ConfigID, ech.kdfID, ech.aeadID, encapKey, encryptedInner)
434 if err != nil {
435 return err
436 }
437 return nil
438 }
439
440
441
442
443
444 func validDNSName(name string) bool {
445 if len(name) > 253 {
446 return false
447 }
448 labels := strings.Split(name, ".")
449 if len(labels) <= 1 {
450 return false
451 }
452 for _, l := range labels {
453 labelLen := len(l)
454 if labelLen == 0 {
455 return false
456 }
457 for i, r := range l {
458 if r == '-' && (i == 0 || i == labelLen-1) {
459 return false
460 }
461 if (r < '0' || r > '9') && (r < 'a' || r > 'z') && (r < 'A' || r > 'Z') && r != '-' {
462 return false
463 }
464 }
465 }
466 return true
467 }
468
469
470
471
472
473
474
475 type ECHRejectionError struct {
476 RetryConfigList []byte
477 }
478
479 func (e *ECHRejectionError) Error() string {
480 return "tls: server rejected ECH"
481 }
482
483 var errMalformedECHExt = errors.New("tls: malformed encrypted_client_hello extension")
484
485 type echExtType uint8
486
487 const (
488 innerECHExt echExtType = 1
489 outerECHExt echExtType = 0
490 )
491
492 func parseECHExt(ext []byte) (echType echExtType, cs echCipher, configID uint8, encap []byte, payload []byte, err error) {
493 data := make([]byte, len(ext))
494 copy(data, ext)
495 s := cryptobyte.String(data)
496 var echInt uint8
497 if !s.ReadUint8(&echInt) {
498 err = errMalformedECHExt
499 return
500 }
501 echType = echExtType(echInt)
502 if echType == innerECHExt {
503 if !s.Empty() {
504 err = errMalformedECHExt
505 return
506 }
507 return echType, cs, 0, nil, nil, nil
508 }
509 if echType != outerECHExt {
510 err = errMalformedECHExt
511 return
512 }
513 if !s.ReadUint16(&cs.KDFID) {
514 err = errMalformedECHExt
515 return
516 }
517 if !s.ReadUint16(&cs.AEADID) {
518 err = errMalformedECHExt
519 return
520 }
521 if !s.ReadUint8(&configID) {
522 err = errMalformedECHExt
523 return
524 }
525 if !readUint16LengthPrefixed(&s, &encap) {
526 err = errMalformedECHExt
527 return
528 }
529 if !readUint16LengthPrefixed(&s, &payload) {
530 err = errMalformedECHExt
531 return
532 }
533
534
535
536 return echType, cs, configID, bytes.Clone(encap), bytes.Clone(payload), nil
537 }
538
539 func marshalEncryptedClientHelloConfigList(configs []EncryptedClientHelloKey) ([]byte, error) {
540 builder := cryptobyte.NewBuilder(nil)
541 builder.AddUint16LengthPrefixed(func(builder *cryptobyte.Builder) {
542 for _, c := range configs {
543 builder.AddBytes(c.Config)
544 }
545 })
546 return builder.Bytes()
547 }
548
549 func (c *Conn) processECHClientHello(outer *clientHelloMsg) (*clientHelloMsg, *echServerContext, error) {
550 echType, echCiphersuite, configID, encap, payload, err := parseECHExt(outer.encryptedClientHello)
551 if err != nil {
552 c.sendAlert(alertDecodeError)
553 return nil, nil, errors.New("tls: client sent invalid encrypted_client_hello extension")
554 }
555
556 if echType == innerECHExt {
557 return outer, &echServerContext{inner: true}, nil
558 }
559
560 if len(c.config.EncryptedClientHelloKeys) == 0 {
561 return outer, nil, nil
562 }
563
564 for _, echKey := range c.config.EncryptedClientHelloKeys {
565 skip, config, err := parseECHConfig(echKey.Config)
566 if err != nil || skip {
567 c.sendAlert(alertInternalError)
568 return nil, nil, fmt.Errorf("tls: invalid EncryptedClientHelloKeys Config: %s", err)
569 }
570 if skip {
571 continue
572 }
573 echPriv, err := hpke.ParseHPKEPrivateKey(config.KemID, echKey.PrivateKey)
574 if err != nil {
575 c.sendAlert(alertInternalError)
576 return nil, nil, fmt.Errorf("tls: invalid EncryptedClientHelloKeys PrivateKey: %s", err)
577 }
578 info := append([]byte("tls ech\x00"), echKey.Config...)
579 hpkeContext, err := hpke.SetupReceipient(hpke.DHKEM_X25519_HKDF_SHA256, echCiphersuite.KDFID, echCiphersuite.AEADID, echPriv, info, encap)
580 if err != nil {
581
582 continue
583 }
584
585 encodedInner, err := decryptECHPayload(hpkeContext, outer.original, payload)
586 if err != nil {
587
588 continue
589 }
590
591
592
593
594
595
596
597 echInner, err := decodeInnerClientHello(outer, encodedInner)
598 if err != nil {
599 c.sendAlert(alertIllegalParameter)
600 return nil, nil, errors.New("tls: client sent invalid encrypted_client_hello extension")
601 }
602
603 c.echAccepted = true
604
605 return echInner, &echServerContext{
606 hpkeContext: hpkeContext,
607 configID: configID,
608 ciphersuite: echCiphersuite,
609 }, nil
610 }
611
612 return outer, nil, nil
613 }
614
615 func buildRetryConfigList(keys []EncryptedClientHelloKey) ([]byte, error) {
616 var atLeastOneRetryConfig bool
617 var retryBuilder cryptobyte.Builder
618 retryBuilder.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
619 for _, c := range keys {
620 if !c.SendAsRetry {
621 continue
622 }
623 atLeastOneRetryConfig = true
624 b.AddBytes(c.Config)
625 }
626 })
627 if !atLeastOneRetryConfig {
628 return nil, nil
629 }
630 return retryBuilder.Bytes()
631 }
632
View as plain text