mirror of
https://github.com/XTLS/Xray-core.git
synced 2025-05-02 02:14:16 +00:00
v1.0.0
This commit is contained in:
parent
47d23e9972
commit
c7f7c08ead
711 changed files with 82154 additions and 2 deletions
241
transport/internet/xtls/config.go
Normal file
241
transport/internet/xtls/config.go
Normal file
|
@ -0,0 +1,241 @@
|
|||
// +build !confonly
|
||||
|
||||
package xtls
|
||||
|
||||
import (
|
||||
"crypto/x509"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
xtls "github.com/xtls/go"
|
||||
|
||||
"github.com/xtls/xray-core/v1/common/net"
|
||||
"github.com/xtls/xray-core/v1/common/protocol/tls/cert"
|
||||
"github.com/xtls/xray-core/v1/transport/internet"
|
||||
)
|
||||
|
||||
var (
|
||||
globalSessionCache = xtls.NewLRUClientSessionCache(128)
|
||||
)
|
||||
|
||||
// ParseCertificate converts a cert.Certificate to Certificate.
|
||||
func ParseCertificate(c *cert.Certificate) *Certificate {
|
||||
if c != nil {
|
||||
certPEM, keyPEM := c.ToPEM()
|
||||
return &Certificate{
|
||||
Certificate: certPEM,
|
||||
Key: keyPEM,
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Config) loadSelfCertPool() (*x509.CertPool, error) {
|
||||
root := x509.NewCertPool()
|
||||
for _, cert := range c.Certificate {
|
||||
if !root.AppendCertsFromPEM(cert.Certificate) {
|
||||
return nil, newError("failed to append cert").AtWarning()
|
||||
}
|
||||
}
|
||||
return root, nil
|
||||
}
|
||||
|
||||
// BuildCertificates builds a list of TLS certificates from proto definition.
|
||||
func (c *Config) BuildCertificates() []xtls.Certificate {
|
||||
certs := make([]xtls.Certificate, 0, len(c.Certificate))
|
||||
for _, entry := range c.Certificate {
|
||||
if entry.Usage != Certificate_ENCIPHERMENT {
|
||||
continue
|
||||
}
|
||||
keyPair, err := xtls.X509KeyPair(entry.Certificate, entry.Key)
|
||||
if err != nil {
|
||||
newError("ignoring invalid X509 key pair").Base(err).AtWarning().WriteToLog()
|
||||
continue
|
||||
}
|
||||
certs = append(certs, keyPair)
|
||||
}
|
||||
return certs
|
||||
}
|
||||
|
||||
func isCertificateExpired(c *xtls.Certificate) bool {
|
||||
if c.Leaf == nil && len(c.Certificate) > 0 {
|
||||
if pc, err := x509.ParseCertificate(c.Certificate[0]); err == nil {
|
||||
c.Leaf = pc
|
||||
}
|
||||
}
|
||||
|
||||
// If leaf is not there, the certificate is probably not used yet. We trust user to provide a valid certificate.
|
||||
return c.Leaf != nil && c.Leaf.NotAfter.Before(time.Now().Add(-time.Minute))
|
||||
}
|
||||
|
||||
func issueCertificate(rawCA *Certificate, domain string) (*xtls.Certificate, error) {
|
||||
parent, err := cert.ParseCertificate(rawCA.Certificate, rawCA.Key)
|
||||
if err != nil {
|
||||
return nil, newError("failed to parse raw certificate").Base(err)
|
||||
}
|
||||
newCert, err := cert.Generate(parent, cert.CommonName(domain), cert.DNSNames(domain))
|
||||
if err != nil {
|
||||
return nil, newError("failed to generate new certificate for ", domain).Base(err)
|
||||
}
|
||||
newCertPEM, newKeyPEM := newCert.ToPEM()
|
||||
cert, err := xtls.X509KeyPair(newCertPEM, newKeyPEM)
|
||||
return &cert, err
|
||||
}
|
||||
|
||||
func (c *Config) getCustomCA() []*Certificate {
|
||||
certs := make([]*Certificate, 0, len(c.Certificate))
|
||||
for _, certificate := range c.Certificate {
|
||||
if certificate.Usage == Certificate_AUTHORITY_ISSUE {
|
||||
certs = append(certs, certificate)
|
||||
}
|
||||
}
|
||||
return certs
|
||||
}
|
||||
|
||||
func getGetCertificateFunc(c *xtls.Config, ca []*Certificate) func(hello *xtls.ClientHelloInfo) (*xtls.Certificate, error) {
|
||||
var access sync.RWMutex
|
||||
|
||||
return func(hello *xtls.ClientHelloInfo) (*xtls.Certificate, error) {
|
||||
domain := hello.ServerName
|
||||
certExpired := false
|
||||
|
||||
access.RLock()
|
||||
certificate, found := c.NameToCertificate[domain]
|
||||
access.RUnlock()
|
||||
|
||||
if found {
|
||||
if !isCertificateExpired(certificate) {
|
||||
return certificate, nil
|
||||
}
|
||||
certExpired = true
|
||||
}
|
||||
|
||||
if certExpired {
|
||||
newCerts := make([]xtls.Certificate, 0, len(c.Certificates))
|
||||
|
||||
access.Lock()
|
||||
for _, certificate := range c.Certificates {
|
||||
if !isCertificateExpired(&certificate) {
|
||||
newCerts = append(newCerts, certificate)
|
||||
}
|
||||
}
|
||||
|
||||
c.Certificates = newCerts
|
||||
access.Unlock()
|
||||
}
|
||||
|
||||
var issuedCertificate *xtls.Certificate
|
||||
|
||||
// Create a new certificate from existing CA if possible
|
||||
for _, rawCert := range ca {
|
||||
if rawCert.Usage == Certificate_AUTHORITY_ISSUE {
|
||||
newCert, err := issueCertificate(rawCert, domain)
|
||||
if err != nil {
|
||||
newError("failed to issue new certificate for ", domain).Base(err).WriteToLog()
|
||||
continue
|
||||
}
|
||||
|
||||
access.Lock()
|
||||
c.Certificates = append(c.Certificates, *newCert)
|
||||
issuedCertificate = &c.Certificates[len(c.Certificates)-1]
|
||||
access.Unlock()
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if issuedCertificate == nil {
|
||||
return nil, newError("failed to create a new certificate for ", domain)
|
||||
}
|
||||
|
||||
access.Lock()
|
||||
c.BuildNameToCertificate()
|
||||
access.Unlock()
|
||||
|
||||
return issuedCertificate, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Config) parseServerName() string {
|
||||
return c.ServerName
|
||||
}
|
||||
|
||||
// GetXTLSConfig converts this Config into xtls.Config.
|
||||
func (c *Config) GetXTLSConfig(opts ...Option) *xtls.Config {
|
||||
root, err := c.getCertPool()
|
||||
if err != nil {
|
||||
newError("failed to load system root certificate").AtError().Base(err).WriteToLog()
|
||||
}
|
||||
|
||||
if c == nil {
|
||||
return &xtls.Config{
|
||||
ClientSessionCache: globalSessionCache,
|
||||
RootCAs: root,
|
||||
InsecureSkipVerify: false,
|
||||
NextProtos: nil,
|
||||
SessionTicketsDisabled: false,
|
||||
}
|
||||
}
|
||||
|
||||
config := &xtls.Config{
|
||||
ClientSessionCache: globalSessionCache,
|
||||
RootCAs: root,
|
||||
InsecureSkipVerify: c.AllowInsecure,
|
||||
NextProtos: c.NextProtocol,
|
||||
SessionTicketsDisabled: c.DisableSessionResumption,
|
||||
}
|
||||
|
||||
for _, opt := range opts {
|
||||
opt(config)
|
||||
}
|
||||
|
||||
config.Certificates = c.BuildCertificates()
|
||||
config.BuildNameToCertificate()
|
||||
|
||||
caCerts := c.getCustomCA()
|
||||
if len(caCerts) > 0 {
|
||||
config.GetCertificate = getGetCertificateFunc(config, caCerts)
|
||||
}
|
||||
|
||||
if sn := c.parseServerName(); len(sn) > 0 {
|
||||
config.ServerName = sn
|
||||
}
|
||||
|
||||
if len(config.NextProtos) == 0 {
|
||||
config.NextProtos = []string{"h2", "http/1.1"}
|
||||
}
|
||||
|
||||
return config
|
||||
}
|
||||
|
||||
// Option for building XTLS config.
|
||||
type Option func(*xtls.Config)
|
||||
|
||||
// WithDestination sets the server name in XTLS config.
|
||||
func WithDestination(dest net.Destination) Option {
|
||||
return func(config *xtls.Config) {
|
||||
if dest.Address.Family().IsDomain() && config.ServerName == "" {
|
||||
config.ServerName = dest.Address.Domain()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WithNextProto sets the ALPN values in XTLS config.
|
||||
func WithNextProto(protocol ...string) Option {
|
||||
return func(config *xtls.Config) {
|
||||
if len(config.NextProtos) == 0 {
|
||||
config.NextProtos = protocol
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ConfigFromStreamSettings fetches Config from stream settings. Nil if not found.
|
||||
func ConfigFromStreamSettings(settings *internet.MemoryStreamConfig) *Config {
|
||||
if settings == nil {
|
||||
return nil
|
||||
}
|
||||
config, ok := settings.SecuritySettings.(*Config)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
return config
|
||||
}
|
378
transport/internet/xtls/config.pb.go
Normal file
378
transport/internet/xtls/config.pb.go
Normal file
|
@ -0,0 +1,378 @@
|
|||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.25.0
|
||||
// protoc v3.14.0
|
||||
// source: transport/internet/xtls/config.proto
|
||||
|
||||
package xtls
|
||||
|
||||
import (
|
||||
proto "github.com/golang/protobuf/proto"
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
// This is a compile-time assertion that a sufficiently up-to-date version
|
||||
// of the legacy proto package is being used.
|
||||
const _ = proto.ProtoPackageIsVersion4
|
||||
|
||||
type Certificate_Usage int32
|
||||
|
||||
const (
|
||||
Certificate_ENCIPHERMENT Certificate_Usage = 0
|
||||
Certificate_AUTHORITY_VERIFY Certificate_Usage = 1
|
||||
Certificate_AUTHORITY_ISSUE Certificate_Usage = 2
|
||||
)
|
||||
|
||||
// Enum value maps for Certificate_Usage.
|
||||
var (
|
||||
Certificate_Usage_name = map[int32]string{
|
||||
0: "ENCIPHERMENT",
|
||||
1: "AUTHORITY_VERIFY",
|
||||
2: "AUTHORITY_ISSUE",
|
||||
}
|
||||
Certificate_Usage_value = map[string]int32{
|
||||
"ENCIPHERMENT": 0,
|
||||
"AUTHORITY_VERIFY": 1,
|
||||
"AUTHORITY_ISSUE": 2,
|
||||
}
|
||||
)
|
||||
|
||||
func (x Certificate_Usage) Enum() *Certificate_Usage {
|
||||
p := new(Certificate_Usage)
|
||||
*p = x
|
||||
return p
|
||||
}
|
||||
|
||||
func (x Certificate_Usage) String() string {
|
||||
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
|
||||
}
|
||||
|
||||
func (Certificate_Usage) Descriptor() protoreflect.EnumDescriptor {
|
||||
return file_transport_internet_xtls_config_proto_enumTypes[0].Descriptor()
|
||||
}
|
||||
|
||||
func (Certificate_Usage) Type() protoreflect.EnumType {
|
||||
return &file_transport_internet_xtls_config_proto_enumTypes[0]
|
||||
}
|
||||
|
||||
func (x Certificate_Usage) Number() protoreflect.EnumNumber {
|
||||
return protoreflect.EnumNumber(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use Certificate_Usage.Descriptor instead.
|
||||
func (Certificate_Usage) EnumDescriptor() ([]byte, []int) {
|
||||
return file_transport_internet_xtls_config_proto_rawDescGZIP(), []int{0, 0}
|
||||
}
|
||||
|
||||
type Certificate struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
// XTLS certificate in x509 format.
|
||||
Certificate []byte `protobuf:"bytes,1,opt,name=Certificate,proto3" json:"Certificate,omitempty"`
|
||||
// XTLS key in x509 format.
|
||||
Key []byte `protobuf:"bytes,2,opt,name=Key,proto3" json:"Key,omitempty"`
|
||||
Usage Certificate_Usage `protobuf:"varint,3,opt,name=usage,proto3,enum=xray.transport.internet.xtls.Certificate_Usage" json:"usage,omitempty"`
|
||||
}
|
||||
|
||||
func (x *Certificate) Reset() {
|
||||
*x = Certificate{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_transport_internet_xtls_config_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *Certificate) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*Certificate) ProtoMessage() {}
|
||||
|
||||
func (x *Certificate) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_transport_internet_xtls_config_proto_msgTypes[0]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use Certificate.ProtoReflect.Descriptor instead.
|
||||
func (*Certificate) Descriptor() ([]byte, []int) {
|
||||
return file_transport_internet_xtls_config_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *Certificate) GetCertificate() []byte {
|
||||
if x != nil {
|
||||
return x.Certificate
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *Certificate) GetKey() []byte {
|
||||
if x != nil {
|
||||
return x.Key
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *Certificate) GetUsage() Certificate_Usage {
|
||||
if x != nil {
|
||||
return x.Usage
|
||||
}
|
||||
return Certificate_ENCIPHERMENT
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
// Whether or not to allow self-signed certificates.
|
||||
AllowInsecure bool `protobuf:"varint,1,opt,name=allow_insecure,json=allowInsecure,proto3" json:"allow_insecure,omitempty"`
|
||||
// Whether or not to allow insecure cipher suites.
|
||||
AllowInsecureCiphers bool `protobuf:"varint,5,opt,name=allow_insecure_ciphers,json=allowInsecureCiphers,proto3" json:"allow_insecure_ciphers,omitempty"`
|
||||
// List of certificates to be served on server.
|
||||
Certificate []*Certificate `protobuf:"bytes,2,rep,name=certificate,proto3" json:"certificate,omitempty"`
|
||||
// Override server name.
|
||||
ServerName string `protobuf:"bytes,3,opt,name=server_name,json=serverName,proto3" json:"server_name,omitempty"`
|
||||
// Lists of string as ALPN values.
|
||||
NextProtocol []string `protobuf:"bytes,4,rep,name=next_protocol,json=nextProtocol,proto3" json:"next_protocol,omitempty"`
|
||||
// Whether or not to disable session (ticket) resumption.
|
||||
DisableSessionResumption bool `protobuf:"varint,6,opt,name=disable_session_resumption,json=disableSessionResumption,proto3" json:"disable_session_resumption,omitempty"`
|
||||
// If true, root certificates on the system will not be loaded for
|
||||
// verification.
|
||||
DisableSystemRoot bool `protobuf:"varint,7,opt,name=disable_system_root,json=disableSystemRoot,proto3" json:"disable_system_root,omitempty"`
|
||||
}
|
||||
|
||||
func (x *Config) Reset() {
|
||||
*x = Config{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_transport_internet_xtls_config_proto_msgTypes[1]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *Config) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*Config) ProtoMessage() {}
|
||||
|
||||
func (x *Config) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_transport_internet_xtls_config_proto_msgTypes[1]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use Config.ProtoReflect.Descriptor instead.
|
||||
func (*Config) Descriptor() ([]byte, []int) {
|
||||
return file_transport_internet_xtls_config_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
func (x *Config) GetAllowInsecure() bool {
|
||||
if x != nil {
|
||||
return x.AllowInsecure
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (x *Config) GetAllowInsecureCiphers() bool {
|
||||
if x != nil {
|
||||
return x.AllowInsecureCiphers
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (x *Config) GetCertificate() []*Certificate {
|
||||
if x != nil {
|
||||
return x.Certificate
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *Config) GetServerName() string {
|
||||
if x != nil {
|
||||
return x.ServerName
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *Config) GetNextProtocol() []string {
|
||||
if x != nil {
|
||||
return x.NextProtocol
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *Config) GetDisableSessionResumption() bool {
|
||||
if x != nil {
|
||||
return x.DisableSessionResumption
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (x *Config) GetDisableSystemRoot() bool {
|
||||
if x != nil {
|
||||
return x.DisableSystemRoot
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
var File_transport_internet_xtls_config_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_transport_internet_xtls_config_proto_rawDesc = []byte{
|
||||
0x0a, 0x24, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65,
|
||||
0x72, 0x6e, 0x65, 0x74, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67,
|
||||
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1c, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61,
|
||||
0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e,
|
||||
0x78, 0x74, 0x6c, 0x73, 0x22, 0xce, 0x01, 0x0a, 0x0b, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69,
|
||||
0x63, 0x61, 0x74, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63,
|
||||
0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x43, 0x65, 0x72, 0x74, 0x69,
|
||||
0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20,
|
||||
0x01, 0x28, 0x0c, 0x52, 0x03, 0x4b, 0x65, 0x79, 0x12, 0x45, 0x0a, 0x05, 0x75, 0x73, 0x61, 0x67,
|
||||
0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2f, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74,
|
||||
0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65,
|
||||
0x74, 0x2e, 0x78, 0x74, 0x6c, 0x73, 0x2e, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61,
|
||||
0x74, 0x65, 0x2e, 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x05, 0x75, 0x73, 0x61, 0x67, 0x65, 0x22,
|
||||
0x44, 0x0a, 0x05, 0x55, 0x73, 0x61, 0x67, 0x65, 0x12, 0x10, 0x0a, 0x0c, 0x45, 0x4e, 0x43, 0x49,
|
||||
0x50, 0x48, 0x45, 0x52, 0x4d, 0x45, 0x4e, 0x54, 0x10, 0x00, 0x12, 0x14, 0x0a, 0x10, 0x41, 0x55,
|
||||
0x54, 0x48, 0x4f, 0x52, 0x49, 0x54, 0x59, 0x5f, 0x56, 0x45, 0x52, 0x49, 0x46, 0x59, 0x10, 0x01,
|
||||
0x12, 0x13, 0x0a, 0x0f, 0x41, 0x55, 0x54, 0x48, 0x4f, 0x52, 0x49, 0x54, 0x59, 0x5f, 0x49, 0x53,
|
||||
0x53, 0x55, 0x45, 0x10, 0x02, 0x22, 0xe6, 0x02, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
|
||||
0x12, 0x25, 0x0a, 0x0e, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x5f, 0x69, 0x6e, 0x73, 0x65, 0x63, 0x75,
|
||||
0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x49,
|
||||
0x6e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x12, 0x34, 0x0a, 0x16, 0x61, 0x6c, 0x6c, 0x6f, 0x77,
|
||||
0x5f, 0x69, 0x6e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x5f, 0x63, 0x69, 0x70, 0x68, 0x65, 0x72,
|
||||
0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x14, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x49, 0x6e,
|
||||
0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x43, 0x69, 0x70, 0x68, 0x65, 0x72, 0x73, 0x12, 0x4b, 0x0a,
|
||||
0x0b, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x03,
|
||||
0x28, 0x0b, 0x32, 0x29, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70,
|
||||
0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x78, 0x74, 0x6c,
|
||||
0x73, 0x2e, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x52, 0x0b, 0x63,
|
||||
0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x65,
|
||||
0x72, 0x76, 0x65, 0x72, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x0a, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x6e,
|
||||
0x65, 0x78, 0x74, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x04, 0x20, 0x03,
|
||||
0x28, 0x09, 0x52, 0x0c, 0x6e, 0x65, 0x78, 0x74, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c,
|
||||
0x12, 0x3c, 0x0a, 0x1a, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x73, 0x65, 0x73, 0x73,
|
||||
0x69, 0x6f, 0x6e, 0x5f, 0x72, 0x65, 0x73, 0x75, 0x6d, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x06,
|
||||
0x20, 0x01, 0x28, 0x08, 0x52, 0x18, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x53, 0x65, 0x73,
|
||||
0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x75, 0x6d, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2e,
|
||||
0x0a, 0x13, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d,
|
||||
0x5f, 0x72, 0x6f, 0x6f, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x64, 0x69, 0x73,
|
||||
0x61, 0x62, 0x6c, 0x65, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x52, 0x6f, 0x6f, 0x74, 0x42, 0x79,
|
||||
0x0a, 0x20, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73,
|
||||
0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x78, 0x74,
|
||||
0x6c, 0x73, 0x50, 0x01, 0x5a, 0x34, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d,
|
||||
0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f,
|
||||
0x76, 0x31, 0x2f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x69, 0x6e, 0x74,
|
||||
0x65, 0x72, 0x6e, 0x65, 0x74, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0xaa, 0x02, 0x1c, 0x58, 0x72, 0x61,
|
||||
0x79, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x49, 0x6e, 0x74, 0x65,
|
||||
0x72, 0x6e, 0x65, 0x74, 0x2e, 0x58, 0x74, 0x6c, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||
0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
file_transport_internet_xtls_config_proto_rawDescOnce sync.Once
|
||||
file_transport_internet_xtls_config_proto_rawDescData = file_transport_internet_xtls_config_proto_rawDesc
|
||||
)
|
||||
|
||||
func file_transport_internet_xtls_config_proto_rawDescGZIP() []byte {
|
||||
file_transport_internet_xtls_config_proto_rawDescOnce.Do(func() {
|
||||
file_transport_internet_xtls_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_transport_internet_xtls_config_proto_rawDescData)
|
||||
})
|
||||
return file_transport_internet_xtls_config_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_transport_internet_xtls_config_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
|
||||
var file_transport_internet_xtls_config_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
|
||||
var file_transport_internet_xtls_config_proto_goTypes = []interface{}{
|
||||
(Certificate_Usage)(0), // 0: xray.transport.internet.xtls.Certificate.Usage
|
||||
(*Certificate)(nil), // 1: xray.transport.internet.xtls.Certificate
|
||||
(*Config)(nil), // 2: xray.transport.internet.xtls.Config
|
||||
}
|
||||
var file_transport_internet_xtls_config_proto_depIdxs = []int32{
|
||||
0, // 0: xray.transport.internet.xtls.Certificate.usage:type_name -> xray.transport.internet.xtls.Certificate.Usage
|
||||
1, // 1: xray.transport.internet.xtls.Config.certificate:type_name -> xray.transport.internet.xtls.Certificate
|
||||
2, // [2:2] is the sub-list for method output_type
|
||||
2, // [2:2] is the sub-list for method input_type
|
||||
2, // [2:2] is the sub-list for extension type_name
|
||||
2, // [2:2] is the sub-list for extension extendee
|
||||
0, // [0:2] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_transport_internet_xtls_config_proto_init() }
|
||||
func file_transport_internet_xtls_config_proto_init() {
|
||||
if File_transport_internet_xtls_config_proto != nil {
|
||||
return
|
||||
}
|
||||
if !protoimpl.UnsafeEnabled {
|
||||
file_transport_internet_xtls_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*Certificate); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_transport_internet_xtls_config_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*Config); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_transport_internet_xtls_config_proto_rawDesc,
|
||||
NumEnums: 1,
|
||||
NumMessages: 2,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
GoTypes: file_transport_internet_xtls_config_proto_goTypes,
|
||||
DependencyIndexes: file_transport_internet_xtls_config_proto_depIdxs,
|
||||
EnumInfos: file_transport_internet_xtls_config_proto_enumTypes,
|
||||
MessageInfos: file_transport_internet_xtls_config_proto_msgTypes,
|
||||
}.Build()
|
||||
File_transport_internet_xtls_config_proto = out.File
|
||||
file_transport_internet_xtls_config_proto_rawDesc = nil
|
||||
file_transport_internet_xtls_config_proto_goTypes = nil
|
||||
file_transport_internet_xtls_config_proto_depIdxs = nil
|
||||
}
|
47
transport/internet/xtls/config.proto
Normal file
47
transport/internet/xtls/config.proto
Normal file
|
@ -0,0 +1,47 @@
|
|||
syntax = "proto3";
|
||||
|
||||
package xray.transport.internet.xtls;
|
||||
option csharp_namespace = "Xray.Transport.Internet.Xtls";
|
||||
option go_package = "github.com/xtls/xray-core/v1/transport/internet/xtls";
|
||||
option java_package = "com.xray.transport.internet.xtls";
|
||||
option java_multiple_files = true;
|
||||
|
||||
message Certificate {
|
||||
// XTLS certificate in x509 format.
|
||||
bytes Certificate = 1;
|
||||
|
||||
// XTLS key in x509 format.
|
||||
bytes Key = 2;
|
||||
|
||||
enum Usage {
|
||||
ENCIPHERMENT = 0;
|
||||
AUTHORITY_VERIFY = 1;
|
||||
AUTHORITY_ISSUE = 2;
|
||||
}
|
||||
|
||||
Usage usage = 3;
|
||||
}
|
||||
|
||||
message Config {
|
||||
// Whether or not to allow self-signed certificates.
|
||||
bool allow_insecure = 1;
|
||||
|
||||
// Whether or not to allow insecure cipher suites.
|
||||
bool allow_insecure_ciphers = 5;
|
||||
|
||||
// List of certificates to be served on server.
|
||||
repeated Certificate certificate = 2;
|
||||
|
||||
// Override server name.
|
||||
string server_name = 3;
|
||||
|
||||
// Lists of string as ALPN values.
|
||||
repeated string next_protocol = 4;
|
||||
|
||||
// Whether or not to disable session (ticket) resumption.
|
||||
bool disable_session_resumption = 6;
|
||||
|
||||
// If true, root certificates on the system will not be loaded for
|
||||
// verification.
|
||||
bool disable_system_root = 7;
|
||||
}
|
53
transport/internet/xtls/config_other.go
Normal file
53
transport/internet/xtls/config_other.go
Normal file
|
@ -0,0 +1,53 @@
|
|||
// +build !windows
|
||||
// +build !confonly
|
||||
|
||||
package xtls
|
||||
|
||||
import (
|
||||
"crypto/x509"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type rootCertsCache struct {
|
||||
sync.Mutex
|
||||
pool *x509.CertPool
|
||||
}
|
||||
|
||||
func (c *rootCertsCache) load() (*x509.CertPool, error) {
|
||||
c.Lock()
|
||||
defer c.Unlock()
|
||||
|
||||
if c.pool != nil {
|
||||
return c.pool, nil
|
||||
}
|
||||
|
||||
pool, err := x509.SystemCertPool()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c.pool = pool
|
||||
return pool, nil
|
||||
}
|
||||
|
||||
var rootCerts rootCertsCache
|
||||
|
||||
func (c *Config) getCertPool() (*x509.CertPool, error) {
|
||||
if c.DisableSystemRoot {
|
||||
return c.loadSelfCertPool()
|
||||
}
|
||||
|
||||
if len(c.Certificate) == 0 {
|
||||
return rootCerts.load()
|
||||
}
|
||||
|
||||
pool, err := x509.SystemCertPool()
|
||||
if err != nil {
|
||||
return nil, newError("system root").AtWarning().Base(err)
|
||||
}
|
||||
for _, cert := range c.Certificate {
|
||||
if !pool.AppendCertsFromPEM(cert.Certificate) {
|
||||
return nil, newError("append cert to root").AtWarning().Base(err)
|
||||
}
|
||||
}
|
||||
return pool, err
|
||||
}
|
100
transport/internet/xtls/config_test.go
Normal file
100
transport/internet/xtls/config_test.go
Normal file
|
@ -0,0 +1,100 @@
|
|||
package xtls_test
|
||||
|
||||
import (
|
||||
"crypto/x509"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
xtls "github.com/xtls/go"
|
||||
|
||||
"github.com/xtls/xray-core/v1/common"
|
||||
"github.com/xtls/xray-core/v1/common/protocol/tls/cert"
|
||||
. "github.com/xtls/xray-core/v1/transport/internet/xtls"
|
||||
)
|
||||
|
||||
func TestCertificateIssuing(t *testing.T) {
|
||||
certificate := ParseCertificate(cert.MustGenerate(nil, cert.Authority(true), cert.KeyUsage(x509.KeyUsageCertSign)))
|
||||
certificate.Usage = Certificate_AUTHORITY_ISSUE
|
||||
|
||||
c := &Config{
|
||||
Certificate: []*Certificate{
|
||||
certificate,
|
||||
},
|
||||
}
|
||||
|
||||
xtlsConfig := c.GetXTLSConfig()
|
||||
xrayCert, err := xtlsConfig.GetCertificate(&xtls.ClientHelloInfo{
|
||||
ServerName: "www.example.com",
|
||||
})
|
||||
common.Must(err)
|
||||
|
||||
x509Cert, err := x509.ParseCertificate(xrayCert.Certificate[0])
|
||||
common.Must(err)
|
||||
if !x509Cert.NotAfter.After(time.Now()) {
|
||||
t.Error("NotAfter: ", x509Cert.NotAfter)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExpiredCertificate(t *testing.T) {
|
||||
caCert := cert.MustGenerate(nil, cert.Authority(true), cert.KeyUsage(x509.KeyUsageCertSign))
|
||||
expiredCert := cert.MustGenerate(caCert, cert.NotAfter(time.Now().Add(time.Minute*-2)), cert.CommonName("www.example.com"), cert.DNSNames("www.example.com"))
|
||||
|
||||
certificate := ParseCertificate(caCert)
|
||||
certificate.Usage = Certificate_AUTHORITY_ISSUE
|
||||
|
||||
certificate2 := ParseCertificate(expiredCert)
|
||||
|
||||
c := &Config{
|
||||
Certificate: []*Certificate{
|
||||
certificate,
|
||||
certificate2,
|
||||
},
|
||||
}
|
||||
|
||||
xtlsConfig := c.GetXTLSConfig()
|
||||
xrayCert, err := xtlsConfig.GetCertificate(&xtls.ClientHelloInfo{
|
||||
ServerName: "www.example.com",
|
||||
})
|
||||
common.Must(err)
|
||||
|
||||
x509Cert, err := x509.ParseCertificate(xrayCert.Certificate[0])
|
||||
common.Must(err)
|
||||
if !x509Cert.NotAfter.After(time.Now()) {
|
||||
t.Error("NotAfter: ", x509Cert.NotAfter)
|
||||
}
|
||||
}
|
||||
|
||||
func TestInsecureCertificates(t *testing.T) {
|
||||
c := &Config{
|
||||
AllowInsecureCiphers: true,
|
||||
}
|
||||
|
||||
xtlsConfig := c.GetXTLSConfig()
|
||||
if len(xtlsConfig.CipherSuites) > 0 {
|
||||
t.Fatal("Unexpected tls cipher suites list: ", xtlsConfig.CipherSuites)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkCertificateIssuing(b *testing.B) {
|
||||
certificate := ParseCertificate(cert.MustGenerate(nil, cert.Authority(true), cert.KeyUsage(x509.KeyUsageCertSign)))
|
||||
certificate.Usage = Certificate_AUTHORITY_ISSUE
|
||||
|
||||
c := &Config{
|
||||
Certificate: []*Certificate{
|
||||
certificate,
|
||||
},
|
||||
}
|
||||
|
||||
xtlsConfig := c.GetXTLSConfig()
|
||||
lenCerts := len(xtlsConfig.Certificates)
|
||||
|
||||
b.ResetTimer()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, _ = xtlsConfig.GetCertificate(&xtls.ClientHelloInfo{
|
||||
ServerName: "www.example.com",
|
||||
})
|
||||
delete(xtlsConfig.NameToCertificate, "www.example.com")
|
||||
xtlsConfig.Certificates = xtlsConfig.Certificates[:lenCerts]
|
||||
}
|
||||
}
|
14
transport/internet/xtls/config_windows.go
Normal file
14
transport/internet/xtls/config_windows.go
Normal file
|
@ -0,0 +1,14 @@
|
|||
// +build windows
|
||||
// +build !confonly
|
||||
|
||||
package xtls
|
||||
|
||||
import "crypto/x509"
|
||||
|
||||
func (c *Config) getCertPool() (*x509.CertPool, error) {
|
||||
if c.DisableSystemRoot {
|
||||
return c.loadSelfCertPool()
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
9
transport/internet/xtls/errors.generated.go
Normal file
9
transport/internet/xtls/errors.generated.go
Normal file
|
@ -0,0 +1,9 @@
|
|||
package xtls
|
||||
|
||||
import "github.com/xtls/xray-core/v1/common/errors"
|
||||
|
||||
type errPathObjHolder struct{}
|
||||
|
||||
func newError(values ...interface{}) *errors.Error {
|
||||
return errors.New(values...).WithPathObj(errPathObjHolder{})
|
||||
}
|
38
transport/internet/xtls/xtls.go
Normal file
38
transport/internet/xtls/xtls.go
Normal file
|
@ -0,0 +1,38 @@
|
|||
// +build !confonly
|
||||
|
||||
package xtls
|
||||
|
||||
import (
|
||||
xtls "github.com/xtls/go"
|
||||
|
||||
"github.com/xtls/xray-core/v1/common/net"
|
||||
)
|
||||
|
||||
//go:generate go run github.com/xtls/xray-core/v1/common/errors/errorgen
|
||||
|
||||
type Conn struct {
|
||||
*xtls.Conn
|
||||
}
|
||||
|
||||
func (c *Conn) HandshakeAddress() net.Address {
|
||||
if err := c.Handshake(); err != nil {
|
||||
return nil
|
||||
}
|
||||
state := c.ConnectionState()
|
||||
if state.ServerName == "" {
|
||||
return nil
|
||||
}
|
||||
return net.ParseAddress(state.ServerName)
|
||||
}
|
||||
|
||||
// Client initiates a XTLS client handshake on the given connection.
|
||||
func Client(c net.Conn, config *xtls.Config) net.Conn {
|
||||
xtlsConn := xtls.Client(c, config)
|
||||
return &Conn{Conn: xtlsConn}
|
||||
}
|
||||
|
||||
// Server initiates a XTLS server handshake on the given connection.
|
||||
func Server(c net.Conn, config *xtls.Config) net.Conn {
|
||||
xtlsConn := xtls.Server(c, config)
|
||||
return &Conn{Conn: xtlsConn}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue