├── README.md ├── LICENSE.md └── httpscerts.go /README.md: -------------------------------------------------------------------------------- 1 | # httpscerts 2 | A simple library to generate server certs and keys for HTTPS support directly within your Go program. 3 | 4 | The code is modified from http://golang.org/src/crypto/tls/generate_cert.go. 5 | 6 | Use this library for testing purposes only, e.g. to experiment with the built-in Go HTTPS server. Do NOT use in production! 7 | 8 | # Usage 9 | 10 | 11 | package main 12 | 13 | import ( 14 | "fmt" 15 | "github.com/kabukky/httpscerts" 16 | "log" 17 | "net/http" 18 | ) 19 | 20 | func handler(w http.ResponseWriter, r *http.Request) { 21 | fmt.Fprintf(w, "Hi there!") 22 | } 23 | 24 | func main() { 25 | // Check if the cert files are available. 26 | err := httpscerts.Check("cert.pem", "key.pem") 27 | // If they are not available, generate new ones. 28 | if err != nil { 29 | err = httpscerts.Generate("cert.pem", "key.pem", "127.0.0.1:8081") 30 | if err != nil { 31 | log.Fatal("Error: Couldn't create https certs.") 32 | } 33 | } 34 | http.HandleFunc("/", handler) 35 | http.ListenAndServeTLS(":8081", "cert.pem", "key.pem", nil) 36 | } 37 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 The Go Authors. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are 5 | met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above 10 | copyright notice, this list of conditions and the following disclaimer 11 | in the documentation and/or other materials provided with the 12 | distribution. 13 | * Neither the name of Google Inc. nor the names of its 14 | contributors may be used to endorse or promote products derived from 15 | this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /httpscerts.go: -------------------------------------------------------------------------------- 1 | // Copyright 2009 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Generate a self-signed X.509 certificate for a TLS server. Outputs to 6 | // 'cert.pem' and 'key.pem' and will overwrite existing files. 7 | 8 | // Small modifications by kabukky 9 | 10 | package httpscerts 11 | 12 | import ( 13 | "crypto/ecdsa" 14 | "crypto/elliptic" 15 | "crypto/rand" 16 | "crypto/rsa" 17 | "crypto/x509" 18 | "crypto/x509/pkix" 19 | "encoding/pem" 20 | "fmt" 21 | "log" 22 | "math/big" 23 | "net" 24 | "os" 25 | "strings" 26 | "time" 27 | ) 28 | 29 | var ( 30 | validFrom = "" 31 | validFor = 365 * 24 * time.Hour 32 | isCA = true 33 | rsaBits = 2048 34 | ecdsaCurve = "" 35 | ) 36 | 37 | func publicKey(priv interface{}) interface{} { 38 | switch k := priv.(type) { 39 | case *rsa.PrivateKey: 40 | return &k.PublicKey 41 | case *ecdsa.PrivateKey: 42 | return &k.PublicKey 43 | default: 44 | return nil 45 | } 46 | } 47 | 48 | func pemBlockForKey(priv interface{}) *pem.Block { 49 | switch k := priv.(type) { 50 | case *rsa.PrivateKey: 51 | return &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(k)} 52 | case *ecdsa.PrivateKey: 53 | b, err := x509.MarshalECPrivateKey(k) 54 | if err != nil { 55 | fmt.Fprintf(os.Stderr, "Unable to marshal ECDSA private key: %v", err) 56 | os.Exit(2) 57 | } 58 | return &pem.Block{Type: "EC PRIVATE KEY", Bytes: b} 59 | default: 60 | return nil 61 | } 62 | } 63 | 64 | func Check(certPath string, keyPath string) error { 65 | if _, err := os.Stat(certPath); os.IsNotExist(err) { 66 | return err 67 | } else if _, err := os.Stat(keyPath); os.IsNotExist(err) { 68 | return err 69 | } 70 | return nil 71 | } 72 | 73 | func Generate(certPath string, keyPath string, host string) error { 74 | var priv interface{} 75 | var err error 76 | switch ecdsaCurve { 77 | case "": 78 | priv, err = rsa.GenerateKey(rand.Reader, rsaBits) 79 | case "P224": 80 | priv, err = ecdsa.GenerateKey(elliptic.P224(), rand.Reader) 81 | case "P256": 82 | priv, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader) 83 | case "P384": 84 | priv, err = ecdsa.GenerateKey(elliptic.P384(), rand.Reader) 85 | case "P521": 86 | priv, err = ecdsa.GenerateKey(elliptic.P521(), rand.Reader) 87 | default: 88 | fmt.Fprintf(os.Stderr, "Unrecognized elliptic curve: %q", ecdsaCurve) 89 | os.Exit(1) 90 | } 91 | if err != nil { 92 | log.Printf("failed to generate private key: %s", err) 93 | return err 94 | } 95 | 96 | var notBefore time.Time 97 | if len(validFrom) == 0 { 98 | notBefore = time.Now() 99 | } else { 100 | notBefore, err = time.Parse("Jan 2 15:04:05 2006", validFrom) 101 | if err != nil { 102 | fmt.Fprintf(os.Stderr, "Failed to parse creation date: %s\n", err) 103 | return err 104 | } 105 | } 106 | 107 | notAfter := notBefore.Add(validFor) 108 | 109 | serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128) 110 | serialNumber, err := rand.Int(rand.Reader, serialNumberLimit) 111 | if err != nil { 112 | log.Printf("failed to generate serial number: %s", err) 113 | return err 114 | } 115 | 116 | template := x509.Certificate{ 117 | SerialNumber: serialNumber, 118 | Subject: pkix.Name{ 119 | Organization: []string{"Acme Co"}, 120 | }, 121 | NotBefore: notBefore, 122 | NotAfter: notAfter, 123 | 124 | KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, 125 | ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, 126 | BasicConstraintsValid: true, 127 | } 128 | 129 | hosts := strings.Split(host, ",") 130 | for _, h := range hosts { 131 | if ip := net.ParseIP(h); ip != nil { 132 | template.IPAddresses = append(template.IPAddresses, ip) 133 | } else { 134 | template.DNSNames = append(template.DNSNames, h) 135 | } 136 | } 137 | 138 | if isCA { 139 | template.IsCA = true 140 | template.KeyUsage |= x509.KeyUsageCertSign 141 | } 142 | 143 | derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, publicKey(priv), priv) 144 | if err != nil { 145 | log.Printf("Failed to create certificate: %s", err) 146 | return err 147 | } 148 | 149 | certOut, err := os.Create(certPath) 150 | if err != nil { 151 | log.Printf("failed to open "+certPath+" for writing: %s", err) 152 | return err 153 | } 154 | pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}) 155 | certOut.Close() 156 | log.Print("written cert.pem\n") 157 | 158 | keyOut, err := os.OpenFile(keyPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600) 159 | if err != nil { 160 | log.Print("failed to open "+keyPath+" for writing:", err) 161 | return err 162 | } 163 | pem.Encode(keyOut, pemBlockForKey(priv)) 164 | keyOut.Close() 165 | log.Print("written key.pem\n") 166 | return nil 167 | } 168 | --------------------------------------------------------------------------------