mirror of
https://github.com/SagerNet/sing-box.git
synced 2024-11-10 11:03:13 +00:00
242 lines
7.1 KiB
Go
242 lines
7.1 KiB
Go
// Copyright 2021 Cloudflare, Inc. All rights reserved. Use of this source code
|
|
// is governed by a BSD-style license that can be found in the LICENSE file.
|
|
|
|
package tls
|
|
|
|
import (
|
|
"time"
|
|
|
|
circlPki "github.com/cloudflare/circl/pki"
|
|
circlSign "github.com/cloudflare/circl/sign"
|
|
"github.com/cloudflare/circl/sign/eddilithium3"
|
|
)
|
|
|
|
const (
|
|
// Constants for ECH status events.
|
|
echStatusBypassed = 1 + iota
|
|
echStatusInner
|
|
echStatusOuter
|
|
)
|
|
|
|
// To add a signature scheme from Circl
|
|
//
|
|
// 1. make sure it implements TLSScheme and CertificateScheme,
|
|
// 2. follow the instructions in crypto/x509/x509_cf.go
|
|
// 3. add a signature<NameOfAlg> to the iota in common.go
|
|
// 4. add row in the circlSchemes lists below
|
|
|
|
var circlSchemes = [...]struct {
|
|
sigType uint8
|
|
scheme circlSign.Scheme
|
|
}{
|
|
{signatureEdDilithium3, eddilithium3.Scheme()},
|
|
}
|
|
|
|
func circlSchemeBySigType(sigType uint8) circlSign.Scheme {
|
|
for _, cs := range circlSchemes {
|
|
if cs.sigType == sigType {
|
|
return cs.scheme
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func sigTypeByCirclScheme(scheme circlSign.Scheme) uint8 {
|
|
for _, cs := range circlSchemes {
|
|
if cs.scheme == scheme {
|
|
return cs.sigType
|
|
}
|
|
}
|
|
return 0
|
|
}
|
|
|
|
var supportedSignatureAlgorithmsWithCircl []SignatureScheme
|
|
|
|
// supportedSignatureAlgorithms returns enabled signature schemes. PQ signature
|
|
// schemes are only included when tls.Config#PQSignatureSchemesEnabled is set.
|
|
func (c *Config) supportedSignatureAlgorithms() []SignatureScheme {
|
|
if c != nil && c.PQSignatureSchemesEnabled {
|
|
return supportedSignatureAlgorithmsWithCircl
|
|
}
|
|
return supportedSignatureAlgorithms
|
|
}
|
|
|
|
func init() {
|
|
supportedSignatureAlgorithmsWithCircl = append([]SignatureScheme{}, supportedSignatureAlgorithms...)
|
|
for _, cs := range circlSchemes {
|
|
supportedSignatureAlgorithmsWithCircl = append(supportedSignatureAlgorithmsWithCircl,
|
|
SignatureScheme(cs.scheme.(circlPki.TLSScheme).TLSIdentifier()))
|
|
}
|
|
}
|
|
|
|
// CFEvent is a value emitted at various points in the handshake that is
|
|
// handled by the callback Config.CFEventHandler.
|
|
type CFEvent interface {
|
|
Name() string
|
|
}
|
|
|
|
// CFEventTLS13ClientHandshakeTimingInfo carries intra-stack time durations for
|
|
// TLS 1.3 client-state machine changes. It can be used for tracking metrics
|
|
// during a connection. Some durations may be sensitive, such as the amount of
|
|
// time to process a particular handshake message, so this event should only be
|
|
// used for experimental purposes.
|
|
type CFEventTLS13ClientHandshakeTimingInfo struct {
|
|
timer func() time.Time
|
|
start time.Time
|
|
WriteClientHello time.Duration
|
|
ProcessServerHello time.Duration
|
|
ReadEncryptedExtensions time.Duration
|
|
ReadCertificate time.Duration
|
|
ReadCertificateVerify time.Duration
|
|
ReadServerFinished time.Duration
|
|
WriteCertificate time.Duration
|
|
WriteCertificateVerify time.Duration
|
|
WriteClientFinished time.Duration
|
|
}
|
|
|
|
// Name is required by the CFEvent interface.
|
|
func (e CFEventTLS13ClientHandshakeTimingInfo) Name() string {
|
|
return "TLS13ClientHandshakeTimingInfo"
|
|
}
|
|
|
|
func (e CFEventTLS13ClientHandshakeTimingInfo) elapsedTime() time.Duration {
|
|
if e.timer == nil {
|
|
return 0
|
|
}
|
|
return e.timer().Sub(e.start)
|
|
}
|
|
|
|
func createTLS13ClientHandshakeTimingInfo(timerFunc func() time.Time) CFEventTLS13ClientHandshakeTimingInfo {
|
|
timer := time.Now
|
|
if timerFunc != nil {
|
|
timer = timerFunc
|
|
}
|
|
|
|
return CFEventTLS13ClientHandshakeTimingInfo{
|
|
timer: timer,
|
|
start: timer(),
|
|
}
|
|
}
|
|
|
|
// CFEventTLS13ServerHandshakeTimingInfo carries intra-stack time durations
|
|
// for TLS 1.3 state machine changes. It can be used for tracking metrics during a
|
|
// connection. Some durations may be sensitive, such as the amount of time to
|
|
// process a particular handshake message, so this event should only be used
|
|
// for experimental purposes.
|
|
type CFEventTLS13ServerHandshakeTimingInfo struct {
|
|
timer func() time.Time
|
|
start time.Time
|
|
ProcessClientHello time.Duration
|
|
WriteServerHello time.Duration
|
|
WriteEncryptedExtensions time.Duration
|
|
WriteCertificate time.Duration
|
|
WriteCertificateVerify time.Duration
|
|
WriteServerFinished time.Duration
|
|
ReadCertificate time.Duration
|
|
ReadCertificateVerify time.Duration
|
|
ReadClientFinished time.Duration
|
|
}
|
|
|
|
// Name is required by the CFEvent interface.
|
|
func (e CFEventTLS13ServerHandshakeTimingInfo) Name() string {
|
|
return "TLS13ServerHandshakeTimingInfo"
|
|
}
|
|
|
|
func (e CFEventTLS13ServerHandshakeTimingInfo) elapsedTime() time.Duration {
|
|
if e.timer == nil {
|
|
return 0
|
|
}
|
|
return e.timer().Sub(e.start)
|
|
}
|
|
|
|
func createTLS13ServerHandshakeTimingInfo(timerFunc func() time.Time) CFEventTLS13ServerHandshakeTimingInfo {
|
|
timer := time.Now
|
|
if timerFunc != nil {
|
|
timer = timerFunc
|
|
}
|
|
|
|
return CFEventTLS13ServerHandshakeTimingInfo{
|
|
timer: timer,
|
|
start: timer(),
|
|
}
|
|
}
|
|
|
|
// CFEventECHClientStatus is emitted once it is known whether the client
|
|
// bypassed, offered, or greased ECH.
|
|
type CFEventECHClientStatus int
|
|
|
|
// Bypassed returns true if the client bypassed ECH.
|
|
func (e CFEventECHClientStatus) Bypassed() bool {
|
|
return e == echStatusBypassed
|
|
}
|
|
|
|
// Offered returns true if the client offered ECH.
|
|
func (e CFEventECHClientStatus) Offered() bool {
|
|
return e == echStatusInner
|
|
}
|
|
|
|
// Greased returns true if the client greased ECH.
|
|
func (e CFEventECHClientStatus) Greased() bool {
|
|
return e == echStatusOuter
|
|
}
|
|
|
|
// Name is required by the CFEvent interface.
|
|
func (e CFEventECHClientStatus) Name() string {
|
|
return "ech client status"
|
|
}
|
|
|
|
// CFEventECHServerStatus is emitted once it is known whether the client
|
|
// bypassed, offered, or greased ECH.
|
|
type CFEventECHServerStatus int
|
|
|
|
// Bypassed returns true if the client bypassed ECH.
|
|
func (e CFEventECHServerStatus) Bypassed() bool {
|
|
return e == echStatusBypassed
|
|
}
|
|
|
|
// Accepted returns true if the client offered ECH.
|
|
func (e CFEventECHServerStatus) Accepted() bool {
|
|
return e == echStatusInner
|
|
}
|
|
|
|
// Rejected returns true if the client greased ECH.
|
|
func (e CFEventECHServerStatus) Rejected() bool {
|
|
return e == echStatusOuter
|
|
}
|
|
|
|
// Name is required by the CFEvent interface.
|
|
func (e CFEventECHServerStatus) Name() string {
|
|
return "ech server status"
|
|
}
|
|
|
|
// CFEventECHPublicNameMismatch is emitted if the outer SNI does not match
|
|
// match the public name of the ECH configuration. Note that we do not record
|
|
// the outer SNI in order to avoid collecting this potentially sensitive data.
|
|
type CFEventECHPublicNameMismatch struct{}
|
|
|
|
// Name is required by the CFEvent interface.
|
|
func (e CFEventECHPublicNameMismatch) Name() string {
|
|
return "ech public name does not match outer sni"
|
|
}
|
|
|
|
// For backwards compatibility.
|
|
type CFEventTLS13NegotiatedKEX = CFEventTLSNegotiatedNamedKEX
|
|
|
|
// CFEventTLSNegotiatedNamedKEX is emitted when a key agreement mechanism has been
|
|
// established that uses a named group. This includes all key agreements
|
|
// in TLSv1.3, but excludes RSA and DH in TLS 1.2 and earlier.
|
|
type CFEventTLSNegotiatedNamedKEX struct {
|
|
KEX CurveID
|
|
}
|
|
|
|
func (e CFEventTLSNegotiatedNamedKEX) Name() string {
|
|
return "CFEventTLSNegotiatedNamedKEX"
|
|
}
|
|
|
|
// CFEventTLS13HRR is emitted when a HRR is sent or received
|
|
type CFEventTLS13HRR struct{}
|
|
|
|
func (e CFEventTLS13HRR) Name() string {
|
|
return "CFEventTLS13HRR"
|
|
}
|