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  }