Implement JWS-compatible signature marshaling (#6077)
This currently only applies to ECDSA signatures, and is a toggleable option.
This commit is contained in:
parent
4f05192be3
commit
5e126f6de8
|
@ -205,12 +205,9 @@ func testTransit_RSA(t *testing.T, keyType string) {
|
|||
"hash_algorithm": "invalid",
|
||||
}
|
||||
resp, err = b.HandleRequest(context.Background(), signReq)
|
||||
if err != nil {
|
||||
if err == nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if resp == nil || !resp.IsError() {
|
||||
t.Fatal("expected an error response")
|
||||
}
|
||||
|
||||
signReq.Data = map[string]interface{}{
|
||||
"input": plaintext,
|
||||
|
|
|
@ -2,11 +2,8 @@ package transit
|
|||
|
||||
import (
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"crypto/sha512"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"hash"
|
||||
|
||||
"github.com/hashicorp/vault/helper/errutil"
|
||||
"github.com/hashicorp/vault/helper/keysutil"
|
||||
|
@ -18,23 +15,23 @@ func (b *backend) pathSign() *framework.Path {
|
|||
return &framework.Path{
|
||||
Pattern: "sign/" + framework.GenericNameRegex("name") + framework.OptionalParamRegex("urlalgorithm"),
|
||||
Fields: map[string]*framework.FieldSchema{
|
||||
"name": &framework.FieldSchema{
|
||||
"name": {
|
||||
Type: framework.TypeString,
|
||||
Description: "The key to use",
|
||||
},
|
||||
|
||||
"input": &framework.FieldSchema{
|
||||
"input": {
|
||||
Type: framework.TypeString,
|
||||
Description: "The base64-encoded input data",
|
||||
},
|
||||
|
||||
"context": &framework.FieldSchema{
|
||||
"context": {
|
||||
Type: framework.TypeString,
|
||||
Description: `Base64 encoded context for key derivation. Required if key
|
||||
derivation is enabled; currently only available with ed25519 keys.`,
|
||||
},
|
||||
|
||||
"hash_algorithm": &framework.FieldSchema{
|
||||
"hash_algorithm": {
|
||||
Type: framework.TypeString,
|
||||
Default: "sha2-256",
|
||||
Description: `Hash algorithm to use (POST body parameter). Valid values are:
|
||||
|
@ -48,33 +45,40 @@ Defaults to "sha2-256". Not valid for all key types,
|
|||
including ed25519.`,
|
||||
},
|
||||
|
||||
"algorithm": &framework.FieldSchema{
|
||||
"algorithm": {
|
||||
Type: framework.TypeString,
|
||||
Default: "sha2-256",
|
||||
Description: `Deprecated: use "hash_algorithm" instead.`,
|
||||
},
|
||||
|
||||
"urlalgorithm": &framework.FieldSchema{
|
||||
"urlalgorithm": {
|
||||
Type: framework.TypeString,
|
||||
Description: `Hash algorithm to use (POST URL parameter)`,
|
||||
},
|
||||
|
||||
"key_version": &framework.FieldSchema{
|
||||
"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": &framework.FieldSchema{
|
||||
"prehashed": {
|
||||
Type: framework.TypeBool,
|
||||
Description: `Set to 'true' when the input is already hashed. If the key type is 'rsa-2048' or 'rsa-4096', then the algorithm used to hash the input should be indicated by the 'algorithm' parameter.`,
|
||||
},
|
||||
"signature_algorithm": &framework.FieldSchema{
|
||||
|
||||
"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".`,
|
||||
},
|
||||
},
|
||||
|
||||
Callbacks: map[logical.Operation]framework.OperationFunc{
|
||||
|
@ -95,33 +99,33 @@ func (b *backend) pathVerify() *framework.Path {
|
|||
Description: "The key to use",
|
||||
},
|
||||
|
||||
"context": &framework.FieldSchema{
|
||||
"context": {
|
||||
Type: framework.TypeString,
|
||||
Description: `Base64 encoded context for key derivation. Required if key
|
||||
derivation is enabled; currently only available with ed25519 keys.`,
|
||||
},
|
||||
|
||||
"signature": &framework.FieldSchema{
|
||||
"signature": {
|
||||
Type: framework.TypeString,
|
||||
Description: "The signature, including vault header/key version",
|
||||
},
|
||||
|
||||
"hmac": &framework.FieldSchema{
|
||||
"hmac": {
|
||||
Type: framework.TypeString,
|
||||
Description: "The HMAC, including vault header/key version",
|
||||
},
|
||||
|
||||
"input": &framework.FieldSchema{
|
||||
"input": {
|
||||
Type: framework.TypeString,
|
||||
Description: "The base64-encoded input data to verify",
|
||||
},
|
||||
|
||||
"urlalgorithm": &framework.FieldSchema{
|
||||
"urlalgorithm": {
|
||||
Type: framework.TypeString,
|
||||
Description: `Hash algorithm to use (POST URL parameter)`,
|
||||
},
|
||||
|
||||
"hash_algorithm": &framework.FieldSchema{
|
||||
"hash_algorithm": {
|
||||
Type: framework.TypeString,
|
||||
Default: "sha2-256",
|
||||
Description: `Hash algorithm to use (POST body parameter). Valid values are:
|
||||
|
@ -133,21 +137,29 @@ derivation is enabled; currently only available with ed25519 keys.`,
|
|||
|
||||
Defaults to "sha2-256". Not valid for all key types.`,
|
||||
},
|
||||
"algorithm": &framework.FieldSchema{
|
||||
|
||||
"algorithm": {
|
||||
Type: framework.TypeString,
|
||||
Default: "sha2-256",
|
||||
Description: `Deprecated: use "hash_algorithm" instead.`,
|
||||
},
|
||||
|
||||
"prehashed": &framework.FieldSchema{
|
||||
"prehashed": {
|
||||
Type: framework.TypeBool,
|
||||
Description: `Set to 'true' when the input is already hashed. If the key type is 'rsa-2048' or 'rsa-4096', then the algorithm used to hash the input should be indicated by the 'algorithm' parameter.`,
|
||||
},
|
||||
"signature_algorithm": &framework.FieldSchema{
|
||||
|
||||
"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".`,
|
||||
},
|
||||
},
|
||||
|
||||
Callbacks: map[logical.Operation]framework.OperationFunc{
|
||||
|
@ -163,13 +175,25 @@ func (b *backend) pathSignWrite(ctx context.Context, req *logical.Request, d *fr
|
|||
name := d.Get("name").(string)
|
||||
ver := d.Get("key_version").(int)
|
||||
inputB64 := d.Get("input").(string)
|
||||
hashAlgorithm := d.Get("urlalgorithm").(string)
|
||||
if hashAlgorithm == "" {
|
||||
hashAlgorithm = d.Get("hash_algorithm").(string)
|
||||
if hashAlgorithm == "" {
|
||||
hashAlgorithm = d.Get("algorithm").(string)
|
||||
hashAlgorithmStr := d.Get("urlalgorithm").(string)
|
||||
if hashAlgorithmStr == "" {
|
||||
hashAlgorithmStr = d.Get("hash_algorithm").(string)
|
||||
if hashAlgorithmStr == "" {
|
||||
hashAlgorithmStr = d.Get("algorithm").(string)
|
||||
}
|
||||
}
|
||||
|
||||
hashAlgorithm, ok := keysutil.HashTypeMap[hashAlgorithmStr]
|
||||
if !ok {
|
||||
return logical.ErrorResponse(fmt.Sprintf("invalid hash algorithm %q", hashAlgorithmStr)), logical.ErrInvalidRequest
|
||||
}
|
||||
|
||||
marshalingStr := d.Get("marshaling_algorithm").(string)
|
||||
marshaling, ok := keysutil.MarshalingTypeMap[marshalingStr]
|
||||
if !ok {
|
||||
return logical.ErrorResponse(fmt.Sprintf("invalid marshaling type %q", marshalingStr)), logical.ErrInvalidRequest
|
||||
}
|
||||
|
||||
prehashed := d.Get("prehashed").(bool)
|
||||
sigAlgorithm := d.Get("signature_algorithm").(string)
|
||||
|
||||
|
@ -209,25 +233,12 @@ func (b *backend) pathSignWrite(ctx context.Context, req *logical.Request, d *fr
|
|||
}
|
||||
|
||||
if p.Type.HashSignatureInput() && !prehashed {
|
||||
var hf hash.Hash
|
||||
switch hashAlgorithm {
|
||||
case "sha2-224":
|
||||
hf = sha256.New224()
|
||||
case "sha2-256":
|
||||
hf = sha256.New()
|
||||
case "sha2-384":
|
||||
hf = sha512.New384()
|
||||
case "sha2-512":
|
||||
hf = sha512.New()
|
||||
default:
|
||||
p.Unlock()
|
||||
return logical.ErrorResponse(fmt.Sprintf("unsupported hash algorithm %s", hashAlgorithm)), nil
|
||||
}
|
||||
hf := keysutil.HashFuncMap[hashAlgorithm]()
|
||||
hf.Write(input)
|
||||
input = hf.Sum(nil)
|
||||
}
|
||||
|
||||
sig, err := p.Sign(ver, context, input, hashAlgorithm, sigAlgorithm)
|
||||
sig, err := p.Sign(ver, context, input, hashAlgorithm, sigAlgorithm, marshaling)
|
||||
if err != nil {
|
||||
p.Unlock()
|
||||
return nil, err
|
||||
|
@ -253,7 +264,6 @@ func (b *backend) pathSignWrite(ctx context.Context, req *logical.Request, d *fr
|
|||
}
|
||||
|
||||
func (b *backend) pathVerifyWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
|
||||
|
||||
sig := d.Get("signature").(string)
|
||||
hmac := d.Get("hmac").(string)
|
||||
switch {
|
||||
|
@ -269,13 +279,25 @@ func (b *backend) pathVerifyWrite(ctx context.Context, req *logical.Request, d *
|
|||
|
||||
name := d.Get("name").(string)
|
||||
inputB64 := d.Get("input").(string)
|
||||
hashAlgorithm := d.Get("urlalgorithm").(string)
|
||||
if hashAlgorithm == "" {
|
||||
hashAlgorithm = d.Get("hash_algorithm").(string)
|
||||
if hashAlgorithm == "" {
|
||||
hashAlgorithm = d.Get("algorithm").(string)
|
||||
hashAlgorithmStr := d.Get("urlalgorithm").(string)
|
||||
if hashAlgorithmStr == "" {
|
||||
hashAlgorithmStr = d.Get("hash_algorithm").(string)
|
||||
if hashAlgorithmStr == "" {
|
||||
hashAlgorithmStr = d.Get("algorithm").(string)
|
||||
}
|
||||
}
|
||||
|
||||
hashAlgorithm, ok := keysutil.HashTypeMap[hashAlgorithmStr]
|
||||
if !ok {
|
||||
return logical.ErrorResponse(fmt.Sprintf("invalid hash algorithm %q", hashAlgorithmStr)), logical.ErrInvalidRequest
|
||||
}
|
||||
|
||||
marshalingStr := d.Get("marshaling_algorithm").(string)
|
||||
marshaling, ok := keysutil.MarshalingTypeMap[marshalingStr]
|
||||
if !ok {
|
||||
return logical.ErrorResponse(fmt.Sprintf("invalid marshaling type %q", marshalingStr)), logical.ErrInvalidRequest
|
||||
}
|
||||
|
||||
prehashed := d.Get("prehashed").(bool)
|
||||
sigAlgorithm := d.Get("signature_algorithm").(string)
|
||||
|
||||
|
@ -315,25 +337,12 @@ func (b *backend) pathVerifyWrite(ctx context.Context, req *logical.Request, d *
|
|||
}
|
||||
|
||||
if p.Type.HashSignatureInput() && !prehashed {
|
||||
var hf hash.Hash
|
||||
switch hashAlgorithm {
|
||||
case "sha2-224":
|
||||
hf = sha256.New224()
|
||||
case "sha2-256":
|
||||
hf = sha256.New()
|
||||
case "sha2-384":
|
||||
hf = sha512.New384()
|
||||
case "sha2-512":
|
||||
hf = sha512.New()
|
||||
default:
|
||||
p.Unlock()
|
||||
return logical.ErrorResponse(fmt.Sprintf("unsupported hash algorithm %s", hashAlgorithm)), nil
|
||||
}
|
||||
hf := keysutil.HashFuncMap[hashAlgorithm]()
|
||||
hf.Write(input)
|
||||
input = hf.Sum(nil)
|
||||
}
|
||||
|
||||
valid, err := p.VerifySignature(context, input, sig, hashAlgorithm, sigAlgorithm)
|
||||
valid, err := p.VerifySignature(context, input, hashAlgorithm, sigAlgorithm, marshaling, sig)
|
||||
if err != nil {
|
||||
switch err.(type) {
|
||||
case errutil.UserError:
|
||||
|
|
|
@ -83,6 +83,7 @@ func TestTransit_SignVerify_P256(t *testing.T) {
|
|||
}
|
||||
|
||||
signRequest := func(req *logical.Request, errExpected bool, postpath string) string {
|
||||
t.Helper()
|
||||
req.Path = "sign/foo" + postpath
|
||||
resp, err := b.HandleRequest(context.Background(), req)
|
||||
if err != nil && !errExpected {
|
||||
|
@ -108,6 +109,7 @@ func TestTransit_SignVerify_P256(t *testing.T) {
|
|||
}
|
||||
|
||||
verifyRequest := func(req *logical.Request, errExpected bool, postpath, sig string) {
|
||||
t.Helper()
|
||||
req.Path = "verify/foo" + postpath
|
||||
req.Data["signature"] = sig
|
||||
resp, err := b.HandleRequest(context.Background(), req)
|
||||
|
@ -166,6 +168,22 @@ func TestTransit_SignVerify_P256(t *testing.T) {
|
|||
verifyRequest(req, false, "", sig)
|
||||
delete(req.Data, "prehashed")
|
||||
|
||||
// Test marshaling selection
|
||||
// Bad value
|
||||
req.Data["marshaling_algorithm"] = "asn2"
|
||||
sig = signRequest(req, true, "")
|
||||
// Use the default, verify we can't validate with jws
|
||||
req.Data["marshaling_algorithm"] = "asn1"
|
||||
sig = signRequest(req, false, "")
|
||||
req.Data["marshaling_algorithm"] = "jws"
|
||||
verifyRequest(req, true, "", sig)
|
||||
// Sign with jws, verify we can validate
|
||||
sig = signRequest(req, false, "")
|
||||
verifyRequest(req, false, "", sig)
|
||||
// If we change marshaling back to asn1 we shouldn't be able to verify
|
||||
delete(req.Data, "marshaling_algorithm")
|
||||
verifyRequest(req, true, "", sig)
|
||||
|
||||
// Test 512 and save sig for later to ensure we can't validate once min
|
||||
// decryption version is set
|
||||
req.Data["hash_algorithm"] = "sha2-512"
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
package keysutil
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"crypto/sha512"
|
||||
"hash"
|
||||
)
|
||||
|
||||
type HashType uint32
|
||||
|
||||
const (
|
||||
_ = iota
|
||||
HashTypeSHA2224 HashType = iota
|
||||
HashTypeSHA2256
|
||||
HashTypeSHA2384
|
||||
HashTypeSHA2512
|
||||
)
|
||||
|
||||
type MarshalingType uint32
|
||||
|
||||
const (
|
||||
_ = iota
|
||||
MarshalingTypeASN1 MarshalingType = iota
|
||||
MarshalingTypeJWS
|
||||
)
|
||||
|
||||
var (
|
||||
HashTypeMap = map[string]HashType{
|
||||
"sha2-224": HashTypeSHA2224,
|
||||
"sha2-256": HashTypeSHA2256,
|
||||
"sha2-384": HashTypeSHA2384,
|
||||
"sha2-512": HashTypeSHA2512,
|
||||
}
|
||||
|
||||
HashFuncMap = map[HashType]func() hash.Hash{
|
||||
HashTypeSHA2224: sha256.New224,
|
||||
HashTypeSHA2256: sha256.New,
|
||||
HashTypeSHA2384: sha512.New384,
|
||||
HashTypeSHA2512: sha512.New,
|
||||
}
|
||||
|
||||
MarshalingTypeMap = map[string]MarshalingType{
|
||||
"asn1": MarshalingTypeASN1,
|
||||
"jws": MarshalingTypeJWS,
|
||||
}
|
||||
)
|
|
@ -1043,7 +1043,7 @@ func (p *Policy) HMACKey(version int) ([]byte, error) {
|
|||
return p.Keys[strconv.Itoa(version)].HMACKey, nil
|
||||
}
|
||||
|
||||
func (p *Policy) Sign(ver int, context, input []byte, hashAlgorithm, sigAlgorithm string) (*SigningResult, error) {
|
||||
func (p *Policy) Sign(ver int, context, input []byte, hashAlgorithm HashType, sigAlgorithm string, marshaling MarshalingType) (*SigningResult, error) {
|
||||
if !p.Type.SigningSupported() {
|
||||
return nil, fmt.Errorf("message signing not supported for key type %v", p.Type)
|
||||
}
|
||||
|
@ -1064,6 +1064,7 @@ func (p *Policy) Sign(ver int, context, input []byte, hashAlgorithm, sigAlgorith
|
|||
var err error
|
||||
switch p.Type {
|
||||
case KeyType_ECDSA_P256:
|
||||
curveBits := 256
|
||||
keyParams := p.Keys[strconv.Itoa(ver)]
|
||||
key := &ecdsa.PrivateKey{
|
||||
PublicKey: ecdsa.PublicKey{
|
||||
|
@ -1073,18 +1074,46 @@ func (p *Policy) Sign(ver int, context, input []byte, hashAlgorithm, sigAlgorith
|
|||
},
|
||||
D: keyParams.EC_D,
|
||||
}
|
||||
|
||||
r, s, err := ecdsa.Sign(rand.Reader, key, input)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
marshaledSig, err := asn1.Marshal(ecdsaSignature{
|
||||
R: r,
|
||||
S: s,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
switch marshaling {
|
||||
case MarshalingTypeASN1:
|
||||
// This is used by openssl and X.509
|
||||
sig, err = asn1.Marshal(ecdsaSignature{
|
||||
R: r,
|
||||
S: s,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
case MarshalingTypeJWS:
|
||||
// This is used by JWS
|
||||
|
||||
// First we have to get the length of the curve in bytes. Although
|
||||
// we only support 256 now, we'll do this in an agnostic way so we
|
||||
// can reuse this marshaling if we support e.g. 521. Getting the
|
||||
// number of bytes without rounding up would be 65.125 so we need
|
||||
// to add one in that case.
|
||||
keyLen := curveBits / 8
|
||||
if curveBits%8 > 0 {
|
||||
keyLen++
|
||||
}
|
||||
|
||||
// Now create the output array
|
||||
sig = make([]byte, keyLen*2)
|
||||
rb := r.Bytes()
|
||||
sb := s.Bytes()
|
||||
copy(sig[keyLen-len(rb):], rb)
|
||||
copy(sig[2*keyLen-len(sb):], sb)
|
||||
|
||||
default:
|
||||
return nil, errutil.UserError{Err: "requested marshaling type is invalid"}
|
||||
}
|
||||
sig = marshaledSig
|
||||
|
||||
case KeyType_ED25519:
|
||||
var key ed25519.PrivateKey
|
||||
|
@ -1113,16 +1142,16 @@ func (p *Policy) Sign(ver int, context, input []byte, hashAlgorithm, sigAlgorith
|
|||
|
||||
var algo crypto.Hash
|
||||
switch hashAlgorithm {
|
||||
case "sha2-224":
|
||||
case HashTypeSHA2224:
|
||||
algo = crypto.SHA224
|
||||
case "sha2-256":
|
||||
case HashTypeSHA2256:
|
||||
algo = crypto.SHA256
|
||||
case "sha2-384":
|
||||
case HashTypeSHA2384:
|
||||
algo = crypto.SHA384
|
||||
case "sha2-512":
|
||||
case HashTypeSHA2512:
|
||||
algo = crypto.SHA512
|
||||
default:
|
||||
return nil, errutil.InternalError{Err: fmt.Sprintf("unsupported hash algorithm %s", hashAlgorithm)}
|
||||
return nil, errutil.InternalError{Err: "unsupported hash algorithm"}
|
||||
}
|
||||
|
||||
if sigAlgorithm == "" {
|
||||
|
@ -1149,7 +1178,13 @@ func (p *Policy) Sign(ver int, context, input []byte, hashAlgorithm, sigAlgorith
|
|||
}
|
||||
|
||||
// Convert to base64
|
||||
encoded := base64.StdEncoding.EncodeToString(sig)
|
||||
var encoded string
|
||||
switch marshaling {
|
||||
case MarshalingTypeASN1:
|
||||
encoded = base64.StdEncoding.EncodeToString(sig)
|
||||
case MarshalingTypeJWS:
|
||||
encoded = base64.RawURLEncoding.EncodeToString(sig)
|
||||
}
|
||||
res := &SigningResult{
|
||||
Signature: p.getVersionPrefix(ver) + encoded,
|
||||
PublicKey: pubKey,
|
||||
|
@ -1158,7 +1193,7 @@ func (p *Policy) Sign(ver int, context, input []byte, hashAlgorithm, sigAlgorith
|
|||
return res, nil
|
||||
}
|
||||
|
||||
func (p *Policy) VerifySignature(context, input []byte, sig, hashAlgorithm string, sigAlgorithm string) (bool, error) {
|
||||
func (p *Policy) VerifySignature(context, input []byte, hashAlgorithm HashType, sigAlgorithm string, marshaling MarshalingType, sig string) (bool, error) {
|
||||
if !p.Type.SigningSupported() {
|
||||
return false, errutil.UserError{Err: fmt.Sprintf("message verification not supported for key type %v", p.Type)}
|
||||
}
|
||||
|
@ -1191,7 +1226,15 @@ func (p *Policy) VerifySignature(context, input []byte, sig, hashAlgorithm strin
|
|||
return false, errutil.UserError{Err: ErrTooOld}
|
||||
}
|
||||
|
||||
sigBytes, err := base64.StdEncoding.DecodeString(splitVerSig[1])
|
||||
var sigBytes []byte
|
||||
switch marshaling {
|
||||
case MarshalingTypeASN1:
|
||||
sigBytes, err = base64.StdEncoding.DecodeString(splitVerSig[1])
|
||||
case MarshalingTypeJWS:
|
||||
sigBytes, err = base64.RawURLEncoding.DecodeString(splitVerSig[1])
|
||||
default:
|
||||
return false, errutil.UserError{Err: "requested marshaling type is invalid"}
|
||||
}
|
||||
if err != nil {
|
||||
return false, errutil.UserError{Err: "invalid base64 signature value"}
|
||||
}
|
||||
|
@ -1199,12 +1242,25 @@ func (p *Policy) VerifySignature(context, input []byte, sig, hashAlgorithm strin
|
|||
switch p.Type {
|
||||
case KeyType_ECDSA_P256:
|
||||
var ecdsaSig ecdsaSignature
|
||||
rest, err := asn1.Unmarshal(sigBytes, &ecdsaSig)
|
||||
if err != nil {
|
||||
return false, errutil.UserError{Err: "supplied signature is invalid"}
|
||||
}
|
||||
if rest != nil && len(rest) != 0 {
|
||||
return false, errutil.UserError{Err: "supplied signature contains extra data"}
|
||||
|
||||
switch marshaling {
|
||||
case MarshalingTypeASN1:
|
||||
rest, err := asn1.Unmarshal(sigBytes, &ecdsaSig)
|
||||
if err != nil {
|
||||
return false, errutil.UserError{Err: "supplied signature is invalid"}
|
||||
}
|
||||
if rest != nil && len(rest) != 0 {
|
||||
return false, errutil.UserError{Err: "supplied signature contains extra data"}
|
||||
}
|
||||
|
||||
case MarshalingTypeJWS:
|
||||
paramLen := len(sigBytes) / 2
|
||||
rb := sigBytes[:paramLen]
|
||||
sb := sigBytes[paramLen:]
|
||||
ecdsaSig.R = new(big.Int)
|
||||
ecdsaSig.R.SetBytes(rb)
|
||||
ecdsaSig.S = new(big.Int)
|
||||
ecdsaSig.S.SetBytes(sb)
|
||||
}
|
||||
|
||||
keyParams := p.Keys[strconv.Itoa(ver)]
|
||||
|
@ -1237,16 +1293,16 @@ func (p *Policy) VerifySignature(context, input []byte, sig, hashAlgorithm strin
|
|||
|
||||
var algo crypto.Hash
|
||||
switch hashAlgorithm {
|
||||
case "sha2-224":
|
||||
case HashTypeSHA2224:
|
||||
algo = crypto.SHA224
|
||||
case "sha2-256":
|
||||
case HashTypeSHA2256:
|
||||
algo = crypto.SHA256
|
||||
case "sha2-384":
|
||||
case HashTypeSHA2384:
|
||||
algo = crypto.SHA384
|
||||
case "sha2-512":
|
||||
case HashTypeSHA2512:
|
||||
algo = crypto.SHA512
|
||||
default:
|
||||
return false, errutil.InternalError{Err: fmt.Sprintf("unsupported hash algorithm %s", hashAlgorithm)}
|
||||
return false, errutil.InternalError{Err: "unsupported hash algorithm"}
|
||||
}
|
||||
|
||||
if sigAlgorithm == "" {
|
||||
|
|
|
@ -825,6 +825,12 @@ supports signing.
|
|||
- `pss`
|
||||
- `pkcs1v15`
|
||||
|
||||
- `marshaling_algorithm` `(string: "asn1")` – Specifies the way in which the signature should be marshaled. This currently only applies to ECDSA keys. Supported types are:
|
||||
|
||||
- `asn1`: The default, used by OpenSSL and X.509
|
||||
- `jws`: The version used by JWS (and thus for JWTs). Selecting this will
|
||||
also change the output encoding to URL-safe Base64 encoding instead of
|
||||
standard Base64-encoding.
|
||||
|
||||
### Sample Payload
|
||||
|
||||
|
@ -901,6 +907,13 @@ data.
|
|||
- `pss`
|
||||
- `pkcs1v15`
|
||||
|
||||
- `marshaling_algorithm` `(string: "asn1")` – Specifies the way in which the signature was originally marshaled. This currently only applies to ECDSA keys. Supported types are:
|
||||
|
||||
- `asn1`: The default, used by OpenSSL and X.509
|
||||
- `jws`: The version used by JWS (and thus for JWTs). Selecting this will
|
||||
also expect the input encoding to URL-safe Base64 encoding instead of
|
||||
standard Base64-encoding.
|
||||
|
||||
### Sample Payload
|
||||
|
||||
```json
|
||||
|
|
Loading…
Reference in New Issue