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