Skip to content

Commit

Permalink
Allow BuildHandshakeState to inspect ClientHello before setting Sessi…
Browse files Browse the repository at this point in the history
…onTicket/PSK (#301)

* Lock sessionController only on last call to BuildHandshakeState

* Add public getter/setter for SessionState.extMasterSecret

* Fix breaking exported MakeClientSessionState

* Revert `(*UConn).BuildHandshakeState` to lock session controller

This partially reverts ebe5d66
and introduces BuildHandshakeStateWithoutSession.

* fix: Marshal the Client Hello after loading session


---------

Signed-off-by: Gaukas Wang <i@gaukas.wang>
  • Loading branch information
adotkhan authored Jun 27, 2024
1 parent 4f71339 commit 925bfb3
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 6 deletions.
30 changes: 24 additions & 6 deletions u_conn.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,23 @@ func UClient(conn net.Conn, config *Config, clientHelloID ClientHelloID) *UConn
// [each call] marshal ClientHello.
//
// BuildHandshakeState is automatically called before uTLS performs handshake,
// amd should only be called explicitly to inspect/change fields of
// and should only be called explicitly to inspect/change fields of
// default/mimicked ClientHello.
// With the excpetion of session ticket and psk extensions, which cannot be changed
// after calling BuildHandshakeState, all other fields can be modified.
func (uconn *UConn) BuildHandshakeState() error {
return uconn.buildHandshakeState(true)
}

// BuildHandshakeStateWithoutSession is the same as BuildHandshakeState, but does not
// set the session. This is only useful when you want to inspect the ClientHello before
// setting the session manually through SetSessionTicketExtension or SetPSKExtension.
// BuildHandshakeState is automatically called before uTLS performs handshake.
func (uconn *UConn) BuildHandshakeStateWithoutSession() error {
return uconn.buildHandshakeState(false)
}

func (uconn *UConn) buildHandshakeState(loadSession bool) error {
if uconn.ClientHelloID == HelloGolang {
if uconn.clientHelloBuildStatus == BuildByGoTLS {
return nil
Expand Down Expand Up @@ -125,19 +139,23 @@ func (uconn *UConn) BuildHandshakeState() error {
return err
}

err = uconn.uLoadSession()
if err != nil {
return err
if loadSession {
err = uconn.uLoadSession()
if err != nil {
return err
}
}

err = uconn.MarshalClientHello()
if err != nil {
return err
}

uconn.uApplyPatch()
if loadSession {
uconn.uApplyPatch()
uconn.sessionController.finalCheck()
}

uconn.sessionController.finalCheck()
uconn.clientHelloBuildStatus = BuildByUtls
}
return nil
Expand Down
14 changes: 14 additions & 0 deletions u_public.go
Original file line number Diff line number Diff line change
Expand Up @@ -617,6 +617,9 @@ func (PSS PskIdentities) ToPrivate() []pskIdentity {

// ClientSessionState is public, but all its fields are private. Let's add setters, getters and constructor

// TODO! can we change this enought (or export SessionState),
// such that we wouldn't need to fork crypto/tls?

// ClientSessionState contains the state needed by clients to resume TLS sessions.
func MakeClientSessionState(
SessionTicket []uint8,
Expand All @@ -625,6 +628,7 @@ func MakeClientSessionState(
MasterSecret []byte,
ServerCertificates []*x509.Certificate,
VerifiedChains [][]*x509.Certificate) *ClientSessionState {
// TODO: Add EMS to this constructor in uTLS v2
css := &ClientSessionState{
ticket: SessionTicket,
session: &SessionState{
Expand Down Expand Up @@ -658,6 +662,10 @@ func (css *ClientSessionState) MasterSecret() []byte {
return css.session.secret
}

func (css *ClientSessionState) EMS() bool {
return css.session.extMasterSecret
}

// Certificate chain presented by the server
func (css *ClientSessionState) ServerCertificates() []*x509.Certificate {
return css.session.peerCertificates
Expand Down Expand Up @@ -689,6 +697,12 @@ func (css *ClientSessionState) SetMasterSecret(MasterSecret []byte) {
}
css.session.secret = MasterSecret
}
func (css *ClientSessionState) SetEMS(ems bool) {
if css.session == nil {
css.session = &SessionState{}
}
css.session.extMasterSecret = ems
}
func (css *ClientSessionState) SetServerCertificates(ServerCertificates []*x509.Certificate) {
if css.session == nil {
css.session = &SessionState{}
Expand Down

0 comments on commit 925bfb3

Please sign in to comment.