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/internal/hpke"
    10  	"errors"
    11  	"fmt"
    12  	"slices"
    13  	"strings"
    14  
    15  	"golang.org/x/crypto/cryptobyte"
    16  )
    17  
    18  // sortedSupportedAEADs is just a sorted version of hpke.SupportedAEADS.
    19  // We need this so that when we insert them into ECHConfigs the ordering
    20  // is stable.
    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  // parseECHConfigList parses a draft-ietf-tls-esni-18 ECHConfigList, returning a
   136  // slice of parsed ECHConfigs, in the same order they were parsed, or an error
   137  // if the list is malformed.
   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  			// If high order bit is set to 1 the extension is mandatory.
   190  			// Since we don't support any extensions, if we see a mandatory
   191  			// bit, we skip the config.
   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  		// NOTE: all of the supported AEADs and KDFs are fine, rather than
   207  		// imposing some sort of preference here, we just pick the first valid
   208  		// suite.
   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:] // strip four byte prefix
   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) || // header, version, random
   262  		!skipUint8LengthPrefixed(&s) || // session ID
   263  		!skipUint16LengthPrefixed(&s) || // cipher suites
   264  		!skipUint8LengthPrefixed(&s) { // compression methods
   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  	// Reconstructing the inner client hello from its encoded form is somewhat
   287  	// complicated. It is missing its header (message type and length), session
   288  	// ID, and the extensions may be compressed. Since we need to put the
   289  	// extensions back in the same order as they were in the raw outer hello,
   290  	// and since we don't store the raw extensions, or the order we parsed them
   291  	// in, we need to reparse the raw extensions from the outer hello in order
   292  	// to properly insert them into the inner hello. This _should_ result in raw
   293  	// bytes which match the hello as it was generated by the client.
   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  	// The specification says we must verify that the trailing padding is all
   307  	// zeros. This is kind of weird for TLS messages, where we generally just
   308  	// throw away any trailing garbage.
   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  		// Skip GREASE values (values of the form 0x?A0A).
   398  		// GREASE (Generate Random Extensions And Sustain Extensibility) is a mechanism used by
   399  		// browsers like Chrome to ensure TLS implementations correctly ignore unknown values.
   400  		// GREASE values follow a specific pattern: 0x?A0A, where ? can be any hex digit.
   401  		// These values should be ignored when processing supported TLS versions.
   402  		if v&0x0F0F == 0x0A0A && v&0xff == v>>8 {
   403  			continue
   404  		}
   405  
   406  		// Ensure at least TLS 1.3 is offered.
   407  		if v == VersionTLS13 {
   408  			hasTLS13 = true
   409  		} else if v < VersionTLS13 {
   410  			// Reject if any non-GREASE value is below TLS 1.3, as ECH requires TLS 1.3+.
   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) // outer
   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  	// NOTE: the tag lengths for all of the supported AEADs are the same (16
   448  	// bytes), so we have hardcoded it here. If we add support for another AEAD
   449  	// with a different tag length, we will need to change this.
   450  	encryptedLen := len(encodedInner) + 16 // AEAD tag length
   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:] // strip the four byte prefix
   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  // validDNSName is a rather rudimentary check for the validity of a DNS name.
   472  // This is used to check if the public_name in a ECHConfig is valid when we are
   473  // picking a config. This can be somewhat lax because even if we pick a
   474  // valid-looking name, the DNS layer will later reject it anyway.
   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  // ECHRejectionError is the error type returned when ECH is rejected by a remote
   501  // server. If the server offered a ECHConfigList to use for retries, the
   502  // RetryConfigList field will contain this list.
   503  //
   504  // The client may treat an ECHRejectionError with an empty set of RetryConfigs
   505  // as a secure signal from the server.
   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  	// NOTE: clone encap and payload so that mutating them does not mutate the
   567  	// raw extension bytes.
   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  			// attempt next trial decryption
   619  			continue
   620  		}
   621  
   622  		encodedInner, err := decryptECHPayload(hpkeContext, outer.original, payload)
   623  		if err != nil {
   624  			// attempt next trial decryption
   625  			continue
   626  		}
   627  
   628  		// NOTE: we do not enforce that the sent server_name matches the ECH
   629  		// configs PublicName, since this is not particularly important, and
   630  		// the client already had to know what it was in order to properly
   631  		// encrypt the payload. This is only a MAY in the spec, so we're not
   632  		// doing anything revolutionary.
   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