diff --git a/builtin/logical/pki/backend_test.go b/builtin/logical/pki/backend_test.go index 5a9c480dd28ed..91a89c4052e65 100644 --- a/builtin/logical/pki/backend_test.go +++ b/builtin/logical/pki/backend_test.go @@ -676,6 +676,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 8692486d87da5..ea6b083c7eed0 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 77b8c1f974b77..843a2207e8e77 100644 --- a/builtin/logical/pki/cert_util.go +++ b/builtin/logical/pki/cert_util.go @@ -1056,6 +1056,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 c67e39eaac20b..149001aa52b95 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 4d23484079e70..a1ca4e13f9c17 100644 --- a/builtin/logical/pki/path_roles.go +++ b/builtin/logical/pki/path_roles.go @@ -206,6 +206,14 @@ certainly want to change this if you adjust the key_type.`, }, + "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"}, @@ -560,6 +568,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), @@ -614,6 +623,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) @@ -751,6 +764,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"` @@ -801,6 +815,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 0000000000000..4f20c690efda5 --- /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 12198798e8c5c..66c012ffe21a9 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 1c7c190777a57..5867454db366d 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