mirror of
https://github.com/SagerNet/sing-box.git
synced 2025-09-08 10:18:49 +08:00
174 lines
5.0 KiB
Go
174 lines
5.0 KiB
Go
// Copyright 2009 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
//go:build linux && go1.25 && !without_badtls
|
|
|
|
package ktls
|
|
|
|
import (
|
|
"crypto/tls"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
)
|
|
|
|
// handlePostHandshakeMessage processes a handshake message arrived after the
|
|
// handshake is complete. Up to TLS 1.2, it indicates the start of a renegotiation.
|
|
func (c *Conn) handlePostHandshakeMessage() error {
|
|
if *c.rawConn.Vers != tls.VersionTLS13 {
|
|
return errors.New("ktls: kernel does not support TLS 1.2 renegotiation")
|
|
}
|
|
|
|
msg, err := c.readHandshake(nil)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
//c.retryCount++
|
|
//if c.retryCount > maxUselessRecords {
|
|
// c.sendAlert(alertUnexpectedMessage)
|
|
// return c.in.setErrorLocked(errors.New("tls: too many non-advancing records"))
|
|
//}
|
|
|
|
switch msg := msg.(type) {
|
|
case *newSessionTicketMsgTLS13:
|
|
// return errors.New("ktls: received new session ticket")
|
|
return nil
|
|
case *keyUpdateMsg:
|
|
return c.handleKeyUpdate(msg)
|
|
}
|
|
// The QUIC layer is supposed to treat an unexpected post-handshake CertificateRequest
|
|
// as a QUIC-level PROTOCOL_VIOLATION error (RFC 9001, Section 4.4). Returning an
|
|
// unexpected_message alert here doesn't provide it with enough information to distinguish
|
|
// this condition from other unexpected messages. This is probably fine.
|
|
c.sendAlert(alertUnexpectedMessage)
|
|
return fmt.Errorf("tls: received unexpected handshake message of type %T", msg)
|
|
}
|
|
|
|
func (c *Conn) handleKeyUpdate(keyUpdate *keyUpdateMsg) error {
|
|
//if c.quic != nil {
|
|
// c.sendAlert(alertUnexpectedMessage)
|
|
// return c.in.setErrorLocked(errors.New("tls: received unexpected key update message"))
|
|
//}
|
|
|
|
cipherSuite := cipherSuiteTLS13ByID(*c.rawConn.CipherSuite)
|
|
if cipherSuite == nil {
|
|
return c.rawConn.In.SetErrorLocked(c.sendAlert(alertInternalError))
|
|
}
|
|
|
|
newSecret := nextTrafficSecret(cipherSuite, *c.rawConn.In.TrafficSecret)
|
|
c.rawConn.In.SetTrafficSecret(cipherSuite, 0 /*tls.QUICEncryptionLevelInitial*/, newSecret)
|
|
|
|
err := c.resetupRX()
|
|
if err != nil {
|
|
c.sendAlert(alertInternalError)
|
|
return c.rawConn.In.SetErrorLocked(fmt.Errorf("ktls: resetupRX failed: %w", err))
|
|
}
|
|
|
|
if keyUpdate.updateRequested {
|
|
c.rawConn.Out.Lock()
|
|
defer c.rawConn.Out.Unlock()
|
|
|
|
resetup, err := c.resetupTX()
|
|
if err != nil {
|
|
c.sendAlertLocked(alertInternalError)
|
|
return c.rawConn.Out.SetErrorLocked(fmt.Errorf("ktls: resetupTX failed: %w", err))
|
|
}
|
|
|
|
msg := &keyUpdateMsg{}
|
|
msgBytes, err := msg.marshal()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
_, err = c.writeRecordLocked(recordTypeHandshake, msgBytes)
|
|
if err != nil {
|
|
// Surface the error at the next write.
|
|
c.rawConn.Out.SetErrorLocked(err)
|
|
return nil
|
|
}
|
|
|
|
newSecret := nextTrafficSecret(cipherSuite, *c.rawConn.Out.TrafficSecret)
|
|
c.rawConn.Out.SetTrafficSecret(cipherSuite, 0 /*QUICEncryptionLevelInitial*/, newSecret)
|
|
|
|
err = resetup()
|
|
if err != nil {
|
|
return c.rawConn.Out.SetErrorLocked(fmt.Errorf("ktls: resetupTX failed: %w", err))
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (c *Conn) readHandshakeBytes(n int) error {
|
|
//if c.quic != nil {
|
|
// return c.quicReadHandshakeBytes(n)
|
|
//}
|
|
for c.rawConn.Hand.Len() < n {
|
|
if err := c.readRecord(); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (c *Conn) readHandshake(transcript io.Writer) (any, error) {
|
|
if err := c.readHandshakeBytes(4); err != nil {
|
|
return nil, err
|
|
}
|
|
data := c.rawConn.Hand.Bytes()
|
|
|
|
maxHandshakeSize := maxHandshake
|
|
// hasVers indicates we're past the first message, forcing someone trying to
|
|
// make us just allocate a large buffer to at least do the initial part of
|
|
// the handshake first.
|
|
//if c.haveVers && data[0] == typeCertificate {
|
|
// Since certificate messages are likely to be the only messages that
|
|
// can be larger than maxHandshake, we use a special limit for just
|
|
// those messages.
|
|
//maxHandshakeSize = maxHandshakeCertificateMsg
|
|
//}
|
|
|
|
n := int(data[1])<<16 | int(data[2])<<8 | int(data[3])
|
|
if n > maxHandshakeSize {
|
|
c.sendAlertLocked(alertInternalError)
|
|
return nil, c.rawConn.In.SetErrorLocked(fmt.Errorf("tls: handshake message of length %d bytes exceeds maximum of %d bytes", n, maxHandshakeSize))
|
|
}
|
|
if err := c.readHandshakeBytes(4 + n); err != nil {
|
|
return nil, err
|
|
}
|
|
data = c.rawConn.Hand.Next(4 + n)
|
|
return c.unmarshalHandshakeMessage(data, transcript)
|
|
}
|
|
|
|
func (c *Conn) unmarshalHandshakeMessage(data []byte, transcript io.Writer) (any, error) {
|
|
var m handshakeMessage
|
|
switch data[0] {
|
|
case typeNewSessionTicket:
|
|
if *c.rawConn.Vers == tls.VersionTLS13 {
|
|
m = new(newSessionTicketMsgTLS13)
|
|
} else {
|
|
return nil, os.ErrInvalid
|
|
}
|
|
case typeKeyUpdate:
|
|
m = new(keyUpdateMsg)
|
|
default:
|
|
return nil, c.rawConn.In.SetErrorLocked(c.sendAlert(alertUnexpectedMessage))
|
|
}
|
|
|
|
// The handshake message unmarshalers
|
|
// expect to be able to keep references to data,
|
|
// so pass in a fresh copy that won't be overwritten.
|
|
data = append([]byte(nil), data...)
|
|
|
|
if !m.unmarshal(data) {
|
|
return nil, c.rawConn.In.SetErrorLocked(c.sendAlert(alertDecodeError))
|
|
}
|
|
|
|
if transcript != nil {
|
|
transcript.Write(data)
|
|
}
|
|
|
|
return m, nil
|
|
}
|