2016-09-21 14:29:42 +00:00
package transit
import (
2018-01-08 18:31:38 +00:00
"context"
2016-09-21 14:29:42 +00:00
"crypto/sha256"
"crypto/sha512"
"encoding/base64"
"fmt"
"hash"
"github.com/hashicorp/vault/helper/errutil"
"github.com/hashicorp/vault/logical"
"github.com/hashicorp/vault/logical/framework"
)
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 {
Type : framework . TypeString ,
Description : "The key to use" ,
} ,
"input" : & framework . FieldSchema {
Type : framework . TypeString ,
Description : "The base64-encoded input data" ,
} ,
2017-06-05 19:00:39 +00:00
"context" : & framework . FieldSchema {
Type : framework . TypeString ,
Description : ` Base64 encoded context for key derivation . Required if key
derivation is enabled ; currently only available with ed25519 keys . ` ,
} ,
2018-03-15 16:17:02 +00:00
"hash_algorithm" : & framework . FieldSchema {
2016-09-21 14:29:42 +00:00
Type : framework . TypeString ,
Default : "sha2-256" ,
Description : ` Hash algorithm to use ( POST body parameter ) . Valid values are :
* sha2 - 224
* sha2 - 256
* sha2 - 384
* sha2 - 512
2017-07-28 13:30:27 +00:00
Defaults to "sha2-256" . Not valid for all key types ,
including ed25519 . ` ,
2016-09-21 14:29:42 +00:00
} ,
2018-03-15 16:17:02 +00:00
"algorithm" : & framework . FieldSchema {
Type : framework . TypeString ,
Default : "sha2-256" ,
Description : ` Deprecated: use "hash_algorithm" instead. ` ,
} ,
2016-09-21 14:29:42 +00:00
"urlalgorithm" : & framework . FieldSchema {
Type : framework . TypeString ,
Description : ` Hash algorithm to use (POST URL parameter) ` ,
} ,
2017-06-06 20:02:54 +00:00
"key_version" : & framework . FieldSchema {
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 . ` ,
} ,
2017-11-03 14:45:53 +00:00
"prehashed" : & framework . FieldSchema {
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. ` ,
} ,
2018-03-15 16:17:02 +00:00
"signature_algorithm" : & framework . FieldSchema {
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 ' ` ,
} ,
2016-09-21 14:29:42 +00:00
} ,
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" ) ,
Fields : map [ string ] * framework . FieldSchema {
"name" : & framework . FieldSchema {
Type : framework . TypeString ,
Description : "The key to use" ,
} ,
2017-06-05 19:00:39 +00:00
"context" : & framework . FieldSchema {
Type : framework . TypeString ,
Description : ` Base64 encoded context for key derivation . Required if key
derivation is enabled ; currently only available with ed25519 keys . ` ,
} ,
2016-09-21 14:29:42 +00:00
"signature" : & framework . FieldSchema {
Type : framework . TypeString ,
Description : "The signature, including vault header/key version" ,
} ,
"hmac" : & framework . FieldSchema {
Type : framework . TypeString ,
Description : "The HMAC, including vault header/key version" ,
} ,
"input" : & framework . FieldSchema {
Type : framework . TypeString ,
Description : "The base64-encoded input data to verify" ,
} ,
"urlalgorithm" : & framework . FieldSchema {
Type : framework . TypeString ,
Description : ` Hash algorithm to use (POST URL parameter) ` ,
} ,
2018-03-15 16:17:02 +00:00
"hash_algorithm" : & framework . FieldSchema {
2016-09-21 14:29:42 +00:00
Type : framework . TypeString ,
Default : "sha2-256" ,
Description : ` Hash algorithm to use ( POST body parameter ) . Valid values are :
* sha2 - 224
* sha2 - 256
* sha2 - 384
* sha2 - 512
2017-06-05 19:00:39 +00:00
Defaults to "sha2-256" . Not valid for all key types . ` ,
2016-09-21 14:29:42 +00:00
} ,
2018-03-15 16:17:02 +00:00
"algorithm" : & framework . FieldSchema {
Type : framework . TypeString ,
Default : "sha2-256" ,
Description : ` Deprecated: use "hash_algorithm" instead. ` ,
} ,
2017-11-03 14:45:53 +00:00
"prehashed" : & framework . FieldSchema {
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. ` ,
} ,
2018-03-15 16:17:02 +00:00
"signature_algorithm" : & framework . FieldSchema {
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 ' ` ,
} ,
2016-09-21 14:29:42 +00:00
} ,
Callbacks : map [ logical . Operation ] framework . OperationFunc {
logical . UpdateOperation : b . pathVerifyWrite ,
} ,
HelpSynopsis : pathVerifyHelpSyn ,
HelpDescription : pathVerifyHelpDesc ,
}
}
2018-01-08 18:31:38 +00:00
func ( b * backend ) pathSignWrite ( ctx context . Context , req * logical . Request , d * framework . FieldData ) ( * logical . Response , error ) {
2016-09-21 14:29:42 +00:00
name := d . Get ( "name" ) . ( string )
2017-06-06 20:02:54 +00:00
ver := d . Get ( "key_version" ) . ( int )
2016-09-21 14:29:42 +00:00
inputB64 := d . Get ( "input" ) . ( string )
2018-03-15 16:17:02 +00:00
hashAlgorithm := d . Get ( "urlalgorithm" ) . ( string )
if hashAlgorithm == "" {
hashAlgorithm = d . Get ( "hash_algorithm" ) . ( string )
if hashAlgorithm == "" {
hashAlgorithm = d . Get ( "algorithm" ) . ( string )
}
2016-09-21 14:29:42 +00:00
}
2017-11-03 14:45:53 +00:00
prehashed := d . Get ( "prehashed" ) . ( bool )
2018-03-15 16:17:02 +00:00
sigAlgorithm := d . Get ( "signature_algorithm" ) . ( string )
2016-09-21 14:29:42 +00:00
input , err := base64 . StdEncoding . DecodeString ( inputB64 )
if err != nil {
return logical . ErrorResponse ( fmt . Sprintf ( "unable to decode input as base64: %s" , err ) ) , logical . ErrInvalidRequest
}
// Get the policy
2018-01-19 06:44:44 +00:00
p , lock , err := b . lm . GetPolicyShared ( ctx , req . Storage , name )
2016-09-21 14:29:42 +00:00
if lock != nil {
defer lock . RUnlock ( )
}
if err != nil {
return nil , err
}
if p == nil {
2017-05-12 18:14:00 +00:00
return logical . ErrorResponse ( "encryption key not found" ) , logical . ErrInvalidRequest
2016-09-21 14:29:42 +00:00
}
if ! p . Type . SigningSupported ( ) {
return logical . ErrorResponse ( fmt . Sprintf ( "key type %v does not support signing" , p . Type ) ) , logical . ErrInvalidRequest
}
2017-06-05 19:00:39 +00:00
contextRaw := d . Get ( "context" ) . ( string )
var context [ ] byte
if len ( contextRaw ) != 0 {
context , err = base64 . StdEncoding . DecodeString ( contextRaw )
if err != nil {
return logical . ErrorResponse ( "failed to base64-decode context" ) , logical . ErrInvalidRequest
}
}
2017-11-03 14:45:53 +00:00
if p . Type . HashSignatureInput ( ) && ! prehashed {
2017-06-05 19:00:39 +00:00
var hf hash . Hash
2018-03-15 16:17:02 +00:00
switch hashAlgorithm {
2017-06-05 19:00:39 +00:00
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 :
2018-03-15 16:17:02 +00:00
return logical . ErrorResponse ( fmt . Sprintf ( "unsupported hash algorithm %s" , hashAlgorithm ) ) , nil
2017-06-05 19:00:39 +00:00
}
hf . Write ( input )
input = hf . Sum ( nil )
}
2018-03-15 16:17:02 +00:00
sig , err := p . Sign ( ver , context , input , hashAlgorithm , sigAlgorithm )
2016-09-21 14:29:42 +00:00
if err != nil {
return nil , err
}
2017-06-05 19:00:39 +00:00
if sig == nil {
2016-09-21 14:29:42 +00:00
return nil , fmt . Errorf ( "signature could not be computed" )
}
// Generate the response
resp := & logical . Response {
Data : map [ string ] interface { } {
2017-06-05 19:00:39 +00:00
"signature" : sig . Signature ,
2016-09-21 14:29:42 +00:00
} ,
}
2017-06-05 19:00:39 +00:00
if len ( sig . PublicKey ) > 0 {
resp . Data [ "public_key" ] = sig . PublicKey
}
2016-09-21 14:29:42 +00:00
return resp , nil
}
2018-01-08 18:31:38 +00:00
func ( b * backend ) pathVerifyWrite ( ctx context . Context , req * logical . Request , d * framework . FieldData ) ( * logical . Response , error ) {
2016-09-21 14:29:42 +00:00
sig := d . Get ( "signature" ) . ( string )
hmac := d . Get ( "hmac" ) . ( string )
switch {
case sig != "" && hmac != "" :
return logical . ErrorResponse ( "provide one of 'signature' or 'hmac'" ) , logical . ErrInvalidRequest
case sig == "" && hmac == "" :
return logical . ErrorResponse ( "neither a 'signature' nor an 'hmac' were given to verify" ) , logical . ErrInvalidRequest
case hmac != "" :
2018-01-08 18:31:38 +00:00
return b . pathHMACVerify ( ctx , req , d , hmac )
2016-09-21 14:29:42 +00:00
}
name := d . Get ( "name" ) . ( string )
inputB64 := d . Get ( "input" ) . ( string )
2018-03-15 16:17:02 +00:00
hashAlgorithm := d . Get ( "urlalgorithm" ) . ( string )
if hashAlgorithm == "" {
hashAlgorithm = d . Get ( "hash_algorithm" ) . ( string )
if hashAlgorithm == "" {
hashAlgorithm = d . Get ( "algorithm" ) . ( string )
}
2016-09-21 14:29:42 +00:00
}
2017-11-03 14:45:53 +00:00
prehashed := d . Get ( "prehashed" ) . ( bool )
2018-03-15 16:17:02 +00:00
sigAlgorithm := d . Get ( "signature_algorithm" ) . ( string )
2016-09-21 14:29:42 +00:00
input , err := base64 . StdEncoding . DecodeString ( inputB64 )
if err != nil {
return logical . ErrorResponse ( fmt . Sprintf ( "unable to decode input as base64: %s" , err ) ) , logical . ErrInvalidRequest
}
// Get the policy
2018-01-19 06:44:44 +00:00
p , lock , err := b . lm . GetPolicyShared ( ctx , req . Storage , name )
2016-09-21 14:29:42 +00:00
if lock != nil {
defer lock . RUnlock ( )
}
if err != nil {
return nil , err
}
if p == nil {
2017-05-12 18:14:00 +00:00
return logical . ErrorResponse ( "encryption key not found" ) , logical . ErrInvalidRequest
2016-09-21 14:29:42 +00:00
}
2017-06-05 19:00:39 +00:00
if ! p . Type . SigningSupported ( ) {
return logical . ErrorResponse ( fmt . Sprintf ( "key type %v does not support verification" , p . Type ) ) , logical . ErrInvalidRequest
}
contextRaw := d . Get ( "context" ) . ( string )
var context [ ] byte
if len ( contextRaw ) != 0 {
context , err = base64 . StdEncoding . DecodeString ( contextRaw )
if err != nil {
return logical . ErrorResponse ( "failed to base64-decode context" ) , logical . ErrInvalidRequest
}
}
2017-11-03 14:45:53 +00:00
if p . Type . HashSignatureInput ( ) && ! prehashed {
2017-06-05 19:00:39 +00:00
var hf hash . Hash
2018-03-15 16:17:02 +00:00
switch hashAlgorithm {
2017-06-05 19:00:39 +00:00
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 :
2018-03-15 16:17:02 +00:00
return logical . ErrorResponse ( fmt . Sprintf ( "unsupported hash algorithm %s" , hashAlgorithm ) ) , nil
2017-06-05 19:00:39 +00:00
}
hf . Write ( input )
input = hf . Sum ( nil )
}
2018-03-15 16:17:02 +00:00
valid , err := p . VerifySignature ( context , input , sig , hashAlgorithm , sigAlgorithm )
2016-09-21 14:29:42 +00:00
if err != nil {
switch err . ( type ) {
case errutil . UserError :
return logical . ErrorResponse ( err . Error ( ) ) , logical . ErrInvalidRequest
case errutil . InternalError :
return nil , err
default :
return nil , err
}
}
// Generate the response
resp := & logical . Response {
Data : map [ string ] interface { } {
"valid" : valid ,
} ,
}
return resp , nil
}
const pathSignHelpSyn = ` Generate a signature for input data using the named key `
const pathSignHelpDesc = `
Generates a signature of the input data using the named key and the given hash algorithm .
`
const pathVerifyHelpSyn = ` Verify a signature or HMAC for input data created using the named key `
const pathVerifyHelpDesc = `
Verifies a signature or HMAC of the input data using the named key and the given hash algorithm .
`