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"
2018-06-12 16:24:12 +00:00
"errors"
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"
2018-06-12 16:24:12 +00:00
"sync/atomic"
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"
2018-04-05 15:49:21 +00:00
"github.com/hashicorp/errwrap"
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" `
2018-06-05 22:51:35 +00:00
// If convergent is enabled, the version (falling back to what's in the
// policy)
ConvergentVersion int ` json:"convergent_version" `
2017-06-05 19:00:39 +00:00
// 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
2018-06-05 22:51:35 +00:00
// never used.
2018-03-09 05:06:25 +00:00
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 {
return & Policy {
2018-06-12 16:24:12 +00:00
l : new ( sync . RWMutex ) ,
2018-03-09 05:06:25 +00:00
Name : config . Name ,
Type : config . Type ,
Derived : config . Derived ,
KDF : config . KDF ,
ConvergentEncryption : config . ConvergentEncryption ,
2018-06-05 22:51:35 +00:00
ConvergentVersion : - 1 ,
2018-03-09 05:06:25 +00:00
Exportable : config . Exportable ,
DeletionAllowed : config . DeletionAllowed ,
AllowPlaintextBackup : config . AllowPlaintextBackup ,
VersionTemplate : config . VersionTemplate ,
StoragePrefix : config . StoragePrefix ,
}
}
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
}
2018-06-12 16:24:12 +00:00
policy . l = new ( sync . RWMutex )
2018-03-09 19:01:24 +00:00
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 {
2018-06-12 16:24:12 +00:00
// This is a pointer on purpose: if we are running with cache disabled we
// need to actually swap in the lock manager's lock for this policy with
// the local lock.
l * sync . RWMutex
// writeLocked allows us to implement Lock() and Unlock()
writeLocked bool
// Stores whether it's been deleted. This acts as a guard for operations
// that may write data, e.g. if one request rotates and that request is
// served after a delete.
deleted uint32
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" `
2018-10-17 16:05:05 +00:00
// ArchiveMinVersion is the minimum version of the key in the archive.
ArchiveMinVersion int ` json:"archive_min_version" `
// MinAvailableVersion is the minimum version of the key present. All key
// versions before this would have been deleted.
MinAvailableVersion int ` json:"min_available_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
2018-06-12 16:24:12 +00:00
// versionPrefixCache stores caches of version prefix strings and the split
2018-03-09 01:58:50 +00:00
// version template.
2018-06-12 16:24:12 +00:00
versionPrefixCache sync . Map
}
func ( p * Policy ) Lock ( exclusive bool ) {
if exclusive {
p . l . Lock ( )
p . writeLocked = true
} else {
p . l . RLock ( )
}
}
func ( p * Policy ) Unlock ( ) {
if p . writeLocked {
p . writeLocked = false
p . l . Unlock ( )
} else {
p . l . RUnlock ( )
}
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 ++ {
2018-10-17 16:05:05 +00:00
p . Keys [ strconv . Itoa ( i ) ] = archive . Keys [ i - p . MinAvailableVersion ]
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
2018-10-17 16:05:05 +00:00
if len ( archive . Keys ) + p . MinAvailableVersion < p . LatestVersion + 1 {
2016-01-27 01:21:58 +00:00
// Increase the size of the archive slice
2018-10-17 16:05:05 +00:00
newKeys := make ( [ ] KeyEntry , p . LatestVersion - p . MinAvailableVersion + 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 ++ {
2018-10-17 16:05:05 +00:00
archive . Keys [ i - p . MinAvailableVersion ] = p . Keys [ strconv . Itoa ( i ) ]
2016-01-27 01:21:58 +00:00
p . ArchiveVersion = i
}
2018-10-17 16:05:05 +00:00
// Trim the keys if required
if p . ArchiveMinVersion < p . MinAvailableVersion {
archive . Keys = archive . Keys [ p . MinAvailableVersion - p . ArchiveMinVersion : ]
p . ArchiveMinVersion = p . MinAvailableVersion
}
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 ) {
2018-06-12 16:24:12 +00:00
if atomic . LoadUint32 ( & p . deleted ) == 1 {
return errors . New ( "key has been deleted, not persisting" )
}
2018-02-12 22:27:28 +00:00
// 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
}
2018-06-05 22:51:35 +00:00
// Need to write the version if zero; for version 3 on we set this to -1 to
// ignore it since we store this information in each key entry
2016-08-26 18:11:03 +00:00
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.
2018-06-05 22:51:35 +00:00
func ( p * Policy ) DeriveKey ( context [ ] byte , ver , numBytes int ) ( [ ] byte , error ) {
// Fast-path non-derived keys
if ! p . Derived {
return p . Keys [ strconv . Itoa ( ver ) ] . Key , nil
}
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
}
// 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 )
2018-06-05 22:51:35 +00:00
derBytes . Grow ( numBytes )
2016-08-30 20:29:09 +00:00
limReader := & io . LimitedReader {
R : reader ,
2018-06-05 22:51:35 +00:00
N : int64 ( numBytes ) ,
2016-08-30 20:29:09 +00:00
}
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 ) }
}
2018-06-05 22:51:35 +00:00
if n != int64 ( numBytes ) {
return nil , errutil . InternalError { Err : fmt . Sprintf ( "unable to read enough derived bytes, needed %d, got %d" , numBytes , n ) }
2017-06-05 19:00:39 +00:00
}
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
}
}
2018-06-05 22:51:35 +00:00
func ( p * Policy ) convergentVersion ( ver int ) int {
if ! p . ConvergentEncryption {
return 0
}
convergentVersion := p . ConvergentVersion
if convergentVersion == 0 {
// For some reason, not upgraded yet
convergentVersion = 1
}
currKey := p . Keys [ strconv . Itoa ( ver ) ]
if currKey . ConvergentVersion != 0 {
convergentVersion = currKey . ConvergentVersion
}
return convergentVersion
}
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 :
2018-06-05 22:51:35 +00:00
hmacKey := context
var aead cipher . AEAD
var encKey [ ] byte
var deriveHMAC bool
numBytes := 32
if p . convergentVersion ( ver ) > 2 {
deriveHMAC = true
numBytes = 64
}
key , err := p . DeriveKey ( context , ver , numBytes )
2017-11-03 14:45:53 +00:00
if err != nil {
return "" , err
}
2015-09-14 20:28:46 +00:00
2018-06-05 22:51:35 +00:00
if len ( key ) < numBytes {
return "" , errutil . InternalError { Err : "could not derive key, length too small" }
}
encKey = key [ : 32 ]
if len ( encKey ) != 32 {
return "" , errutil . InternalError { Err : "could not derive enc key, length not correct" }
}
if deriveHMAC {
hmacKey = key [ 32 : ]
if len ( hmacKey ) != 32 {
return "" , errutil . InternalError { Err : "could not derive hmac key, length not correct" }
}
}
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
2018-06-05 22:51:35 +00:00
aesCipher , err := aes . NewCipher ( encKey )
2018-02-14 16:59:46 +00:00
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 :
2018-06-05 22:51:35 +00:00
cha , err := chacha20poly1305 . New ( encKey )
2018-02-14 16:59:46 +00:00
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 {
2018-06-05 22:51:35 +00:00
convergentVersion := p . convergentVersion ( ver )
switch convergentVersion {
2017-11-03 14:45:53 +00:00
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
}
2018-06-05 22:51:35 +00:00
case 2 , 3 :
if len ( hmacKey ) == 0 {
return "" , errutil . InternalError { Err : fmt . Sprintf ( "invalid hmac key length of zero" ) }
}
nonceHmac := hmac . New ( sha256 . New , hmacKey )
2017-11-03 14:45:53 +00:00
nonceHmac . Write ( plaintext )
nonceSum := nonceHmac . Sum ( nil )
2018-02-14 16:59:46 +00:00
nonce = nonceSum [ : aead . NonceSize ( ) ]
2018-06-05 22:51:35 +00:00
default :
return "" , errutil . InternalError { Err : fmt . Sprintf ( "unhandled convergent version %d" , convergentVersion ) }
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
2018-06-05 22:51:35 +00:00
if ! p . ConvergentEncryption || p . convergentVersion ( ver ) > 1 {
2017-11-03 14:45:53 +00:00
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
}
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
}
2018-06-05 22:51:35 +00:00
convergentVersion := p . convergentVersion ( ver )
if convergentVersion == 1 && ( nonce == nil || len ( nonce ) == 0 ) {
return "" , errutil . UserError { Err : "invalid convergent nonce supplied" }
}
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 :
2018-06-05 22:51:35 +00:00
var aead cipher . AEAD
encKey , err := p . DeriveKey ( context , ver , 32 )
2017-11-03 14:45:53 +00:00
if err != nil {
return "" , err
}
2015-09-14 20:28:46 +00:00
2018-06-05 22:51:35 +00:00
if len ( encKey ) != 32 {
return "" , errutil . InternalError { Err : "could not derive enc key, length not correct" }
}
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
2018-06-05 22:51:35 +00:00
aesCipher , err := aes . NewCipher ( encKey )
2018-02-14 16:59:46 +00:00
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 :
2018-06-05 22:51:35 +00:00
cha , err := chacha20poly1305 . New ( encKey )
2018-02-14 16:59:46 +00:00
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
2018-06-05 22:51:35 +00:00
if p . ConvergentEncryption && convergentVersion == 1 {
2017-11-03 14:45:53 +00:00
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
2018-06-05 22:51:35 +00:00
key , err = p . DeriveKey ( context , ver , 32 )
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
2018-06-05 22:51:35 +00:00
key , err = p . DeriveKey ( context , ver , 32 )
2017-06-05 19:00:39 +00:00
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 {
2018-04-05 15:49:21 +00:00
return errwrap . Wrapf ( "error marshaling public key: {{err}}" , err )
2016-09-21 14:29:42 +00:00
}
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
}
2018-06-05 22:51:35 +00:00
if p . ConvergentEncryption {
if p . ConvergentVersion == - 1 || p . ConvergentVersion > 1 {
entry . ConvergentVersion = currentConvergentVersion
}
}
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 {
2018-04-05 15:49:21 +00:00
return "" , errwrap . Wrapf ( "failed to persist policy with backup info: {{err}}" , err )
2017-12-14 17:51:50 +00:00
}
// 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
}