forked from hashicorp/vault
-
Notifications
You must be signed in to change notification settings - Fork 1
/
path_config_ca.go
149 lines (124 loc) · 4.49 KB
/
path_config_ca.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
package pki
import (
"fmt"
"github.com/hashicorp/vault/helper/certutil"
"github.com/hashicorp/vault/logical"
"github.com/hashicorp/vault/logical/framework"
)
func pathConfigCA(b *backend) *framework.Path {
return &framework.Path{
Pattern: "config/ca",
Fields: map[string]*framework.FieldSchema{
"pem_bundle": &framework.FieldSchema{
Type: framework.TypeString,
Description: `PEM-format, concatenated unencrypted
secret key and certificate, or, if a
CSR was generated with the "generate"
endpoint, just the signed certificate.`,
},
},
Callbacks: map[logical.Operation]framework.OperationFunc{
logical.UpdateOperation: b.pathCAWrite,
},
HelpSynopsis: pathConfigCAHelpSyn,
HelpDescription: pathConfigCAHelpDesc,
}
}
func (b *backend) pathCAWrite(
req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
pemBundle := data.Get("pem_bundle").(string)
parsedBundle, err := certutil.ParsePEMBundle(pemBundle)
if err != nil {
switch err.(type) {
case certutil.InternalError:
return nil, err
default:
return logical.ErrorResponse(err.Error()), nil
}
}
if parsedBundle.PrivateKey == nil ||
parsedBundle.PrivateKeyType == certutil.UnknownPrivateKey {
return logical.ErrorResponse("private key not found in the PEM bundle"), nil
}
// Handle the case of a self-signed certificate; the parsing function will
// see the CA and put it into the issuer
if parsedBundle.Certificate == nil &&
parsedBundle.IssuingCA != nil {
equal, err := certutil.ComparePublicKeys(parsedBundle.IssuingCA.PublicKey, parsedBundle.PrivateKey.Public())
if err != nil {
return logical.ErrorResponse(fmt.Sprintf(
"got only a CA and private key but could not verify the public keys match: %v", err)), nil
}
if !equal {
return logical.ErrorResponse(
"got only a CA and private key but keys do not match"), nil
}
parsedBundle.Certificate = parsedBundle.IssuingCA
parsedBundle.CertificateBytes = parsedBundle.IssuingCABytes
}
if parsedBundle.Certificate == nil {
return logical.ErrorResponse("no certificate found in the PEM bundle"), nil
}
if !parsedBundle.Certificate.IsCA {
return logical.ErrorResponse("the given certificate is not marked for CA use and cannot be used with this backend"), nil
}
cb, err := parsedBundle.ToCertBundle()
if err != nil {
return nil, fmt.Errorf("error converting raw values into cert bundle: %s", err)
}
entry, err := logical.StorageEntryJSON("config/ca_bundle", cb)
if err != nil {
return nil, err
}
err = req.Storage.Put(entry)
if err != nil {
return nil, err
}
// For ease of later use, also store just the certificate at a known
// location, plus a fresh CRL
entry.Key = "ca"
entry.Value = parsedBundle.CertificateBytes
err = req.Storage.Put(entry)
if err != nil {
return nil, err
}
err = buildCRL(b, req)
return nil, err
}
const pathConfigCAHelpSyn = `
Set the CA certificate and private key used for generated credentials.
`
const pathConfigCAHelpDesc = `
This sets the CA information used for credentials generated by this
by this mount. This must be a PEM-format, concatenated unencrypted
secret key and certificate.
For security reasons, the secret key cannot be retrieved later.
`
const pathConfigCAGenerateHelpSyn = `
Generate a new CA certificate and private key used for signing.
`
const pathConfigCAGenerateHelpDesc = `
This path generates a CA certificate and private key to be used for
credentials generated by this mount. The path can either
end in "internal" or "exported"; this controls whether the
unencrypted private key is exported after generation. This will
be your only chance to export the private key; for security reasons
it cannot be read or exported later.
If the "type" option is set to "self-signed", the generated
certificate will be a self-signed root CA. Otherwise, this mount
will act as an intermediate CA; a CSR will be returned, to be signed
by your chosen CA (which could be another mount of this backend).
Note that the CRL path will be set to this mount's CRL path; if you
need further customization it is recommended that you create a CSR
separately and get it signed. Either way, use the "config/ca/set"
endpoint to load the signed certificate into Vault.
`
const pathConfigCASignHelpSyn = `
Generate a signed CA certificate from a CSR.
`
const pathConfigCASignHelpDesc = `
This path generates a CA certificate to be used for credentials
generated by the certificate's destination mount.
Use the "config/ca/set" endpoint to load the signed certificate
into Vault another Vault mount.
`