mirror of
https://github.com/optim-enterprises-bv/vault.git
synced 2025-10-30 18:17:55 +00:00
Refactor sign/issue response logic to be usable by CIEPS codebase (#22053)
- Extract out the sign/issue certificate (non-CA) response into a function that can be used by the CIEPS sign/issue API handlers.
This commit is contained in:
@@ -70,8 +70,61 @@ var (
|
|||||||
|
|
||||||
// OIDs for X.509 certificate extensions used below.
|
// OIDs for X.509 certificate extensions used below.
|
||||||
oidExtensionSubjectAltName = []int{2, 5, 29, 17}
|
oidExtensionSubjectAltName = []int{2, 5, 29, 17}
|
||||||
|
|
||||||
|
// Cloned from https://github.com/golang/go/blob/82c713feb05da594567631972082af2fcba0ee4f/src/crypto/x509/x509.go#L327-L379
|
||||||
|
oidSignatureMD2WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 2}
|
||||||
|
oidSignatureMD5WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 4}
|
||||||
|
oidSignatureSHA1WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 5}
|
||||||
|
oidSignatureSHA256WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 11}
|
||||||
|
oidSignatureSHA384WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 12}
|
||||||
|
oidSignatureSHA512WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 13}
|
||||||
|
oidSignatureRSAPSS = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 10}
|
||||||
|
oidSignatureDSAWithSHA1 = asn1.ObjectIdentifier{1, 2, 840, 10040, 4, 3}
|
||||||
|
oidSignatureDSAWithSHA256 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 3, 2}
|
||||||
|
oidSignatureECDSAWithSHA1 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 1}
|
||||||
|
oidSignatureECDSAWithSHA256 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 2}
|
||||||
|
oidSignatureECDSAWithSHA384 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 3}
|
||||||
|
oidSignatureECDSAWithSHA512 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 4}
|
||||||
|
oidSignatureEd25519 = asn1.ObjectIdentifier{1, 3, 101, 112}
|
||||||
|
oidISOSignatureSHA1WithRSA = asn1.ObjectIdentifier{1, 3, 14, 3, 2, 29}
|
||||||
|
|
||||||
|
signatureAlgorithmDetails = []struct {
|
||||||
|
algo x509.SignatureAlgorithm
|
||||||
|
name string
|
||||||
|
oid asn1.ObjectIdentifier
|
||||||
|
pubKeyAlgo x509.PublicKeyAlgorithm
|
||||||
|
hash crypto.Hash
|
||||||
|
}{
|
||||||
|
{x509.MD2WithRSA, "MD2-RSA", oidSignatureMD2WithRSA, x509.RSA, crypto.Hash(0) /* no value for MD2 */},
|
||||||
|
{x509.MD5WithRSA, "MD5-RSA", oidSignatureMD5WithRSA, x509.RSA, crypto.MD5},
|
||||||
|
{x509.SHA1WithRSA, "SHA1-RSA", oidSignatureSHA1WithRSA, x509.RSA, crypto.SHA1},
|
||||||
|
{x509.SHA1WithRSA, "SHA1-RSA", oidISOSignatureSHA1WithRSA, x509.RSA, crypto.SHA1},
|
||||||
|
{x509.SHA256WithRSA, "SHA256-RSA", oidSignatureSHA256WithRSA, x509.RSA, crypto.SHA256},
|
||||||
|
{x509.SHA384WithRSA, "SHA384-RSA", oidSignatureSHA384WithRSA, x509.RSA, crypto.SHA384},
|
||||||
|
{x509.SHA512WithRSA, "SHA512-RSA", oidSignatureSHA512WithRSA, x509.RSA, crypto.SHA512},
|
||||||
|
{x509.SHA256WithRSAPSS, "SHA256-RSAPSS", oidSignatureRSAPSS, x509.RSA, crypto.SHA256},
|
||||||
|
{x509.SHA384WithRSAPSS, "SHA384-RSAPSS", oidSignatureRSAPSS, x509.RSA, crypto.SHA384},
|
||||||
|
{x509.SHA512WithRSAPSS, "SHA512-RSAPSS", oidSignatureRSAPSS, x509.RSA, crypto.SHA512},
|
||||||
|
{x509.DSAWithSHA1, "DSA-SHA1", oidSignatureDSAWithSHA1, x509.DSA, crypto.SHA1},
|
||||||
|
{x509.DSAWithSHA256, "DSA-SHA256", oidSignatureDSAWithSHA256, x509.DSA, crypto.SHA256},
|
||||||
|
{x509.ECDSAWithSHA1, "ECDSA-SHA1", oidSignatureECDSAWithSHA1, x509.ECDSA, crypto.SHA1},
|
||||||
|
{x509.ECDSAWithSHA256, "ECDSA-SHA256", oidSignatureECDSAWithSHA256, x509.ECDSA, crypto.SHA256},
|
||||||
|
{x509.ECDSAWithSHA384, "ECDSA-SHA384", oidSignatureECDSAWithSHA384, x509.ECDSA, crypto.SHA384},
|
||||||
|
{x509.ECDSAWithSHA512, "ECDSA-SHA512", oidSignatureECDSAWithSHA512, x509.ECDSA, crypto.SHA512},
|
||||||
|
{x509.PureEd25519, "Ed25519", oidSignatureEd25519, x509.Ed25519, crypto.Hash(0) /* no pre-hashing */},
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func doesPublicKeyAlgoMatchSignatureAlgo(pubKey x509.PublicKeyAlgorithm, algo x509.SignatureAlgorithm) bool {
|
||||||
|
for _, detail := range signatureAlgorithmDetails {
|
||||||
|
if detail.algo == algo {
|
||||||
|
return pubKey == detail.pubKeyAlgo
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func getFormat(data *framework.FieldData) string {
|
func getFormat(data *framework.FieldData) string {
|
||||||
format := data.Get("format").(string)
|
format := data.Get("format").(string)
|
||||||
switch format {
|
switch format {
|
||||||
|
|||||||
@@ -167,16 +167,6 @@ func buildPathSign(b *backend, pattern string, displayAttrs *framework.DisplayAt
|
|||||||
Description: `Time of expiration`,
|
Description: `Time of expiration`,
|
||||||
Required: true,
|
Required: true,
|
||||||
},
|
},
|
||||||
"private_key": {
|
|
||||||
Type: framework.TypeString,
|
|
||||||
Description: `Private key`,
|
|
||||||
Required: false,
|
|
||||||
},
|
|
||||||
"private_key_type": {
|
|
||||||
Type: framework.TypeString,
|
|
||||||
Description: `Private key type`,
|
|
||||||
Required: false,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}},
|
}},
|
||||||
},
|
},
|
||||||
@@ -260,16 +250,6 @@ func buildPathIssuerSignVerbatim(b *backend, pattern string, displayAttrs *frame
|
|||||||
Description: `Time of expiration`,
|
Description: `Time of expiration`,
|
||||||
Required: true,
|
Required: true,
|
||||||
},
|
},
|
||||||
"private_key": {
|
|
||||||
Type: framework.TypeString,
|
|
||||||
Description: `Private key`,
|
|
||||||
Required: false,
|
|
||||||
},
|
|
||||||
"private_key_type": {
|
|
||||||
Type: framework.TypeString,
|
|
||||||
Description: `Private key type`,
|
|
||||||
Required: false,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}},
|
}},
|
||||||
},
|
},
|
||||||
@@ -403,73 +383,23 @@ func (b *backend) pathIssueSignCert(ctx context.Context, req *logical.Request, d
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
signingCB, err := signingBundle.ToCertBundle()
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("error converting raw signing bundle to cert bundle: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
cb, err := parsedBundle.ToCertBundle()
|
cb, err := parsedBundle.ToCertBundle()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("error converting raw cert bundle to cert bundle: %w", err)
|
return nil, fmt.Errorf("error converting raw cert bundle to cert bundle: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
caChainGen := newCaChainOutput(parsedBundle, data)
|
resp, err := signIssueApiResponse(data, parsedBundle, signingBundle, warnings)
|
||||||
|
if err != nil {
|
||||||
respData := map[string]interface{}{
|
return nil, err
|
||||||
"expiration": int64(parsedBundle.Certificate.NotAfter.Unix()),
|
|
||||||
"serial_number": cb.SerialNumber,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch format {
|
|
||||||
case "pem":
|
|
||||||
respData["issuing_ca"] = signingCB.Certificate
|
|
||||||
respData["certificate"] = cb.Certificate
|
|
||||||
if caChainGen.containsChain() {
|
|
||||||
respData["ca_chain"] = caChainGen.pemEncodedChain()
|
|
||||||
}
|
|
||||||
if !useCSR {
|
|
||||||
respData["private_key"] = cb.PrivateKey
|
|
||||||
respData["private_key_type"] = cb.PrivateKeyType
|
|
||||||
}
|
|
||||||
|
|
||||||
case "pem_bundle":
|
|
||||||
respData["issuing_ca"] = signingCB.Certificate
|
|
||||||
respData["certificate"] = cb.ToPEMBundle()
|
|
||||||
if caChainGen.containsChain() {
|
|
||||||
respData["ca_chain"] = caChainGen.pemEncodedChain()
|
|
||||||
}
|
|
||||||
if !useCSR {
|
|
||||||
respData["private_key"] = cb.PrivateKey
|
|
||||||
respData["private_key_type"] = cb.PrivateKeyType
|
|
||||||
}
|
|
||||||
|
|
||||||
case "der":
|
|
||||||
respData["certificate"] = base64.StdEncoding.EncodeToString(parsedBundle.CertificateBytes)
|
|
||||||
respData["issuing_ca"] = base64.StdEncoding.EncodeToString(signingBundle.CertificateBytes)
|
|
||||||
|
|
||||||
if caChainGen.containsChain() {
|
|
||||||
respData["ca_chain"] = caChainGen.derEncodedChain()
|
|
||||||
}
|
|
||||||
|
|
||||||
if !useCSR {
|
|
||||||
respData["private_key"] = base64.StdEncoding.EncodeToString(parsedBundle.PrivateKeyBytes)
|
|
||||||
respData["private_key_type"] = cb.PrivateKeyType
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return nil, fmt.Errorf("unsupported format: %s", format)
|
|
||||||
}
|
|
||||||
|
|
||||||
var resp *logical.Response
|
|
||||||
switch {
|
switch {
|
||||||
case role.GenerateLease == nil:
|
case role.GenerateLease == nil:
|
||||||
return nil, fmt.Errorf("generate lease in role is nil")
|
return nil, fmt.Errorf("generate lease in role is nil")
|
||||||
case !*role.GenerateLease:
|
case !*role.GenerateLease:
|
||||||
// If lease generation is disabled do not populate `Secret` field in
|
// Use resp from above
|
||||||
// the response
|
|
||||||
resp = &logical.Response{
|
|
||||||
Data: respData,
|
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
|
respData := resp.Data
|
||||||
resp = b.Secret(SecretCertsType).Response(
|
resp = b.Secret(SecretCertsType).Response(
|
||||||
respData,
|
respData,
|
||||||
map[string]interface{}{
|
map[string]interface{}{
|
||||||
@@ -478,13 +408,6 @@ func (b *backend) pathIssueSignCert(ctx context.Context, req *logical.Request, d
|
|||||||
resp.Secret.TTL = parsedBundle.Certificate.NotAfter.Sub(time.Now())
|
resp.Secret.TTL = parsedBundle.Certificate.NotAfter.Sub(time.Now())
|
||||||
}
|
}
|
||||||
|
|
||||||
if data.Get("private_key_format").(string) == "pkcs8" {
|
|
||||||
err = convertRespToPKCS8(resp)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !role.NoStore {
|
if !role.NoStore {
|
||||||
key := "certs/" + normalizeSerial(cb.SerialNumber)
|
key := "certs/" + normalizeSerial(cb.SerialNumber)
|
||||||
certsCounted := b.certsCounted.Load()
|
certsCounted := b.certsCounted.Load()
|
||||||
@@ -556,6 +479,83 @@ func (cac *caChainOutput) derEncodedChain() []string {
|
|||||||
return derCaChain
|
return derCaChain
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func signIssueApiResponse(data *framework.FieldData, parsedBundle *certutil.ParsedCertBundle, signingBundle *certutil.CAInfoBundle, warnings []string) (*logical.Response, error) {
|
||||||
|
cb, err := parsedBundle.ToCertBundle()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error converting raw cert bundle to cert bundle: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
signingCB, err := signingBundle.ToCertBundle()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error converting raw signing bundle to cert bundle: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
caChainGen := newCaChainOutput(parsedBundle, data)
|
||||||
|
includeKey := parsedBundle.PrivateKey != nil
|
||||||
|
|
||||||
|
respData := map[string]interface{}{
|
||||||
|
"expiration": parsedBundle.Certificate.NotAfter.Unix(),
|
||||||
|
"serial_number": cb.SerialNumber,
|
||||||
|
}
|
||||||
|
|
||||||
|
format := getFormat(data)
|
||||||
|
switch format {
|
||||||
|
case "pem":
|
||||||
|
respData["issuing_ca"] = signingCB.Certificate
|
||||||
|
respData["certificate"] = cb.Certificate
|
||||||
|
if caChainGen.containsChain() {
|
||||||
|
respData["ca_chain"] = caChainGen.pemEncodedChain()
|
||||||
|
}
|
||||||
|
if includeKey {
|
||||||
|
respData["private_key"] = cb.PrivateKey
|
||||||
|
respData["private_key_type"] = cb.PrivateKeyType
|
||||||
|
}
|
||||||
|
|
||||||
|
case "pem_bundle":
|
||||||
|
respData["issuing_ca"] = signingCB.Certificate
|
||||||
|
respData["certificate"] = cb.ToPEMBundle()
|
||||||
|
if caChainGen.containsChain() {
|
||||||
|
respData["ca_chain"] = caChainGen.pemEncodedChain()
|
||||||
|
}
|
||||||
|
if includeKey {
|
||||||
|
respData["private_key"] = cb.PrivateKey
|
||||||
|
respData["private_key_type"] = cb.PrivateKeyType
|
||||||
|
}
|
||||||
|
|
||||||
|
case "der":
|
||||||
|
respData["certificate"] = base64.StdEncoding.EncodeToString(parsedBundle.CertificateBytes)
|
||||||
|
respData["issuing_ca"] = base64.StdEncoding.EncodeToString(signingBundle.CertificateBytes)
|
||||||
|
|
||||||
|
if caChainGen.containsChain() {
|
||||||
|
respData["ca_chain"] = caChainGen.derEncodedChain()
|
||||||
|
}
|
||||||
|
|
||||||
|
if includeKey {
|
||||||
|
respData["private_key"] = base64.StdEncoding.EncodeToString(parsedBundle.PrivateKeyBytes)
|
||||||
|
respData["private_key_type"] = cb.PrivateKeyType
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("unsupported format: %s", format)
|
||||||
|
}
|
||||||
|
|
||||||
|
resp := &logical.Response{
|
||||||
|
Data: respData,
|
||||||
|
}
|
||||||
|
|
||||||
|
if includeKey {
|
||||||
|
if keyFormat := data.Get("private_key_format"); keyFormat == "pkcs8" {
|
||||||
|
err := convertRespToPKCS8(resp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resp = addWarnings(resp, warnings)
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
const pathIssueHelpSyn = `
|
const pathIssueHelpSyn = `
|
||||||
Request a certificate using a certain role with the provided details.
|
Request a certificate using a certain role with the provided details.
|
||||||
`
|
`
|
||||||
|
|||||||
Reference in New Issue
Block a user