Source file src/crypto/tls/ech.go

     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  	"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  // parseECHConfigList parses a draft-ietf-tls-esni-18 ECHConfigList, returning a
   123  // slice of parsed ECHConfigs, in the same order they were parsed, or an error
   124  // if the list is malformed.
   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  			// If high order bit is set to 1 the extension is mandatory.
   160  			// Since we don't support any extensions, if we see a mandatory
   161  			// bit, we skip the config.
   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  			// This is an error in the config, but killing the connection feels
   176  			// excessive.
   177  			continue
   178  		}
   179  		for _, cs := range ec.SymmetricCipherSuite {
   180  			// All of the supported AEADs and KDFs are fine, rather than
   181  			// imposing some sort of preference here, we just pick the first
   182  			// valid suite.
   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:] // strip four byte prefix
   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) || // header, version, random
   239  		!skipUint8LengthPrefixed(&s) || // session ID
   240  		!skipUint16LengthPrefixed(&s) || // cipher suites
   241  		!skipUint8LengthPrefixed(&s) { // compression methods
   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  	// Reconstructing the inner client hello from its encoded form is somewhat
   264  	// complicated. It is missing its header (message type and length), session
   265  	// ID, and the extensions may be compressed. Since we need to put the
   266  	// extensions back in the same order as they were in the raw outer hello,
   267  	// and since we don't store the raw extensions, or the order we parsed them
   268  	// in, we need to reparse the raw extensions from the outer hello in order
   269  	// to properly insert them into the inner hello. This _should_ result in raw
   270  	// bytes which match the hello as it was generated by the client.
   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  	// The specification says we must verify that the trailing padding is all
   284  	// zeros. This is kind of weird for TLS messages, where we generally just
   285  	// throw away any trailing garbage.
   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  		// Skip GREASE values (values of the form 0x?A0A).
   375  		// GREASE (Generate Random Extensions And Sustain Extensibility) is a mechanism used by
   376  		// browsers like Chrome to ensure TLS implementations correctly ignore unknown values.
   377  		// GREASE values follow a specific pattern: 0x?A0A, where ? can be any hex digit.
   378  		// These values should be ignored when processing supported TLS versions.
   379  		if v&0x0F0F == 0x0A0A && v&0xff == v>>8 {
   380  			continue
   381  		}
   382  
   383  		// Ensure at least TLS 1.3 is offered.
   384  		if v == VersionTLS13 {
   385  			hasTLS13 = true
   386  		} else if v < VersionTLS13 {
   387  			// Reject if any non-GREASE value is below TLS 1.3, as ECH requires TLS 1.3+.
   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) // outer
   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  	// NOTE: the tag lengths for all of the supported AEADs are the same (16
   425  	// bytes), so we have hardcoded it here. If we add support for another AEAD
   426  	// with a different tag length, we will need to change this.
   427  	encryptedLen := len(encodedInner) + 16 // AEAD tag length
   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:] // strip the four byte prefix
   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  // validDNSName is a rather rudimentary check for the validity of a DNS name.
   449  // This is used to check if the public_name in a ECHConfig is valid when we are
   450  // picking a config. This can be somewhat lax because even if we pick a
   451  // valid-looking name, the DNS layer will later reject it anyway.
   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  // ECHRejectionError is the error type returned when ECH is rejected by a remote
   478  // server. If the server offered a ECHConfigList to use for retries, the
   479  // RetryConfigList field will contain this list.
   480  //
   481  // The client may treat an ECHRejectionError with an empty set of RetryConfigs
   482  // as a secure signal from the server.
   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  	// NOTE: clone encap and payload so that mutating them does not mutate the
   544  	// raw extension bytes.
   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  			// attempt next trial decryption
   601  			continue
   602  		}
   603  
   604  		encodedInner, err := decryptECHPayload(hpkeContext, outer.original, payload)
   605  		if err != nil {
   606  			// attempt next trial decryption
   607  			continue
   608  		}
   609  
   610  		// NOTE: we do not enforce that the sent server_name matches the ECH
   611  		// configs PublicName, since this is not particularly important, and
   612  		// the client already had to know what it was in order to properly
   613  		// encrypt the payload. This is only a MAY in the spec, so we're not
   614  		// doing anything revolutionary.
   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