71d9c33802
* Add "plumbing" for surfacing warnings, and add warning about TTL > maxTTL when issuing a cert.
184 lines
5.6 KiB
Go
184 lines
5.6 KiB
Go
package pki
|
|
|
|
import (
|
|
"context"
|
|
"encoding/base64"
|
|
"fmt"
|
|
|
|
"github.com/hashicorp/vault/sdk/framework"
|
|
"github.com/hashicorp/vault/sdk/helper/errutil"
|
|
"github.com/hashicorp/vault/sdk/logical"
|
|
)
|
|
|
|
func pathGenerateIntermediate(b *backend) *framework.Path {
|
|
return buildPathGenerateIntermediate(b, "intermediate/generate/"+framework.GenericNameRegex("exported"))
|
|
}
|
|
|
|
func pathSetSignedIntermediate(b *backend) *framework.Path {
|
|
ret := &framework.Path{
|
|
Pattern: "intermediate/set-signed",
|
|
|
|
Fields: map[string]*framework.FieldSchema{
|
|
"certificate": {
|
|
Type: framework.TypeString,
|
|
Description: `PEM-format certificate. This must be a CA
|
|
certificate with a public key matching the
|
|
previously-generated key from the generation
|
|
endpoint. Additional parent CAs may be optionally
|
|
appended to the bundle.`,
|
|
},
|
|
},
|
|
Operations: map[logical.Operation]framework.OperationHandler{
|
|
logical.UpdateOperation: &framework.PathOperation{
|
|
Callback: b.pathImportIssuers,
|
|
// Read more about why these flags are set in backend.go
|
|
ForwardPerformanceStandby: true,
|
|
ForwardPerformanceSecondary: true,
|
|
},
|
|
},
|
|
|
|
HelpSynopsis: pathSetSignedIntermediateHelpSyn,
|
|
HelpDescription: pathSetSignedIntermediateHelpDesc,
|
|
}
|
|
|
|
return ret
|
|
}
|
|
|
|
func (b *backend) pathGenerateIntermediate(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
|
|
// Since we're planning on updating issuers here, grab the lock so we've
|
|
// got a consistent view.
|
|
b.issuersLock.Lock()
|
|
defer b.issuersLock.Unlock()
|
|
|
|
var err error
|
|
|
|
if b.useLegacyBundleCaStorage() {
|
|
return logical.ErrorResponse("Can not create intermediate until migration has completed"), nil
|
|
}
|
|
|
|
// Nasty hack :-) For cross-signing, we want to use the existing key, but
|
|
// this isn't _actually_ part of the path. Put it into the request
|
|
// parameters as if it was.
|
|
if req.Path == "intermediate/cross-sign" {
|
|
data.Raw["exported"] = "existing"
|
|
}
|
|
|
|
// Nasty hack part two. :-) For generation of CSRs, certutil presently doesn't
|
|
// support configuration of this. However, because we need generation parameters,
|
|
// which create a role and attempt to read this parameter, we need to provide
|
|
// a value (which will be ignored). Hence, we stub in the missing parameters here,
|
|
// including its schema, just enough for it to work..
|
|
data.Schema["signature_bits"] = &framework.FieldSchema{
|
|
Type: framework.TypeInt,
|
|
Default: 0,
|
|
}
|
|
data.Raw["signature_bits"] = 0
|
|
data.Schema["use_pss"] = &framework.FieldSchema{
|
|
Type: framework.TypeBool,
|
|
Default: false,
|
|
}
|
|
data.Raw["use_pss"] = false
|
|
|
|
sc := b.makeStorageContext(ctx, req.Storage)
|
|
exported, format, role, errorResp := getGenerationParams(sc, data)
|
|
if errorResp != nil {
|
|
return errorResp, nil
|
|
}
|
|
|
|
keyName, err := getKeyName(sc, data)
|
|
if err != nil {
|
|
return logical.ErrorResponse(err.Error()), nil
|
|
}
|
|
var resp *logical.Response
|
|
input := &inputBundle{
|
|
role: role,
|
|
req: req,
|
|
apiData: data,
|
|
}
|
|
parsedBundle, warnings, err := generateIntermediateCSR(sc, input, b.Backend.GetRandomReader())
|
|
if err != nil {
|
|
switch err.(type) {
|
|
case errutil.UserError:
|
|
return logical.ErrorResponse(err.Error()), nil
|
|
default:
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
csrb, err := parsedBundle.ToCSRBundle()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("error converting raw CSR bundle to CSR bundle: %w", err)
|
|
}
|
|
|
|
resp = &logical.Response{
|
|
Data: map[string]interface{}{},
|
|
}
|
|
|
|
entries, err := getGlobalAIAURLs(ctx, req.Storage)
|
|
if err == nil && len(entries.OCSPServers) == 0 && len(entries.IssuingCertificates) == 0 && len(entries.CRLDistributionPoints) == 0 {
|
|
// If the operator hasn't configured any of the URLs prior to
|
|
// generating this issuer, we should add a warning to the response,
|
|
// informing them they might want to do so and re-generate the issuer.
|
|
resp.AddWarning("This mount hasn't configured any authority information access (AIA) fields; this may make it harder for systems to find missing certificates in the chain or to validate revocation status of certificates. Consider updating /config/urls or the newly generated issuer with this information. Since this certificate is an intermediate, it might be useful to regenerate this certificate after fixing this problem for the root mount.")
|
|
}
|
|
|
|
switch format {
|
|
case "pem":
|
|
resp.Data["csr"] = csrb.CSR
|
|
if exported {
|
|
resp.Data["private_key"] = csrb.PrivateKey
|
|
resp.Data["private_key_type"] = csrb.PrivateKeyType
|
|
}
|
|
|
|
case "pem_bundle":
|
|
resp.Data["csr"] = csrb.CSR
|
|
if exported {
|
|
resp.Data["csr"] = fmt.Sprintf("%s\n%s", csrb.PrivateKey, csrb.CSR)
|
|
resp.Data["private_key"] = csrb.PrivateKey
|
|
resp.Data["private_key_type"] = csrb.PrivateKeyType
|
|
}
|
|
|
|
case "der":
|
|
resp.Data["csr"] = base64.StdEncoding.EncodeToString(parsedBundle.CSRBytes)
|
|
if exported {
|
|
resp.Data["private_key"] = base64.StdEncoding.EncodeToString(parsedBundle.PrivateKeyBytes)
|
|
resp.Data["private_key_type"] = csrb.PrivateKeyType
|
|
}
|
|
default:
|
|
return nil, fmt.Errorf("unsupported format argument: %s", format)
|
|
}
|
|
|
|
if data.Get("private_key_format").(string) == "pkcs8" {
|
|
err = convertRespToPKCS8(resp)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
myKey, _, err := sc.importKey(csrb.PrivateKey, keyName, csrb.PrivateKeyType)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
resp.Data["key_id"] = myKey.ID
|
|
|
|
resp = addWarnings(resp, warnings)
|
|
|
|
return resp, nil
|
|
}
|
|
|
|
const pathGenerateIntermediateHelpSyn = `
|
|
Generate a new CSR and private key used for signing.
|
|
`
|
|
|
|
const pathGenerateIntermediateHelpDesc = `
|
|
See the API documentation for more information.
|
|
`
|
|
|
|
const pathSetSignedIntermediateHelpSyn = `
|
|
Provide the signed intermediate CA cert.
|
|
`
|
|
|
|
const pathSetSignedIntermediateHelpDesc = `
|
|
See the API documentation for more information.
|
|
`
|