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

View as plain text