Skip to content

Commit

Permalink
improvement: add signature_bits field to CA and signers (hashicorp#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 authored and jartek committed Sep 11, 2021
1 parent fe19488 commit 36de41a
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 36de41a

Please sign in to comment.