mirror of
https://github.com/refraction-networking/utls.git
synced 2025-04-04 12:37:35 +03:00
fix: ech with hrr
This commit is contained in:
parent
9b2ccad920
commit
f6f3c9867d
3 changed files with 105 additions and 71 deletions
|
@ -76,18 +76,14 @@ func (hs *clientHandshakeStateTLS13) handshake() error {
|
||||||
if hs.echContext != nil {
|
if hs.echContext != nil {
|
||||||
hs.echContext.innerTranscript = hs.suite.hash.New()
|
hs.echContext.innerTranscript = hs.suite.hash.New()
|
||||||
// [uTLS SECTION BEGIN]
|
// [uTLS SECTION BEGIN]
|
||||||
encodedInner, err := encodeInnerClientHelloReorderOuterExts(hs.echContext.innerHello, int(hs.echContext.config.MaxNameLength), hs.uconn.extensionsList())
|
if hs.uconn != nil && hs.uconn.clientHelloBuildStatus == BuildByUtls {
|
||||||
if err != nil {
|
if err := hs.uconn.echTranscriptMsg(hs.hello, hs.echContext); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
decodedInner, err := decodeInnerClientHello(hs.hello, encodedInner)
|
if err := transcriptMsg(hs.echContext.innerHello, hs.echContext.innerTranscript); err != nil {
|
||||||
if err != nil {
|
return err
|
||||||
return err
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if err := transcriptMsg(decodedInner, hs.echContext.innerTranscript); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
// [uTLS SECTION END]
|
// [uTLS SECTION END]
|
||||||
}
|
}
|
||||||
|
@ -438,7 +434,7 @@ func (hs *clientHandshakeStateTLS13) processHelloRetryRequest() error {
|
||||||
hs.uconn.Extensions[cookieIndex:]...)...)
|
hs.uconn.Extensions[cookieIndex:]...)...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err := hs.uconn.MarshalClientHello(); err != nil {
|
if err := hs.uconn.MarshalClientHelloNoECH(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
hs.hello.original = hs.uconn.HandshakeState.Hello.Raw
|
hs.hello.original = hs.uconn.HandshakeState.Hello.Raw
|
||||||
|
@ -457,12 +453,24 @@ func (hs *clientHandshakeStateTLS13) processHelloRetryRequest() error {
|
||||||
// extension which may have changed is keyShares.
|
// extension which may have changed is keyShares.
|
||||||
hs.hello.keyShares = hello.keyShares
|
hs.hello.keyShares = hello.keyShares
|
||||||
hs.echContext.innerHello = hello
|
hs.echContext.innerHello = hello
|
||||||
if err := transcriptMsg(hs.echContext.innerHello, hs.echContext.innerTranscript); err != nil {
|
if hs.uconn != nil && hs.uconn.clientHelloBuildStatus == BuildByUtls {
|
||||||
return err
|
if err := hs.uconn.computeAndUpdateOuterECHExtension(hs.echContext.innerHello, hs.echContext, false); err != nil {
|
||||||
}
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
if err := computeAndUpdateOuterECHExtension(hs.hello, hs.echContext.innerHello, hs.echContext, false); err != nil {
|
if err := hs.uconn.echTranscriptMsg(hs.hello, hs.echContext); err != nil {
|
||||||
return err
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
hs.hello.original = hs.uconn.HandshakeState.Hello.Raw
|
||||||
|
} else {
|
||||||
|
if err := transcriptMsg(hs.echContext.innerHello, hs.echContext.innerTranscript); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := computeAndUpdateOuterECHExtension(hs.hello, hs.echContext.innerHello, hs.echContext, false); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
hs.hello = hello
|
hs.hello = hello
|
||||||
|
|
114
u_conn.go
114
u_conn.go
|
@ -503,6 +503,66 @@ func (uconn *UConn) extensionsList() []uint16 {
|
||||||
return outerExts
|
return outerExts
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (uconn *UConn) computeAndUpdateOuterECHExtension(inner *clientHelloMsg, ech *echClientContext, useKey bool) error {
|
||||||
|
|
||||||
|
var encapKey []byte
|
||||||
|
if useKey {
|
||||||
|
encapKey = ech.encapsulatedKey
|
||||||
|
}
|
||||||
|
|
||||||
|
encodedInner, err := encodeInnerClientHelloReorderOuterExts(inner, int(ech.config.MaxNameLength), uconn.extensionsList())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: the tag lengths for all of the supported AEADs are the same (16
|
||||||
|
// bytes), so we have hardcoded it here. If we add support for another AEAD
|
||||||
|
// with a different tag length, we will need to change this.
|
||||||
|
encryptedLen := len(encodedInner) + 16 // AEAD tag length
|
||||||
|
outerECHExt, err := generateOuterECHExt(ech.config.ConfigID, ech.kdfID, ech.aeadID, encapKey, make([]byte, encryptedLen))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
echExtIdx := slices.IndexFunc(uconn.Extensions, func(ext TLSExtension) bool {
|
||||||
|
_, ok := ext.(EncryptedClientHelloExtension)
|
||||||
|
return ok
|
||||||
|
})
|
||||||
|
oldExt := uconn.Extensions[echExtIdx]
|
||||||
|
|
||||||
|
uconn.Extensions[echExtIdx] = &GenericExtension{
|
||||||
|
Id: extensionEncryptedClientHello,
|
||||||
|
Data: outerECHExt,
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := uconn.MarshalClientHelloNoECH(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
serializedOuter := uconn.HandshakeState.Hello.Raw
|
||||||
|
serializedOuter = serializedOuter[4:] // strip the four byte prefix
|
||||||
|
encryptedInner, err := ech.hpkeContext.Seal(serializedOuter, encodedInner)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
outerECHExt, err = generateOuterECHExt(ech.config.ConfigID, ech.kdfID, ech.aeadID, encapKey, encryptedInner)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
uconn.Extensions[echExtIdx] = &GenericExtension{
|
||||||
|
Id: extensionEncryptedClientHello,
|
||||||
|
Data: outerECHExt,
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := uconn.MarshalClientHelloNoECH(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
uconn.Extensions[echExtIdx] = oldExt
|
||||||
|
return nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
func (uconn *UConn) MarshalClientHello() error {
|
func (uconn *UConn) MarshalClientHello() error {
|
||||||
if len(uconn.config.EncryptedClientHelloConfigList) > 0 {
|
if len(uconn.config.EncryptedClientHelloConfigList) > 0 {
|
||||||
inner, _, ech, err := uconn.makeClientHello()
|
inner, _, ech, err := uconn.makeClientHello()
|
||||||
|
@ -518,22 +578,6 @@ func (uconn *UConn) MarshalClientHello() error {
|
||||||
|
|
||||||
ech.innerHello = inner
|
ech.innerHello = inner
|
||||||
|
|
||||||
encapKey := ech.encapsulatedKey
|
|
||||||
|
|
||||||
encodedInner, err := encodeInnerClientHelloReorderOuterExts(inner, int(ech.config.MaxNameLength), uconn.extensionsList())
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOTE: the tag lengths for all of the supported AEADs are the same (16
|
|
||||||
// bytes), so we have hardcoded it here. If we add support for another AEAD
|
|
||||||
// with a different tag length, we will need to change this.
|
|
||||||
encryptedLen := len(encodedInner) + 16 // AEAD tag length
|
|
||||||
outerECHExt, err := generateOuterECHExt(ech.config.ConfigID, ech.kdfID, ech.aeadID, encapKey, make([]byte, encryptedLen))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
sniExtIdex := slices.IndexFunc(uconn.Extensions, func(ext TLSExtension) bool {
|
sniExtIdex := slices.IndexFunc(uconn.Extensions, func(ext TLSExtension) bool {
|
||||||
_, ok := ext.(*SNIExtension)
|
_, ok := ext.(*SNIExtension)
|
||||||
return ok
|
return ok
|
||||||
|
@ -542,43 +586,7 @@ func (uconn *UConn) MarshalClientHello() error {
|
||||||
ServerName: string(ech.config.PublicName),
|
ServerName: string(ech.config.PublicName),
|
||||||
}
|
}
|
||||||
|
|
||||||
echExtIdx := slices.IndexFunc(uconn.Extensions, func(ext TLSExtension) bool {
|
uconn.computeAndUpdateOuterECHExtension(inner, ech, true)
|
||||||
_, ok := ext.(EncryptedClientHelloExtension)
|
|
||||||
return ok
|
|
||||||
})
|
|
||||||
uconn.Extensions[echExtIdx] = &GenericExtension{
|
|
||||||
Id: extensionEncryptedClientHello,
|
|
||||||
Data: outerECHExt,
|
|
||||||
}
|
|
||||||
|
|
||||||
// uconn.HandshakeState.Hello.Random = make([]byte, 32)
|
|
||||||
// _, err = io.ReadFull(uconn.config.rand(), uconn.HandshakeState.Hello.Random)
|
|
||||||
// if err != nil {
|
|
||||||
// return errors.New("tls: short read from Rand: " + err.Error())
|
|
||||||
// }
|
|
||||||
|
|
||||||
if err := uconn.MarshalClientHelloNoECH(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
serializedOuter := uconn.HandshakeState.Hello.Raw
|
|
||||||
serializedOuter = serializedOuter[4:] // strip the four byte prefix
|
|
||||||
encryptedInner, err := ech.hpkeContext.Seal(serializedOuter, encodedInner)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
outerECHExt, err = generateOuterECHExt(ech.config.ConfigID, ech.kdfID, ech.aeadID, encapKey, encryptedInner)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
uconn.Extensions[echExtIdx] = &GenericExtension{
|
|
||||||
Id: extensionEncryptedClientHello,
|
|
||||||
Data: outerECHExt,
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := uconn.MarshalClientHelloNoECH(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
uconn.echCtx = ech
|
uconn.echCtx = ech
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -578,3 +578,21 @@ func (c *UConn) clientHandshake(ctx context.Context) (err error) {
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *UConn) echTranscriptMsg(outer *clientHelloMsg, echCtx *echClientContext) (err error) {
|
||||||
|
encodedInner, err := encodeInnerClientHelloReorderOuterExts(echCtx.innerHello, int(echCtx.config.MaxNameLength), c.extensionsList())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
decodedInner, err := decodeInnerClientHello(outer, encodedInner)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := transcriptMsg(decodedInner, echCtx.innerTranscript); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue