diff --git a/common.go b/common.go index 73b6dad5..a5372e34 100644 --- a/common.go +++ b/common.go @@ -711,6 +711,12 @@ type Config struct { // this behavior at their own discretion. OmitEmptyPsk bool // [uTLS] + // AlwaysIncludePSK controls whether the PreSharedKey extension is always + // included in the ClientHello if there is a cached session, even if not specified + // in the selected ClientHelloSpec. If there are no cached sessions, OmitEmptyPsk + // controls whether the extension is omitted. + AlwaysIncludePSK bool // [uTLS] + // InsecureServerNameToVerify is used to verify the hostname on the returned // certificates. It is intended to use with spoofed ServerName. // If InsecureServerNameToVerify is "*", crypto/tls will do normal @@ -999,6 +1005,7 @@ func (c *Config) Clone() *Config { InsecureSkipTimeVerify: c.InsecureSkipTimeVerify, InsecureServerNameToVerify: c.InsecureServerNameToVerify, OmitEmptyPsk: c.OmitEmptyPsk, + AlwaysIncludePSK: c.AlwaysIncludePSK, CipherSuites: c.CipherSuites, PreferServerCipherSuites: c.PreferServerCipherSuites, SessionTicketsDisabled: c.SessionTicketsDisabled, diff --git a/tls_test.go b/tls_test.go index c91263b1..2df707a4 100644 --- a/tls_test.go +++ b/tls_test.go @@ -877,7 +877,7 @@ func TestCloneNonFuncFields(t *testing.T) { f.Set(reflect.ValueOf("b")) case "ClientAuth": f.Set(reflect.ValueOf(VerifyClientCertIfGiven)) - case "InsecureSkipVerify", "InsecureSkipTimeVerify", "SessionTicketsDisabled", "DynamicRecordSizingDisabled", "PreferServerCipherSuites", "OmitEmptyPsk", "PreferSkipResumptionOnNilExtension": + case "InsecureSkipVerify", "InsecureSkipTimeVerify", "SessionTicketsDisabled", "DynamicRecordSizingDisabled", "PreferServerCipherSuites", "OmitEmptyPsk", "PreferSkipResumptionOnNilExtension", "AlwaysIncludePSK": f.Set(reflect.ValueOf(true)) case "InsecureServerNameToVerify": f.Set(reflect.ValueOf("c")) diff --git a/u_parrots.go b/u_parrots.go index 8416fa33..cef77308 100644 --- a/u_parrots.go +++ b/u_parrots.go @@ -3015,6 +3015,23 @@ func (uconn *UConn) ApplyPreset(p *ClientHelloSpec) error { return err } + // Add PSK extension if not specified in the spec. + if uconn.config.AlwaysIncludePSK { + supportsPSK := uconn.config.MaxVersion >= VersionTLS13 + if supportsPSK { + hasPskExt := false + for _, ext := range p.Extensions { + if _, ok := ext.(PreSharedKeyExtension); ok { + hasPskExt = true + } + } + if !hasPskExt { + // pre_shared_key must be the last extension (RFC 8446, Section 4.2.11). + p.Extensions = append(p.Extensions, &UtlsPreSharedKeyExtension{}) + } + } + } + privateHello, clientKeySharePrivate, ech, err := uconn.makeClientHelloForApplyPreset() if err != nil { return err