From 97286eea1e53ea7dff0fe1feb386abc6557f8d36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Sat, 21 Oct 2023 12:00:00 +0800 Subject: [PATCH] Add TLS self sign generate command --- cmd/sing-box/cmd_generate.go | 49 +-------------------- cmd/sing-box/cmd_generate_tls.go | 40 +++++++++++++++++ cmd/sing-box/cmd_generate_vapid.go | 40 +++++++++++++++++ cmd/sing-box/cmd_generate_wireguard.go | 61 ++++++++++++++++++++++++++ common/tls/mkcert.go | 34 ++++++++------ common/tls/std_server.go | 2 +- 6 files changed, 164 insertions(+), 62 deletions(-) create mode 100644 cmd/sing-box/cmd_generate_tls.go create mode 100644 cmd/sing-box/cmd_generate_vapid.go create mode 100644 cmd/sing-box/cmd_generate_wireguard.go diff --git a/cmd/sing-box/cmd_generate.go b/cmd/sing-box/cmd_generate.go index cf00d58a..74d64c55 100644 --- a/cmd/sing-box/cmd_generate.go +++ b/cmd/sing-box/cmd_generate.go @@ -11,7 +11,6 @@ import ( "github.com/gofrs/uuid/v5" "github.com/spf13/cobra" - "golang.zx2c4.com/wireguard/wgctrl/wgtypes" ) var commandGenerate = &cobra.Command{ @@ -22,8 +21,7 @@ var commandGenerate = &cobra.Command{ func init() { commandGenerate.AddCommand(commandGenerateUUID) commandGenerate.AddCommand(commandGenerateRandom) - commandGenerate.AddCommand(commandGenerateWireGuardKeyPair) - commandGenerate.AddCommand(commandGenerateRealityKeyPair) + mainCommand.AddCommand(commandGenerate) } @@ -92,48 +90,3 @@ func generateUUID() error { _, err = os.Stdout.WriteString(newUUID.String() + "\n") return err } - -var commandGenerateWireGuardKeyPair = &cobra.Command{ - Use: "wg-keypair", - Short: "Generate WireGuard key pair", - Args: cobra.NoArgs, - Run: func(cmd *cobra.Command, args []string) { - err := generateWireGuardKey() - if err != nil { - log.Fatal(err) - } - }, -} - -func generateWireGuardKey() error { - privateKey, err := wgtypes.GeneratePrivateKey() - if err != nil { - return err - } - os.Stdout.WriteString("PrivateKey: " + privateKey.String() + "\n") - os.Stdout.WriteString("PublicKey: " + privateKey.PublicKey().String() + "\n") - return nil -} - -var commandGenerateRealityKeyPair = &cobra.Command{ - Use: "reality-keypair", - Short: "Generate reality key pair", - Args: cobra.NoArgs, - Run: func(cmd *cobra.Command, args []string) { - err := generateRealityKey() - if err != nil { - log.Fatal(err) - } - }, -} - -func generateRealityKey() error { - privateKey, err := wgtypes.GeneratePrivateKey() - if err != nil { - return err - } - publicKey := privateKey.PublicKey() - os.Stdout.WriteString("PrivateKey: " + base64.RawURLEncoding.EncodeToString(privateKey[:]) + "\n") - os.Stdout.WriteString("PublicKey: " + base64.RawURLEncoding.EncodeToString(publicKey[:]) + "\n") - return nil -} diff --git a/cmd/sing-box/cmd_generate_tls.go b/cmd/sing-box/cmd_generate_tls.go new file mode 100644 index 00000000..d871566f --- /dev/null +++ b/cmd/sing-box/cmd_generate_tls.go @@ -0,0 +1,40 @@ +package main + +import ( + "os" + "time" + + "github.com/sagernet/sing-box/common/tls" + "github.com/sagernet/sing-box/log" + + "github.com/spf13/cobra" +) + +var flagGenerateTLSKeyPairMonths int + +var commandGenerateTLSKeyPair = &cobra.Command{ + Use: "tls-keypair ", + Short: "Generate TLS self sign key pair", + Args: cobra.ExactArgs(1), + Run: func(cmd *cobra.Command, args []string) { + err := generateTLSKeyPair(args[0]) + if err != nil { + log.Fatal(err) + } + }, +} + +func init() { + commandGenerateTLSKeyPair.Flags().IntVarP(&flagGenerateTLSKeyPairMonths, "months", "m", 1, "Valid months") + commandGenerate.AddCommand(commandGenerateTLSKeyPair) +} + +func generateTLSKeyPair(serverName string) error { + privateKeyPem, publicKeyPem, err := tls.GenerateKeyPair(time.Now, serverName, time.Now().AddDate(0, flagGenerateTLSKeyPairMonths, 0)) + if err != nil { + return err + } + os.Stdout.WriteString(string(privateKeyPem) + "\n") + os.Stdout.WriteString(string(publicKeyPem) + "\n") + return nil +} diff --git a/cmd/sing-box/cmd_generate_vapid.go b/cmd/sing-box/cmd_generate_vapid.go new file mode 100644 index 00000000..e83e6d80 --- /dev/null +++ b/cmd/sing-box/cmd_generate_vapid.go @@ -0,0 +1,40 @@ +//go:build go1.20 + +package main + +import ( + "crypto/ecdh" + "crypto/rand" + "encoding/base64" + "os" + + "github.com/sagernet/sing-box/log" + + "github.com/spf13/cobra" +) + +var commandGenerateVAPIDKeyPair = &cobra.Command{ + Use: "vapid-keypair", + Short: "Generate VAPID key pair", + Run: func(cmd *cobra.Command, args []string) { + err := generateVAPIDKeyPair() + if err != nil { + log.Fatal(err) + } + }, +} + +func init() { + commandGenerate.AddCommand(commandGenerateVAPIDKeyPair) +} + +func generateVAPIDKeyPair() error { + privateKey, err := ecdh.P256().GenerateKey(rand.Reader) + if err != nil { + return err + } + publicKey := privateKey.PublicKey() + os.Stdout.WriteString("PrivateKey: " + base64.RawURLEncoding.EncodeToString(privateKey.Bytes()) + "\n") + os.Stdout.WriteString("PublicKey: " + base64.RawURLEncoding.EncodeToString(publicKey.Bytes()) + "\n") + return nil +} diff --git a/cmd/sing-box/cmd_generate_wireguard.go b/cmd/sing-box/cmd_generate_wireguard.go new file mode 100644 index 00000000..087e74b2 --- /dev/null +++ b/cmd/sing-box/cmd_generate_wireguard.go @@ -0,0 +1,61 @@ +package main + +import ( + "encoding/base64" + "os" + + "github.com/sagernet/sing-box/log" + + "github.com/spf13/cobra" + "golang.zx2c4.com/wireguard/wgctrl/wgtypes" +) + +func init() { + commandGenerate.AddCommand(commandGenerateWireGuardKeyPair) + commandGenerate.AddCommand(commandGenerateRealityKeyPair) +} + +var commandGenerateWireGuardKeyPair = &cobra.Command{ + Use: "wg-keypair", + Short: "Generate WireGuard key pair", + Args: cobra.NoArgs, + Run: func(cmd *cobra.Command, args []string) { + err := generateWireGuardKey() + if err != nil { + log.Fatal(err) + } + }, +} + +func generateWireGuardKey() error { + privateKey, err := wgtypes.GeneratePrivateKey() + if err != nil { + return err + } + os.Stdout.WriteString("PrivateKey: " + privateKey.String() + "\n") + os.Stdout.WriteString("PublicKey: " + privateKey.PublicKey().String() + "\n") + return nil +} + +var commandGenerateRealityKeyPair = &cobra.Command{ + Use: "reality-keypair", + Short: "Generate reality key pair", + Args: cobra.NoArgs, + Run: func(cmd *cobra.Command, args []string) { + err := generateRealityKey() + if err != nil { + log.Fatal(err) + } + }, +} + +func generateRealityKey() error { + privateKey, err := wgtypes.GeneratePrivateKey() + if err != nil { + return err + } + publicKey := privateKey.PublicKey() + os.Stdout.WriteString("PrivateKey: " + base64.RawURLEncoding.EncodeToString(privateKey[:]) + "\n") + os.Stdout.WriteString("PublicKey: " + base64.RawURLEncoding.EncodeToString(publicKey[:]) + "\n") + return nil +} diff --git a/common/tls/mkcert.go b/common/tls/mkcert.go index 9598cffa..1e71a763 100644 --- a/common/tls/mkcert.go +++ b/common/tls/mkcert.go @@ -11,22 +11,34 @@ import ( "time" ) -func GenerateKeyPair(timeFunc func() time.Time, serverName string) (*tls.Certificate, error) { +func GenerateCertificate(timeFunc func() time.Time, serverName string) (*tls.Certificate, error) { + privateKeyPem, publicKeyPem, err := GenerateKeyPair(timeFunc, serverName, timeFunc().Add(time.Hour)) + if err != nil { + return nil, err + } + certificate, err := tls.X509KeyPair(publicKeyPem, privateKeyPem) + if err != nil { + return nil, err + } + return &certificate, err +} + +func GenerateKeyPair(timeFunc func() time.Time, serverName string, expire time.Time) (privateKeyPem []byte, publicKeyPem []byte, err error) { if timeFunc == nil { timeFunc = time.Now } key, err := rsa.GenerateKey(rand.Reader, 2048) if err != nil { - return nil, err + return } serialNumber, err := rand.Int(rand.Reader, new(big.Int).Lsh(big.NewInt(1), 128)) if err != nil { - return nil, err + return } template := &x509.Certificate{ SerialNumber: serialNumber, NotBefore: timeFunc().Add(time.Hour * -1), - NotAfter: timeFunc().Add(time.Hour), + NotAfter: expire, KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, BasicConstraintsValid: true, @@ -37,17 +49,13 @@ func GenerateKeyPair(timeFunc func() time.Time, serverName string) (*tls.Certifi } publicDer, err := x509.CreateCertificate(rand.Reader, template, template, key.Public(), key) if err != nil { - return nil, err + return } privateDer, err := x509.MarshalPKCS8PrivateKey(key) if err != nil { - return nil, err + return } - publicPem := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: publicDer}) - privPem := pem.EncodeToMemory(&pem.Block{Type: "PRIVATE KEY", Bytes: privateDer}) - keyPair, err := tls.X509KeyPair(publicPem, privPem) - if err != nil { - return nil, err - } - return &keyPair, err + publicKeyPem = pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: publicDer}) + privateKeyPem = pem.EncodeToMemory(&pem.Block{Type: "PRIVATE KEY", Bytes: privateDer}) + return } diff --git a/common/tls/std_server.go b/common/tls/std_server.go index 36ce67b6..28a94cf1 100644 --- a/common/tls/std_server.go +++ b/common/tls/std_server.go @@ -233,7 +233,7 @@ func NewSTDServer(ctx context.Context, logger log.Logger, options option.Inbound } if certificate == nil && key == nil && options.Insecure { tlsConfig.GetCertificate = func(info *tls.ClientHelloInfo) (*tls.Certificate, error) { - return GenerateKeyPair(ntp.TimeFuncFromContext(ctx), info.ServerName) + return GenerateCertificate(ntp.TimeFuncFromContext(ctx), info.ServerName) } } else { if certificate == nil {