This repository has been archived by the owner on Mar 24, 2023. It is now read-only.
/
certs.go
158 lines (136 loc) · 4.17 KB
/
certs.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
package util
import (
"crypto/x509"
"encoding/pem"
"fmt"
"strconv"
"strings"
"time"
"github.com/cloudflare/cfssl/config"
"github.com/cloudflare/cfssl/csr"
"github.com/cloudflare/cfssl/helpers"
"github.com/cloudflare/cfssl/initca"
"github.com/cloudflare/cfssl/signer"
"github.com/cloudflare/cfssl/signer/local"
"github.com/pkg/errors"
)
type CertType struct {
Cert string
Key string
}
type CAType struct {
Cert string
Key string
}
func makeKeyRequest(certKind string) (csr.BasicKeyRequest, error) {
kindParts := strings.Split(certKind, "-")
if len(kindParts) == 2 {
if kindParts[0] == "rsa" {
rsaBits, err := strconv.ParseInt(kindParts[1], 10, 32)
if err != nil {
return csr.BasicKeyRequest{}, errors.Wrapf(err, "unable to parse kind %s", certKind)
}
return csr.BasicKeyRequest{A: "rsa", S: int(rsaBits)}, nil
}
} else if len(kindParts) == 1 {
switch certKind {
case "":
// use 2048 bit rsa if no key type is specified
return csr.BasicKeyRequest{A: "rsa", S: 2048}, nil
// elliptic curve keys
case "P256":
return csr.BasicKeyRequest{A: "ecdsa", S: 256}, nil
case "P384":
return csr.BasicKeyRequest{A: "ecdsa", S: 384}, nil
case "P521":
return csr.BasicKeyRequest{A: "ecdsa", S: 521}, nil
default:
}
}
return csr.BasicKeyRequest{}, fmt.Errorf("unable to parse kind %s", certKind)
}
func MakeCert(host []string, certKind, CACert, CAKey string) (CertType, error) {
parsedCaCert, err := helpers.ParseCertificatePEM([]byte(CACert))
if err != nil {
return CertType{}, errors.Wrap(err, "parse cert pem")
}
parsedCaKey, err := helpers.ParsePrivateKeyPEM([]byte(CAKey))
if err != nil {
return CertType{}, errors.Wrap(err, "parse key pem")
}
keyRequest, err := makeKeyRequest(certKind)
if err != nil {
return CertType{}, errors.Wrap(err, "parse kind")
}
req := csr.CertificateRequest{
KeyRequest: &keyRequest,
Hosts: host,
}
certReq, key, err := csr.ParseRequest(&req)
if err != nil {
return CertType{}, errors.Wrap(err, "parse csr")
}
twoYearConfig := config.DefaultConfig()
twoYearConfig.Expiry = 17520 * time.Hour // two years
twoYearConfig.ExpiryString = "17520h"
signConfig := config.Signing{
Default: twoYearConfig,
}
localSigner, err := local.NewSigner(parsedCaKey, parsedCaCert, signer.DefaultSigAlgo(parsedCaKey), &signConfig)
if err != nil {
return CertType{}, errors.Wrap(err, "create signer")
}
signedCert, err := localSigner.Sign(signer.SignRequest{Hosts: host, Request: string(certReq), NotBefore: time.Now()})
if err != nil {
return CertType{}, errors.Wrap(err, "sign request")
}
return CertType{Cert: string(signedCert), Key: string(key)}, nil
}
func MakeCA(caKind string) (CAType, error) {
keyRequest, err := makeKeyRequest(caKind)
if err != nil {
return CAType{}, errors.Wrap(err, "parse kind")
}
req := csr.CertificateRequest{
KeyRequest: &keyRequest,
CN: "gatekeeper_ca",
Hosts: []string{
"gatekeeper_ca",
},
CA: &csr.CAConfig{
Expiry: "43800h", // 5 years
},
}
cert, _, key, err := initca.New(&req)
if err != nil {
return CAType{}, errors.Wrap(err, "initca")
}
return CAType{Cert: string(cert), Key: string(key)}, nil
}
// TimeToExpire takes a certificate, parses it, and returns the duration left until the certificate expires.
func TimeToExpire(cert []byte) (time.Duration, error) {
block, _ := pem.Decode(cert)
parsedCert, err := x509.ParseCertificate(block.Bytes)
if err != nil {
return time.Duration(0), errors.Wrap(err, "parse cert for expiration")
}
return time.Until(parsedCert.NotAfter), nil
}
// RenewCA takes an existing CA and generates a new certificate with the notBefore/notAfter dates updated.
func RenewCA(ca CAType) (CAType, error) {
// regenerate the CA cert *with the same key*
parsedCert, err := helpers.ParseCertificatePEM([]byte(ca.Cert))
if err != nil {
return CAType{}, errors.Wrap(err, "parse ca certificate")
}
parsedKey, err := helpers.ParsePrivateKeyPEM([]byte(ca.Key))
if err != nil {
return CAType{}, errors.Wrap(err, "parse ca key")
}
newCABytes, err := initca.RenewFromSigner(parsedCert, parsedKey)
if err != nil {
return CAType{}, errors.Wrap(err, "renew ca certificate")
}
ca.Cert = string(newCABytes)
return ca, nil
}