mirror of
https://github.com/XTLS/REALITY.git
synced 2026-10-06 22:08:12 +03:00
Sync upstream Go 1.27+; Add "[REALITY] SECTION" comments (#30)
https://github.com/XTLS/REALITY/pull/30#issuecomment-5579024460 https://github.com/XTLS/REALITY/pull/30#issuecomment-5594872257 https://github.com/XTLS/REALITY/pull/38#issuecomment-5752892932
This commit is contained in:
@@ -25,11 +25,13 @@ import (
|
||||
// A Conn represents a secured connection.
|
||||
// It implements the net.Conn interface.
|
||||
type Conn struct {
|
||||
//////////////////////////////////// [REALITY] SECTION: define var
|
||||
AuthKey []byte
|
||||
ClientVer [3]byte
|
||||
ClientTime time.Time
|
||||
ClientShortId [8]byte
|
||||
MaxUselessRecords int
|
||||
//////////////////////////////////// [REALITY] SECTION END
|
||||
|
||||
// constant
|
||||
conn net.Conn
|
||||
@@ -56,9 +58,11 @@ type Conn struct {
|
||||
didHRR bool // whether a HelloRetryRequest was sent/received
|
||||
cipherSuite uint16
|
||||
curveID CurveID
|
||||
peerSigAlg SignatureScheme
|
||||
ocspResponse []byte // stapled OCSP response
|
||||
scts [][]byte // signed certificate timestamps from server
|
||||
peerCertificates []*x509.Certificate
|
||||
localCertificate [][]byte
|
||||
// verifiedChains contains the certificate chains that we built, as
|
||||
// opposed to the ones presented by the server.
|
||||
verifiedChains [][]*x509.Certificate
|
||||
@@ -103,12 +107,27 @@ type Conn struct {
|
||||
clientProtocol string
|
||||
|
||||
// input/output
|
||||
in, out halfConn
|
||||
rawInput bytes.Buffer // raw input, starting with a record header
|
||||
input bytes.Reader // application data waiting to be read, from rawInput.Next
|
||||
hand bytes.Buffer // handshake data waiting to be read
|
||||
buffering bool // whether records are buffered in sendBuf
|
||||
sendBuf []byte // a buffer of records waiting to be sent
|
||||
in, out halfConn
|
||||
// rawInput holds raw input, starting with a record header.
|
||||
// It is nil when no input is buffered, in which case the buffer has
|
||||
// been returned to rawInputPool so that connections idle in Read do
|
||||
// not pin a record-sized buffer. It is lazily repopulated from the
|
||||
// pool by readFromUntil.
|
||||
rawInput *bytes.Buffer
|
||||
// smallInput is a small buffer that serves as rawInput while
|
||||
// waiting for a record header after rawInput has been returned to
|
||||
// rawInputPool. It is lazily allocated by readFromUntil and then
|
||||
// kept for the life of the connection.
|
||||
smallInput *bytes.Buffer
|
||||
// input holds application data waiting to be read, from rawInput.Next.
|
||||
input bytes.Reader
|
||||
// hand holds handshake data waiting to be read.
|
||||
// It is nil when no handshake data is buffered, in which case the
|
||||
// buffer has been returned to handPool. Use handBuf and handLen to
|
||||
// access it.
|
||||
hand *bytes.Buffer
|
||||
buffering bool // whether records are buffered in sendBuf
|
||||
sendBuf []byte // a buffer of records waiting to be sent
|
||||
|
||||
// bytesSent counts the bytes of application data sent.
|
||||
// packetsSent counts packets.
|
||||
@@ -171,8 +190,10 @@ func (c *Conn) NetConn() net.Conn {
|
||||
// A halfConn represents one direction of the record layer
|
||||
// connection, either sending or receiving.
|
||||
type halfConn struct {
|
||||
//////////////////////////////////// [REALITY] SECTION: define var
|
||||
handshakeLen [7]int
|
||||
handshakeBuf []byte
|
||||
//////////////////////////////////// [REALITY] SECTION END
|
||||
|
||||
sync.Mutex
|
||||
|
||||
@@ -227,20 +248,19 @@ func (hc *halfConn) changeCipherSpec() error {
|
||||
hc.mac = hc.nextMac
|
||||
hc.nextCipher = nil
|
||||
hc.nextMac = nil
|
||||
for i := range hc.seq {
|
||||
hc.seq[i] = 0
|
||||
}
|
||||
clear(hc.seq[:])
|
||||
return nil
|
||||
}
|
||||
|
||||
// setTrafficSecret sets the traffic secret for the given encryption level. setTrafficSecret
|
||||
// should not be called directly, but rather through the Conn setWriteTrafficSecret and
|
||||
// setReadTrafficSecret wrapper methods.
|
||||
func (hc *halfConn) setTrafficSecret(suite *cipherSuiteTLS13, level QUICEncryptionLevel, secret []byte) {
|
||||
hc.trafficSecret = secret
|
||||
hc.level = level
|
||||
key, iv := suite.trafficKey(secret)
|
||||
hc.cipher = suite.aead(key, iv)
|
||||
for i := range hc.seq {
|
||||
hc.seq[i] = 0
|
||||
}
|
||||
clear(hc.seq[:])
|
||||
}
|
||||
|
||||
// incSeq increments the sequence number.
|
||||
@@ -528,6 +548,7 @@ func (hc *halfConn) encrypt(record, payload []byte, rand io.Reader) ([]byte, err
|
||||
|
||||
// Encrypt the actual ContentType and replace the plaintext one.
|
||||
record = append(record, record[0])
|
||||
//////////////////////////////////// [REALITY] SECTION: mimic recorded handshakeLen
|
||||
padding := 0
|
||||
if recordType(record[0]) == recordTypeHandshake && hc.handshakeLen[1] != 0 {
|
||||
switch payload[0] {
|
||||
@@ -558,6 +579,7 @@ func (hc *halfConn) encrypt(record, payload []byte, rand io.Reader) ([]byte, err
|
||||
record[0] = byte(recordTypeApplicationData)
|
||||
|
||||
n := len(record) + c.Overhead() - recordHeaderLen
|
||||
//////////////////////////////////// [REALITY] SECTION END
|
||||
record[3] = byte(n >> 8)
|
||||
record[4] = byte(n)
|
||||
|
||||
@@ -615,7 +637,9 @@ func (e RecordHeaderError) Error() string { return "tls: " + e.Msg }
|
||||
func (c *Conn) newRecordHeaderError(conn net.Conn, msg string) (err RecordHeaderError) {
|
||||
err.Msg = msg
|
||||
err.Conn = conn
|
||||
copy(err.RecordHeader[:], c.rawInput.Bytes())
|
||||
if c.rawInput != nil {
|
||||
copy(err.RecordHeader[:], c.rawInput.Bytes())
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -657,6 +681,19 @@ func (c *Conn) readRecordOrCCS(expectChangeCipherSpec bool) error {
|
||||
return c.in.setErrorLocked(errors.New("tls: internal error: attempted to read record with QUIC transport"))
|
||||
}
|
||||
|
||||
// If rawInput is empty, we are about to block in a Read on the
|
||||
// underlying connection waiting for the next record, possibly for a
|
||||
// long time. A previous record may have grown rawInput to the maximum
|
||||
// record size; don't pin that memory while idle. Return the buffer to
|
||||
// the pool, and let readFromUntil read the header into a small buffer
|
||||
// and switch back to a pooled record-sized buffer only once the
|
||||
// payload length is known.
|
||||
if c.rawInput != nil && c.rawInput.Len() == 0 && c.rawInput != c.smallInput && c.rawInput.Cap() > maxIdleInputCap {
|
||||
c.rawInput.Reset()
|
||||
rawInputPool.Put(c.rawInput)
|
||||
c.rawInput = nil
|
||||
}
|
||||
|
||||
// Read header, payload.
|
||||
if err := c.readFromUntil(c.conn, recordHeaderLen); err != nil {
|
||||
// RFC 8446, Section 6.1 suggests that EOF without an alertCloseNotify
|
||||
@@ -731,13 +768,13 @@ func (c *Conn) readRecordOrCCS(expectChangeCipherSpec bool) error {
|
||||
return c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
|
||||
}
|
||||
|
||||
if typ != recordTypeAlert && typ != recordTypeChangeCipherSpec && len(data) > 0 {
|
||||
if (typ == recordTypeApplicationData || (typ == recordTypeHandshake && !handshakeComplete)) && len(data) > 0 {
|
||||
// This is a state-advancing message: reset the retry count.
|
||||
c.retryCount = 0
|
||||
}
|
||||
|
||||
// Handshake messages MUST NOT be interleaved with other record types in TLS 1.3.
|
||||
if c.vers == VersionTLS13 && typ != recordTypeHandshake && c.hand.Len() > 0 {
|
||||
if c.vers == VersionTLS13 && typ != recordTypeHandshake && c.handLen() > 0 {
|
||||
return c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
|
||||
}
|
||||
|
||||
@@ -782,7 +819,7 @@ func (c *Conn) readRecordOrCCS(expectChangeCipherSpec bool) error {
|
||||
return c.in.setErrorLocked(c.sendAlert(alertDecodeError))
|
||||
}
|
||||
// Handshake messages are not allowed to fragment across the CCS.
|
||||
if c.hand.Len() > 0 {
|
||||
if c.handLen() > 0 {
|
||||
return c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
|
||||
}
|
||||
// In TLS 1.3, change_cipher_spec records are ignored until the
|
||||
@@ -790,7 +827,9 @@ func (c *Conn) readRecordOrCCS(expectChangeCipherSpec bool) error {
|
||||
// 5, a server can send a ChangeCipherSpec before its ServerHello, when
|
||||
// c.vers is still unset. That's not useful though and suspicious if the
|
||||
// server then selects a lower protocol version, so don't allow that.
|
||||
//////////////////////////////////// [REALITY] SECTION: reject change_cipher_spec record after handshake in TLS 1.3
|
||||
if c.vers == VersionTLS13 && !handshakeComplete {
|
||||
//////////////////////////////////// [REALITY] SECTION END
|
||||
return c.retryReadRecord(expectChangeCipherSpec)
|
||||
}
|
||||
if !expectChangeCipherSpec {
|
||||
@@ -818,7 +857,7 @@ func (c *Conn) readRecordOrCCS(expectChangeCipherSpec bool) error {
|
||||
if len(data) == 0 || expectChangeCipherSpec {
|
||||
return c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
|
||||
}
|
||||
c.hand.Write(data)
|
||||
c.handBuf().Write(data)
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -828,52 +867,125 @@ func (c *Conn) readRecordOrCCS(expectChangeCipherSpec bool) error {
|
||||
// a warning alert, empty application_data, or a change_cipher_spec in TLS 1.3.
|
||||
func (c *Conn) retryReadRecord(expectChangeCipherSpec bool) error {
|
||||
c.retryCount++
|
||||
//////////////////////////////////// [REALITY] SECTION: mimic recorded maxUselessRecords
|
||||
if c.MaxUselessRecords <= 0 {
|
||||
c.MaxUselessRecords = maxUselessRecords
|
||||
}
|
||||
if c.retryCount > c.MaxUselessRecords {
|
||||
//////////////////////////////////// [REALITY] SECTION END
|
||||
c.sendAlert(alertUnexpectedMessage)
|
||||
return c.in.setErrorLocked(errors.New("tls: too many ignored records"))
|
||||
}
|
||||
return c.readRecordOrCCS(expectChangeCipherSpec)
|
||||
}
|
||||
|
||||
// atLeastReader reads from R, stopping with EOF once at least N bytes have been
|
||||
// read. It is different from an io.LimitedReader in that it doesn't cut short
|
||||
// the last Read call, and in that it considers an early EOF an error.
|
||||
type atLeastReader struct {
|
||||
R io.Reader
|
||||
N int64
|
||||
// rawInputPool pools the record-sized buffers that back Conn.rawInput
|
||||
// while records are being received. A connection returns its buffer to
|
||||
// the pool before blocking to wait for a new record, often for a long
|
||||
// time, so that idle connections do not each pin a record-sized buffer.
|
||||
// Only buffers with capacity above maxIdleInputCap are pooled; smaller
|
||||
// buffers stay attached to their connection.
|
||||
var rawInputPool = sync.Pool{New: func() any { return new(bytes.Buffer) }}
|
||||
|
||||
// maxIdleInputCap is the largest rawInput capacity that a connection
|
||||
// keeps while waiting for a new record to arrive. It is large enough to
|
||||
// hold a record header and small records, so that only connections
|
||||
// receiving larger records pay for the pooled buffer switch below.
|
||||
const maxIdleInputCap = 1024
|
||||
|
||||
// handPool pools the buffers that back Conn.hand, which typically grow
|
||||
// to hold the peer's largest flight of handshake messages. A connection
|
||||
// returns its buffer to the pool once the handshake completes and after
|
||||
// buffered post-handshake messages have been consumed, so that
|
||||
// established connections do not pin it.
|
||||
var handPool = sync.Pool{New: func() any { return new(bytes.Buffer) }}
|
||||
|
||||
// handBuf returns c.hand for writing, getting a buffer from handPool if
|
||||
// c.hand is nil.
|
||||
func (c *Conn) handBuf() *bytes.Buffer {
|
||||
if c.hand == nil {
|
||||
c.hand = handPool.Get().(*bytes.Buffer)
|
||||
}
|
||||
return c.hand
|
||||
}
|
||||
|
||||
func (r *atLeastReader) Read(p []byte) (int, error) {
|
||||
if r.N <= 0 {
|
||||
return 0, io.EOF
|
||||
// handLen returns the number of buffered handshake bytes.
|
||||
func (c *Conn) handLen() int {
|
||||
if c.hand == nil {
|
||||
return 0
|
||||
}
|
||||
n, err := r.R.Read(p)
|
||||
r.N -= int64(n) // won't underflow unless len(p) >= n > 9223372036854775809
|
||||
if r.N > 0 && err == io.EOF {
|
||||
return n, io.ErrUnexpectedEOF
|
||||
return c.hand.Len()
|
||||
}
|
||||
|
||||
// releaseHand returns c.hand to handPool if it is empty.
|
||||
func (c *Conn) releaseHand() {
|
||||
if c.hand != nil && c.hand.Len() == 0 {
|
||||
c.hand.Reset()
|
||||
handPool.Put(c.hand)
|
||||
c.hand = nil
|
||||
}
|
||||
if r.N <= 0 && err == nil {
|
||||
return n, io.EOF
|
||||
}
|
||||
return n, err
|
||||
}
|
||||
|
||||
// readFromUntil reads from r into c.rawInput until c.rawInput contains
|
||||
// at least n bytes or else returns an error.
|
||||
func (c *Conn) readFromUntil(r io.Reader, n int) error {
|
||||
if c.rawInput == nil {
|
||||
// The record buffer was released while waiting for a new
|
||||
// record. Block for the header using the connection's small
|
||||
// buffer; the switch to a pooled record-sized buffer below
|
||||
// happens only once the payload length is known and data is
|
||||
// flowing.
|
||||
if c.smallInput == nil {
|
||||
c.smallInput = new(bytes.Buffer)
|
||||
}
|
||||
c.rawInput = c.smallInput
|
||||
}
|
||||
if c.rawInput.Len() >= n {
|
||||
return nil
|
||||
}
|
||||
needs := n - c.rawInput.Len()
|
||||
if want := c.rawInput.Len() + needs + bytes.MinRead; want > maxIdleInputCap && want > c.rawInput.Cap() {
|
||||
// Growing past maxIdleInputCap: switch to a pooled buffer so
|
||||
// that record-sized buffers are recycled across connections
|
||||
// rather than allocated for every record.
|
||||
b := rawInputPool.Get().(*bytes.Buffer)
|
||||
b.Write(c.rawInput.Bytes())
|
||||
if c.rawInput == c.smallInput {
|
||||
c.smallInput.Reset()
|
||||
} else if c.rawInput.Cap() > maxIdleInputCap {
|
||||
c.rawInput.Reset()
|
||||
rawInputPool.Put(c.rawInput)
|
||||
}
|
||||
c.rawInput = b
|
||||
}
|
||||
// There might be extra input waiting on the wire. Make a best effort
|
||||
// attempt to fetch it so that it can be used in (*Conn).Read to
|
||||
// "predict" closeNotify alerts.
|
||||
// TODO(dmo): we use bytes.MinRead here because we used the buffer
|
||||
// ReadFrom mechanism to avoid allocations, but we've hoisted this
|
||||
// loop for performance. We really should use our own heuristic here
|
||||
// for how much to read ahead.
|
||||
c.rawInput.Grow(needs + bytes.MinRead)
|
||||
_, err := c.rawInput.ReadFrom(&atLeastReader{r, int64(needs)})
|
||||
return err
|
||||
for {
|
||||
buf := c.rawInput.AvailableBuffer()[:c.rawInput.Available()]
|
||||
n, err := r.Read(buf)
|
||||
// This write is just to update the internal state of the
|
||||
// rawInput bytes.Buffer. It cannot fail.
|
||||
c.rawInput.Write(buf[:n])
|
||||
needs -= n
|
||||
if needs <= 0 {
|
||||
if err == io.EOF {
|
||||
err = nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
if err == io.EOF {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// sendAlertLocked sends a TLS alert message.
|
||||
@@ -1100,6 +1212,7 @@ func (c *Conn) writeHandshakeRecord(msg handshakeMessage, transcript transcriptH
|
||||
transcript.Write(data)
|
||||
}
|
||||
|
||||
//////////////////////////////////// [REALITY] SECTION: mimic recorded handshakeBuf
|
||||
if c.out.handshakeBuf != nil && len(data) > 0 && data[0] != typeServerHello {
|
||||
c.out.handshakeBuf = append(c.out.handshakeBuf, data...)
|
||||
if data[0] != typeFinished {
|
||||
@@ -1131,6 +1244,7 @@ func (c *Conn) writeRecord(typ recordType, data []byte) (int, error) {
|
||||
|
||||
return c.writeRecordLocked(typ, data)
|
||||
}
|
||||
//////////////////////////////////// [REALITY] SECTION END
|
||||
|
||||
// writeChangeCipherRecord writes a ChangeCipherSpec message to the connection and
|
||||
// updates the record layer state.
|
||||
@@ -1146,7 +1260,7 @@ func (c *Conn) readHandshakeBytes(n int) error {
|
||||
if c.quic != nil {
|
||||
return c.quicReadHandshakeBytes(n)
|
||||
}
|
||||
for c.hand.Len() < n {
|
||||
for c.handLen() < n {
|
||||
if err := c.readRecord(); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -1379,7 +1493,9 @@ func (c *Conn) handlePostHandshakeMessage() error {
|
||||
return err
|
||||
}
|
||||
c.retryCount++
|
||||
//////////////////////////////////// [REALITY] SECTION: mimic recorded maxUselessRecords
|
||||
if c.retryCount > c.MaxUselessRecords {
|
||||
//////////////////////////////////// [REALITY] SECTION END
|
||||
c.sendAlert(alertUnexpectedMessage)
|
||||
return c.in.setErrorLocked(errors.New("tls: too many non-advancing records"))
|
||||
}
|
||||
@@ -1409,9 +1525,6 @@ func (c *Conn) handleKeyUpdate(keyUpdate *keyUpdateMsg) error {
|
||||
return c.in.setErrorLocked(c.sendAlert(alertInternalError))
|
||||
}
|
||||
|
||||
newSecret := cipherSuite.nextTrafficSecret(c.in.trafficSecret)
|
||||
c.in.setTrafficSecret(cipherSuite, QUICEncryptionLevelInitial, newSecret)
|
||||
|
||||
if keyUpdate.updateRequested {
|
||||
c.out.Lock()
|
||||
defer c.out.Unlock()
|
||||
@@ -1429,7 +1542,12 @@ func (c *Conn) handleKeyUpdate(keyUpdate *keyUpdateMsg) error {
|
||||
}
|
||||
|
||||
newSecret := cipherSuite.nextTrafficSecret(c.out.trafficSecret)
|
||||
c.out.setTrafficSecret(cipherSuite, QUICEncryptionLevelInitial, newSecret)
|
||||
c.setWriteTrafficSecret(cipherSuite, QUICEncryptionLevelInitial, newSecret)
|
||||
}
|
||||
|
||||
newSecret := cipherSuite.nextTrafficSecret(c.in.trafficSecret)
|
||||
if err := c.setReadTrafficSecret(cipherSuite, QUICEncryptionLevelInitial, newSecret, keyUpdate.updateRequested); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -1458,11 +1576,12 @@ func (c *Conn) Read(b []byte) (int, error) {
|
||||
if err := c.readRecord(); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
for c.hand.Len() > 0 {
|
||||
for c.handLen() > 0 {
|
||||
if err := c.handlePostHandshakeMessage(); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
c.releaseHand()
|
||||
}
|
||||
|
||||
n, _ := c.input.Read(b)
|
||||
@@ -1590,37 +1709,23 @@ func (c *Conn) handshakeContext(ctx context.Context) (ret error) {
|
||||
}
|
||||
|
||||
handshakeCtx, cancel := context.WithCancel(ctx)
|
||||
// Note: defer this before starting the "interrupter" goroutine
|
||||
// Note: defer this before calling context.AfterFunc
|
||||
// so that we can tell the difference between the input being canceled and
|
||||
// this cancellation. In the former case, we need to close the connection.
|
||||
defer cancel()
|
||||
|
||||
if c.quic != nil {
|
||||
c.quic.cancelc = handshakeCtx.Done()
|
||||
c.quic.ctx = handshakeCtx
|
||||
c.quic.cancel = cancel
|
||||
} else if ctx.Done() != nil {
|
||||
// Start the "interrupter" goroutine, if this context might be canceled.
|
||||
// (The background context cannot).
|
||||
//
|
||||
// The interrupter goroutine waits for the input context to be done and
|
||||
// closes the connection if this happens before the function returns.
|
||||
done := make(chan struct{})
|
||||
interruptRes := make(chan error, 1)
|
||||
// Close the connection if ctx is canceled before the function returns.
|
||||
stop := context.AfterFunc(ctx, func() {
|
||||
_ = c.conn.Close()
|
||||
})
|
||||
defer func() {
|
||||
close(done)
|
||||
if ctxErr := <-interruptRes; ctxErr != nil {
|
||||
if !stop() {
|
||||
// Return context error to user.
|
||||
ret = ctxErr
|
||||
}
|
||||
}()
|
||||
go func() {
|
||||
select {
|
||||
case <-handshakeCtx.Done():
|
||||
// Close the connection, discarding the error
|
||||
_ = c.conn.Close()
|
||||
interruptRes <- handshakeCtx.Err()
|
||||
case <-done:
|
||||
interruptRes <- nil
|
||||
ret = ctx.Err()
|
||||
}
|
||||
}()
|
||||
}
|
||||
@@ -1654,17 +1759,27 @@ func (c *Conn) handshakeContext(ctx context.Context) (ret error) {
|
||||
panic("tls: internal error: handshake returned an error but is marked successful")
|
||||
}
|
||||
|
||||
// The handshake buffer typically grew to hold the peer's largest
|
||||
// flight of handshake messages and is now empty. Post-handshake
|
||||
// messages are rare and small, so release the buffer rather than
|
||||
// pinning it for the life of the connection.
|
||||
if c.handshakeErr == nil {
|
||||
c.releaseHand()
|
||||
}
|
||||
|
||||
if c.quic != nil {
|
||||
if c.handshakeErr == nil {
|
||||
c.quicHandshakeComplete()
|
||||
// Provide the 1-RTT read secret now that the handshake is complete.
|
||||
// The QUIC layer MUST NOT decrypt 1-RTT packets prior to completing
|
||||
// the handshake (RFC 9001, Section 5.7).
|
||||
c.quicSetReadSecret(QUICEncryptionLevelApplication, c.cipherSuite, c.in.trafficSecret)
|
||||
if err := c.quicSetReadSecret(QUICEncryptionLevelApplication, c.cipherSuite, c.in.trafficSecret); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
var a alert
|
||||
c.out.Lock()
|
||||
if !errors.As(c.out.err, &a) {
|
||||
a, ok := errors.AsType[alert](c.out.err)
|
||||
if !ok {
|
||||
a = alertInternalError
|
||||
}
|
||||
c.out.Unlock()
|
||||
@@ -1682,6 +1797,12 @@ func (c *Conn) handshakeContext(ctx context.Context) (ret error) {
|
||||
}
|
||||
|
||||
// ConnectionState returns basic TLS details about the connection.
|
||||
//
|
||||
// The returned [ConnectionState] is only meaningful after the handshake has
|
||||
// completed, as reported by [ConnectionState.HandshakeComplete]; before then
|
||||
// its fields are not populated. The handshake is run automatically by the
|
||||
// first [Conn.Read] or [Conn.Write], or it can be triggered explicitly with
|
||||
// [Conn.Handshake].
|
||||
func (c *Conn) ConnectionState() ConnectionState {
|
||||
c.handshakeMutex.Lock()
|
||||
defer c.handshakeMutex.Unlock()
|
||||
@@ -1694,12 +1815,14 @@ func (c *Conn) connectionStateLocked() ConnectionState {
|
||||
state.Version = c.vers
|
||||
state.NegotiatedProtocol = c.clientProtocol
|
||||
state.DidResume = c.didResume
|
||||
state.testingOnlyDidHRR = c.didHRR
|
||||
state.HelloRetryRequest = c.didHRR
|
||||
state.testingOnlyPeerSignatureAlgorithm = c.peerSigAlg
|
||||
state.CurveID = c.curveID
|
||||
state.NegotiatedProtocolIsMutual = true
|
||||
state.ServerName = c.serverName
|
||||
state.CipherSuite = c.cipherSuite
|
||||
state.PeerCertificates = c.peerCertificates
|
||||
state.LocalCertificate = c.localCertificate
|
||||
state.VerifiedChains = c.verifiedChains
|
||||
state.SignedCertificateTimestamps = c.scts
|
||||
state.OCSPResponse = c.ocspResponse
|
||||
@@ -1713,13 +1836,7 @@ func (c *Conn) connectionStateLocked() ConnectionState {
|
||||
if c.config.Renegotiation != RenegotiateNever {
|
||||
state.ekm = noEKMBecauseRenegotiation
|
||||
} else if c.vers != VersionTLS13 && !c.extMasterSecret {
|
||||
state.ekm = func(label string, context []byte, length int) ([]byte, error) {
|
||||
// if ekmgodebug.Value() == "1" {
|
||||
// ekmgodebug.IncNonDefault()
|
||||
// return c.ekm(label, context, length)
|
||||
// }
|
||||
return noEKMBecauseNoEMS(label, context, length)
|
||||
}
|
||||
state.ekm = noEKMBecauseNoEMS
|
||||
} else {
|
||||
state.ekm = c.ekm
|
||||
}
|
||||
@@ -1753,3 +1870,29 @@ func (c *Conn) VerifyHostname(host string) error {
|
||||
}
|
||||
return c.peerCertificates[0].VerifyHostname(host)
|
||||
}
|
||||
|
||||
// setReadTrafficSecret sets the read traffic secret for the given encryption level. If
|
||||
// being called at the same time as setWriteTrafficSecret, the caller must ensure the call
|
||||
// to setWriteTrafficSecret happens first so any alerts are sent at the write level.
|
||||
func (c *Conn) setReadTrafficSecret(suite *cipherSuiteTLS13, level QUICEncryptionLevel, secret []byte, locked bool) error {
|
||||
// Ensure that there are no buffered handshake messages before changing the
|
||||
// read keys, since that can cause messages to be parsed that were encrypted
|
||||
// using old keys which are no longer appropriate.
|
||||
if c.handLen() != 0 {
|
||||
if locked {
|
||||
c.sendAlertLocked(alertUnexpectedMessage)
|
||||
} else {
|
||||
c.sendAlert(alertUnexpectedMessage)
|
||||
}
|
||||
return errors.New("tls: handshake buffer not empty before setting read traffic secret")
|
||||
}
|
||||
c.in.setTrafficSecret(suite, level, secret)
|
||||
return nil
|
||||
}
|
||||
|
||||
// setWriteTrafficSecret sets the write traffic secret for the given encryption level. If
|
||||
// being called at the same time as setReadTrafficSecret, the caller must ensure the call
|
||||
// to setWriteTrafficSecret happens first so any alerts are sent at the write level.
|
||||
func (c *Conn) setWriteTrafficSecret(suite *cipherSuiteTLS13, level QUICEncryptionLevel, secret []byte) {
|
||||
c.out.setTrafficSecret(suite, level, secret)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user