diff --git a/builtin/logical/transit/path_sign_verify.go b/builtin/logical/transit/path_sign_verify.go
index bcadf56f4baa..feed68309ef7 100644
--- a/builtin/logical/transit/path_sign_verify.go
+++ b/builtin/logical/transit/path_sign_verify.go
@@ -120,60 +120,33 @@ func (b *backend) pathSign() *framework.Path {
OperationSuffix: "|with-algorithm",
},
- Fields: pathSignFieldArgs(),
-
- Callbacks: map[logical.Operation]framework.OperationFunc{
- logical.UpdateOperation: b.pathSignWrite,
- },
-
- HelpSynopsis: pathSignHelpSyn,
- HelpDescription: pathSignHelpDesc,
- }
-}
-
-func (b *backend) pathVerify() *framework.Path {
- return &framework.Path{
- Pattern: "verify/" + framework.GenericNameRegex("name") + framework.OptionalParamRegex("urlalgorithm"),
-
- DisplayAttrs: &framework.DisplayAttributes{
- OperationPrefix: operationPrefixTransit,
- OperationVerb: "verify",
- OperationSuffix: "|with-algorithm",
- },
-
- Fields: pathVerifyFieldArgs(),
-
- Callbacks: map[logical.Operation]framework.OperationFunc{
- logical.UpdateOperation: b.pathVerifyWrite,
- },
-
- HelpSynopsis: pathVerifyHelpSyn,
- HelpDescription: pathVerifyHelpDesc,
- }
-}
-
-func pathSignFieldArgs() map[string]*framework.FieldSchema {
- fields := map[string]*framework.FieldSchema{
- "name": {
- Type: framework.TypeString,
- Description: "The key to use",
- },
-
- "input": {
- Type: framework.TypeString,
- Description: "The base64-encoded input data",
- },
-
- "context": {
- Type: framework.TypeString,
- Description: `Base64 encoded context for key derivation. Required if key
+ Fields: map[string]*framework.FieldSchema{
+ "name": {
+ Type: framework.TypeString,
+ Description: "The key to use",
+ },
+
+ "input": {
+ Type: framework.TypeString,
+ Description: "The base64-encoded input data",
+ },
+
+ "context": {
+ Type: framework.TypeString,
+ Description: `Base64 encoded context for key derivation. Required if key
derivation is enabled; currently only available with ed25519 keys.`,
- },
+ },
+
+ "signature_context": {
+ Type: framework.TypeString,
+ Description: `Base64 encoded context for Ed25519ph and Ed25519ctx signatures.
+Currently only available with Ed25519 keys. (Enterprise Only)`,
+ },
- "hash_algorithm": {
- Type: framework.TypeString,
- Default: defaultHashAlgorithm,
- Description: `Hash algorithm to use (POST body parameter). Valid values are:
+ "hash_algorithm": {
+ Type: framework.TypeString,
+ Default: defaultHashAlgorithm,
+ Description: `Hash algorithm to use (POST body parameter). Valid values are:
* sha1
* sha2-224
@@ -190,105 +163,130 @@ Defaults to "sha2-256". Not valid for all key types,
including ed25519. Using none requires setting prehashed=true and
signature_algorithm=pkcs1v15, yielding a PKCSv1_5_NoOID instead of
the usual PKCSv1_5_DERnull signature.`,
- },
-
- "algorithm": {
- Type: framework.TypeString,
- Default: defaultHashAlgorithm,
- Description: `Deprecated: use "hash_algorithm" instead.`,
- },
-
- "urlalgorithm": {
- Type: framework.TypeString,
- Description: `Hash algorithm to use (POST URL parameter)`,
- },
-
- "key_version": {
- Type: framework.TypeInt,
- Description: `The version of the key to use for signing.
+ },
+
+ "algorithm": {
+ Type: framework.TypeString,
+ Default: defaultHashAlgorithm,
+ Description: `Deprecated: use "hash_algorithm" instead.`,
+ },
+
+ "urlalgorithm": {
+ Type: framework.TypeString,
+ Description: `Hash algorithm to use (POST URL parameter)`,
+ },
+
+ "key_version": {
+ Type: framework.TypeInt,
+ Description: `The version of the key to use for signing.
Must be 0 (for latest) or a value greater than or equal
to the min_encryption_version configured on the key.`,
- },
+ },
- "prehashed": {
- Type: framework.TypeBool,
- Description: `Set to 'true' when the input is already hashed. If the key type is 'rsa-2048', 'rsa-3072' or 'rsa-4096', then the algorithm used to hash the input should be indicated by the 'algorithm' parameter.`,
- },
+ "prehashed": {
+ Type: framework.TypeBool,
+ Description: `Set to 'true' when the input is already hashed. If the key type is 'rsa-2048', 'rsa-3072' or 'rsa-4096', then the algorithm used to hash the input should be indicated by the 'algorithm' parameter.`,
+ },
- "signature_algorithm": {
- Type: framework.TypeString,
- Description: `The signature algorithm to use for signing. Currently only applies to RSA key types.
+ "signature_algorithm": {
+ Type: framework.TypeString,
+ Description: `The signature algorithm to use for signing. Currently only applies to RSA key types.
Options are 'pss' or 'pkcs1v15'. Defaults to 'pss'`,
- },
-
- "marshaling_algorithm": {
- Type: framework.TypeString,
- Default: "asn1",
- Description: `The method by which to marshal the signature. The default is 'asn1' which is used by openssl and X.509. It can also be set to 'jws' which is used for JWT signatures; setting it to this will also cause the encoding of the signature to be url-safe base64 instead of using standard base64 encoding. Currently only valid for ECDSA P-256 key types".`,
- },
-
- "salt_length": {
- Type: framework.TypeString,
- Default: "auto",
- Description: `The salt length used to sign. Currently only applies to the RSA PSS signature scheme.
+ },
+
+ "marshaling_algorithm": {
+ Type: framework.TypeString,
+ Default: "asn1",
+ Description: `The method by which to marshal the signature. The default is 'asn1' which is used by openssl and X.509. It can also be set to 'jws' which is used for JWT signatures; setting it to this will also cause the encoding of the signature to be url-safe base64 instead of using standard base64 encoding. Currently only valid for ECDSA P-256 key types".`,
+ },
+
+ "salt_length": {
+ Type: framework.TypeString,
+ Default: "auto",
+ Description: `The salt length used to sign. Currently only applies to the RSA PSS signature scheme.
Options are 'auto' (the default used by Golang, causing the salt to be as large as possible when signing), 'hash' (causes the salt length to equal the length of the hash used in the signature), or an integer between the minimum and the maximum permissible salt lengths for the given RSA key size. Defaults to 'auto'.`,
- },
+ },
- "batch_input": {
- Type: framework.TypeSlice,
- Description: `Specifies a list of items for processing. When this parameter is set,
+ "batch_input": {
+ Type: framework.TypeSlice,
+ Description: `Specifies a list of items for processing. When this parameter is set,
any supplied 'input' or 'context' parameters will be ignored. Responses are returned in the
'batch_results' array component of the 'data' element of the response. Any batch output will
preserve the order of the batch input`,
- },
- }
-
- addEntSignFieldArgs(fields)
- return fields
-}
-
-func pathVerifyFieldArgs() map[string]*framework.FieldSchema {
- fields := map[string]*framework.FieldSchema{
- "name": {
- Type: framework.TypeString,
- Description: "The key to use",
- },
-
- "context": {
- Type: framework.TypeString,
- Description: `Base64 encoded context for key derivation. Required if key
-derivation is enabled; currently only available with ed25519 keys.`,
+ },
},
- "signature": {
- Type: framework.TypeString,
- Description: "The signature, including vault header/key version",
+ Callbacks: map[logical.Operation]framework.OperationFunc{
+ logical.UpdateOperation: b.pathSignWrite,
},
- "hmac": {
- Type: framework.TypeString,
- Description: "The HMAC, including vault header/key version",
- },
+ HelpSynopsis: pathSignHelpSyn,
+ HelpDescription: pathSignHelpDesc,
+ }
+}
- "input": {
- Type: framework.TypeString,
- Description: "The base64-encoded input data to verify",
- },
+func (b *backend) pathVerify() *framework.Path {
+ return &framework.Path{
+ Pattern: "verify/" + framework.GenericNameRegex("name") + framework.OptionalParamRegex("urlalgorithm"),
- "urlalgorithm": {
- Type: framework.TypeString,
- Description: `Hash algorithm to use (POST URL parameter)`,
+ DisplayAttrs: &framework.DisplayAttributes{
+ OperationPrefix: operationPrefixTransit,
+ OperationVerb: "verify",
+ OperationSuffix: "|with-algorithm",
},
- "mac_length": {
- Type: framework.TypeInt,
- Description: `MAC length to use (POST body parameter). Valid values are:`,
- },
+ Fields: map[string]*framework.FieldSchema{
+ "name": {
+ Type: framework.TypeString,
+ Description: "The key to use",
+ },
- "hash_algorithm": {
- Type: framework.TypeString,
- Default: defaultHashAlgorithm,
- Description: `Hash algorithm to use (POST body parameter). Valid values are:
+ "context": {
+ Type: framework.TypeString,
+ Description: `Base64 encoded context for key derivation. Required if key
+derivation is enabled; currently only available with ed25519 keys.`,
+ },
+
+ "signature_context": {
+ Type: framework.TypeString,
+ Description: `Base64 encoded context for Ed25519ph and Ed25519ctx signatures.
+Currently only available with Ed25519 keys. (Enterprise Only)`,
+ },
+
+ "signature": {
+ Type: framework.TypeString,
+ Description: "The signature, including vault header/key version",
+ },
+
+ "hmac": {
+ Type: framework.TypeString,
+ Description: "The HMAC, including vault header/key version",
+ },
+
+ "cmac": {
+ Type: framework.TypeString,
+ Description: "The CMAC, including vault header/key version (Enterprise only)",
+ },
+
+ "input": {
+ Type: framework.TypeString,
+ Description: "The base64-encoded input data to verify",
+ },
+
+ "urlalgorithm": {
+ Type: framework.TypeString,
+ Description: `Hash algorithm to use (POST URL parameter)`,
+ },
+
+ "mac_length": {
+ Type: framework.TypeInt,
+ Description: `MAC length to use (POST body parameter). Valid values are:`,
+ },
+
+ "hash_algorithm": {
+ Type: framework.TypeString,
+ Default: defaultHashAlgorithm,
+ Description: `Hash algorithm to use (POST body parameter). Valid values are:
* sha1
* sha2-224
@@ -303,49 +301,54 @@ derivation is enabled; currently only available with ed25519 keys.`,
Defaults to "sha2-256". Not valid for all key types. See note about
none on signing path.`,
- },
-
- "algorithm": {
- Type: framework.TypeString,
- Default: defaultHashAlgorithm,
- Description: `Deprecated: use "hash_algorithm" instead.`,
- },
-
- "prehashed": {
- Type: framework.TypeBool,
- Description: `Set to 'true' when the input is already hashed. If the key type is 'rsa-2048', 'rsa-3072' or 'rsa-4096', then the algorithm used to hash the input should be indicated by the 'algorithm' parameter.`,
- },
-
- "signature_algorithm": {
- Type: framework.TypeString,
- Description: `The signature algorithm to use for signature verification. Currently only applies to RSA key types.
+ },
+
+ "algorithm": {
+ Type: framework.TypeString,
+ Default: defaultHashAlgorithm,
+ Description: `Deprecated: use "hash_algorithm" instead.`,
+ },
+
+ "prehashed": {
+ Type: framework.TypeBool,
+ Description: `Set to 'true' when the input is already hashed. If the key type is 'rsa-2048', 'rsa-3072' or 'rsa-4096', then the algorithm used to hash the input should be indicated by the 'algorithm' parameter.`,
+ },
+
+ "signature_algorithm": {
+ Type: framework.TypeString,
+ Description: `The signature algorithm to use for signature verification. Currently only applies to RSA key types.
Options are 'pss' or 'pkcs1v15'. Defaults to 'pss'`,
- },
-
- "marshaling_algorithm": {
- Type: framework.TypeString,
- Default: "asn1",
- Description: `The method by which to unmarshal the signature when verifying. The default is 'asn1' which is used by openssl and X.509; can also be set to 'jws' which is used for JWT signatures in which case the signature is also expected to be url-safe base64 encoding instead of standard base64 encoding. Currently only valid for ECDSA P-256 key types".`,
- },
-
- "salt_length": {
- Type: framework.TypeString,
- Default: "auto",
- Description: `The salt length used to sign. Currently only applies to the RSA PSS signature scheme.
+ },
+
+ "marshaling_algorithm": {
+ Type: framework.TypeString,
+ Default: "asn1",
+ Description: `The method by which to unmarshal the signature when verifying. The default is 'asn1' which is used by openssl and X.509; can also be set to 'jws' which is used for JWT signatures in which case the signature is also expected to be url-safe base64 encoding instead of standard base64 encoding. Currently only valid for ECDSA P-256 key types".`,
+ },
+
+ "salt_length": {
+ Type: framework.TypeString,
+ Default: "auto",
+ Description: `The salt length used to sign. Currently only applies to the RSA PSS signature scheme.
Options are 'auto' (the default used by Golang, causing the salt to be as large as possible when signing), 'hash' (causes the salt length to equal the length of the hash used in the signature), or an integer between the minimum and the maximum permissible salt lengths for the given RSA key size. Defaults to 'auto'.`,
- },
+ },
- "batch_input": {
- Type: framework.TypeSlice,
- Description: `Specifies a list of items for processing. When this parameter is set,
+ "batch_input": {
+ Type: framework.TypeSlice,
+ Description: `Specifies a list of items for processing. When this parameter is set,
any supplied 'input', 'hmac', 'cmac' or 'signature' parameters will be ignored. Responses are returned in the
'batch_results' array component of the 'data' element of the response. Any batch output will
preserve the order of the batch input`,
+ },
},
- }
- addEntVerifyFieldArgs(fields)
- return fields
+ Callbacks: map[logical.Operation]framework.OperationFunc{
+ logical.UpdateOperation: b.pathVerifyWrite,
+ },
+
+ HelpSynopsis: pathVerifyHelpSyn,
+ HelpDescription: pathVerifyHelpDesc,
+ }
}
func getSaltLength(d *framework.FieldData) (int, error) {
@@ -527,7 +530,7 @@ func (b *backend) getPolicySignArgs(ctx context.Context, p *keysutil.Policy, arg
}
if err := b.populateEntPolicySigningOptions(ctx, p, args, item, &psa); err != nil {
- return policySignArgs{}, nil
+ return policySignArgs{}, fmt.Errorf("failed to parse batch item: %s", err)
}
return psa, nil
}
diff --git a/builtin/logical/transit/path_sign_verify_ce.go b/builtin/logical/transit/path_sign_verify_ce.go
index 41d23aaa0592..a0f416a18f9f 100644
--- a/builtin/logical/transit/path_sign_verify_ce.go
+++ b/builtin/logical/transit/path_sign_verify_ce.go
@@ -9,20 +9,9 @@ import (
"context"
"fmt"
- "github.com/hashicorp/vault/sdk/framework"
"github.com/hashicorp/vault/sdk/helper/keysutil"
)
-// addEntSignFieldArgs adds the enterprise only fields to the field schema definition
-func addEntSignFieldArgs(_ map[string]*framework.FieldSchema) {
- // Do nothing
-}
-
-// addEntVerifyFieldArgs adds the enterprise only fields to the field schema definition
-func addEntVerifyFieldArgs(_ map[string]*framework.FieldSchema) {
- // Do nothing
-}
-
// validateSignApiArgsVersionSpecific will perform a validation of the Sign API parameters
// from the Enterprise or CE point of view.
func validateSignApiArgsVersionSpecific(p *keysutil.Policy, apiArgs commonSignVerifyApiArgs) error {
@@ -41,13 +30,44 @@ func validateSignApiArgsVersionSpecific(p *keysutil.Policy, apiArgs commonSignVe
// populateEntPolicySigning augments or tweaks the input parameters to the SDK policy.SignWithOptions for
// Enterprise usage.
-func (b *backend) populateEntPolicySigningOptions(_ context.Context, _ *keysutil.Policy, _ signApiArgs, _ batchRequestSignItem, _ *policySignArgs) error {
- return nil
+func (b *backend) populateEntPolicySigningOptions(_ context.Context, p *keysutil.Policy, args signApiArgs, item batchRequestSignItem, _ *policySignArgs) error {
+ return _forbidEd25519EntBehavior(p, args.commonSignVerifyApiArgs, item["signature_context"])
}
// populateEntPolicyVerifyOptions augments or tweaks the input parameters to the SDK policy.VerifyWithOptions for
// Enterprise usage.
-func (b *backend) populateEntPolicyVerifyOptions(ctx context.Context, p *keysutil.Policy, args verifyApiArgs, item batchRequestVerifyItem, vsa *policyVerifyArgs) error {
+func (b *backend) populateEntPolicyVerifyOptions(_ context.Context, p *keysutil.Policy, args verifyApiArgs, item batchRequestVerifyItem, _ *policyVerifyArgs) error {
+ sigContext, err := _validateString(item, "signature_context")
+ if err != nil {
+ return err
+ }
+ return _forbidEd25519EntBehavior(p, args.commonSignVerifyApiArgs, sigContext)
+}
+
+func _validateString(item batchRequestVerifyItem, key string) (string, error) {
+ if itemVal, exists := item[key]; exists {
+ if itemStrVal, ok := itemVal.(string); ok {
+ return itemStrVal, nil
+ }
+ return "", fmt.Errorf("expected string for key=%q, got=%q", key, itemVal)
+ }
+ return "", nil
+}
+
+func _forbidEd25519EntBehavior(p *keysutil.Policy, apiArgs commonSignVerifyApiArgs, sigContext string) error {
+ if p.Type != keysutil.KeyType_ED25519 {
+ return nil
+ }
+
+ switch {
+ case apiArgs.prehashed:
+ return fmt.Errorf("only Pure Ed25519 signatures supported, prehashed must be false")
+ case apiArgs.hashAlgorithm == keysutil.HashTypeSHA2512:
+ return fmt.Errorf("only Pure Ed25519 signatures supported, hash_alogithm should not be set")
+ case sigContext != "":
+ return fmt.Errorf("only Pure Ed25519 signatures supported, signature_context must be empty")
+ }
+
return nil
}
diff --git a/builtin/logical/transit/path_sign_verify_test.go b/builtin/logical/transit/path_sign_verify_test.go
index 1421f71c34dd..19c2fa37eda7 100644
--- a/builtin/logical/transit/path_sign_verify_test.go
+++ b/builtin/logical/transit/path_sign_verify_test.go
@@ -7,6 +7,7 @@ import (
"context"
"encoding/base64"
"fmt"
+ "maps"
"strconv"
"strings"
"testing"
@@ -15,6 +16,7 @@ import (
"github.com/hashicorp/vault/sdk/helper/keysutil"
"github.com/hashicorp/vault/sdk/logical"
"github.com/mitchellh/mapstructure"
+ "github.com/stretchr/testify/require"
"golang.org/x/crypto/ed25519"
)
@@ -368,6 +370,103 @@ func validatePublicKey(t *testing.T, in string, sig string, pubKeyRaw []byte, ex
}
}
+// TestTransit_SignVerify_Ed25519Behavior makes sure the options on ENT for a
+// Ed25519ph/ctx signature fail on CE and ENT if invalid
+func TestTransit_SignVerify_Ed25519Behavior(t *testing.T) {
+ b, storage := createBackendWithSysView(t)
+
+ // First create a key
+ req := &logical.Request{
+ Storage: storage,
+ Operation: logical.UpdateOperation,
+ Path: "keys/foo",
+ Data: map[string]interface{}{
+ "type": "ed25519",
+ },
+ }
+ _, err := b.HandleRequest(context.Background(), req)
+ require.NoError(t, err, "failed creating ed25519 key")
+
+ tests := []struct {
+ name string
+ args map[string]interface{}
+ worksOnEnt bool
+ }{
+ {"sha2-512 only", map[string]interface{}{"hash_algorithm": "sha2-512"}, false},
+ {"prehashed only", map[string]interface{}{"prehashed": "true"}, false},
+ {"incorrect input for ph args", map[string]interface{}{"prehashed": "true", "hash_algorithm": "sha2-512"}, false},
+ {"context too long", map[string]interface{}{"signature_context": strings.Repeat("x", 1024)}, false},
+ {
+ name: "ctx-signature",
+ args: map[string]interface{}{
+ "signature_context": "dGVzdGluZyBjb250ZXh0Cg==",
+ },
+ worksOnEnt: true,
+ },
+ {
+ name: "ph-signature",
+ args: map[string]interface{}{
+ "input": "3a81oZNherrMQXNJriBBMRLm+k6JqX6iCp7u5ktV05ohkpkqJ0/BqDa6PCOj/uu9RU1EI2Q86A4qmslPpUyknw==",
+ "prehashed": "true",
+ "hash_algorithm": "sha2-512",
+ "signature_context": "dGVzdGluZyBjb250ZXh0Cg==",
+ },
+ worksOnEnt: true,
+ },
+ }
+ for _, tc := range tests {
+ t.Run(tc.name, func(t *testing.T) {
+ signData := map[string]interface{}{"input": "dGhlIHF1aWNrIGJyb3duIGZveA=="}
+
+ // if tc.args specifies input, this should overwrite our static value above.
+ maps.Copy(signData, tc.args)
+
+ req = &logical.Request{
+ Storage: storage,
+ Operation: logical.UpdateOperation,
+ Path: "sign/foo",
+ Data: signData,
+ }
+
+ signSignature := "YmFkIHNpZ25hdHVyZQo=" // "bad signature" but is overwritten if sign works
+ resp, err := b.HandleRequest(context.Background(), req)
+ if constants.IsEnterprise && tc.worksOnEnt {
+ require.NoError(t, err, "expected sign to work on ENT but failed: resp: %v", resp)
+ require.NotNil(t, resp, "sign should have had non-nil response on ENT")
+ require.False(t, resp.IsError(), "sign expected to work on ENT but failed")
+ signSignature = resp.Data["signature"].(string)
+ require.NotEmpty(t, signSignature, "sign expected to work on ENT but was empty")
+ } else {
+ require.ErrorContains(t, err, "invalid request", "expected sign request to fail with invalid request")
+ }
+
+ verifyData := map[string]interface{}{
+ "input": signData["input"],
+ "signature": signSignature,
+ }
+
+ // if tc.args specifies input, this should overwrite our static value above.
+ maps.Copy(verifyData, tc.args)
+
+ req = &logical.Request{
+ Storage: storage,
+ Operation: logical.UpdateOperation,
+ Path: "verify/foo",
+ Data: verifyData,
+ }
+ resp, err = b.HandleRequest(context.Background(), req)
+ if constants.IsEnterprise && tc.worksOnEnt {
+ require.NoError(t, err, "verify expected to work on ENT but failed: resp: %v", resp)
+ require.NotNil(t, resp, "verify should have had non-nil response on ENT")
+ require.False(t, resp.IsError(), "expected verify to work on ENT but failed")
+ require.True(t, resp.Data["valid"].(bool), "signature verification should have worked")
+ } else {
+ require.ErrorContains(t, err, "invalid request", "expected verify request to fail with invalid request")
+ }
+ })
+ }
+}
+
func TestTransit_SignVerify_ED25519(t *testing.T) {
b, storage := createBackendWithSysView(t)
diff --git a/sdk/helper/keysutil/policy.go b/sdk/helper/keysutil/policy.go
index 7d3d73852352..0d50775c666d 100644
--- a/sdk/helper/keysutil/policy.go
+++ b/sdk/helper/keysutil/policy.go
@@ -90,6 +90,20 @@ const (
PaddingScheme_PKCS1v15 = PaddingScheme("pkcs1v15")
)
+var genEd25519Options = func(hashAlgorithm HashType, signatureContext string) (*stdlibEd25519.Options, error) {
+ if signatureContext != "" {
+ return nil, fmt.Errorf("signature context is not supported feature")
+ }
+
+ if hashAlgorithm == HashTypeSHA2512 {
+ return nil, fmt.Errorf("hash algorithm of SHA2 512 is not supported feature")
+ }
+
+ return &stdlibEd25519.Options{
+ Hash: crypto.Hash(0),
+ }, nil
+}
+
func (p PaddingScheme) String() string {
return string(p)
}
@@ -1302,11 +1316,11 @@ func (p *Policy) SignWithOptions(ver int, context, input []byte, options *Signin
key = ed25519.PrivateKey(keyParams.Key)
}
- opts := genEd25519Options(hashAlgorithm, options.SigContext)
+ opts, err := genEd25519Options(hashAlgorithm, options.SigContext)
+ if err != nil {
+ return nil, errutil.UserError{Err: fmt.Sprintf("error generating Ed25519 options: %v", err)}
+ }
- // Per docs, do not pre-hash ed25519; it does two passes and performs
- // its own hashing when we specify crypto.Hash(0). Ed25519Ph assumes
- // pre-hashed with SHA512
sig, err = key.Sign(rand.Reader, input, opts)
if err != nil {
return nil, err
@@ -1503,7 +1517,10 @@ func (p *Policy) VerifySignatureWithOptions(context, input []byte, sig string, o
pub = ed25519.PublicKey(raw)
}
- opts := genEd25519Options(hashAlgorithm, options.SigContext)
+ opts, err := genEd25519Options(hashAlgorithm, options.SigContext)
+ if err != nil {
+ return false, errutil.UserError{Err: fmt.Sprintf("error generating Ed25519 options: %v", err)}
+ }
if err := stdlibEd25519.VerifyWithOptions(pub, input, sigBytes, opts); err != nil {
// We drop the error, just report back that we failed signature verification
return false, nil
@@ -1561,20 +1578,6 @@ func (p *Policy) VerifySignatureWithOptions(context, input []byte, sig string, o
}
}
-func genEd25519Options(hashAlgorithm HashType, sigContext string) *stdlibEd25519.Options {
- opts := &stdlibEd25519.Options{
- Hash: crypto.Hash(0),
- }
- if hashAlgorithm == HashTypeSHA2512 {
- // activate ph mode, we assume input is prehashed
- opts.Hash = crypto.SHA512
- }
- if len(sigContext) > 0 {
- opts.Context = sigContext
- }
- return opts
-}
-
func (p *Policy) Import(ctx context.Context, storage logical.Storage, key []byte, randReader io.Reader) error {
return p.ImportPublicOrPrivate(ctx, storage, key, true, randReader)
}
diff --git a/website/content/api-docs/secret/transit.mdx b/website/content/api-docs/secret/transit.mdx
index 6cbc2a61487e..140cad0d72c6 100644
--- a/website/content/api-docs/secret/transit.mdx
+++ b/website/content/api-docs/secret/transit.mdx
@@ -1480,6 +1480,9 @@ supports signing.
signature rather than the `PKCSv1_5_DERnull` signature type usually
created. See [RFC 3447 Section 9.2](https://www.rfc-editor.org/rfc/rfc3447#section-9.2).
+ ~> **Note**: using `hash_algorithm=sha2-512` requires setting `prehashed=true`
+ for Ed25519 backed keys which enabled Ed25519ph signature support on Enterprise.
+
- `input` `(string: "")` – Specifies the **base64 encoded** input data. One of
`input` or `batch_input` must be supplied.
@@ -1526,9 +1529,9 @@ supports signing.
data you want signed, when set, `input` is expected to be base64-encoded
binary hashed data, not hex-formatted. (As an example, on the command line,
you could generate a suitable input via `openssl dgst -sha256 -binary | base64`.)
- On Enterprise , enabling this will activate
- Ed25519ph signatures for Ed25519 keys along with hash_algorithm being either `none`
- or `sha2-512`.
+ On Enterprise , enabling this along with
+ hash_algorithm being set to `sha2-512` will activate Ed25519ph signatures for
+ Ed25519 keys
- `signature_algorithm` `(string: "pss")` – When using a RSA key, specifies the RSA
signature algorithm to use for signing. Supported signature types are:
@@ -1669,6 +1672,9 @@ or [generate CMAC](#generate-cmac) API calls.
signature rather than the `PKCSv1_5_DERnull` signature type usually
verified. See [RFC 3447 Section 9.2](https://www.rfc-editor.org/rfc/rfc3447#section-9.2).
+ ~> **Note**: using `hash_algorithm=sha2-512` requires setting `prehashed=true`
+ for Ed25519 backed keys which enabled Ed25519ph signature support on Enterprise.
+
- `input` `(string: "")` – Specifies the **base64 encoded** input data. One of
`input` or `batch_input` must be supplied.
@@ -1730,9 +1736,9 @@ or [generate CMAC](#generate-cmac) API calls.
data you want signed, when set, `input` is expected to be base64-encoded
binary hashed data, not hex-formatted. (As an example, on the command line,
you could generate a suitable input via `openssl dgst -sha256 -binary | base64`.)
- On Enterprise , enabling this will activate
- Ed25519ph signatures for Ed25519 keys along with hash_algorithm being either `none`
- or `sha2-512`.
+ On Enterprise , enabling this along with
+ hash_algorithm being set to `sha2-512` will activate Ed25519ph signatures for
+ Ed25519 keys
- `signature_algorithm` `(string: "pss")` – When using a RSA key, specifies the RSA
signature algorithm to use for signature verification. Supported signature types