Add ECH TLS client

This commit is contained in:
世界
2022-09-09 18:19:50 +08:00
parent a3bb9c2877
commit 3ad4370fa5
8 changed files with 242 additions and 18 deletions

View File

@@ -834,6 +834,8 @@ type Config struct {
// Otherwise, if ECH is enabled, it will send a dummy ECH extension.
ClientECHConfigs []ECHConfig
GetClientECHConfigs func(ctx context.Context, serverName string) ([]ECHConfig, error)
// ServerECHProvider is the ECH provider used by the client-facing server
// for the ECH extension. If the client offers ECH and TLS 1.3 is
// negotiated, then the provider is used to compute the HPKE context

View File

@@ -4,6 +4,7 @@
package tls
import (
"context"
"errors"
"fmt"
"io"
@@ -37,7 +38,7 @@ var zeros = [8]byte{}
//
// TODO(cjpatton): "[When offering ECH, the client] MUST NOT offer to resume any
// session for TLS 1.2 and below [in ClientHelloInner]."
func (c *Conn) echOfferOrGrease(helloBase *clientHelloMsg) (hello, helloInner *clientHelloMsg, err error) {
func (c *Conn) echOfferOrGrease(ctx context.Context, helloBase *clientHelloMsg) (hello, helloInner *clientHelloMsg, err error) {
config := c.config
if !config.ECHEnabled || testingECHTriggerBypassBeforeHRR {
@@ -47,7 +48,10 @@ func (c *Conn) echOfferOrGrease(helloBase *clientHelloMsg) (hello, helloInner *c
// Choose the ECHConfig to use for this connection. If none is available, or
// if we're not offering TLS 1.3 or above, then GREASE.
echConfig := config.echSelectConfig()
echConfig, err := config.echSelectConfig(ctx, helloBase.serverName)
if err != nil {
return nil, nil, fmt.Errorf("tls: ech: fetch ech config: %s", err)
}
if echConfig == nil || config.maxSupportedVersion(roleClient) < VersionTLS13 {
var err error
@@ -1008,14 +1012,26 @@ func splitClientHelloExtensions(data []byte) ([]byte, []byte) {
//
// TODO(cjpatton): Implement ECH config extensions as described in
// draft-ietf-tls-esni-13, Section 4.1.
func (c *Config) echSelectConfig() *ECHConfig {
func (c *Config) echSelectConfig(ctx context.Context, serverName string) (*ECHConfig, error) {
for _, echConfig := range c.ClientECHConfigs {
if _, err := echConfig.selectSuite(); err == nil &&
echConfig.version == extensionECH {
return &echConfig
return &echConfig, nil
}
}
return nil
if c.GetClientECHConfigs != nil {
echConfigs, err := c.GetClientECHConfigs(ctx, serverName)
if err != nil {
return nil, err
}
for _, echConfig := range echConfigs {
if _, err = echConfig.selectSuite(); err == nil &&
echConfig.version == extensionECH {
return &echConfig, nil
}
}
}
return nil, nil
}
func (c *Config) echCanOffer() bool {
@@ -1023,7 +1039,6 @@ func (c *Config) echCanOffer() bool {
return false
}
return c.ECHEnabled &&
c.echSelectConfig() != nil &&
c.maxSupportedVersion(roleClient) >= VersionTLS13
}

View File

@@ -187,7 +187,7 @@ func (c *Conn) clientHandshake(ctx context.Context) (err error) {
return err
}
hello, helloInner, err := c.echOfferOrGrease(helloBase)
hello, helloInner, err := c.echOfferOrGrease(ctx, helloBase)
if err != nil {
return err
}