2020-11-30 07:08:08 -05:00
|
|
|
package tls
|
2020-11-23 10:38:43 -05:00
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"crypto/x509"
|
|
|
|
"encoding/json"
|
|
|
|
"os"
|
|
|
|
"strings"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/v2fly/v2ray-core/v4/common"
|
|
|
|
"github.com/v2fly/v2ray-core/v4/common/protocol/tls/cert"
|
|
|
|
"github.com/v2fly/v2ray-core/v4/common/task"
|
2020-12-04 09:32:55 -05:00
|
|
|
"github.com/v2fly/v2ray-core/v4/main/commands/base"
|
2020-11-23 10:38:43 -05:00
|
|
|
)
|
|
|
|
|
2020-11-30 07:08:08 -05:00
|
|
|
// cmdCert is the tls cert command
|
|
|
|
var cmdCert = &base.Command{
|
2021-02-21 10:02:42 -05:00
|
|
|
UsageLine: "{{.Exec}} tls cert [--ca] [--domain=v2fly.org] [--expire=240h]",
|
2020-11-23 10:38:43 -05:00
|
|
|
Short: "Generate TLS certificates",
|
|
|
|
Long: `
|
|
|
|
Generate TLS certificates.
|
|
|
|
|
|
|
|
Arguments:
|
|
|
|
|
2021-02-21 10:02:42 -05:00
|
|
|
-domain <domain_name>
|
2020-11-23 10:38:43 -05:00
|
|
|
The domain name for the certificate.
|
|
|
|
|
2021-02-21 10:02:42 -05:00
|
|
|
-org <organization>
|
2020-11-23 10:38:43 -05:00
|
|
|
The organization name for the certificate.
|
|
|
|
|
|
|
|
-ca
|
2021-02-21 10:02:42 -05:00
|
|
|
The certificate is a CA
|
2020-11-23 10:38:43 -05:00
|
|
|
|
|
|
|
-json
|
2021-02-21 10:02:42 -05:00
|
|
|
To output certificate to JSON
|
2020-11-23 10:38:43 -05:00
|
|
|
|
2021-02-21 10:02:42 -05:00
|
|
|
-file <path>
|
2020-11-23 10:38:43 -05:00
|
|
|
The certificate path to save.
|
|
|
|
|
2021-02-21 10:02:42 -05:00
|
|
|
-expire <days>
|
|
|
|
Expire days of the certificate. Default 90 days.
|
2020-11-23 10:38:43 -05:00
|
|
|
`,
|
|
|
|
}
|
|
|
|
|
|
|
|
func init() {
|
2020-11-30 07:08:08 -05:00
|
|
|
cmdCert.Run = executeCert // break init loop
|
2020-11-23 10:38:43 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
var (
|
|
|
|
certDomainNames stringList
|
|
|
|
_ = func() bool {
|
2020-11-30 07:08:08 -05:00
|
|
|
cmdCert.Flag.Var(&certDomainNames, "domain", "Domain name for the certificate")
|
2020-11-23 10:38:43 -05:00
|
|
|
return true
|
|
|
|
}()
|
|
|
|
|
2021-02-21 10:02:42 -05:00
|
|
|
certCommonName = cmdCert.Flag.String("name", "V2Ray Inc", "")
|
|
|
|
certOrganization = cmdCert.Flag.String("org", "V2Ray Inc", "")
|
|
|
|
certIsCA = cmdCert.Flag.Bool("ca", false, "")
|
|
|
|
certJSONOutput = cmdCert.Flag.Bool("json", true, "")
|
|
|
|
certFileOutput = cmdCert.Flag.String("file", "", "")
|
|
|
|
certExpire = cmdCert.Flag.Uint("expire", 90, "")
|
2020-11-23 10:38:43 -05:00
|
|
|
)
|
|
|
|
|
|
|
|
func executeCert(cmd *base.Command, args []string) {
|
|
|
|
var opts []cert.Option
|
|
|
|
if *certIsCA {
|
|
|
|
opts = append(opts, cert.Authority(*certIsCA))
|
|
|
|
opts = append(opts, cert.KeyUsage(x509.KeyUsageCertSign|x509.KeyUsageKeyEncipherment|x509.KeyUsageDigitalSignature))
|
|
|
|
}
|
|
|
|
|
2021-02-21 10:02:42 -05:00
|
|
|
opts = append(opts, cert.NotAfter(time.Now().Add(time.Duration(*certExpire)*time.Hour*24)))
|
2020-11-23 10:38:43 -05:00
|
|
|
opts = append(opts, cert.CommonName(*certCommonName))
|
|
|
|
if len(certDomainNames) > 0 {
|
|
|
|
opts = append(opts, cert.DNSNames(certDomainNames...))
|
|
|
|
}
|
|
|
|
opts = append(opts, cert.Organization(*certOrganization))
|
|
|
|
|
|
|
|
cert, err := cert.Generate(nil, opts...)
|
|
|
|
if err != nil {
|
|
|
|
base.Fatalf("failed to generate TLS certificate: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if *certJSONOutput {
|
|
|
|
printJSON(cert)
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(*certFileOutput) > 0 {
|
|
|
|
if err := printFile(cert, *certFileOutput); err != nil {
|
|
|
|
base.Fatalf("failed to save file: %s", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func printJSON(certificate *cert.Certificate) {
|
|
|
|
certPEM, keyPEM := certificate.ToPEM()
|
|
|
|
jCert := &jsonCert{
|
|
|
|
Certificate: strings.Split(strings.TrimSpace(string(certPEM)), "\n"),
|
|
|
|
Key: strings.Split(strings.TrimSpace(string(keyPEM)), "\n"),
|
|
|
|
}
|
|
|
|
content, err := json.MarshalIndent(jCert, "", " ")
|
|
|
|
common.Must(err)
|
|
|
|
os.Stdout.Write(content)
|
|
|
|
os.Stdout.WriteString("\n")
|
|
|
|
}
|
|
|
|
|
|
|
|
func writeFile(content []byte, name string) error {
|
|
|
|
f, err := os.Create(name)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer f.Close()
|
|
|
|
|
|
|
|
return common.Error2(f.Write(content))
|
|
|
|
}
|
|
|
|
|
|
|
|
func printFile(certificate *cert.Certificate, name string) error {
|
|
|
|
certPEM, keyPEM := certificate.ToPEM()
|
|
|
|
return task.Run(context.Background(), func() error {
|
|
|
|
return writeFile(certPEM, name+"_cert.pem")
|
|
|
|
}, func() error {
|
|
|
|
return writeFile(keyPEM, name+"_key.pem")
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
type stringList []string
|
|
|
|
|
|
|
|
func (l *stringList) String() string {
|
|
|
|
return "String list"
|
|
|
|
}
|
|
|
|
|
|
|
|
func (l *stringList) Set(v string) error {
|
|
|
|
if v == "" {
|
|
|
|
base.Fatalf("empty value")
|
|
|
|
}
|
|
|
|
*l = append(*l, v)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
type jsonCert struct {
|
|
|
|
Certificate []string `json:"certificate"`
|
|
|
|
Key []string `json:"key"`
|
|
|
|
}
|