/
certificates.go
166 lines (136 loc) · 4.66 KB
/
certificates.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
package commands
import (
"crypto/elliptic"
"fmt"
"log"
"os"
"path/filepath"
"time"
"github.com/spf13/cobra"
"github.com/authelia/authelia/v4/internal/utils"
)
// NewCertificatesCmd returns a new Certificates Cmd.
func NewCertificatesCmd() (cmd *cobra.Command) {
cmd = &cobra.Command{
Use: "certificates",
Short: "Commands related to certificate generation",
Args: cobra.NoArgs,
}
cmd.PersistentFlags().StringSlice("host", []string{}, "Comma-separated hostnames and IPs to generate a certificate for")
err := cmd.MarkPersistentFlagRequired("host")
if err != nil {
log.Fatal(err)
}
cmd.AddCommand(newCertificatesGenerateCmd())
return cmd
}
func newCertificatesGenerateCmd() (cmd *cobra.Command) {
cmd = &cobra.Command{
Use: "generate",
Short: "Generate a self-signed certificate",
Args: cobra.NoArgs,
Run: cmdCertificatesGenerateRun,
}
cmd.Flags().String("start-date", "", "Creation date formatted as Jan 1 15:04:05 2011")
cmd.Flags().Duration("duration", 365*24*time.Hour, "Duration that certificate is valid for")
cmd.Flags().Bool("ca", false, "Whether this cert should be its own Certificate Authority")
cmd.Flags().Int("rsa-bits", 2048, "Size of RSA key to generate. Ignored if --ecdsa-curve is set")
cmd.Flags().String("ecdsa-curve", "", "ECDSA curve to use to generate a key. Valid values are P224, P256 (recommended), P384, P521")
cmd.Flags().Bool("ed25519", false, "Generate an Ed25519 key")
cmd.Flags().String("dir", "", "Target directory where the certificate and keys will be stored")
return cmd
}
func cmdCertificatesGenerateRun(cmd *cobra.Command, _ []string) {
// implementation retrieved from https://golang.org/src/crypto/tls/generate_cert.go
ecdsaCurve, err := cmd.Flags().GetString("ecdsa-curve")
if err != nil {
fmt.Printf("Failed to parse ecdsa-curve flag: %v\n", err)
os.Exit(1)
}
ed25519Key, err := cmd.Flags().GetBool("ed25519")
if err != nil {
fmt.Printf("Failed to parse ed25519 flag: %v\n", err)
os.Exit(1)
}
rsaBits, err := cmd.Flags().GetInt("rsa-bits")
if err != nil {
fmt.Printf("Failed to parse rsa-bits flag: %v\n", err)
os.Exit(1)
}
hosts, err := cmd.Flags().GetStringSlice("host")
if err != nil {
fmt.Printf("Failed to parse host flag: %v\n", err)
os.Exit(1)
}
validFrom, err := cmd.Flags().GetString("start-date")
if err != nil {
fmt.Printf("Failed to parse start-date flag: %v\n", err)
os.Exit(1)
}
validFor, err := cmd.Flags().GetDuration("duration")
if err != nil {
fmt.Printf("Failed to parse duration flag: %v\n", err)
os.Exit(1)
}
isCA, err := cmd.Flags().GetBool("ca")
if err != nil {
fmt.Printf("Failed to parse ca flag: %v\n", err)
os.Exit(1)
}
certificateTargetDirectory, err := cmd.Flags().GetString("dir")
if err != nil {
fmt.Printf("Failed to parse dir flag: %v\n", err)
os.Exit(1)
}
cmdCertificatesGenerateRunExtended(hosts, ecdsaCurve, validFrom, certificateTargetDirectory, ed25519Key, isCA, rsaBits, validFor)
}
func cmdCertificatesGenerateRunExtended(hosts []string, ecdsaCurve, validFrom, certificateTargetDirectory string, ed25519Key, isCA bool, rsaBits int, validFor time.Duration) {
certPath := filepath.Join(certificateTargetDirectory, "cert.pem")
keyPath := filepath.Join(certificateTargetDirectory, "key.pem")
var (
notBefore time.Time
err error
)
switch len(validFrom) {
case 0:
notBefore = time.Now()
default:
notBefore, err = time.Parse("Jan 2 15:04:05 2006", validFrom)
if err != nil {
log.Fatalf("Failed to parse start date: %v", err)
}
}
var privateKeyBuilder utils.PrivateKeyBuilder
switch ecdsaCurve {
case "":
if ed25519Key {
privateKeyBuilder = utils.Ed25519KeyBuilder{}
} else {
privateKeyBuilder = utils.RSAKeyBuilder{}.WithKeySize(rsaBits)
}
case "P224":
privateKeyBuilder = utils.ECDSAKeyBuilder{}.WithCurve(elliptic.P224())
case "P256":
privateKeyBuilder = utils.ECDSAKeyBuilder{}.WithCurve(elliptic.P256())
case "P384":
privateKeyBuilder = utils.ECDSAKeyBuilder{}.WithCurve(elliptic.P384())
case "P521":
privateKeyBuilder = utils.ECDSAKeyBuilder{}.WithCurve(elliptic.P521())
default:
log.Fatalf("Failed to generate private key: unrecognized elliptic curve: \"%s\"", ecdsaCurve)
}
certBytes, keyBytes, err := utils.GenerateCertificate(privateKeyBuilder, hosts, notBefore, validFor, isCA)
if err != nil {
log.Fatal(err)
}
err = os.WriteFile(certPath, certBytes, 0600)
if err != nil {
log.Fatalf("failed to write %s for writing: %v", certPath, err)
}
fmt.Printf("Certificate written to %s\n", certPath)
err = os.WriteFile(keyPath, keyBytes, 0600)
if err != nil {
log.Fatalf("failed to write %s for writing: %v", certPath, err)
}
fmt.Printf("Private Key written to %s\n", keyPath)
}