diff --git a/handshake_client.go b/handshake_client.go index d12bb84bc2..0a5f7ee4e2 100644 --- a/handshake_client.go +++ b/handshake_client.go @@ -457,6 +457,15 @@ func (c *Conn) loadSession(hello *clientHelloMsg) ( } if session.version != VersionTLS13 { + // [uTLS] TLS 1.2 resumption requires the cached session EMS state to + // match the new ClientHello. A ClientHelloSpec may omit the + // extended_master_secret extension, in which case a server holding an + // EMS session will reject the handshake. Skip resumption instead, so + // the dial proceeds with the selected spec. + if session.extMasterSecret != hello.extendedMasterSecret { + return nil, nil, nil, nil + } + // In TLS 1.2 the cipher suite must match the resumed session. Ensure we // are still offering it. if mutualCipherSuite(hello.cipherSuites, session.cipherSuite) == nil { diff --git a/u_parrots.go b/u_parrots.go index 9b6c5b61b8..dbdee7e3e7 100644 --- a/u_parrots.go +++ b/u_parrots.go @@ -3045,6 +3045,13 @@ func (uconn *UConn) ApplyPreset(p *ClientHelloSpec) error { uconn.echCtx = ech hello := uconn.HandshakeState.Hello + // [uTLS] A preset must control TLS 1.2 extended_master_secret through its + // extension list. The default ClientHello enables EMS unconditionally, so + // clear it here and let ExtendedMasterSecretExtension.writeToUConn set it + // again only when the spec actually carries the extension. The EMS state + // check in Conn.loadSession depends on this being accurate. + hello.Ems = false + switch len(hello.Random) { case 0: hello.Random = make([]byte, 32)