You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

cert.go 5.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. // Copyright 2009 The Go Authors. All rights reserved.
  2. // Copyright 2014 The Gogs Authors. All rights reserved.
  3. // Copyright 2016 The Gitea Authors. All rights reserved.
  4. // SPDX-License-Identifier: MIT
  5. package cmd
  6. import (
  7. "crypto/ecdsa"
  8. "crypto/elliptic"
  9. "crypto/rand"
  10. "crypto/rsa"
  11. "crypto/x509"
  12. "crypto/x509/pkix"
  13. "encoding/pem"
  14. "log"
  15. "math/big"
  16. "net"
  17. "os"
  18. "strings"
  19. "time"
  20. "github.com/urfave/cli"
  21. )
  22. // CmdCert represents the available cert sub-command.
  23. var CmdCert = cli.Command{
  24. Name: "cert",
  25. Usage: "Generate self-signed certificate",
  26. Description: `Generate a self-signed X.509 certificate for a TLS server.
  27. Outputs to 'cert.pem' and 'key.pem' and will overwrite existing files.`,
  28. Action: runCert,
  29. Flags: []cli.Flag{
  30. cli.StringFlag{
  31. Name: "host",
  32. Value: "",
  33. Usage: "Comma-separated hostnames and IPs to generate a certificate for",
  34. },
  35. cli.StringFlag{
  36. Name: "ecdsa-curve",
  37. Value: "",
  38. Usage: "ECDSA curve to use to generate a key. Valid values are P224, P256, P384, P521",
  39. },
  40. cli.IntFlag{
  41. Name: "rsa-bits",
  42. Value: 2048,
  43. Usage: "Size of RSA key to generate. Ignored if --ecdsa-curve is set",
  44. },
  45. cli.StringFlag{
  46. Name: "start-date",
  47. Value: "",
  48. Usage: "Creation date formatted as Jan 1 15:04:05 2011",
  49. },
  50. cli.DurationFlag{
  51. Name: "duration",
  52. Value: 365 * 24 * time.Hour,
  53. Usage: "Duration that certificate is valid for",
  54. },
  55. cli.BoolFlag{
  56. Name: "ca",
  57. Usage: "whether this cert should be its own Certificate Authority",
  58. },
  59. },
  60. }
  61. func publicKey(priv interface{}) interface{} {
  62. switch k := priv.(type) {
  63. case *rsa.PrivateKey:
  64. return &k.PublicKey
  65. case *ecdsa.PrivateKey:
  66. return &k.PublicKey
  67. default:
  68. return nil
  69. }
  70. }
  71. func pemBlockForKey(priv interface{}) *pem.Block {
  72. switch k := priv.(type) {
  73. case *rsa.PrivateKey:
  74. return &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(k)}
  75. case *ecdsa.PrivateKey:
  76. b, err := x509.MarshalECPrivateKey(k)
  77. if err != nil {
  78. log.Fatalf("Unable to marshal ECDSA private key: %v", err)
  79. }
  80. return &pem.Block{Type: "EC PRIVATE KEY", Bytes: b}
  81. default:
  82. return nil
  83. }
  84. }
  85. func runCert(c *cli.Context) error {
  86. if err := argsSet(c, "host"); err != nil {
  87. return err
  88. }
  89. var priv interface{}
  90. var err error
  91. switch c.String("ecdsa-curve") {
  92. case "":
  93. priv, err = rsa.GenerateKey(rand.Reader, c.Int("rsa-bits"))
  94. case "P224":
  95. priv, err = ecdsa.GenerateKey(elliptic.P224(), rand.Reader)
  96. case "P256":
  97. priv, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
  98. case "P384":
  99. priv, err = ecdsa.GenerateKey(elliptic.P384(), rand.Reader)
  100. case "P521":
  101. priv, err = ecdsa.GenerateKey(elliptic.P521(), rand.Reader)
  102. default:
  103. log.Fatalf("Unrecognized elliptic curve: %q", c.String("ecdsa-curve"))
  104. }
  105. if err != nil {
  106. log.Fatalf("Failed to generate private key: %v", err)
  107. }
  108. var notBefore time.Time
  109. if startDate := c.String("start-date"); startDate != "" {
  110. notBefore, err = time.Parse("Jan 2 15:04:05 2006", startDate)
  111. if err != nil {
  112. log.Fatalf("Failed to parse creation date: %v", err)
  113. }
  114. } else {
  115. notBefore = time.Now()
  116. }
  117. notAfter := notBefore.Add(c.Duration("duration"))
  118. serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
  119. serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
  120. if err != nil {
  121. log.Fatalf("Failed to generate serial number: %v", err)
  122. }
  123. template := x509.Certificate{
  124. SerialNumber: serialNumber,
  125. Subject: pkix.Name{
  126. Organization: []string{"Acme Co"},
  127. CommonName: "Gitea",
  128. },
  129. NotBefore: notBefore,
  130. NotAfter: notAfter,
  131. KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
  132. ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
  133. BasicConstraintsValid: true,
  134. }
  135. hosts := strings.Split(c.String("host"), ",")
  136. for _, h := range hosts {
  137. if ip := net.ParseIP(h); ip != nil {
  138. template.IPAddresses = append(template.IPAddresses, ip)
  139. } else {
  140. template.DNSNames = append(template.DNSNames, h)
  141. }
  142. }
  143. if c.Bool("ca") {
  144. template.IsCA = true
  145. template.KeyUsage |= x509.KeyUsageCertSign
  146. }
  147. derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, publicKey(priv), priv)
  148. if err != nil {
  149. log.Fatalf("Failed to create certificate: %v", err)
  150. }
  151. certOut, err := os.Create("cert.pem")
  152. if err != nil {
  153. log.Fatalf("Failed to open cert.pem for writing: %v", err)
  154. }
  155. err = pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
  156. if err != nil {
  157. log.Fatalf("Failed to encode certificate: %v", err)
  158. }
  159. err = certOut.Close()
  160. if err != nil {
  161. log.Fatalf("Failed to write cert: %v", err)
  162. }
  163. log.Println("Written cert.pem")
  164. keyOut, err := os.OpenFile("key.pem", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0o600)
  165. if err != nil {
  166. log.Fatalf("Failed to open key.pem for writing: %v", err)
  167. }
  168. err = pem.Encode(keyOut, pemBlockForKey(priv))
  169. if err != nil {
  170. log.Fatalf("Failed to encode key: %v", err)
  171. }
  172. err = keyOut.Close()
  173. if err != nil {
  174. log.Fatalf("Failed to write key: %v", err)
  175. }
  176. log.Println("Written key.pem")
  177. return nil
  178. }