2016-10-26 23:52:31 +00:00
package keysutil
2015-09-14 20:28:46 +00:00
import (
2016-08-30 20:29:09 +00:00
"bytes"
2018-01-19 06:44:44 +00:00
"context"
2017-06-05 19:00:39 +00:00
"crypto"
2015-09-14 20:28:46 +00:00
"crypto/aes"
"crypto/cipher"
2016-09-21 14:29:42 +00:00
"crypto/ecdsa"
"crypto/elliptic"
"crypto/hmac"
"crypto/rand"
2017-11-03 14:45:53 +00:00
"crypto/rsa"
2016-08-30 20:29:09 +00:00
"crypto/sha256"
2016-09-21 14:29:42 +00:00
"crypto/x509"
"encoding/asn1"
2015-09-14 20:28:46 +00:00
"encoding/base64"
"encoding/json"
2016-09-21 14:29:42 +00:00
"encoding/pem"
2016-01-15 19:02:51 +00:00
"fmt"
2016-08-30 20:29:09 +00:00
"io"
2016-09-21 14:29:42 +00:00
"math/big"
2018-03-09 01:58:50 +00:00
"path"
2015-09-14 20:28:46 +00:00
"strconv"
"strings"
2018-03-09 01:58:50 +00:00
"sync"
2015-09-14 20:28:46 +00:00
"time"
2018-02-14 16:59:46 +00:00
"golang.org/x/crypto/chacha20poly1305"
2017-06-05 19:00:39 +00:00
"golang.org/x/crypto/ed25519"
2016-08-30 20:29:09 +00:00
"golang.org/x/crypto/hkdf"
2016-08-08 20:30:48 +00:00
uuid "github.com/hashicorp/go-uuid"
2016-07-28 19:19:27 +00:00
"github.com/hashicorp/vault/helper/errutil"
2016-07-06 16:25:40 +00:00
"github.com/hashicorp/vault/helper/jsonutil"
2015-09-14 20:28:46 +00:00
"github.com/hashicorp/vault/helper/kdf"
"github.com/hashicorp/vault/logical"
)
2016-09-21 14:29:42 +00:00
// Careful with iota; don't put anything before it in this const block because
// we need the default of zero to be the old-style KDF
2015-09-14 20:28:46 +00:00
const (
2016-10-26 23:52:31 +00:00
Kdf_hmac_sha256_counter = iota // built-in helper
Kdf_hkdf_sha256 // golang.org/x/crypto/hkdf
2015-09-14 20:28:46 +00:00
)
2016-09-21 14:29:42 +00:00
// Or this one...we need the default of zero to be the original AES256-GCM96
const (
2016-10-26 23:52:31 +00:00
KeyType_AES256_GCM96 = iota
KeyType_ECDSA_P256
2017-06-05 19:00:39 +00:00
KeyType_ED25519
2017-11-03 14:45:53 +00:00
KeyType_RSA2048
KeyType_RSA4096
2018-02-14 16:59:46 +00:00
KeyType_ChaCha20_Poly1305
2016-09-21 14:29:42 +00:00
)
2018-03-09 01:58:50 +00:00
const (
// ErrTooOld is returned whtn the ciphertext or signatures's key version is
// too old.
ErrTooOld = "ciphertext or signature version is disallowed by policy (too old)"
// DefaultVersionTemplate is used when no version template is provided.
DefaultVersionTemplate = "vault:v{{version}}:"
)
2016-09-21 14:29:42 +00:00
2017-12-14 17:51:50 +00:00
type RestoreInfo struct {
Time time . Time ` json:"time" `
Version int ` json:"version" `
}
type BackupInfo struct {
Time time . Time ` json:"time" `
Version int ` json:"version" `
}
2017-06-05 19:00:39 +00:00
type SigningResult struct {
Signature string
PublicKey [ ] byte
}
2016-09-21 14:29:42 +00:00
type ecdsaSignature struct {
R , S * big . Int
}
type KeyType int
func ( kt KeyType ) EncryptionSupported ( ) bool {
switch kt {
2018-02-14 16:59:46 +00:00
case KeyType_AES256_GCM96 , KeyType_ChaCha20_Poly1305 , KeyType_RSA2048 , KeyType_RSA4096 :
2016-09-21 14:29:42 +00:00
return true
}
return false
}
func ( kt KeyType ) DecryptionSupported ( ) bool {
switch kt {
2018-02-14 16:59:46 +00:00
case KeyType_AES256_GCM96 , KeyType_ChaCha20_Poly1305 , KeyType_RSA2048 , KeyType_RSA4096 :
2016-09-21 14:29:42 +00:00
return true
}
return false
}
func ( kt KeyType ) SigningSupported ( ) bool {
2017-06-05 19:00:39 +00:00
switch kt {
2017-11-03 14:45:53 +00:00
case KeyType_ECDSA_P256 , KeyType_ED25519 , KeyType_RSA2048 , KeyType_RSA4096 :
2017-06-05 19:00:39 +00:00
return true
}
return false
}
func ( kt KeyType ) HashSignatureInput ( ) bool {
2016-09-21 14:29:42 +00:00
switch kt {
2017-11-03 14:45:53 +00:00
case KeyType_ECDSA_P256 , KeyType_RSA2048 , KeyType_RSA4096 :
2016-09-21 14:29:42 +00:00
return true
}
return false
}
func ( kt KeyType ) DerivationSupported ( ) bool {
switch kt {
2018-02-14 16:59:46 +00:00
case KeyType_AES256_GCM96 , KeyType_ChaCha20_Poly1305 , KeyType_ED25519 :
2016-09-21 14:29:42 +00:00
return true
}
return false
}
func ( kt KeyType ) String ( ) string {
switch kt {
2016-10-26 23:52:31 +00:00
case KeyType_AES256_GCM96 :
2016-09-21 14:29:42 +00:00
return "aes256-gcm96"
2018-02-14 16:59:46 +00:00
case KeyType_ChaCha20_Poly1305 :
return "chacha20-poly1305"
2016-10-26 23:52:31 +00:00
case KeyType_ECDSA_P256 :
2016-09-21 14:29:42 +00:00
return "ecdsa-p256"
2017-06-05 19:00:39 +00:00
case KeyType_ED25519 :
return "ed25519"
2017-11-03 14:45:53 +00:00
case KeyType_RSA2048 :
return "rsa-2048"
case KeyType_RSA4096 :
return "rsa-4096"
2016-09-21 14:29:42 +00:00
}
return "[unknown]"
}
2016-08-30 20:29:09 +00:00
2017-12-14 17:51:50 +00:00
type KeyData struct {
Policy * Policy ` json:"policy" `
ArchivedKeys * archivedKeys ` json:"archived_keys" `
}
2016-10-26 23:52:31 +00:00
// KeyEntry stores the key and metadata
type KeyEntry struct {
2017-06-05 19:00:39 +00:00
// AES or some other kind that is a pure byte slice like ED25519
Key [ ] byte ` json:"key" `
// Key used for HMAC functions
HMACKey [ ] byte ` json:"hmac_key" `
// Time of creation
CreationTime time . Time ` json:"time" `
EC_X * big . Int ` json:"ec_x" `
EC_Y * big . Int ` json:"ec_y" `
EC_D * big . Int ` json:"ec_d" `
2017-11-03 14:45:53 +00:00
RSAKey * rsa . PrivateKey ` json:"rsa_key" `
2017-06-05 19:00:39 +00:00
// The public key in an appropriate format for the type of key
FormattedPublicKey string ` json:"public_key" `
// This is deprecated (but still filled) in favor of the value above which
// is more precise
DeprecatedCreationTime int64 ` json:"creation_time" `
2015-09-14 20:28:46 +00:00
}
2017-12-06 23:24:00 +00:00
// deprecatedKeyEntryMap is used to allow JSON marshal/unmarshal
type deprecatedKeyEntryMap map [ int ] KeyEntry
2015-09-14 20:28:46 +00:00
// MarshalJSON implements JSON marshaling
2017-12-06 23:24:00 +00:00
func ( kem deprecatedKeyEntryMap ) MarshalJSON ( ) ( [ ] byte , error ) {
2016-10-26 23:52:31 +00:00
intermediate := map [ string ] KeyEntry { }
2015-09-14 20:28:46 +00:00
for k , v := range kem {
intermediate [ strconv . Itoa ( k ) ] = v
}
return json . Marshal ( & intermediate )
}
2018-03-20 18:54:10 +00:00
// MarshalJSON implements JSON unmarshalling
2017-12-06 23:24:00 +00:00
func ( kem deprecatedKeyEntryMap ) UnmarshalJSON ( data [ ] byte ) error {
2016-10-26 23:52:31 +00:00
intermediate := map [ string ] KeyEntry { }
2016-07-06 16:25:40 +00:00
if err := jsonutil . DecodeJSON ( data , & intermediate ) ; err != nil {
2015-09-14 20:28:46 +00:00
return err
}
for k , v := range intermediate {
keyval , err := strconv . Atoi ( k )
if err != nil {
return err
}
kem [ keyval ] = v
}
return nil
}
2017-12-06 23:24:00 +00:00
// keyEntryMap is used to allow JSON marshal/unmarshal
type keyEntryMap map [ string ] KeyEntry
2018-03-09 05:06:25 +00:00
// PolicyConfig is used to create a new policy
type PolicyConfig struct {
// The name of the policy
Name string ` json:"name" `
// The type of key
Type KeyType
// Derived keys MUST provide a context and the master underlying key is
// never used. If convergent encryption is true, the context will be used
// as the nonce as well.
Derived bool
KDF int
ConvergentEncryption bool
// Whether the key is exportable
Exportable bool
// Whether the key is allowed to be deleted
DeletionAllowed bool
// AllowPlaintextBackup allows taking backup of the policy in plaintext
AllowPlaintextBackup bool
// VersionTemplate is used to prefix the ciphertext with information about
// the key version. It must inclide {{version}} and a delimiter between the
// version prefix and the ciphertext.
VersionTemplate string
// StoragePrefix is used to add a prefix when storing and retrieving the
// policy object.
StoragePrefix string
}
// NewPolicy takes a policy config and returns a Policy with those settings.
func NewPolicy ( config PolicyConfig ) * Policy {
var convergentVersion int
if config . ConvergentEncryption {
convergentVersion = 2
}
return & Policy {
Name : config . Name ,
Type : config . Type ,
Derived : config . Derived ,
KDF : config . KDF ,
ConvergentEncryption : config . ConvergentEncryption ,
ConvergentVersion : convergentVersion ,
Exportable : config . Exportable ,
DeletionAllowed : config . DeletionAllowed ,
AllowPlaintextBackup : config . AllowPlaintextBackup ,
VersionTemplate : config . VersionTemplate ,
StoragePrefix : config . StoragePrefix ,
versionPrefixCache : & sync . Map { } ,
}
}
2018-03-09 19:01:24 +00:00
// LoadPolicy will load a policy from the provided storage path and set the
// necessary un-exported variables. It is particularly useful when accessing a
// policy without the lock manager.
func LoadPolicy ( ctx context . Context , s logical . Storage , path string ) ( * Policy , error ) {
raw , err := s . Get ( ctx , path )
if err != nil {
return nil , err
}
if raw == nil {
return nil , nil
}
var policy Policy
err = jsonutil . DecodeJSON ( raw . Value , & policy )
if err != nil {
return nil , err
}
policy . versionPrefixCache = & sync . Map { }
return & policy , nil
}
2015-09-14 20:28:46 +00:00
// Policy is the struct used to store metadata
2016-10-26 23:52:31 +00:00
type Policy struct {
2016-09-21 14:29:42 +00:00
Name string ` json:"name" `
Key [ ] byte ` json:"key,omitempty" ` //DEPRECATED
Keys keyEntryMap ` json:"keys" `
2015-09-14 20:28:46 +00:00
2016-06-20 17:17:48 +00:00
// Derived keys MUST provide a context and the master underlying key is
// never used. If convergent encryption is true, the context will be used
// as the nonce as well.
2016-08-30 20:29:09 +00:00
Derived bool ` json:"derived" `
KDF int ` json:"kdf" `
ConvergentEncryption bool ` json:"convergent_encryption" `
2015-09-14 20:28:46 +00:00
2017-01-23 16:04:43 +00:00
// Whether the key is exportable
Exportable bool ` json:"exportable" `
2017-06-06 20:02:54 +00:00
// The minimum version of the key allowed to be used for decryption
2015-09-14 20:28:46 +00:00
MinDecryptionVersion int ` json:"min_decryption_version" `
2015-09-17 22:49:50 +00:00
2017-06-06 20:02:54 +00:00
// The minimum version of the key allowed to be used for encryption
MinEncryptionVersion int ` json:"min_encryption_version" `
2016-01-15 19:02:51 +00:00
// The latest key version in this policy
LatestVersion int ` json:"latest_version" `
2016-01-26 17:23:42 +00:00
// The latest key version in the archive. We never delete these, so this is
// a max.
2016-01-15 19:02:51 +00:00
ArchiveVersion int ` json:"archive_version" `
2015-09-17 22:49:50 +00:00
// Whether the key is allowed to be deleted
DeletionAllowed bool ` json:"deletion_allowed" `
2016-08-26 18:11:03 +00:00
// The version of the convergent nonce to use
ConvergentVersion int ` json:"convergent_version" `
2016-09-21 14:29:42 +00:00
// The type of key
Type KeyType ` json:"type" `
2017-12-14 17:51:50 +00:00
// BackupInfo indicates the information about the backup action taken on
// this policy
BackupInfo * BackupInfo ` json:"backup_info" `
// RestoreInfo indicates the information about the restore action taken on
// this policy
RestoreInfo * RestoreInfo ` json:"restore_info" `
// AllowPlaintextBackup allows taking backup of the policy in plaintext
AllowPlaintextBackup bool ` json:"allow_plaintext_backup" `
2018-03-09 01:58:50 +00:00
// VersionTemplate is used to prefix the ciphertext with information about
// the key version. It must inclide {{version}} and a delimiter between the
// version prefix and the ciphertext.
VersionTemplate string ` json:"version_template" `
// StoragePrefix is used to add a prefix when storing and retrieving the
// policy object.
2018-03-09 05:06:25 +00:00
StoragePrefix string ` json:"storage_prefix" `
2018-03-09 01:58:50 +00:00
// versionPrefixCache stores caches of verison prefix strings and the split
// version template.
versionPrefixCache * sync . Map
2015-09-14 20:28:46 +00:00
}
2016-01-26 17:23:42 +00:00
// ArchivedKeys stores old keys. This is used to keep the key loading time sane
// when there are huge numbers of rotations.
2016-09-01 15:57:28 +00:00
type archivedKeys struct {
2016-10-26 23:52:31 +00:00
Keys [ ] KeyEntry ` json:"keys" `
2016-01-15 19:02:51 +00:00
}
2018-01-19 06:44:44 +00:00
func ( p * Policy ) LoadArchive ( ctx context . Context , storage logical . Storage ) ( * archivedKeys , error ) {
2016-09-01 15:57:28 +00:00
archive := & archivedKeys { }
2016-01-15 19:02:51 +00:00
2018-03-09 01:58:50 +00:00
raw , err := storage . Get ( ctx , path . Join ( p . StoragePrefix , "archive" , p . Name ) )
2016-01-15 19:02:51 +00:00
if err != nil {
return nil , err
}
if raw == nil {
2016-10-26 23:52:31 +00:00
archive . Keys = make ( [ ] KeyEntry , 0 )
2016-01-15 19:02:51 +00:00
return archive , nil
}
2016-07-06 16:25:40 +00:00
if err := jsonutil . DecodeJSON ( raw . Value , archive ) ; err != nil {
2016-01-15 19:02:51 +00:00
return nil , err
}
return archive , nil
}
2018-01-19 06:44:44 +00:00
func ( p * Policy ) storeArchive ( ctx context . Context , storage logical . Storage , archive * archivedKeys ) error {
2016-01-15 19:02:51 +00:00
// Encode the policy
buf , err := json . Marshal ( archive )
if err != nil {
return err
}
// Write the policy into storage
2018-01-19 06:44:44 +00:00
err = storage . Put ( ctx , & logical . StorageEntry {
2018-03-09 01:58:50 +00:00
Key : path . Join ( p . StoragePrefix , "archive" , p . Name ) ,
2016-01-15 19:02:51 +00:00
Value : buf ,
} )
if err != nil {
return err
}
return nil
}
// handleArchiving manages the movement of keys to and from the policy archive.
// This should *ONLY* be called from Persist() since it assumes that the policy
// will be persisted afterwards.
2018-01-19 06:44:44 +00:00
func ( p * Policy ) handleArchiving ( ctx context . Context , storage logical . Storage ) error {
2016-09-01 15:57:28 +00:00
// We need to move keys that are no longer accessible to archivedKeys, and keys
2016-01-15 19:02:51 +00:00
// that now need to be accessible back here.
//
// For safety, because there isn't really a good reason to, we never delete
// keys from the archive even when we move them back.
2016-01-26 22:14:21 +00:00
// Check if we have the latest minimum version in the current set of keys
2017-12-06 23:24:00 +00:00
_ , keysContainsMinimum := p . Keys [ strconv . Itoa ( p . MinDecryptionVersion ) ]
2016-01-26 22:14:21 +00:00
2016-01-26 17:23:42 +00:00
// Sanity checks
switch {
case p . MinDecryptionVersion < 1 :
return fmt . Errorf ( "minimum decryption version of %d is less than 1" , p . MinDecryptionVersion )
case p . LatestVersion < 1 :
return fmt . Errorf ( "latest version of %d is less than 1" , p . LatestVersion )
2016-01-26 22:14:21 +00:00
case ! keysContainsMinimum && p . ArchiveVersion != p . LatestVersion :
return fmt . Errorf ( "need to move keys from archive but archive version not up-to-date" )
case p . ArchiveVersion > p . LatestVersion :
return fmt . Errorf ( "archive version of %d is greater than the latest version %d" ,
p . ArchiveVersion , p . LatestVersion )
2017-06-06 20:02:54 +00:00
case p . MinEncryptionVersion > 0 && p . MinEncryptionVersion < p . MinDecryptionVersion :
return fmt . Errorf ( "minimum decryption version of %d is greater than minimum encryption version %d" ,
p . MinDecryptionVersion , p . MinEncryptionVersion )
2016-01-26 17:23:42 +00:00
case p . MinDecryptionVersion > p . LatestVersion :
return fmt . Errorf ( "minimum decryption version of %d is greater than the latest version %d" ,
p . MinDecryptionVersion , p . LatestVersion )
}
2018-01-19 06:44:44 +00:00
archive , err := p . LoadArchive ( ctx , storage )
2016-01-15 19:02:51 +00:00
if err != nil {
return err
}
2016-01-27 01:21:58 +00:00
if ! keysContainsMinimum {
// Need to move keys *from* archive
for i := p . MinDecryptionVersion ; i <= p . LatestVersion ; i ++ {
2017-12-06 23:24:00 +00:00
p . Keys [ strconv . Itoa ( i ) ] = archive . Keys [ i ]
2016-01-15 19:02:51 +00:00
}
2016-01-27 01:21:58 +00:00
return nil
}
2016-01-15 19:02:51 +00:00
2016-01-27 01:21:58 +00:00
// Need to move keys *to* archive
2016-01-15 19:02:51 +00:00
2016-01-27 01:21:58 +00:00
// We need a size that is equivalent to the latest version (number of keys)
// but adding one since slice numbering starts at 0 and we're indexing by
// key version
if len ( archive . Keys ) < p . LatestVersion + 1 {
// Increase the size of the archive slice
2016-10-26 23:52:31 +00:00
newKeys := make ( [ ] KeyEntry , p . LatestVersion + 1 )
2016-01-27 01:21:58 +00:00
copy ( newKeys , archive . Keys )
archive . Keys = newKeys
}
2016-01-15 19:02:51 +00:00
2016-01-27 01:21:58 +00:00
// We are storing all keys in the archive, so we ensure that it is up to
// date up to p.LatestVersion
for i := p . ArchiveVersion + 1 ; i <= p . LatestVersion ; i ++ {
2017-12-06 23:24:00 +00:00
archive . Keys [ i ] = p . Keys [ strconv . Itoa ( i ) ]
2016-01-27 01:21:58 +00:00
p . ArchiveVersion = i
}
2018-01-19 06:44:44 +00:00
err = p . storeArchive ( ctx , storage , archive )
2016-01-27 01:21:58 +00:00
if err != nil {
return err
}
// Perform deletion afterwards so that if there is an error saving we
// haven't messed with the current policy
for i := p . LatestVersion - len ( p . Keys ) + 1 ; i < p . MinDecryptionVersion ; i ++ {
2017-12-06 23:24:00 +00:00
delete ( p . Keys , strconv . Itoa ( i ) )
2016-01-15 19:02:51 +00:00
}
return nil
}
2018-02-12 22:27:28 +00:00
func ( p * Policy ) Persist ( ctx context . Context , storage logical . Storage ) ( retErr error ) {
// Other functions will take care of restoring other values; this is just
// responsible for archiving and keys since the archive function can modify
// keys. At the moment one of the other functions calling persist will also
// roll back keys, but better safe than sorry and this doesn't happen
// enough to worry about the speed tradeoff.
priorArchiveVersion := p . ArchiveVersion
var priorKeys keyEntryMap
if p . Keys != nil {
priorKeys = keyEntryMap { }
for k , v := range p . Keys {
priorKeys [ k ] = v
}
}
defer func ( ) {
if retErr != nil {
p . ArchiveVersion = priorArchiveVersion
p . Keys = priorKeys
}
} ( )
2018-01-19 06:44:44 +00:00
err := p . handleArchiving ( ctx , storage )
2016-01-15 19:02:51 +00:00
if err != nil {
return err
}
2015-09-14 20:28:46 +00:00
// Encode the policy
buf , err := p . Serialize ( )
if err != nil {
return err
}
// Write the policy into storage
2018-01-19 06:44:44 +00:00
err = storage . Put ( ctx , & logical . StorageEntry {
2018-03-09 01:58:50 +00:00
Key : path . Join ( p . StoragePrefix , "policy" , p . Name ) ,
2015-09-14 20:28:46 +00:00
Value : buf ,
} )
if err != nil {
return err
}
return nil
}
2016-10-26 23:52:31 +00:00
func ( p * Policy ) Serialize ( ) ( [ ] byte , error ) {
2015-09-14 20:28:46 +00:00
return json . Marshal ( p )
}
2016-10-26 23:52:31 +00:00
func ( p * Policy ) NeedsUpgrade ( ) bool {
2016-04-26 15:39:19 +00:00
// Ensure we've moved from Key -> Keys
if p . Key != nil && len ( p . Key ) > 0 {
return true
}
2016-09-21 14:29:42 +00:00
// With archiving, past assumptions about the length of the keys map are no
// longer valid
2016-04-26 15:39:19 +00:00
if p . LatestVersion == 0 && len ( p . Keys ) != 0 {
return true
}
// We disallow setting the version to 0, since they start at 1 since moving
// to rotate-able keys, so update if it's set to 0
if p . MinDecryptionVersion == 0 {
return true
}
// On first load after an upgrade, copy keys to the archive
if p . ArchiveVersion == 0 {
return true
}
2016-08-26 18:11:03 +00:00
// Need to write the version
if p . ConvergentEncryption && p . ConvergentVersion == 0 {
return true
}
2017-12-06 23:24:00 +00:00
if p . Keys [ strconv . Itoa ( p . LatestVersion ) ] . HMACKey == nil || len ( p . Keys [ strconv . Itoa ( p . LatestVersion ) ] . HMACKey ) == 0 {
2016-09-21 15:10:57 +00:00
return true
}
2016-04-26 15:39:19 +00:00
return false
}
2018-02-12 22:27:28 +00:00
func ( p * Policy ) Upgrade ( ctx context . Context , storage logical . Storage ) ( retErr error ) {
priorKey := p . Key
priorLatestVersion := p . LatestVersion
priorMinDecryptionVersion := p . MinDecryptionVersion
priorConvergentVersion := p . ConvergentVersion
var priorKeys keyEntryMap
if p . Keys != nil {
priorKeys = keyEntryMap { }
for k , v := range p . Keys {
priorKeys [ k ] = v
}
}
defer func ( ) {
if retErr != nil {
p . Key = priorKey
p . LatestVersion = priorLatestVersion
p . MinDecryptionVersion = priorMinDecryptionVersion
p . ConvergentVersion = priorConvergentVersion
p . Keys = priorKeys
}
} ( )
2016-04-26 15:39:19 +00:00
persistNeeded := false
// Ensure we've moved from Key -> Keys
if p . Key != nil && len ( p . Key ) > 0 {
2016-10-26 23:52:31 +00:00
p . MigrateKeyToKeysMap ( )
2016-04-26 15:39:19 +00:00
persistNeeded = true
}
2016-09-21 14:29:42 +00:00
// With archiving, past assumptions about the length of the keys map are no
// longer valid
2016-04-26 15:39:19 +00:00
if p . LatestVersion == 0 && len ( p . Keys ) != 0 {
p . LatestVersion = len ( p . Keys )
persistNeeded = true
}
// We disallow setting the version to 0, since they start at 1 since moving
// to rotate-able keys, so update if it's set to 0
if p . MinDecryptionVersion == 0 {
p . MinDecryptionVersion = 1
persistNeeded = true
}
// On first load after an upgrade, copy keys to the archive
if p . ArchiveVersion == 0 {
persistNeeded = true
}
2016-08-26 18:11:03 +00:00
if p . ConvergentEncryption && p . ConvergentVersion == 0 {
p . ConvergentVersion = 1
persistNeeded = true
}
2017-12-06 23:24:00 +00:00
if p . Keys [ strconv . Itoa ( p . LatestVersion ) ] . HMACKey == nil || len ( p . Keys [ strconv . Itoa ( p . LatestVersion ) ] . HMACKey ) == 0 {
entry := p . Keys [ strconv . Itoa ( p . LatestVersion ) ]
2016-09-21 15:10:57 +00:00
hmacKey , err := uuid . GenerateRandomBytes ( 32 )
if err != nil {
return err
}
entry . HMACKey = hmacKey
2017-12-06 23:24:00 +00:00
p . Keys [ strconv . Itoa ( p . LatestVersion ) ] = entry
2016-09-21 15:10:57 +00:00
persistNeeded = true
}
2016-04-26 15:39:19 +00:00
if persistNeeded {
2018-01-19 06:44:44 +00:00
err := p . Persist ( ctx , storage )
2016-04-26 15:39:19 +00:00
if err != nil {
return err
}
}
return nil
}
2016-08-30 20:29:09 +00:00
// DeriveKey is used to derive the encryption key that should be used depending
// on the policy. If derivation is disabled the raw key is used and no context
// is required, otherwise the KDF mode is used with the context to derive the
// proper key.
2016-10-26 23:52:31 +00:00
func ( p * Policy ) DeriveKey ( context [ ] byte , ver int ) ( [ ] byte , error ) {
2016-09-21 14:29:42 +00:00
if ! p . Type . DerivationSupported ( ) {
return nil , errutil . UserError { Err : fmt . Sprintf ( "derivation not supported for key type %v" , p . Type ) }
}
2016-01-15 19:02:51 +00:00
if p . Keys == nil || p . LatestVersion == 0 {
2016-07-28 19:19:27 +00:00
return nil , errutil . InternalError { Err : "unable to access the key; no key versions found" }
2015-09-14 20:28:46 +00:00
}
2016-01-15 19:02:51 +00:00
if ver <= 0 || ver > p . LatestVersion {
2016-07-28 19:19:27 +00:00
return nil , errutil . UserError { Err : "invalid key version" }
2015-09-14 20:28:46 +00:00
}
// Fast-path non-derived keys
if ! p . Derived {
2017-12-06 23:24:00 +00:00
return p . Keys [ strconv . Itoa ( ver ) ] . Key , nil
2015-09-14 20:28:46 +00:00
}
// Ensure a context is provided
if len ( context ) == 0 {
2017-09-13 15:05:57 +00:00
return nil , errutil . UserError { Err : "missing 'context' for key derivation; the key was created using a derived key, which means additional, per-request information must be included in order to perform operations with the key" }
2015-09-14 20:28:46 +00:00
}
2016-08-30 20:29:09 +00:00
switch p . KDF {
2016-10-26 23:52:31 +00:00
case Kdf_hmac_sha256_counter :
2015-09-14 20:28:46 +00:00
prf := kdf . HMACSHA256PRF
prfLen := kdf . HMACSHA256PRFLen
2017-12-06 23:24:00 +00:00
return kdf . CounterMode ( prf , prfLen , p . Keys [ strconv . Itoa ( ver ) ] . Key , context , 256 )
2017-06-05 19:00:39 +00:00
2016-10-26 23:52:31 +00:00
case Kdf_hkdf_sha256 :
2017-12-06 23:24:00 +00:00
reader := hkdf . New ( sha256 . New , p . Keys [ strconv . Itoa ( ver ) ] . Key , nil , context )
2016-08-30 20:29:09 +00:00
derBytes := bytes . NewBuffer ( nil )
derBytes . Grow ( 32 )
limReader := & io . LimitedReader {
R : reader ,
N : 32 ,
}
2017-06-05 19:00:39 +00:00
switch p . Type {
2018-02-14 16:59:46 +00:00
case KeyType_AES256_GCM96 , KeyType_ChaCha20_Poly1305 :
2017-06-05 19:00:39 +00:00
n , err := derBytes . ReadFrom ( limReader )
if err != nil {
return nil , errutil . InternalError { Err : fmt . Sprintf ( "error reading returned derived bytes: %v" , err ) }
}
if n != 32 {
return nil , errutil . InternalError { Err : fmt . Sprintf ( "unable to read enough derived bytes, needed 32, got %d" , n ) }
}
return derBytes . Bytes ( ) , nil
case KeyType_ED25519 :
// We use the limited reader containing the derived bytes as the
// "random" input to the generation function
_ , pri , err := ed25519 . GenerateKey ( limReader )
if err != nil {
return nil , errutil . InternalError { Err : fmt . Sprintf ( "error generating derived key: %v" , err ) }
}
return pri , nil
default :
return nil , errutil . InternalError { Err : "unsupported key type for derivation" }
2016-08-30 20:29:09 +00:00
}
2017-06-05 19:00:39 +00:00
2015-09-14 20:28:46 +00:00
default :
2016-07-28 19:19:27 +00:00
return nil , errutil . InternalError { Err : "unsupported key derivation mode" }
2015-09-14 20:28:46 +00:00
}
}
2017-06-06 20:02:54 +00:00
func ( p * Policy ) Encrypt ( ver int , context , nonce [ ] byte , value string ) ( string , error ) {
2016-09-21 14:29:42 +00:00
if ! p . Type . EncryptionSupported ( ) {
return "" , errutil . UserError { Err : fmt . Sprintf ( "message encryption not supported for key type %v" , p . Type ) }
}
2015-09-14 20:28:46 +00:00
// Decode the plaintext value
plaintext , err := base64 . StdEncoding . DecodeString ( value )
if err != nil {
2017-10-20 15:21:45 +00:00
return "" , errutil . UserError { Err : err . Error ( ) }
2015-09-14 20:28:46 +00:00
}
2017-06-06 20:02:54 +00:00
switch {
case ver == 0 :
ver = p . LatestVersion
case ver < 0 :
return "" , errutil . UserError { Err : "requested version for encryption is negative" }
case ver > p . LatestVersion :
return "" , errutil . UserError { Err : "requested version for encryption is higher than the latest key version" }
case ver < p . MinEncryptionVersion :
return "" , errutil . UserError { Err : "requested version for encryption is less than the minimum encryption key version" }
}
2017-11-03 14:45:53 +00:00
var ciphertext [ ] byte
2015-09-14 20:28:46 +00:00
2016-09-21 14:29:42 +00:00
switch p . Type {
2018-02-14 16:59:46 +00:00
case KeyType_AES256_GCM96 , KeyType_ChaCha20_Poly1305 :
2017-11-03 14:45:53 +00:00
// Derive the key that should be used
key , err := p . DeriveKey ( context , ver )
if err != nil {
return "" , err
}
2015-09-14 20:28:46 +00:00
2018-02-14 16:59:46 +00:00
var aead cipher . AEAD
2015-09-14 20:28:46 +00:00
2018-02-14 16:59:46 +00:00
switch p . Type {
case KeyType_AES256_GCM96 :
// Setup the cipher
aesCipher , err := aes . NewCipher ( key )
if err != nil {
return "" , errutil . InternalError { Err : err . Error ( ) }
}
// Setup the GCM AEAD
gcm , err := cipher . NewGCM ( aesCipher )
if err != nil {
return "" , errutil . InternalError { Err : err . Error ( ) }
}
aead = gcm
case KeyType_ChaCha20_Poly1305 :
cha , err := chacha20poly1305 . New ( key )
if err != nil {
return "" , errutil . InternalError { Err : err . Error ( ) }
}
aead = cha
2016-06-20 17:17:48 +00:00
}
2015-09-14 20:28:46 +00:00
2017-11-03 14:45:53 +00:00
if p . ConvergentEncryption {
switch p . ConvergentVersion {
case 1 :
2018-02-14 16:59:46 +00:00
if len ( nonce ) != aead . NonceSize ( ) {
return "" , errutil . UserError { Err : fmt . Sprintf ( "base64-decoded nonce must be %d bytes long when using convergent encryption with this key" , aead . NonceSize ( ) ) }
2017-11-03 14:45:53 +00:00
}
default :
nonceHmac := hmac . New ( sha256 . New , context )
nonceHmac . Write ( plaintext )
nonceSum := nonceHmac . Sum ( nil )
2018-02-14 16:59:46 +00:00
nonce = nonceSum [ : aead . NonceSize ( ) ]
2017-11-03 14:45:53 +00:00
}
} else {
// Compute random nonce
2018-02-14 16:59:46 +00:00
nonce , err = uuid . GenerateRandomBytes ( aead . NonceSize ( ) )
2017-11-03 14:45:53 +00:00
if err != nil {
return "" , errutil . InternalError { Err : err . Error ( ) }
}
}
2018-02-14 16:59:46 +00:00
// Encrypt and tag with AEAD
ciphertext = aead . Seal ( nil , nonce , plaintext , nil )
2017-11-03 14:45:53 +00:00
// Place the encrypted data after the nonce
if ! p . ConvergentEncryption || p . ConvergentVersion > 1 {
ciphertext = append ( nonce , ciphertext ... )
}
case KeyType_RSA2048 , KeyType_RSA4096 :
2017-12-06 23:24:00 +00:00
key := p . Keys [ strconv . Itoa ( ver ) ] . RSAKey
2017-11-03 14:45:53 +00:00
ciphertext , err = rsa . EncryptOAEP ( sha256 . New ( ) , rand . Reader , & key . PublicKey , plaintext , nil )
if err != nil {
return "" , errutil . InternalError { Err : fmt . Sprintf ( "failed to RSA encrypt the plaintext: %v" , err ) }
}
2015-09-14 20:28:46 +00:00
2017-11-03 14:45:53 +00:00
default :
return "" , errutil . InternalError { Err : fmt . Sprintf ( "unsupported key type %v" , p . Type ) }
2016-08-05 21:52:44 +00:00
}
2015-09-14 20:28:46 +00:00
// Convert to base64
2017-11-03 14:45:53 +00:00
encoded := base64 . StdEncoding . EncodeToString ( ciphertext )
2015-09-14 20:28:46 +00:00
// Prepend some information
2018-03-09 01:58:50 +00:00
encoded = p . getVersionPrefix ( ver ) + encoded
2015-09-14 20:28:46 +00:00
return encoded , nil
}
2016-10-26 23:52:31 +00:00
func ( p * Policy ) Decrypt ( context , nonce [ ] byte , value string ) ( string , error ) {
2016-09-21 14:29:42 +00:00
if ! p . Type . DecryptionSupported ( ) {
return "" , errutil . UserError { Err : fmt . Sprintf ( "message decryption not supported for key type %v" , p . Type ) }
}
2018-03-09 01:58:50 +00:00
tplParts , err := p . getTemplateParts ( )
if err != nil {
return "" , err
}
2015-09-14 20:28:46 +00:00
// Verify the prefix
2018-03-09 01:58:50 +00:00
if ! strings . HasPrefix ( value , tplParts [ 0 ] ) {
2016-07-28 19:19:27 +00:00
return "" , errutil . UserError { Err : "invalid ciphertext: no prefix" }
2015-09-14 20:28:46 +00:00
}
2016-08-26 21:01:56 +00:00
if p . ConvergentEncryption && p . ConvergentVersion == 1 && ( nonce == nil || len ( nonce ) == 0 ) {
2016-08-05 21:52:44 +00:00
return "" , errutil . UserError { Err : "invalid convergent nonce supplied" }
}
2018-03-09 01:58:50 +00:00
splitVerCiphertext := strings . SplitN ( strings . TrimPrefix ( value , tplParts [ 0 ] ) , tplParts [ 1 ] , 2 )
2015-09-14 20:28:46 +00:00
if len ( splitVerCiphertext ) != 2 {
2016-07-28 19:19:27 +00:00
return "" , errutil . UserError { Err : "invalid ciphertext: wrong number of fields" }
2015-09-14 20:28:46 +00:00
}
ver , err := strconv . Atoi ( splitVerCiphertext [ 0 ] )
if err != nil {
2016-07-28 19:19:27 +00:00
return "" , errutil . UserError { Err : "invalid ciphertext: version number could not be decoded" }
2015-09-14 20:28:46 +00:00
}
if ver == 0 {
2016-01-22 19:10:09 +00:00
// Compatibility mode with initial implementation, where keys start at
// zero
2015-09-14 20:28:46 +00:00
ver = 1
}
2016-04-21 20:32:06 +00:00
if ver > p . LatestVersion {
2016-07-28 19:19:27 +00:00
return "" , errutil . UserError { Err : "invalid ciphertext: version is too new" }
2016-04-21 20:32:06 +00:00
}
2015-09-14 20:28:46 +00:00
if p . MinDecryptionVersion > 0 && ver < p . MinDecryptionVersion {
2016-07-28 19:19:27 +00:00
return "" , errutil . UserError { Err : ErrTooOld }
2015-09-14 20:28:46 +00:00
}
2017-11-03 14:45:53 +00:00
// Decode the base64
decoded , err := base64 . StdEncoding . DecodeString ( splitVerCiphertext [ 1 ] )
2015-09-14 20:28:46 +00:00
if err != nil {
2017-11-03 14:45:53 +00:00
return "" , errutil . UserError { Err : "invalid ciphertext: could not decode base64" }
2015-09-14 20:28:46 +00:00
}
2017-11-03 14:45:53 +00:00
var plain [ ] byte
2016-09-21 14:29:42 +00:00
switch p . Type {
2018-02-14 16:59:46 +00:00
case KeyType_AES256_GCM96 , KeyType_ChaCha20_Poly1305 :
2017-11-03 14:45:53 +00:00
key , err := p . DeriveKey ( context , ver )
if err != nil {
return "" , err
}
2015-09-14 20:28:46 +00:00
2018-02-14 16:59:46 +00:00
var aead cipher . AEAD
2015-09-14 20:28:46 +00:00
2018-02-14 16:59:46 +00:00
switch p . Type {
case KeyType_AES256_GCM96 :
// Setup the cipher
aesCipher , err := aes . NewCipher ( key )
if err != nil {
return "" , errutil . InternalError { Err : err . Error ( ) }
}
// Setup the GCM AEAD
gcm , err := cipher . NewGCM ( aesCipher )
if err != nil {
return "" , errutil . InternalError { Err : err . Error ( ) }
}
aead = gcm
case KeyType_ChaCha20_Poly1305 :
cha , err := chacha20poly1305 . New ( key )
if err != nil {
return "" , errutil . InternalError { Err : err . Error ( ) }
}
aead = cha
2017-11-03 14:45:53 +00:00
}
2015-09-14 20:28:46 +00:00
2018-02-14 16:59:46 +00:00
if len ( decoded ) < aead . NonceSize ( ) {
2017-11-03 14:45:53 +00:00
return "" , errutil . UserError { Err : "invalid ciphertext length" }
}
2015-09-14 20:28:46 +00:00
2017-11-03 14:45:53 +00:00
// Extract the nonce and ciphertext
var ciphertext [ ] byte
if p . ConvergentEncryption && p . ConvergentVersion < 2 {
ciphertext = decoded
} else {
2018-02-14 16:59:46 +00:00
nonce = decoded [ : aead . NonceSize ( ) ]
ciphertext = decoded [ aead . NonceSize ( ) : ]
2017-11-03 14:45:53 +00:00
}
2017-11-02 21:40:52 +00:00
2017-11-03 14:45:53 +00:00
// Verify and Decrypt
2018-02-14 16:59:46 +00:00
plain , err = aead . Open ( nil , nonce , ciphertext , nil )
2017-11-03 14:45:53 +00:00
if err != nil {
return "" , errutil . UserError { Err : "invalid ciphertext: unable to decrypt" }
}
2015-09-14 20:28:46 +00:00
2017-11-03 14:45:53 +00:00
case KeyType_RSA2048 , KeyType_RSA4096 :
2017-12-06 23:24:00 +00:00
key := p . Keys [ strconv . Itoa ( ver ) ] . RSAKey
2017-11-03 14:45:53 +00:00
plain , err = rsa . DecryptOAEP ( sha256 . New ( ) , rand . Reader , key , decoded , nil )
if err != nil {
return "" , errutil . InternalError { Err : fmt . Sprintf ( "failed to RSA decrypt the ciphertext: %v" , err ) }
}
default :
return "" , errutil . InternalError { Err : fmt . Sprintf ( "unsupported key type %v" , p . Type ) }
2015-09-14 20:28:46 +00:00
}
return base64 . StdEncoding . EncodeToString ( plain ) , nil
}
2016-10-26 23:52:31 +00:00
func ( p * Policy ) HMACKey ( version int ) ( [ ] byte , error ) {
2017-06-06 20:02:54 +00:00
switch {
case version < 0 :
return nil , fmt . Errorf ( "key version does not exist (cannot be negative)" )
case version > p . LatestVersion :
2016-09-21 14:29:42 +00:00
return nil , fmt . Errorf ( "key version does not exist; latest key version is %d" , p . LatestVersion )
}
2017-12-06 23:24:00 +00:00
if p . Keys [ strconv . Itoa ( version ) ] . HMACKey == nil {
2016-09-21 14:29:42 +00:00
return nil , fmt . Errorf ( "no HMAC key exists for that key version" )
}
2017-12-06 23:24:00 +00:00
return p . Keys [ strconv . Itoa ( version ) ] . HMACKey , nil
2016-09-21 14:29:42 +00:00
}
2018-03-15 16:17:02 +00:00
func ( p * Policy ) Sign ( ver int , context , input [ ] byte , hashAlgorithm , sigAlgorithm string ) ( * SigningResult , error ) {
2016-09-21 14:29:42 +00:00
if ! p . Type . SigningSupported ( ) {
2017-06-05 19:00:39 +00:00
return nil , fmt . Errorf ( "message signing not supported for key type %v" , p . Type )
2016-09-21 14:29:42 +00:00
}
2017-06-06 20:02:54 +00:00
switch {
case ver == 0 :
ver = p . LatestVersion
case ver < 0 :
return nil , errutil . UserError { Err : "requested version for signing is negative" }
case ver > p . LatestVersion :
return nil , errutil . UserError { Err : "requested version for signing is higher than the latest key version" }
case p . MinEncryptionVersion > 0 && ver < p . MinEncryptionVersion :
return nil , errutil . UserError { Err : "requested version for signing is less than the minimum encryption key version" }
}
2016-09-21 14:29:42 +00:00
var sig [ ] byte
2017-06-05 19:00:39 +00:00
var pubKey [ ] byte
var err error
2016-09-21 14:29:42 +00:00
switch p . Type {
2016-10-26 23:52:31 +00:00
case KeyType_ECDSA_P256 :
2017-12-06 23:24:00 +00:00
keyParams := p . Keys [ strconv . Itoa ( ver ) ]
2016-09-21 14:29:42 +00:00
key := & ecdsa . PrivateKey {
PublicKey : ecdsa . PublicKey {
Curve : elliptic . P256 ( ) ,
X : keyParams . EC_X ,
Y : keyParams . EC_Y ,
} ,
D : keyParams . EC_D ,
}
2017-06-05 19:00:39 +00:00
r , s , err := ecdsa . Sign ( rand . Reader , key , input )
2016-09-21 14:29:42 +00:00
if err != nil {
2017-06-05 19:00:39 +00:00
return nil , err
2016-09-21 14:29:42 +00:00
}
marshaledSig , err := asn1 . Marshal ( ecdsaSignature {
R : r ,
S : s ,
} )
if err != nil {
2017-06-05 19:00:39 +00:00
return nil , err
2016-09-21 14:29:42 +00:00
}
sig = marshaledSig
2017-06-05 19:00:39 +00:00
case KeyType_ED25519 :
var key ed25519 . PrivateKey
if p . Derived {
// Derive the key that should be used
var err error
2017-06-06 20:02:54 +00:00
key , err = p . DeriveKey ( context , ver )
2017-06-05 19:00:39 +00:00
if err != nil {
return nil , errutil . InternalError { Err : fmt . Sprintf ( "error deriving key: %v" , err ) }
}
pubKey = key . Public ( ) . ( ed25519 . PublicKey )
} else {
2017-12-06 23:24:00 +00:00
key = ed25519 . PrivateKey ( p . Keys [ strconv . Itoa ( ver ) ] . Key )
2017-06-05 19:00:39 +00:00
}
// Per docs, do not pre-hash ed25519; it does two passes and performs
// its own hashing
sig , err = key . Sign ( rand . Reader , input , crypto . Hash ( 0 ) )
if err != nil {
return nil , err
}
2017-11-03 14:45:53 +00:00
case KeyType_RSA2048 , KeyType_RSA4096 :
2017-12-06 23:24:00 +00:00
key := p . Keys [ strconv . Itoa ( ver ) ] . RSAKey
2017-11-03 14:45:53 +00:00
var algo crypto . Hash
2018-03-15 16:17:02 +00:00
switch hashAlgorithm {
2017-11-03 14:45:53 +00:00
case "sha2-224" :
algo = crypto . SHA224
case "sha2-256" :
algo = crypto . SHA256
case "sha2-384" :
algo = crypto . SHA384
case "sha2-512" :
algo = crypto . SHA512
default :
2018-03-15 16:17:02 +00:00
return nil , errutil . InternalError { Err : fmt . Sprintf ( "unsupported hash algorithm %s" , hashAlgorithm ) }
2017-11-03 14:45:53 +00:00
}
2018-03-15 16:17:02 +00:00
if sigAlgorithm == "" {
sigAlgorithm = "pss"
}
switch sigAlgorithm {
case "pss" :
sig , err = rsa . SignPSS ( rand . Reader , key , algo , input , nil )
if err != nil {
return nil , err
}
case "pkcs1v15" :
sig , err = rsa . SignPKCS1v15 ( rand . Reader , key , algo , input )
if err != nil {
return nil , err
}
default :
return nil , errutil . InternalError { Err : fmt . Sprintf ( "unsupported rsa signature algorithm %s" , sigAlgorithm ) }
2017-11-03 14:45:53 +00:00
}
2016-09-21 14:29:42 +00:00
default :
2017-06-05 19:00:39 +00:00
return nil , fmt . Errorf ( "unsupported key type %v" , p . Type )
2016-09-21 14:29:42 +00:00
}
// Convert to base64
encoded := base64 . StdEncoding . EncodeToString ( sig )
2017-06-05 19:00:39 +00:00
res := & SigningResult {
2018-03-09 01:58:50 +00:00
Signature : p . getVersionPrefix ( ver ) + encoded ,
2017-06-05 19:00:39 +00:00
PublicKey : pubKey ,
}
2016-09-21 14:29:42 +00:00
2017-06-05 19:00:39 +00:00
return res , nil
2016-09-21 14:29:42 +00:00
}
2018-03-15 16:17:02 +00:00
func ( p * Policy ) VerifySignature ( context , input [ ] byte , sig , hashAlgorithm string , sigAlgorithm string ) ( bool , error ) {
2016-09-21 14:29:42 +00:00
if ! p . Type . SigningSupported ( ) {
return false , errutil . UserError { Err : fmt . Sprintf ( "message verification not supported for key type %v" , p . Type ) }
}
2018-03-09 01:58:50 +00:00
tplParts , err := p . getTemplateParts ( )
if err != nil {
return false , err
}
2016-09-21 14:29:42 +00:00
// Verify the prefix
2018-03-09 01:58:50 +00:00
if ! strings . HasPrefix ( sig , tplParts [ 0 ] ) {
2016-09-21 14:29:42 +00:00
return false , errutil . UserError { Err : "invalid signature: no prefix" }
}
2018-03-09 01:58:50 +00:00
splitVerSig := strings . SplitN ( strings . TrimPrefix ( sig , tplParts [ 0 ] ) , tplParts [ 1 ] , 2 )
2016-09-21 14:29:42 +00:00
if len ( splitVerSig ) != 2 {
return false , errutil . UserError { Err : "invalid signature: wrong number of fields" }
}
ver , err := strconv . Atoi ( splitVerSig [ 0 ] )
if err != nil {
return false , errutil . UserError { Err : "invalid signature: version number could not be decoded" }
}
if ver > p . LatestVersion {
return false , errutil . UserError { Err : "invalid signature: version is too new" }
}
if p . MinDecryptionVersion > 0 && ver < p . MinDecryptionVersion {
return false , errutil . UserError { Err : ErrTooOld }
}
2017-06-05 19:00:39 +00:00
sigBytes , err := base64 . StdEncoding . DecodeString ( splitVerSig [ 1 ] )
if err != nil {
return false , errutil . UserError { Err : "invalid base64 signature value" }
}
2016-09-21 14:29:42 +00:00
switch p . Type {
2016-10-26 23:52:31 +00:00
case KeyType_ECDSA_P256 :
2016-09-21 14:29:42 +00:00
var ecdsaSig ecdsaSignature
2017-06-05 19:00:39 +00:00
rest , err := asn1 . Unmarshal ( sigBytes , & ecdsaSig )
2016-09-21 14:29:42 +00:00
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" }
}
2017-12-06 23:24:00 +00:00
keyParams := p . Keys [ strconv . Itoa ( ver ) ]
2016-09-21 14:29:42 +00:00
key := & ecdsa . PublicKey {
Curve : elliptic . P256 ( ) ,
X : keyParams . EC_X ,
Y : keyParams . EC_Y ,
}
2017-06-05 19:00:39 +00:00
return ecdsa . Verify ( key , input , ecdsaSig . R , ecdsaSig . S ) , nil
case KeyType_ED25519 :
var key ed25519 . PrivateKey
if p . Derived {
// Derive the key that should be used
var err error
key , err = p . DeriveKey ( context , ver )
if err != nil {
return false , errutil . InternalError { Err : fmt . Sprintf ( "error deriving key: %v" , err ) }
}
} else {
2017-12-06 23:24:00 +00:00
key = ed25519 . PrivateKey ( p . Keys [ strconv . Itoa ( ver ) ] . Key )
2017-06-05 19:00:39 +00:00
}
return ed25519 . Verify ( key . Public ( ) . ( ed25519 . PublicKey ) , input , sigBytes ) , nil
2017-11-03 14:45:53 +00:00
case KeyType_RSA2048 , KeyType_RSA4096 :
2017-12-06 23:24:00 +00:00
key := p . Keys [ strconv . Itoa ( ver ) ] . RSAKey
2017-11-03 14:45:53 +00:00
var algo crypto . Hash
2018-03-15 16:17:02 +00:00
switch hashAlgorithm {
2017-11-03 14:45:53 +00:00
case "sha2-224" :
algo = crypto . SHA224
case "sha2-256" :
algo = crypto . SHA256
case "sha2-384" :
algo = crypto . SHA384
case "sha2-512" :
algo = crypto . SHA512
default :
2018-03-15 16:17:02 +00:00
return false , errutil . InternalError { Err : fmt . Sprintf ( "unsupported hash algorithm %s" , hashAlgorithm ) }
}
if sigAlgorithm == "" {
sigAlgorithm = "pss"
2017-11-03 14:45:53 +00:00
}
2018-03-15 16:17:02 +00:00
switch sigAlgorithm {
case "pss" :
err = rsa . VerifyPSS ( & key . PublicKey , algo , input , sigBytes , nil )
case "pkcs1v15" :
err = rsa . VerifyPKCS1v15 ( & key . PublicKey , algo , input , sigBytes )
default :
return false , errutil . InternalError { Err : fmt . Sprintf ( "unsupported rsa signature algorithm %s" , sigAlgorithm ) }
}
2017-11-03 14:45:53 +00:00
return err == nil , nil
2016-09-21 14:29:42 +00:00
default :
return false , errutil . InternalError { Err : fmt . Sprintf ( "unsupported key type %v" , p . Type ) }
}
}
2018-02-12 22:27:28 +00:00
func ( p * Policy ) Rotate ( ctx context . Context , storage logical . Storage ) ( retErr error ) {
priorLatestVersion := p . LatestVersion
priorMinDecryptionVersion := p . MinDecryptionVersion
var priorKeys keyEntryMap
if p . Keys != nil {
priorKeys = keyEntryMap { }
for k , v := range p . Keys {
priorKeys [ k ] = v
}
}
defer func ( ) {
if retErr != nil {
p . LatestVersion = priorLatestVersion
p . MinDecryptionVersion = priorMinDecryptionVersion
p . Keys = priorKeys
}
} ( )
2015-09-14 20:28:46 +00:00
if p . Keys == nil {
2016-01-27 01:21:58 +00:00
// This is an initial key rotation when generating a new policy. We
// don't need to call migrate here because if we've called getPolicy to
// get the policy in the first place it will have been run.
2016-09-01 15:57:28 +00:00
p . Keys = keyEntryMap { }
2015-09-14 20:28:46 +00:00
}
2016-09-21 14:29:42 +00:00
p . LatestVersion += 1
2017-06-05 19:00:39 +00:00
now := time . Now ( )
2016-10-26 23:52:31 +00:00
entry := KeyEntry {
2017-06-05 19:00:39 +00:00
CreationTime : now ,
DeprecatedCreationTime : now . Unix ( ) ,
2016-09-21 14:29:42 +00:00
}
hmacKey , err := uuid . GenerateRandomBytes ( 32 )
2015-09-14 20:28:46 +00:00
if err != nil {
return err
}
2016-09-21 14:29:42 +00:00
entry . HMACKey = hmacKey
2016-01-15 19:02:51 +00:00
2016-09-21 14:29:42 +00:00
switch p . Type {
2018-02-14 16:59:46 +00:00
case KeyType_AES256_GCM96 , KeyType_ChaCha20_Poly1305 :
2016-09-21 14:29:42 +00:00
// Generate a 256bit key
newKey , err := uuid . GenerateRandomBytes ( 32 )
if err != nil {
return err
}
2017-06-05 19:00:39 +00:00
entry . Key = newKey
2016-01-15 19:02:51 +00:00
2016-10-26 23:52:31 +00:00
case KeyType_ECDSA_P256 :
2016-09-21 14:29:42 +00:00
privKey , err := ecdsa . GenerateKey ( elliptic . P256 ( ) , rand . Reader )
if err != nil {
return err
}
entry . EC_D = privKey . D
entry . EC_X = privKey . X
entry . EC_Y = privKey . Y
derBytes , err := x509 . MarshalPKIXPublicKey ( privKey . Public ( ) )
if err != nil {
return fmt . Errorf ( "error marshaling public key: %s" , err )
}
pemBlock := & pem . Block {
Type : "PUBLIC KEY" ,
Bytes : derBytes ,
}
pemBytes := pem . EncodeToMemory ( pemBlock )
if pemBytes == nil || len ( pemBytes ) == 0 {
return fmt . Errorf ( "error PEM-encoding public key" )
}
entry . FormattedPublicKey = string ( pemBytes )
2017-06-05 19:00:39 +00:00
case KeyType_ED25519 :
pub , pri , err := ed25519 . GenerateKey ( rand . Reader )
if err != nil {
return err
}
entry . Key = pri
entry . FormattedPublicKey = base64 . StdEncoding . EncodeToString ( pub )
2017-11-03 14:45:53 +00:00
case KeyType_RSA2048 , KeyType_RSA4096 :
bitSize := 2048
if p . Type == KeyType_RSA4096 {
bitSize = 4096
}
entry . RSAKey , err = rsa . GenerateKey ( rand . Reader , bitSize )
if err != nil {
return err
}
2015-09-14 20:28:46 +00:00
}
2017-12-06 23:24:00 +00:00
p . Keys [ strconv . Itoa ( p . LatestVersion ) ] = entry
2016-09-21 14:29:42 +00:00
2016-01-22 19:10:09 +00:00
// This ensures that with new key creations min decryption version is set
// to 1 rather than the int default of 0, since keys start at 1 (either
// fresh or after migration to the key map)
if p . MinDecryptionVersion == 0 {
p . MinDecryptionVersion = 1
}
2018-01-19 06:44:44 +00:00
return p . Persist ( ctx , storage )
2015-09-14 20:28:46 +00:00
}
2016-10-26 23:52:31 +00:00
func ( p * Policy ) MigrateKeyToKeysMap ( ) {
2017-06-05 19:00:39 +00:00
now := time . Now ( )
2016-09-01 15:57:28 +00:00
p . Keys = keyEntryMap {
2017-12-06 23:24:00 +00:00
"1" : KeyEntry {
2017-06-05 19:00:39 +00:00
Key : p . Key ,
CreationTime : now ,
DeprecatedCreationTime : now . Unix ( ) ,
2015-09-14 20:28:46 +00:00
} ,
}
p . Key = nil
}
2017-12-14 17:51:50 +00:00
// Backup should be called with an exclusive lock held on the policy
2018-02-12 22:27:28 +00:00
func ( p * Policy ) Backup ( ctx context . Context , storage logical . Storage ) ( out string , retErr error ) {
2017-12-14 17:51:50 +00:00
if ! p . Exportable {
return "" , fmt . Errorf ( "exporting is disallowed on the policy" )
}
if ! p . AllowPlaintextBackup {
return "" , fmt . Errorf ( "plaintext backup is disallowed on the policy" )
}
2018-02-12 22:27:28 +00:00
priorBackupInfo := p . BackupInfo
defer func ( ) {
if retErr != nil {
p . BackupInfo = priorBackupInfo
}
} ( )
2017-12-14 17:51:50 +00:00
// Create a record of this backup operation in the policy
p . BackupInfo = & BackupInfo {
Time : time . Now ( ) ,
Version : p . LatestVersion ,
}
2018-01-19 06:44:44 +00:00
err := p . Persist ( ctx , storage )
2017-12-14 17:51:50 +00:00
if err != nil {
return "" , fmt . Errorf ( "failed to persist policy with backup info: %v" , err )
}
// Load the archive only after persisting the policy as the archive can get
// adjusted while persisting the policy
2018-01-19 06:44:44 +00:00
archivedKeys , err := p . LoadArchive ( ctx , storage )
2017-12-14 17:51:50 +00:00
if err != nil {
return "" , err
}
keyData := & KeyData {
Policy : p ,
ArchivedKeys : archivedKeys ,
}
encodedBackup , err := jsonutil . EncodeJSON ( keyData )
if err != nil {
return "" , err
}
return base64 . StdEncoding . EncodeToString ( encodedBackup ) , nil
}
2018-03-09 01:58:50 +00:00
func ( p * Policy ) getTemplateParts ( ) ( [ ] string , error ) {
partsRaw , ok := p . versionPrefixCache . Load ( "template-parts" )
if ok {
return partsRaw . ( [ ] string ) , nil
}
template := p . VersionTemplate
if template == "" {
template = DefaultVersionTemplate
}
tplParts := strings . Split ( template , "{{version}}" )
if len ( tplParts ) != 2 {
return nil , errutil . InternalError { Err : "error parsing version template" }
}
p . versionPrefixCache . Store ( "template-parts" , tplParts )
return tplParts , nil
}
func ( p * Policy ) getVersionPrefix ( ver int ) string {
prefixRaw , ok := p . versionPrefixCache . Load ( ver )
if ok {
return prefixRaw . ( string )
}
template := p . VersionTemplate
if template == "" {
template = DefaultVersionTemplate
}
prefix := strings . Replace ( template , "{{version}}" , strconv . Itoa ( ver ) , - 1 )
p . versionPrefixCache . Store ( ver , prefix )
return prefix
}