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// +build ignore
6
7// Generate a self-signed X.509 certificate for a TLS server. Outputs to
8// 'cert.pem' and 'key.pem' and will overwrite existing files.
9
10package main
11
12import (
13	"crypto/ecdsa"
14	"crypto/ed25519"
15	"crypto/elliptic"
16	"crypto/rand"
17	"crypto/rsa"
18	"crypto/x509"
19	"crypto/x509/pkix"
20	"encoding/pem"
21	"flag"
22	"log"
23	"math/big"
24	"net"
25	"os"
26	"strings"
27	"time"
28)
29
30var (
31	host       = flag.String("host", "", "Comma-separated hostnames and IPs to generate a certificate for")
32	validFrom  = flag.String("start-date", "", "Creation date formatted as Jan 1 15:04:05 2011")
33	validFor   = flag.Duration("duration", 365*24*time.Hour, "Duration that certificate is valid for")
34	isCA       = flag.Bool("ca", false, "whether this cert should be its own Certificate Authority")
35	rsaBits    = flag.Int("rsa-bits", 2048, "Size of RSA key to generate. Ignored if --ecdsa-curve is set")
36	ecdsaCurve = flag.String("ecdsa-curve", "", "ECDSA curve to use to generate a key. Valid values are P224, P256 (recommended), P384, P521")
37	ed25519Key = flag.Bool("ed25519", false, "Generate an Ed25519 key")
38)
39
40func 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	case ed25519.PrivateKey:
47		return k.Public().(ed25519.PublicKey)
48	default:
49		return nil
50	}
51}
52
53func main() {
54	flag.Parse()
55
56	if len(*host) == 0 {
57		log.Fatalf("Missing required --host parameter")
58	}
59
60	var priv interface{}
61	var err error
62	switch *ecdsaCurve {
63	case "":
64		if *ed25519Key {
65			_, priv, err = ed25519.GenerateKey(rand.Reader)
66		} else {
67			priv, err = rsa.GenerateKey(rand.Reader, *rsaBits)
68		}
69	case "P224":
70		priv, err = ecdsa.GenerateKey(elliptic.P224(), rand.Reader)
71	case "P256":
72		priv, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
73	case "P384":
74		priv, err = ecdsa.GenerateKey(elliptic.P384(), rand.Reader)
75	case "P521":
76		priv, err = ecdsa.GenerateKey(elliptic.P521(), rand.Reader)
77	default:
78		log.Fatalf("Unrecognized elliptic curve: %q", *ecdsaCurve)
79	}
80	if err != nil {
81		log.Fatalf("Failed to generate private key: %v", err)
82	}
83
84	// ECDSA, ED25519 and RSA subject keys should have the DigitalSignature
85	// KeyUsage bits set in the x509.Certificate template
86	keyUsage := x509.KeyUsageDigitalSignature
87	// Only RSA subject keys should have the KeyEncipherment KeyUsage bits set. In
88	// the context of TLS this KeyUsage is particular to RSA key exchange and
89	// authentication.
90	if _, isRSA := priv.(*rsa.PrivateKey); isRSA {
91		keyUsage |= x509.KeyUsageKeyEncipherment
92	}
93
94	var notBefore time.Time
95	if len(*validFrom) == 0 {
96		notBefore = time.Now()
97	} else {
98		notBefore, err = time.Parse("Jan 2 15:04:05 2006", *validFrom)
99		if err != nil {
100			log.Fatalf("Failed to parse creation date: %v", err)
101		}
102	}
103
104	notAfter := notBefore.Add(*validFor)
105
106	serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
107	serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
108	if err != nil {
109		log.Fatalf("Failed to generate serial number: %v", err)
110	}
111
112	template := x509.Certificate{
113		SerialNumber: serialNumber,
114		Subject: pkix.Name{
115			Organization: []string{"Acme Co"},
116		},
117		NotBefore: notBefore,
118		NotAfter:  notAfter,
119
120		KeyUsage:              keyUsage,
121		ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
122		BasicConstraintsValid: true,
123	}
124
125	hosts := strings.Split(*host, ",")
126	for _, h := range hosts {
127		if ip := net.ParseIP(h); ip != nil {
128			template.IPAddresses = append(template.IPAddresses, ip)
129		} else {
130			template.DNSNames = append(template.DNSNames, h)
131		}
132	}
133
134	if *isCA {
135		template.IsCA = true
136		template.KeyUsage |= x509.KeyUsageCertSign
137	}
138
139	derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, publicKey(priv), priv)
140	if err != nil {
141		log.Fatalf("Failed to create certificate: %v", err)
142	}
143
144	certOut, err := os.Create("cert.pem")
145	if err != nil {
146		log.Fatalf("Failed to open cert.pem for writing: %v", err)
147	}
148	if err := pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}); err != nil {
149		log.Fatalf("Failed to write data to cert.pem: %v", err)
150	}
151	if err := certOut.Close(); err != nil {
152		log.Fatalf("Error closing cert.pem: %v", err)
153	}
154	log.Print("wrote cert.pem\n")
155
156	keyOut, err := os.OpenFile("key.pem", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
157	if err != nil {
158		log.Fatalf("Failed to open key.pem for writing: %v", err)
159		return
160	}
161	privBytes, err := x509.MarshalPKCS8PrivateKey(priv)
162	if err != nil {
163		log.Fatalf("Unable to marshal private key: %v", err)
164	}
165	if err := pem.Encode(keyOut, &pem.Block{Type: "PRIVATE KEY", Bytes: privBytes}); err != nil {
166		log.Fatalf("Failed to write data to key.pem: %v", err)
167	}
168	if err := keyOut.Close(); err != nil {
169		log.Fatalf("Error closing key.pem: %v", err)
170	}
171	log.Print("wrote key.pem\n")
172}
173