mirror of
https://github.com/XTLS/REALITY.git
synced 2025-08-22 14:38:35 +00:00
crypto/tls: add ConnectionState.CurveID
This required adding a new field to SessionState for TLS 1.0–1.2, since the key exchange is not repeated on resumption. The additional field is unfortunately not backwards compatible because current Go versions check that the encoding has no extra data at the end, but will cause cross-version tickets to be ignored. Relaxed that so we can add fields in a backwards compatible way the next time. For the cipher suite, we check that the session's is still acceptable per the Config. That would arguably make sense here, too: if a Config for example requires PQ, we should reject resumptions of connections that didn't use PQ. However, that only applies to pre-TLS 1.3 connections, since in TLS 1.3 we always do a fresh key exchange on resumption. Since PQ is the only main differentiator between key exchanges (aside from off-by-default non-PFS RSA, which are controlled by the cipher suite in TLS 1.0–1.2) and it's PQ-only, we can skip that check. Fixes #67516 Change-Id: I6a6a465681a6292edf66c7b8df8f4aba4171a76b Reviewed-on: https://go-review.googlesource.com/c/go/+/653315 Reviewed-by: David Chase <drchase@google.com> Auto-Submit: Filippo Valsorda <filippo@golang.org> Reviewed-by: Daniel McCarney <daniel@binaryparadox.net> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Roland Shoemaker <roland@golang.org>
This commit is contained in:
parent
cffe49f981
commit
12fa20f9e0
@ -247,6 +247,11 @@ type ConnectionState struct {
|
||||
// TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, TLS_AES_128_GCM_SHA256).
|
||||
CipherSuite uint16
|
||||
|
||||
// CurveID is the key exchange mechanism used for the connection. The name
|
||||
// refers to elliptic curves for legacy reasons, see [CurveID]. If a legacy
|
||||
// RSA key exchange is used, this value is zero.
|
||||
CurveID CurveID
|
||||
|
||||
// NegotiatedProtocol is the application protocol negotiated with ALPN.
|
||||
NegotiatedProtocol string
|
||||
|
||||
@ -304,10 +309,6 @@ type ConnectionState struct {
|
||||
|
||||
// testingOnlyDidHRR is true if a HelloRetryRequest was sent/received.
|
||||
testingOnlyDidHRR bool
|
||||
|
||||
// testingOnlyCurveID is the selected CurveID, or zero if an RSA exchanges
|
||||
// is performed.
|
||||
testingOnlyCurveID CurveID
|
||||
}
|
||||
|
||||
// ExportKeyingMaterial returns length bytes of exported key material in a new
|
||||
|
3
conn.go
3
conn.go
@ -1694,8 +1694,7 @@ func (c *Conn) connectionStateLocked() ConnectionState {
|
||||
state.NegotiatedProtocol = c.clientProtocol
|
||||
state.DidResume = c.didResume
|
||||
state.testingOnlyDidHRR = c.didHRR
|
||||
// c.curveID is not set on TLS 1.0–1.2 resumptions. Fix that before exposing it.
|
||||
state.testingOnlyCurveID = c.curveID
|
||||
state.CurveID = c.curveID
|
||||
state.NegotiatedProtocolIsMutual = true
|
||||
state.ServerName = c.serverName
|
||||
state.CipherSuite = c.cipherSuite
|
||||
|
@ -271,6 +271,7 @@ func (c *Conn) clientHandshake(ctx context.Context) (err error) {
|
||||
// This may be a renegotiation handshake, in which case some fields
|
||||
// need to be reset.
|
||||
c.didResume = false
|
||||
c.curveID = 0
|
||||
|
||||
hello, keyShareKeys, ech, err := c.makeClientHello()
|
||||
if err != nil {
|
||||
@ -951,10 +952,11 @@ func (hs *clientHandshakeState) processServerHello() (bool, error) {
|
||||
c.verifiedChains = hs.session.verifiedChains
|
||||
c.ocspResponse = hs.session.ocspResponse
|
||||
// Let the ServerHello SCTs override the session SCTs from the original
|
||||
// connection, if any are provided
|
||||
// connection, if any are provided.
|
||||
if len(c.scts) == 0 && len(hs.session.scts) != 0 {
|
||||
c.scts = hs.session.scts
|
||||
}
|
||||
c.curveID = hs.session.curveID
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
@ -526,6 +526,7 @@ func (hs *serverHandshakeState) checkForResumption() error {
|
||||
c.extMasterSecret = sessionState.extMasterSecret
|
||||
hs.sessionState = sessionState
|
||||
hs.suite = suite
|
||||
c.curveID = sessionState.curveID
|
||||
c.didResume = true
|
||||
return nil
|
||||
}
|
||||
|
49
ticket.go
49
ticket.go
@ -44,20 +44,21 @@ type SessionState struct {
|
||||
// case 0: Empty;
|
||||
// case 1: opaque alpn<1..2^8-1>;
|
||||
// };
|
||||
// select (SessionState.type) {
|
||||
// select (SessionState.version) {
|
||||
// case VersionTLS10..VersionTLS12: uint16 curve_id;
|
||||
// case VersionTLS13: select (SessionState.type) {
|
||||
// case server: Empty;
|
||||
// case client: struct {
|
||||
// select (SessionState.version) {
|
||||
// case VersionTLS10..VersionTLS12: Empty;
|
||||
// case VersionTLS13: struct {
|
||||
// uint64 use_by;
|
||||
// uint32 age_add;
|
||||
// };
|
||||
// };
|
||||
// };
|
||||
// };
|
||||
// } SessionState;
|
||||
//
|
||||
// The format can be extended backwards-compatibly by adding new fields at
|
||||
// the end. Otherwise, a new SessionStateType must be used, as different Go
|
||||
// versions may share the same session ticket encryption key.
|
||||
|
||||
// Extra is ignored by crypto/tls, but is encoded by [SessionState.Bytes]
|
||||
// and parsed by [ParseSessionState].
|
||||
@ -97,6 +98,9 @@ type SessionState struct {
|
||||
useBy uint64 // seconds since UNIX epoch
|
||||
ageAdd uint32
|
||||
ticket []byte
|
||||
|
||||
// TLS 1.0–1.2 only fields.
|
||||
curveID CurveID
|
||||
}
|
||||
|
||||
// Bytes encodes the session, including any private fields, so that it can be
|
||||
@ -161,11 +165,13 @@ func (s *SessionState) Bytes() ([]byte, error) {
|
||||
b.AddBytes([]byte(s.alpnProtocol))
|
||||
})
|
||||
}
|
||||
if s.isClient {
|
||||
if s.version >= VersionTLS13 {
|
||||
if s.isClient {
|
||||
addUint64(&b, s.useBy)
|
||||
b.AddUint32(s.ageAdd)
|
||||
}
|
||||
} else {
|
||||
b.AddUint16(uint16(s.curveID))
|
||||
}
|
||||
return b.Bytes()
|
||||
}
|
||||
@ -187,7 +193,6 @@ func ParseSessionState(data []byte) (*SessionState, error) {
|
||||
var extra cryptobyte.String
|
||||
if !s.ReadUint16(&ss.version) ||
|
||||
!s.ReadUint8(&typ) ||
|
||||
(typ != 1 && typ != 2) ||
|
||||
!s.ReadUint16(&ss.cipherSuite) ||
|
||||
!readUint64(&s, &ss.createdAt) ||
|
||||
!readUint8LengthPrefixed(&s, &ss.secret) ||
|
||||
@ -205,6 +210,14 @@ func ParseSessionState(data []byte) (*SessionState, error) {
|
||||
}
|
||||
ss.Extra = append(ss.Extra, e)
|
||||
}
|
||||
switch typ {
|
||||
case 1:
|
||||
ss.isClient = false
|
||||
case 2:
|
||||
ss.isClient = true
|
||||
default:
|
||||
return nil, errors.New("tls: unknown session encoding")
|
||||
}
|
||||
switch extMasterSecret {
|
||||
case 0:
|
||||
ss.extMasterSecret = false
|
||||
@ -229,6 +242,9 @@ func ParseSessionState(data []byte) (*SessionState, error) {
|
||||
ss.activeCertHandles = append(ss.activeCertHandles, c)
|
||||
ss.peerCertificates = append(ss.peerCertificates, c.cert)
|
||||
}
|
||||
if ss.isClient && len(ss.peerCertificates) == 0 {
|
||||
return nil, errors.New("tls: no server certificates in client session")
|
||||
}
|
||||
ss.ocspResponse = cert.OCSPStaple
|
||||
ss.scts = cert.SignedCertificateTimestamps
|
||||
var chainList cryptobyte.String
|
||||
@ -266,24 +282,16 @@ func ParseSessionState(data []byte) (*SessionState, error) {
|
||||
}
|
||||
ss.alpnProtocol = string(alpn)
|
||||
}
|
||||
if isClient := typ == 2; !isClient {
|
||||
if !s.Empty() {
|
||||
if ss.version >= VersionTLS13 {
|
||||
if ss.isClient {
|
||||
if !s.ReadUint64(&ss.useBy) || !s.ReadUint32(&ss.ageAdd) {
|
||||
return nil, errors.New("tls: invalid session encoding")
|
||||
}
|
||||
return ss, nil
|
||||
}
|
||||
ss.isClient = true
|
||||
if len(ss.peerCertificates) == 0 {
|
||||
return nil, errors.New("tls: no server certificates in client session")
|
||||
}
|
||||
if ss.version < VersionTLS13 {
|
||||
if !s.Empty() {
|
||||
} else {
|
||||
if !s.ReadUint16((*uint16)(&ss.curveID)) {
|
||||
return nil, errors.New("tls: invalid session encoding")
|
||||
}
|
||||
return ss, nil
|
||||
}
|
||||
if !s.ReadUint64(&ss.useBy) || !s.ReadUint32(&ss.ageAdd) || !s.Empty() {
|
||||
return nil, errors.New("tls: invalid session encoding")
|
||||
}
|
||||
return ss, nil
|
||||
}
|
||||
@ -303,6 +311,7 @@ func (c *Conn) sessionState() *SessionState {
|
||||
isClient: c.isClient,
|
||||
extMasterSecret: c.extMasterSecret,
|
||||
verifiedChains: c.verifiedChains,
|
||||
curveID: c.curveID,
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user