github.com/v2fly/v2ray-core/v4@v4.45.2/infra/control/cert.go (about) 1 package control 2 3 import ( 4 "context" 5 "crypto/x509" 6 "encoding/json" 7 "flag" 8 "os" 9 "strings" 10 "time" 11 12 "github.com/v2fly/v2ray-core/v4/common" 13 "github.com/v2fly/v2ray-core/v4/common/protocol/tls/cert" 14 "github.com/v2fly/v2ray-core/v4/common/task" 15 ) 16 17 type stringList []string 18 19 func (l *stringList) String() string { 20 return "String list" 21 } 22 23 func (l *stringList) Set(v string) error { 24 if v == "" { 25 return newError("empty value") 26 } 27 *l = append(*l, v) 28 return nil 29 } 30 31 type jsonCert struct { 32 Certificate []string `json:"certificate"` 33 Key []string `json:"key"` 34 } 35 36 type CertificateCommand struct{} 37 38 func (c *CertificateCommand) Name() string { 39 return "cert" 40 } 41 42 func (c *CertificateCommand) Description() Description { 43 return Description{ 44 Short: "Generate TLS certificates.", 45 Usage: []string{ 46 "v2ctl cert [--ca] [--domain=v2fly.org] [--expire=240h]", 47 "Generate new TLS certificate", 48 "--ca The new certificate is a CA certificate", 49 "--domain Common name for the certificate", 50 "--expire Time until certificate expires. 240h = 10 days.", 51 }, 52 } 53 } 54 55 func (c *CertificateCommand) printJSON(certificate *cert.Certificate) { 56 certPEM, keyPEM := certificate.ToPEM() 57 jCert := &jsonCert{ 58 Certificate: strings.Split(strings.TrimSpace(string(certPEM)), "\n"), 59 Key: strings.Split(strings.TrimSpace(string(keyPEM)), "\n"), 60 } 61 content, err := json.MarshalIndent(jCert, "", " ") 62 common.Must(err) 63 os.Stdout.Write(content) 64 os.Stdout.WriteString("\n") 65 } 66 67 func (c *CertificateCommand) writeFile(content []byte, name string) error { 68 f, err := os.Create(name) 69 if err != nil { 70 return err 71 } 72 defer f.Close() 73 74 return common.Error2(f.Write(content)) 75 } 76 77 func (c *CertificateCommand) printFile(certificate *cert.Certificate, name string) error { 78 certPEM, keyPEM := certificate.ToPEM() 79 return task.Run(context.Background(), func() error { 80 return c.writeFile(certPEM, name+"_cert.pem") 81 }, func() error { 82 return c.writeFile(keyPEM, name+"_key.pem") 83 }) 84 } 85 86 func (c *CertificateCommand) Execute(args []string) error { 87 fs := flag.NewFlagSet(c.Name(), flag.ContinueOnError) 88 89 var domainNames stringList 90 fs.Var(&domainNames, "domain", "Domain name for the certificate") 91 92 commonName := fs.String("name", "V2Ray Inc", "The common name of this certificate") 93 organization := fs.String("org", "V2Ray Inc", "Organization of the certificate") 94 95 isCA := fs.Bool("ca", false, "Whether this certificate is a CA") 96 jsonOutput := fs.Bool("json", true, "Print certificate in JSON format") 97 fileOutput := fs.String("file", "", "Save certificate in file.") 98 99 expire := fs.Duration("expire", time.Hour*24*90 /* 90 days */, "Time until the certificate expires. Default value 3 months.") 100 101 if err := fs.Parse(args); err != nil { 102 return err 103 } 104 105 var opts []cert.Option 106 if *isCA { 107 opts = append(opts, cert.Authority(*isCA)) 108 opts = append(opts, cert.KeyUsage(x509.KeyUsageCertSign|x509.KeyUsageKeyEncipherment|x509.KeyUsageDigitalSignature)) 109 } 110 111 opts = append(opts, cert.NotAfter(time.Now().Add(*expire))) 112 opts = append(opts, cert.CommonName(*commonName)) 113 if len(domainNames) > 0 { 114 opts = append(opts, cert.DNSNames(domainNames...)) 115 } 116 opts = append(opts, cert.Organization(*organization)) 117 118 cert, err := cert.Generate(nil, opts...) 119 if err != nil { 120 return newError("failed to generate TLS certificate").Base(err) 121 } 122 123 if *jsonOutput { 124 c.printJSON(cert) 125 } 126 127 if len(*fileOutput) > 0 { 128 if err := c.printFile(cert, *fileOutput); err != nil { 129 return err 130 } 131 } 132 133 return nil 134 } 135 136 func init() { 137 common.Must(RegisterCommand(&CertificateCommand{})) 138 }