cert.go 4.9 KB

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