mirror of
https://github.com/refraction-networking/utls.git
synced 2025-04-03 20:17:36 +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 {
|
||||
hs.echContext.innerTranscript = hs.suite.hash.New()
|
||||
// [uTLS SECTION BEGIN]
|
||||
encodedInner, err := encodeInnerClientHelloReorderOuterExts(hs.echContext.innerHello, int(hs.echContext.config.MaxNameLength), hs.uconn.extensionsList())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
decodedInner, err := decodeInnerClientHello(hs.hello, encodedInner)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := transcriptMsg(decodedInner, hs.echContext.innerTranscript); err != nil {
|
||||
return err
|
||||
if hs.uconn != nil && hs.uconn.clientHelloBuildStatus == BuildByUtls {
|
||||
if err := hs.uconn.echTranscriptMsg(hs.hello, hs.echContext); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if err := transcriptMsg(hs.echContext.innerHello, hs.echContext.innerTranscript); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
// [uTLS SECTION END]
|
||||
}
|
||||
|
@ -438,7 +434,7 @@ func (hs *clientHandshakeStateTLS13) processHelloRetryRequest() error {
|
|||
hs.uconn.Extensions[cookieIndex:]...)...)
|
||||
}
|
||||
}
|
||||
if err := hs.uconn.MarshalClientHello(); err != nil {
|
||||
if err := hs.uconn.MarshalClientHelloNoECH(); err != nil {
|
||||
return err
|
||||
}
|
||||
hs.hello.original = hs.uconn.HandshakeState.Hello.Raw
|
||||
|
@ -457,12 +453,24 @@ func (hs *clientHandshakeStateTLS13) processHelloRetryRequest() error {
|
|||
// extension which may have changed is keyShares.
|
||||
hs.hello.keyShares = hello.keyShares
|
||||
hs.echContext.innerHello = hello
|
||||
if err := transcriptMsg(hs.echContext.innerHello, hs.echContext.innerTranscript); err != nil {
|
||||
return err
|
||||
}
|
||||
if hs.uconn != nil && hs.uconn.clientHelloBuildStatus == BuildByUtls {
|
||||
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 {
|
||||
return err
|
||||
if err := hs.uconn.echTranscriptMsg(hs.hello, hs.echContext); err != nil {
|
||||
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 {
|
||||
hs.hello = hello
|
||||
|
|
114
u_conn.go
114
u_conn.go
|
@ -503,6 +503,66 @@ func (uconn *UConn) extensionsList() []uint16 {
|
|||
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 {
|
||||
if len(uconn.config.EncryptedClientHelloConfigList) > 0 {
|
||||
inner, _, ech, err := uconn.makeClientHello()
|
||||
|
@ -518,22 +578,6 @@ func (uconn *UConn) MarshalClientHello() error {
|
|||
|
||||
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 {
|
||||
_, ok := ext.(*SNIExtension)
|
||||
return ok
|
||||
|
@ -542,43 +586,7 @@ func (uconn *UConn) MarshalClientHello() error {
|
|||
ServerName: string(ech.config.PublicName),
|
||||
}
|
||||
|
||||
echExtIdx := slices.IndexFunc(uconn.Extensions, func(ext TLSExtension) bool {
|
||||
_, 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.computeAndUpdateOuterECHExtension(inner, ech, true)
|
||||
|
||||
uconn.echCtx = ech
|
||||
return nil
|
||||
|
|
|
@ -578,3 +578,21 @@ func (c *UConn) clientHandshake(ctx context.Context) (err error) {
|
|||
}
|
||||
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