mirror of
https://github.com/XTLS/REALITY.git
synced 2025-08-22 14:38:35 +00:00
Expose EchConfig for xray core client config
This commit is contained in:
parent
1292b8ce43
commit
a66a2f0ccf
52
ech.go
52
ech.go
@ -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)
|
||||||
|
@ -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
|
||||||
|
@ -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.
|
||||||
|
Loading…
Reference in New Issue
Block a user