]> source.dussan.org Git - gitea.git/commitdiff
Feature: Integrate crypto/tls/generate_cert.go command
authorUnknwon <joe2010xtmf@163.com>
Mon, 22 Sep 2014 21:30:58 +0000 (17:30 -0400)
committerUnknwon <joe2010xtmf@163.com>
Mon, 22 Sep 2014 21:30:58 +0000 (17:30 -0400)
cmd/cert.go [new file with mode: 0644]
conf/app.ini
gogs.go
modules/log/log.go

diff --git a/cmd/cert.go b/cmd/cert.go
new file mode 100644 (file)
index 0000000..b693b7d
--- /dev/null
@@ -0,0 +1,158 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Copyright 2014 The Gogs Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package cmd
+
+import (
+       "crypto/ecdsa"
+       "crypto/elliptic"
+       "crypto/rand"
+       "crypto/rsa"
+       "crypto/x509"
+       "crypto/x509/pkix"
+       "encoding/pem"
+       "log"
+       "math/big"
+       "net"
+       "os"
+       "strings"
+       "time"
+
+       "github.com/codegangsta/cli"
+)
+
+var CmdCert = cli.Command{
+       Name:  "cert",
+       Usage: "Generate self-signed certificate",
+       Description: `Generate a self-signed X.509 certificate for a TLS server. 
+Outputs to 'cert.pem' and 'key.pem' and will overwrite existing files.`,
+       Action: runCert,
+       Flags: []cli.Flag{
+               cli.StringFlag{"host", "", "Comma-separated hostnames and IPs to generate a certificate for", ""},
+               cli.StringFlag{"ecdsa-curve", "", "ECDSA curve to use to generate a key. Valid values are P224, P256, P384, P521", ""},
+               cli.IntFlag{"rsa-bits", 2048, "Size of RSA key to generate. Ignored if --ecdsa-curve is set", ""},
+               cli.StringFlag{"start-date", "", "Creation date formatted as Jan 1 15:04:05 2011", ""},
+               cli.DurationFlag{"duration", 365 * 24 * time.Hour, "Duration that certificate is valid for", ""},
+               cli.BoolFlag{"ca", "whether this cert should be its own Certificate Authority", ""},
+       },
+}
+
+func publicKey(priv interface{}) interface{} {
+       switch k := priv.(type) {
+       case *rsa.PrivateKey:
+               return &k.PublicKey
+       case *ecdsa.PrivateKey:
+               return &k.PublicKey
+       default:
+               return nil
+       }
+}
+
+func pemBlockForKey(priv interface{}) *pem.Block {
+       switch k := priv.(type) {
+       case *rsa.PrivateKey:
+               return &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(k)}
+       case *ecdsa.PrivateKey:
+               b, err := x509.MarshalECPrivateKey(k)
+               if err != nil {
+                       log.Fatal("unable to marshal ECDSA private key: %v", err)
+               }
+               return &pem.Block{Type: "EC PRIVATE KEY", Bytes: b}
+       default:
+               return nil
+       }
+}
+
+func runCert(ctx *cli.Context) {
+       if len(ctx.String("host")) == 0 {
+               log.Fatal("Missing required --host parameter")
+       }
+
+       var priv interface{}
+       var err error
+       switch ctx.String("ecdsa-curve") {
+       case "":
+               priv, err = rsa.GenerateKey(rand.Reader, ctx.Int("rsa-bits"))
+       case "P224":
+               priv, err = ecdsa.GenerateKey(elliptic.P224(), rand.Reader)
+       case "P256":
+               priv, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
+       case "P384":
+               priv, err = ecdsa.GenerateKey(elliptic.P384(), rand.Reader)
+       case "P521":
+               priv, err = ecdsa.GenerateKey(elliptic.P521(), rand.Reader)
+       default:
+               log.Fatalf("Unrecognized elliptic curve: %q", ctx.String("ecdsa-curve"))
+       }
+       if err != nil {
+               log.Fatalf("Failed to generate private key: %s", err)
+       }
+
+       var notBefore time.Time
+       if len(ctx.String("start-date")) == 0 {
+               notBefore = time.Now()
+       } else {
+               notBefore, err = time.Parse("Jan 2 15:04:05 2006", ctx.String("start-date"))
+               if err != nil {
+                       log.Fatalf("Failed to parse creation date: %s", err)
+               }
+       }
+
+       notAfter := notBefore.Add(ctx.Duration("duration"))
+
+       serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
+       serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
+       if err != nil {
+               log.Fatalf("Failed to generate serial number: %s", err)
+       }
+
+       template := x509.Certificate{
+               SerialNumber: serialNumber,
+               Subject: pkix.Name{
+                       Organization: []string{"Acme Co"},
+               },
+               NotBefore: notBefore,
+               NotAfter:  notAfter,
+
+               KeyUsage:              x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
+               ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
+               BasicConstraintsValid: true,
+       }
+
+       hosts := strings.Split(ctx.String("host"), ",")
+       for _, h := range hosts {
+               if ip := net.ParseIP(h); ip != nil {
+                       template.IPAddresses = append(template.IPAddresses, ip)
+               } else {
+                       template.DNSNames = append(template.DNSNames, h)
+               }
+       }
+
+       if ctx.Bool("ca") {
+               template.IsCA = true
+               template.KeyUsage |= x509.KeyUsageCertSign
+       }
+
+       derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, publicKey(priv), priv)
+       if err != nil {
+               log.Fatalf("Failed to create certificate: %s", err)
+       }
+
+       certOut, err := os.Create("cert.pem")
+       if err != nil {
+               log.Fatalf("Failed to open cert.pem for writing: %s", err)
+       }
+       pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
+       certOut.Close()
+       log.Println("Written cert.pem")
+
+       keyOut, err := os.OpenFile("key.pem", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
+       if err != nil {
+               log.Fatal("failed to open key.pem for writing: %v", err)
+       }
+       pem.Encode(keyOut, pemBlockForKey(priv))
+       keyOut.Close()
+       log.Println("Written key.pem")
+}
index ba73a0e8b26f13c8c2ea64de88b5d1039bd4468a..6c65fd21364deb07c957a1209883dcba42af94c7 100644 (file)
@@ -21,7 +21,7 @@ OFFLINE_MODE = false
 DISABLE_ROUTER_LOG = false
 ; Generate steps:
 ; $ cd path/to/gogs/custom/https
-; $ go run $GOROOT/src/pkg/crypto/tls/generate_cert.go -ca=true -duration=8760h0m0s -host=myhost.example.com
+; $ ./gogs cert -ca=true -duration=8760h0m0s -host=myhost.example.com
 CERT_FILE = custom/https/cert.pem
 KEY_FILE = custom/https/key.pem
 ; Upper level of template and static file path
diff --git a/gogs.go b/gogs.go
index d565d7bbb190fdb8e2ad3cccecb40729ff85e0a8..8473304242ca2fa253b5e42bcebf9673cc2c0daa 100644 (file)
--- a/gogs.go
+++ b/gogs.go
@@ -35,6 +35,7 @@ func main() {
                cmd.CmdUpdate,
                cmd.CmdFix,
                cmd.CmdDump,
+               cmd.CmdCert,
        }
        app.Flags = append(app.Flags, []cli.Flag{}...)
        app.Run(os.Args)
index 8f4de1e1e9d2d884156c3e4bc8e235b35cdc4795..4fb74d40c83dfb70bc2aa77e73c695bb79ddd3a3 100644 (file)
@@ -87,6 +87,12 @@ func Fatal(skip int, format string, v ...interface{}) {
        os.Exit(1)
 }
 
+func Close() {
+       for _, l := range loggers {
+               l.Close()
+       }
+}
+
 // .___        __                 _____
 // |   | _____/  |_  ____________/ ____\____    ____  ____
 // |   |/    \   __\/ __ \_  __ \   __\\__  \ _/ ___\/ __ \