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