improvement: add signature_bits field to CA and signers (#11245)

This change adds the ability to set the signature algorithm of the
CAs that Vault generates and any certificates it signs.  This is a
potentially useful stepping stone for a SHA3 transition down the line.

Summary:
* Adds the field "signature_bits" to CA and Sign endpoints
* Adds support for SHA256, SHA384 and SHA512 signatures on EC and RSA
keytypes.
This commit is contained in:
jhart-cpi 2021-09-10 14:39:05 -07:00 committed by GitHub
parent 22c9be3835
commit fa1611f427
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 99 additions and 7 deletions

View File

@ -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{}

View File

@ -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
}

View File

@ -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),

View File

@ -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",

View File

@ -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,

3
changelog/11245.txt Normal file
View File

@ -0,0 +1,3 @@
```release-note:improvement
pki: adds signature_bits field to customize signature algorithm on CAs and certs signed by Vault
```

View File

@ -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 {

View File

@ -677,6 +677,7 @@ type CreationParameters struct {
ExtKeyUsageOIDs []string
PolicyIdentifiers []string
BasicConstraintsValidForNonCA bool
SignatureBits int
// Only used when signing a CA cert
UseCSRValues bool