Skip to content

Commit

Permalink
improvement: add signature_bits field to CA and signers (#11245)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
jhart-cpi committed Sep 10, 2021
1 parent fd018b4 commit 49c3db0
Show file tree
Hide file tree
Showing 8 changed files with 99 additions and 7 deletions.
1 change: 1 addition & 0 deletions builtin/logical/pki/backend_test.go
Expand Up @@ -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{}
Expand Down
6 changes: 6 additions & 0 deletions builtin/logical/pki/ca_util.go
Expand Up @@ -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,
Expand All @@ -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
}
1 change: 1 addition & 0 deletions builtin/logical/pki/cert_util.go
Expand Up @@ -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),
Expand Down
12 changes: 12 additions & 0 deletions builtin/logical/pki/fields.go
Expand Up @@ -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",
Expand Down
17 changes: 16 additions & 1 deletion builtin/logical/pki/path_roles.go
Expand Up @@ -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
Expand Down Expand Up @@ -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),
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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"`
Expand Down Expand Up @@ -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,
Expand Down
3 changes: 3 additions & 0 deletions 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
```
65 changes: 59 additions & 6 deletions sdk/helper/certutil/helpers.go
Expand Up @@ -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":
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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 {
Expand Down
1 change: 1 addition & 0 deletions sdk/helper/certutil/types.go
Expand Up @@ -677,6 +677,7 @@ type CreationParameters struct {
ExtKeyUsageOIDs []string
PolicyIdentifiers []string
BasicConstraintsValidForNonCA bool
SignatureBits int

// Only used when signing a CA cert
UseCSRValues bool
Expand Down

0 comments on commit 49c3db0

Please sign in to comment.