diff --git a/builtin/logical/pki/backend_test.go b/builtin/logical/pki/backend_test.go index 3f23068f9..bf10fdb6b 100644 --- a/builtin/logical/pki/backend_test.go +++ b/builtin/logical/pki/backend_test.go @@ -683,6 +683,7 @@ func generateRoleSteps(t *testing.T, useCSRs bool) []logicaltest.TestStep { KeyType: "rsa", KeyBits: 2048, RequireCN: true, + SignatureBits: 256, } issueVals := certutil.IssueData{} ret := []logicaltest.TestStep{} diff --git a/builtin/logical/pki/ca_util.go b/builtin/logical/pki/ca_util.go index 8692486d8..ea6b083c7 100644 --- a/builtin/logical/pki/ca_util.go +++ b/builtin/logical/pki/ca_util.go @@ -33,6 +33,7 @@ func (b *backend) getGenerationParams( TTL: time.Duration(data.Get("ttl").(int)) * time.Second, KeyType: data.Get("key_type").(string), KeyBits: data.Get("key_bits").(int), + SignatureBits: data.Get("signature_bits").(int), AllowLocalhost: true, AllowAnyName: true, AllowIPSANs: true, @@ -58,5 +59,10 @@ func (b *backend) getGenerationParams( errorResp = logical.ErrorResponse(err.Error()) } + if err := certutil.ValidateSignatureLength(role.SignatureBits); err != nil { + errorResp = logical.ErrorResponse(err.Error()) + return + } + return } diff --git a/builtin/logical/pki/cert_util.go b/builtin/logical/pki/cert_util.go index ea6f86af6..6df174a89 100644 --- a/builtin/logical/pki/cert_util.go +++ b/builtin/logical/pki/cert_util.go @@ -1060,6 +1060,7 @@ func generateCreationBundle(b *backend, data *inputBundle, caSign *certutil.CAIn OtherSANs: otherSANs, KeyType: data.role.KeyType, KeyBits: data.role.KeyBits, + SignatureBits: data.role.SignatureBits, NotAfter: notAfter, KeyUsage: x509.KeyUsage(parseKeyUsages(data.role.KeyUsage)), ExtKeyUsage: parseExtKeyUsages(data.role), diff --git a/builtin/logical/pki/fields.go b/builtin/logical/pki/fields.go index c67e39eaa..149001aa5 100644 --- a/builtin/logical/pki/fields.go +++ b/builtin/logical/pki/fields.go @@ -254,6 +254,18 @@ the key_type.`, }, } + fields["signature_bits"] = &framework.FieldSchema{ + Type: framework.TypeInt, + Default: 256, + Description: `The number of bits to use in the signature +algorithm. Defaults to 256 for SHA256. +Set to 384 for SHA384 and 512 for SHA512. +`, + DisplayAttrs: &framework.DisplayAttributes{ + Value: 256, + }, + } + fields["key_type"] = &framework.FieldSchema{ Type: framework.TypeString, Default: "rsa", diff --git a/builtin/logical/pki/path_roles.go b/builtin/logical/pki/path_roles.go index 6ca724acd..65d0cc390 100644 --- a/builtin/logical/pki/path_roles.go +++ b/builtin/logical/pki/path_roles.go @@ -205,7 +205,15 @@ certainly want to change this if you adjust the key_type.`, }, - "key_usage": { + "signature_bits": &framework.FieldSchema{ + Type: framework.TypeInt, + Default: 256, + Description: `The number of bits to use in the signature +algorithm. Defaults to 256 for SHA256. +Set to 384 for SHA384 and 512 for SHA512.`, + }, + + "key_usage": &framework.FieldSchema{ Type: framework.TypeCommaStringSlice, Default: []string{"DigitalSignature", "KeyAgreement", "KeyEncipherment"}, Description: `A comma-separated string or list of key usages (not extended @@ -559,6 +567,7 @@ func (b *backend) pathRoleCreate(ctx context.Context, req *logical.Request, data EmailProtectionFlag: data.Get("email_protection_flag").(bool), KeyType: data.Get("key_type").(string), KeyBits: data.Get("key_bits").(int), + SignatureBits: data.Get("signature_bits").(int), UseCSRCommonName: data.Get("use_csr_common_name").(bool), UseCSRSANs: data.Get("use_csr_sans").(bool), KeyUsage: data.Get("key_usage").([]string), @@ -613,6 +622,10 @@ func (b *backend) pathRoleCreate(ctx context.Context, req *logical.Request, data return logical.ErrorResponse(err.Error()), nil } + if err := certutil.ValidateSignatureLength(entry.SignatureBits); err != nil { + return logical.ErrorResponse(err.Error()), nil + } + if len(entry.ExtKeyUsageOIDs) > 0 { for _, oidstr := range entry.ExtKeyUsageOIDs { _, err := certutil.StringToOid(oidstr) @@ -750,6 +763,7 @@ type roleEntry struct { UseCSRSANs bool `json:"use_csr_sans" mapstructure:"use_csr_sans"` KeyType string `json:"key_type" mapstructure:"key_type"` KeyBits int `json:"key_bits" mapstructure:"key_bits"` + SignatureBits int `json:"signature_bits" mapstructure:"signature_bits"` MaxPathLength *int `json:",omitempty" mapstructure:"max_path_length"` KeyUsageOld string `json:"key_usage,omitempty"` KeyUsage []string `json:"key_usage_list" mapstructure:"key_usage"` @@ -800,6 +814,7 @@ func (r *roleEntry) ToResponseData() map[string]interface{} { "use_csr_sans": r.UseCSRSANs, "key_type": r.KeyType, "key_bits": r.KeyBits, + "signature_bits": r.SignatureBits, "key_usage": r.KeyUsage, "ext_key_usage": r.ExtKeyUsage, "ext_key_usage_oids": r.ExtKeyUsageOIDs, diff --git a/changelog/11245.txt b/changelog/11245.txt new file mode 100644 index 000000000..4f20c690e --- /dev/null +++ b/changelog/11245.txt @@ -0,0 +1,3 @@ +```release-note:improvement +pki: adds signature_bits field to customize signature algorithm on CAs and certs signed by Vault +``` diff --git a/sdk/helper/certutil/helpers.go b/sdk/helper/certutil/helpers.go index c23cca994..863ec1284 100644 --- a/sdk/helper/certutil/helpers.go +++ b/sdk/helper/certutil/helpers.go @@ -490,6 +490,17 @@ func StringToOid(in string) (asn1.ObjectIdentifier, error) { return asn1.ObjectIdentifier(ret), nil } +func ValidateSignatureLength(keyBits int) error { + switch keyBits { + case 256: + case 384: + case 512: + default: + return fmt.Errorf("unsupported signature algorithm: %d", keyBits) + } + return nil +} + func ValidateKeyTypeLength(keyType string, keyBits int) error { switch keyType { case "rsa": @@ -598,9 +609,23 @@ func createCertificate(data *CreationBundle, randReader io.Reader) (*ParsedCertB if data.SigningBundle != nil { switch data.SigningBundle.PrivateKeyType { case RSAPrivateKey: - certTemplate.SignatureAlgorithm = x509.SHA256WithRSA + switch data.Params.SignatureBits { + case 256: + certTemplate.SignatureAlgorithm = x509.SHA256WithRSA + case 384: + certTemplate.SignatureAlgorithm = x509.SHA384WithRSA + case 512: + certTemplate.SignatureAlgorithm = x509.SHA512WithRSA + } case ECPrivateKey: - certTemplate.SignatureAlgorithm = x509.ECDSAWithSHA256 + switch data.Params.SignatureBits { + case 256: + certTemplate.SignatureAlgorithm = x509.ECDSAWithSHA256 + case 384: + certTemplate.SignatureAlgorithm = x509.ECDSAWithSHA384 + case 512: + certTemplate.SignatureAlgorithm = x509.ECDSAWithSHA512 + } } caCert := data.SigningBundle.Certificate @@ -618,9 +643,23 @@ func createCertificate(data *CreationBundle, randReader io.Reader) (*ParsedCertB switch data.Params.KeyType { case "rsa": - certTemplate.SignatureAlgorithm = x509.SHA256WithRSA + switch data.Params.SignatureBits { + case 256: + certTemplate.SignatureAlgorithm = x509.SHA256WithRSA + case 384: + certTemplate.SignatureAlgorithm = x509.SHA384WithRSA + case 512: + certTemplate.SignatureAlgorithm = x509.SHA512WithRSA + } case "ec": - certTemplate.SignatureAlgorithm = x509.ECDSAWithSHA256 + switch data.Params.SignatureBits { + case 256: + certTemplate.SignatureAlgorithm = x509.ECDSAWithSHA256 + case 384: + certTemplate.SignatureAlgorithm = x509.ECDSAWithSHA384 + case 512: + certTemplate.SignatureAlgorithm = x509.ECDSAWithSHA512 + } } certTemplate.AuthorityKeyId = subjKeyID @@ -791,9 +830,23 @@ func signCertificate(data *CreationBundle, randReader io.Reader) (*ParsedCertBun switch data.SigningBundle.PrivateKeyType { case RSAPrivateKey: - certTemplate.SignatureAlgorithm = x509.SHA256WithRSA + switch data.Params.SignatureBits { + case 256: + certTemplate.SignatureAlgorithm = x509.SHA256WithRSA + case 384: + certTemplate.SignatureAlgorithm = x509.SHA384WithRSA + case 512: + certTemplate.SignatureAlgorithm = x509.SHA512WithRSA + } case ECPrivateKey: - certTemplate.SignatureAlgorithm = x509.ECDSAWithSHA256 + switch data.Params.SignatureBits { + case 256: + certTemplate.SignatureAlgorithm = x509.ECDSAWithSHA256 + case 384: + certTemplate.SignatureAlgorithm = x509.ECDSAWithSHA384 + case 512: + certTemplate.SignatureAlgorithm = x509.ECDSAWithSHA512 + } } if data.Params.UseCSRValues { diff --git a/sdk/helper/certutil/types.go b/sdk/helper/certutil/types.go index 8a1a1d5fa..be10c19f4 100644 --- a/sdk/helper/certutil/types.go +++ b/sdk/helper/certutil/types.go @@ -677,6 +677,7 @@ type CreationParameters struct { ExtKeyUsageOIDs []string PolicyIdentifiers []string BasicConstraintsValidForNonCA bool + SignatureBits int // Only used when signing a CA cert UseCSRValues bool