0
0
mirror of https://github.com/XTLS/REALITY.git synced 2025-08-22 22:48:36 +00:00

Expose EchConfig for xray core client config

This commit is contained in:
yuhan6665 2025-05-18 22:08:21 -04:00
parent 1292b8ce43
commit a66a2f0ccf
3 changed files with 31 additions and 31 deletions

52
ech.go
View File

@ -28,7 +28,7 @@ func init() {
slices.Sort(sortedSupportedAEADs) slices.Sort(sortedSupportedAEADs)
} }
type echCipher struct { type EchCipher struct {
KDFID uint16 KDFID uint16
AEADID uint16 AEADID uint16
} }
@ -38,7 +38,7 @@ type echExtension struct {
Data []byte Data []byte
} }
type echConfig struct { type EchConfig struct {
raw []byte raw []byte
Version uint16 Version uint16
@ -47,7 +47,7 @@ type echConfig struct {
ConfigID uint8 ConfigID uint8
KemID uint16 KemID uint16
PublicKey []byte PublicKey []byte
SymmetricCipherSuite []echCipher SymmetricCipherSuite []EchCipher
MaxNameLength uint8 MaxNameLength uint8
PublicName []byte PublicName []byte
@ -67,65 +67,65 @@ func (e *echConfigErr) Error() string {
return fmt.Sprintf("tls: malformed ECHConfig, invalid %s field", e.field) return fmt.Sprintf("tls: malformed ECHConfig, invalid %s field", e.field)
} }
func parseECHConfig(enc []byte) (skip bool, ec echConfig, err error) { func parseECHConfig(enc []byte) (skip bool, ec EchConfig, err error) {
s := cryptobyte.String(enc) s := cryptobyte.String(enc)
ec.raw = []byte(enc) ec.raw = []byte(enc)
if !s.ReadUint16(&ec.Version) { if !s.ReadUint16(&ec.Version) {
return false, echConfig{}, &echConfigErr{"version"} return false, EchConfig{}, &echConfigErr{"version"}
} }
if !s.ReadUint16(&ec.Length) { if !s.ReadUint16(&ec.Length) {
return false, echConfig{}, &echConfigErr{"length"} return false, EchConfig{}, &echConfigErr{"length"}
} }
if len(ec.raw) < int(ec.Length)+4 { if len(ec.raw) < int(ec.Length)+4 {
return false, echConfig{}, &echConfigErr{"length"} return false, EchConfig{}, &echConfigErr{"length"}
} }
ec.raw = ec.raw[:ec.Length+4] ec.raw = ec.raw[:ec.Length+4]
if ec.Version != extensionEncryptedClientHello { if ec.Version != extensionEncryptedClientHello {
s.Skip(int(ec.Length)) s.Skip(int(ec.Length))
return true, echConfig{}, nil return true, EchConfig{}, nil
} }
if !s.ReadUint8(&ec.ConfigID) { if !s.ReadUint8(&ec.ConfigID) {
return false, echConfig{}, &echConfigErr{"config_id"} return false, EchConfig{}, &echConfigErr{"config_id"}
} }
if !s.ReadUint16(&ec.KemID) { if !s.ReadUint16(&ec.KemID) {
return false, echConfig{}, &echConfigErr{"kem_id"} return false, EchConfig{}, &echConfigErr{"kem_id"}
} }
if !readUint16LengthPrefixed(&s, &ec.PublicKey) { if !readUint16LengthPrefixed(&s, &ec.PublicKey) {
return false, echConfig{}, &echConfigErr{"public_key"} return false, EchConfig{}, &echConfigErr{"public_key"}
} }
var cipherSuites cryptobyte.String var cipherSuites cryptobyte.String
if !s.ReadUint16LengthPrefixed(&cipherSuites) { if !s.ReadUint16LengthPrefixed(&cipherSuites) {
return false, echConfig{}, &echConfigErr{"cipher_suites"} return false, EchConfig{}, &echConfigErr{"cipher_suites"}
} }
for !cipherSuites.Empty() { for !cipherSuites.Empty() {
var c echCipher var c EchCipher
if !cipherSuites.ReadUint16(&c.KDFID) { if !cipherSuites.ReadUint16(&c.KDFID) {
return false, echConfig{}, &echConfigErr{"cipher_suites kdf_id"} return false, EchConfig{}, &echConfigErr{"cipher_suites kdf_id"}
} }
if !cipherSuites.ReadUint16(&c.AEADID) { if !cipherSuites.ReadUint16(&c.AEADID) {
return false, echConfig{}, &echConfigErr{"cipher_suites aead_id"} return false, EchConfig{}, &echConfigErr{"cipher_suites aead_id"}
} }
ec.SymmetricCipherSuite = append(ec.SymmetricCipherSuite, c) ec.SymmetricCipherSuite = append(ec.SymmetricCipherSuite, c)
} }
if !s.ReadUint8(&ec.MaxNameLength) { if !s.ReadUint8(&ec.MaxNameLength) {
return false, echConfig{}, &echConfigErr{"maximum_name_length"} return false, EchConfig{}, &echConfigErr{"maximum_name_length"}
} }
var publicName cryptobyte.String var publicName cryptobyte.String
if !s.ReadUint8LengthPrefixed(&publicName) { if !s.ReadUint8LengthPrefixed(&publicName) {
return false, echConfig{}, &echConfigErr{"public_name"} return false, EchConfig{}, &echConfigErr{"public_name"}
} }
ec.PublicName = publicName ec.PublicName = publicName
var extensions cryptobyte.String var extensions cryptobyte.String
if !s.ReadUint16LengthPrefixed(&extensions) { if !s.ReadUint16LengthPrefixed(&extensions) {
return false, echConfig{}, &echConfigErr{"extensions"} return false, EchConfig{}, &echConfigErr{"extensions"}
} }
for !extensions.Empty() { for !extensions.Empty() {
var e echExtension var e echExtension
if !extensions.ReadUint16(&e.Type) { if !extensions.ReadUint16(&e.Type) {
return false, echConfig{}, &echConfigErr{"extensions type"} return false, EchConfig{}, &echConfigErr{"extensions type"}
} }
if !extensions.ReadUint16LengthPrefixed((*cryptobyte.String)(&e.Data)) { if !extensions.ReadUint16LengthPrefixed((*cryptobyte.String)(&e.Data)) {
return false, echConfig{}, &echConfigErr{"extensions data"} return false, EchConfig{}, &echConfigErr{"extensions data"}
} }
ec.Extensions = append(ec.Extensions, e) ec.Extensions = append(ec.Extensions, e)
} }
@ -136,7 +136,7 @@ func parseECHConfig(enc []byte) (skip bool, ec echConfig, err error) {
// parseECHConfigList parses a draft-ietf-tls-esni-18 ECHConfigList, returning a // parseECHConfigList parses a draft-ietf-tls-esni-18 ECHConfigList, returning a
// slice of parsed ECHConfigs, in the same order they were parsed, or an error // slice of parsed ECHConfigs, in the same order they were parsed, or an error
// if the list is malformed. // if the list is malformed.
func parseECHConfigList(data []byte) ([]echConfig, error) { func parseECHConfigList(data []byte) ([]EchConfig, error) {
s := cryptobyte.String(data) s := cryptobyte.String(data)
var length uint16 var length uint16
if !s.ReadUint16(&length) { if !s.ReadUint16(&length) {
@ -145,7 +145,7 @@ func parseECHConfigList(data []byte) ([]echConfig, error) {
if length != uint16(len(data)-2) { if length != uint16(len(data)-2) {
return nil, errMalformedECHConfigList return nil, errMalformedECHConfigList
} }
var configs []echConfig var configs []EchConfig
for len(s) > 0 { for len(s) > 0 {
if len(s) < 4 { if len(s) < 4 {
return nil, errors.New("tls: malformed ECHConfig") return nil, errors.New("tls: malformed ECHConfig")
@ -163,7 +163,7 @@ func parseECHConfigList(data []byte) ([]echConfig, error) {
return configs, nil return configs, nil
} }
func pickECHConfig(list []echConfig) *echConfig { func pickECHConfig(list []EchConfig) *EchConfig {
for _, ec := range list { for _, ec := range list {
if _, ok := hpke.SupportedKEMs[ec.KemID]; !ok { if _, ok := hpke.SupportedKEMs[ec.KemID]; !ok {
continue continue
@ -202,7 +202,7 @@ func pickECHConfig(list []echConfig) *echConfig {
return nil return nil
} }
func pickECHCipherSuite(suites []echCipher) (echCipher, error) { func pickECHCipherSuite(suites []EchCipher) (EchCipher, error) {
for _, s := range suites { for _, s := range suites {
// NOTE: all of the supported AEADs and KDFs are fine, rather than // NOTE: all of the supported AEADs and KDFs are fine, rather than
// imposing some sort of preference here, we just pick the first valid // imposing some sort of preference here, we just pick the first valid
@ -215,7 +215,7 @@ func pickECHCipherSuite(suites []echCipher) (echCipher, error) {
} }
return s, nil return s, nil
} }
return echCipher{}, errors.New("tls: no supported symmetric ciphersuites for ECH") return EchCipher{}, errors.New("tls: no supported symmetric ciphersuites for ECH")
} }
func encodeInnerClientHello(inner *clientHelloMsg, maxNameLength int) ([]byte, error) { func encodeInnerClientHello(inner *clientHelloMsg, maxNameLength int) ([]byte, error) {
@ -522,7 +522,7 @@ const (
outerECHExt echExtType = 0 outerECHExt echExtType = 0
) )
func parseECHExt(ext []byte) (echType echExtType, cs echCipher, configID uint8, encap []byte, payload []byte, err error) { func parseECHExt(ext []byte) (echType echExtType, cs EchCipher, configID uint8, encap []byte, payload []byte, err error) {
data := make([]byte, len(ext)) data := make([]byte, len(ext))
copy(data, ext) copy(data, ext)
s := cryptobyte.String(data) s := cryptobyte.String(data)

View File

@ -240,7 +240,7 @@ func (c *Conn) makeClientHello() (*clientHelloMsg, *keySharePrivateKeys, *echCli
} }
type echClientContext struct { type echClientContext struct {
config *echConfig config *EchConfig
hpkeContext *hpke.Sender hpkeContext *hpke.Sender
encapsulatedKey []byte encapsulatedKey []byte
innerHello *clientHelloMsg innerHello *clientHelloMsg

View File

@ -39,7 +39,7 @@ const maxClientPSKIdentities = 5
type echServerContext struct { type echServerContext struct {
hpkeContext *hpke.Recipient hpkeContext *hpke.Recipient
configID uint8 configID uint8
ciphersuite echCipher ciphersuite EchCipher
transcript hash.Hash transcript hash.Hash
// inner indicates that the initial client_hello we recieved contained an // inner indicates that the initial client_hello we recieved contained an
// encrypted_client_hello extension that indicated it was an "inner" hello. // encrypted_client_hello extension that indicated it was an "inner" hello.