-
Notifications
You must be signed in to change notification settings - Fork 1
/
gencert.go
168 lines (147 loc) · 4.07 KB
/
gencert.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
167
168
package csr
import (
"encoding/json"
"fmt"
"strings"
"time"
cfsslconfig "github.com/cloudflare/cfssl/config"
"github.com/cloudflare/cfssl/signer"
"github.com/go-phorce/dolly/algorithms/guid"
"github.com/go-phorce/dolly/cmd/dollypki/cli"
"github.com/go-phorce/dolly/ctl"
"github.com/go-phorce/dolly/xpki/csrprov"
"github.com/pkg/errors"
)
// GenCertFlags specifies flags for GenCert command
type GenCertFlags struct {
// CA specifies file name with CA cert
CA *string
// CAKey specifies file name with CA key
CAKey *string
// CAConfig specifies file name with ca-config
CAConfig *string
// CsrProfile specifies file name with CSR profile
CsrProfile *string
// Label specifies name for generated key
Label *string
// Hostname specifies Host name for generated cert
Hostname *string
// Profile specifies the profile name from ca-config
Profile *string
// Output specifies the optional prefix for output files,
// if not set, the output will be printed to STDOUT only
Output *string
}
func ensureGenCertFlags(f *GenCertFlags) *GenCertFlags {
var (
emptyString = ""
)
if f.CA == nil {
f.CA = &emptyString
}
if f.CAKey == nil {
f.CAKey = &emptyString
}
if f.CAConfig == nil {
f.CAConfig = &emptyString
}
if f.CsrProfile == nil {
f.CsrProfile = &emptyString
}
if f.Label == nil {
f.Label = &emptyString
}
if f.Hostname == nil {
f.Hostname = &emptyString
}
if f.Profile == nil {
f.Profile = &emptyString
}
if f.Output == nil {
f.Output = &emptyString
}
return f
}
// GenCert generates a cert
func GenCert(c ctl.Control, p interface{}) error {
flags := ensureGenCertFlags(p.(*GenCertFlags))
cryptoprov := c.(*cli.Cli).CryptoProv()
if cryptoprov == nil {
return errors.Errorf("unsupported command for this crypto provider")
}
prov := csrprov.New(cryptoprov.Default())
if *flags.CA == "" || *flags.CAKey == "" {
return errors.Errorf("CA certificate and key are required")
}
// Load CSR
csrf, err := cli.ReadStdin(*flags.CsrProfile)
if err != nil {
return errors.WithMessage(err, "read CSR profile")
}
req := csrprov.CertificateRequest{
// TODO: alg and size from params
KeyRequest: prov.NewKeyRequest(prefixKeyLabel(*flags.Label), "ECDSA", 256, csrprov.Signing),
}
err = json.Unmarshal(csrf, &req)
if err != nil {
return errors.WithMessage(err, "invalid CSR")
}
if req.CA != nil {
return errors.New("CA section only permitted with --initca option, use genkey comand instead")
}
// Load ca-config
cacfg, err := cfsslconfig.LoadFile(*flags.CAConfig)
if err != nil {
return errors.WithMessage(err, "ca-config")
}
if cacfg.Signing == nil {
return errors.New("missing signing policy in ca-config")
}
if !cacfg.Signing.Valid() {
return errors.New("invalid signing policy in ca-config")
}
// ensure that signer can be created before the key is generated
s, _, err := csrprov.NewLocalCASignerFromFile(cryptoprov, *flags.CA, *flags.CAKey, cacfg.Signing)
if err != nil {
return errors.WithMessage(err, "create signer")
}
var key, csrPEM []byte
csrPEM, key, _, _, err = prov.ProcessCsrRequest(&req)
if err != nil {
return errors.WithMessage(err, "ProcessRequest")
}
signReq := signer.SignRequest{
Hosts: signer.SplitHosts(*flags.Hostname),
Request: string(csrPEM),
Profile: *flags.Profile,
}
cert, err := s.Sign(signReq)
if *flags.Output == "" {
c.(*cli.Cli).PrintCert(key, csrPEM, cert)
} else {
baseName := *flags.Output
err = cli.WriteFile(baseName+".pem", cert, 0664)
if err != nil {
return errors.WithStack(err)
}
err = cli.WriteFile(baseName+".csr", csrPEM, 0664)
if err != nil {
return errors.WithStack(err)
}
err = cli.WriteFile(baseName+"-key.pem", key, 0600)
if err != nil {
return errors.WithStack(err)
}
}
return nil
}
// prefixKeyLabel adds a date prefix to label for a key
func prefixKeyLabel(label string) string {
if strings.HasSuffix(label, "*") {
g := guid.MustCreate()
t := time.Now().UTC()
label = strings.TrimSuffix(label, "*") +
fmt.Sprintf("_%04d%02d%02d%02d%02d%02d_%x", t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second(), g[:4])
}
return label
}