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"
2019-04-12 21:54:35 +00:00
"github.com/hashicorp/vault/sdk/helper/errutil"
"github.com/hashicorp/vault/sdk/helper/jsonutil"
"github.com/hashicorp/vault/sdk/helper/kdf"
"github.com/hashicorp/vault/sdk/logical"
2015-09-14 20:28:46 +00:00
)
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
2019-10-03 16:32:43 +00:00
KeyType_ECDSA_P384
KeyType_ECDSA_P521
2019-10-03 20:11:43 +00:00
KeyType_AES128_GCM96
2020-02-15 22:40:50 +00:00
KeyType_RSA3072
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 {
2020-02-15 22:40:50 +00:00
case KeyType_AES128_GCM96 , KeyType_AES256_GCM96 , KeyType_ChaCha20_Poly1305 , KeyType_RSA2048 , KeyType_RSA3072 , KeyType_RSA4096 :
2016-09-21 14:29:42 +00:00
return true
}
return false
}
func ( kt KeyType ) DecryptionSupported ( ) bool {
switch kt {
2020-02-15 22:40:50 +00:00
case KeyType_AES128_GCM96 , KeyType_AES256_GCM96 , KeyType_ChaCha20_Poly1305 , KeyType_RSA2048 , KeyType_RSA3072 , 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 {
2020-02-15 22:40:50 +00:00
case KeyType_ECDSA_P256 , KeyType_ECDSA_P384 , KeyType_ECDSA_P521 , KeyType_ED25519 , KeyType_RSA2048 , KeyType_RSA3072 , 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 {
2020-02-15 22:40:50 +00:00
case KeyType_ECDSA_P256 , KeyType_ECDSA_P384 , KeyType_ECDSA_P521 , KeyType_RSA2048 , KeyType_RSA3072 , KeyType_RSA4096 :
2016-09-21 14:29:42 +00:00
return true
}
return false
}
func ( kt KeyType ) DerivationSupported ( ) bool {
switch kt {
2019-10-03 20:11:43 +00:00
case KeyType_AES128_GCM96 , 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 {
2019-10-03 20:11:43 +00:00
case KeyType_AES128_GCM96 :
return "aes128-gcm96"
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"
2019-10-03 16:32:43 +00:00
case KeyType_ECDSA_P384 :
return "ecdsa-p384"
case KeyType_ECDSA_P521 :
return "ecdsa-p521"
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"
2020-02-15 22:40:50 +00:00
case KeyType_RSA3072 :
return "rsa-3072"
2017-11-03 14:45:53 +00:00
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" `
2021-04-08 16:43:39 +00:00
Key [ ] byte ` json:"key,omitempty" ` // DEPRECATED
2016-09-21 14:29:42 +00:00
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
2022-02-17 20:17:59 +00:00
// AutoRotatePeriod defines how frequently the key should automatically
2022-01-20 15:10:15 +00:00
// rotate. Setting this to zero disables automatic rotation for the key.
2022-02-17 20:17:59 +00:00
AutoRotatePeriod time . Duration ` json:"auto_rotate_period" `
2022-01-20 15:10:15 +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
2022-05-16 16:50:38 +00:00
// Imported indicates whether the key was generated by Vault or imported
// from an external source
Imported bool
// AllowImportedKeyRotation indicates whether an imported key may be rotated by Vault
AllowImportedKeyRotation bool
2018-06-12 16:24:12 +00:00
}
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
}
2019-10-17 17:33:00 +00:00
func ( p * Policy ) Upgrade ( ctx context . Context , storage logical . Storage , randReader io . Reader ) ( retErr error ) {
2018-02-12 22:27:28 +00:00
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 ) ]
2019-10-17 17:33:00 +00:00
hmacKey , err := uuid . GenerateRandomBytesWithReader ( 32 , randReader )
2016-09-21 15:10:57 +00:00
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
}
2020-10-02 02:04:36 +00:00
// GetKey is used to derive the encryption key that should be used depending
2016-08-30 20:29:09 +00:00
// 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.
2020-10-02 02:04:36 +00:00
func ( p * Policy ) GetKey ( context [ ] byte , ver , numBytes int ) ( [ ] byte , error ) {
2018-06-05 22:51:35 +00:00
// Fast-path non-derived keys
if ! p . Derived {
2020-10-07 13:21:31 +00:00
keyEntry , err := p . safeGetKeyEntry ( ver )
if err != nil {
return nil , err
}
return keyEntry . Key , nil
2018-06-05 22:51:35 +00:00
}
2020-10-02 02:04:36 +00:00
return p . DeriveKey ( context , nil , ver , numBytes )
}
// DeriveKey is used to derive a symmetric key given a context and salt. This does not
// check the policies Derived flag, but just implements the derivation logic. GetKey
// is responsible for switching on the policy config.
func ( p * Policy ) DeriveKey ( context , salt [ ] byte , ver int , numBytes 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
}
// 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
}
2020-10-07 13:21:31 +00:00
keyEntry , err := p . safeGetKeyEntry ( ver )
if err != nil {
return nil , err
}
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
2020-10-07 13:21:31 +00:00
return kdf . CounterMode ( prf , prfLen , keyEntry . Key , append ( context , salt ... ) , 256 )
2017-06-05 19:00:39 +00:00
2016-10-26 23:52:31 +00:00
case Kdf_hkdf_sha256 :
2020-10-07 13:21:31 +00:00
reader := hkdf . New ( sha256 . New , keyEntry . Key , salt , 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 {
2019-10-03 20:11:43 +00:00
case KeyType_AES128_GCM96 , 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
}
}
2020-10-07 13:21:31 +00:00
func ( p * Policy ) safeGetKeyEntry ( ver int ) ( KeyEntry , error ) {
keyVerStr := strconv . Itoa ( ver )
keyEntry , ok := p . Keys [ keyVerStr ]
if ! ok {
return keyEntry , errutil . UserError { Err : "no such key version" }
}
return keyEntry , nil
}
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 {
2019-10-03 20:11:43 +00:00
case KeyType_AES128_GCM96 , KeyType_AES256_GCM96 , KeyType_ChaCha20_Poly1305 :
2018-06-05 22:51:35 +00:00
hmacKey := context
var encKey [ ] byte
var deriveHMAC bool
2019-10-03 20:11:43 +00:00
encBytes := 32
hmacBytes := 0
2018-06-05 22:51:35 +00:00
if p . convergentVersion ( ver ) > 2 {
deriveHMAC = true
2019-10-03 20:11:43 +00:00
hmacBytes = 32
}
if p . Type == KeyType_AES128_GCM96 {
encBytes = 16
2018-06-05 22:51:35 +00:00
}
2019-10-03 20:11:43 +00:00
2020-10-02 02:04:36 +00:00
key , err := p . GetKey ( context , ver , encBytes + hmacBytes )
2017-11-03 14:45:53 +00:00
if err != nil {
return "" , err
}
2015-09-14 20:28:46 +00:00
2019-10-03 20:11:43 +00:00
if len ( key ) < encBytes + hmacBytes {
2018-06-05 22:51:35 +00:00
return "" , errutil . InternalError { Err : "could not derive key, length too small" }
}
2019-10-03 20:11:43 +00:00
encKey = key [ : encBytes ]
if len ( encKey ) != encBytes {
2018-06-05 22:51:35 +00:00
return "" , errutil . InternalError { Err : "could not derive enc key, length not correct" }
}
if deriveHMAC {
2019-10-03 20:11:43 +00:00
hmacKey = key [ encBytes : ]
if len ( hmacKey ) != hmacBytes {
2018-06-05 22:51:35 +00:00
return "" , errutil . InternalError { Err : "could not derive hmac key, length not correct" }
}
}
2015-09-14 20:28:46 +00:00
2020-10-02 02:04:36 +00:00
ciphertext , err = p . SymmetricEncryptRaw ( ver , encKey , plaintext ,
SymmetricOpts {
Convergent : p . ConvergentEncryption ,
HMACKey : hmacKey ,
Nonce : nonce ,
} )
2017-11-03 14:45:53 +00:00
2020-10-02 02:04:36 +00:00
if err != nil {
return "" , err
2017-11-03 14:45:53 +00:00
}
2020-02-15 22:40:50 +00:00
case KeyType_RSA2048 , KeyType_RSA3072 , KeyType_RSA4096 :
2020-10-07 13:21:31 +00:00
keyEntry , err := p . safeGetKeyEntry ( ver )
if err != nil {
return "" , err
}
key := keyEntry . 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 {
2019-10-03 20:11:43 +00:00
case KeyType_AES128_GCM96 , KeyType_AES256_GCM96 , KeyType_ChaCha20_Poly1305 :
numBytes := 32
if p . Type == KeyType_AES128_GCM96 {
numBytes = 16
}
2020-10-02 02:04:36 +00:00
encKey , err := p . GetKey ( context , ver , numBytes )
2017-11-03 14:45:53 +00:00
if err != nil {
return "" , err
}
2015-09-14 20:28:46 +00:00
2019-10-03 20:11:43 +00:00
if len ( encKey ) != numBytes {
2018-06-05 22:51:35 +00:00
return "" , errutil . InternalError { Err : "could not derive enc key, length not correct" }
}
2015-09-14 20:28:46 +00:00
2020-10-02 02:04:36 +00:00
plain , err = p . SymmetricDecryptRaw ( encKey , decoded ,
SymmetricOpts {
Convergent : p . ConvergentEncryption ,
ConvergentVersion : p . ConvergentVersion ,
} )
2017-11-03 14:45:53 +00:00
if err != nil {
2020-10-02 02:04:36 +00:00
return "" , err
2017-11-03 14:45:53 +00:00
}
2020-02-15 22:40:50 +00:00
case KeyType_RSA2048 , KeyType_RSA3072 , KeyType_RSA4096 :
2020-10-07 13:21:31 +00:00
keyEntry , err := p . safeGetKeyEntry ( ver )
if err != nil {
return "" , err
}
key := keyEntry . 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 )
}
2020-10-07 13:21:31 +00:00
keyEntry , err := p . safeGetKeyEntry ( version )
if err != nil {
return nil , err
}
if keyEntry . HMACKey == nil {
2016-09-21 14:29:42 +00:00
return nil , fmt . Errorf ( "no HMAC key exists for that key version" )
}
2020-10-07 13:21:31 +00:00
return keyEntry . HMACKey , nil
2016-09-21 14:29:42 +00:00
}
2019-01-23 17:31:34 +00:00
func ( p * Policy ) Sign ( ver int , context , input [ ] byte , hashAlgorithm HashType , sigAlgorithm string , marshaling MarshalingType ) ( * 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
2020-10-07 13:21:31 +00:00
keyParams , err := p . safeGetKeyEntry ( ver )
if err != nil {
return nil , err
}
2016-09-21 14:29:42 +00:00
switch p . Type {
2019-10-03 16:32:43 +00:00
case KeyType_ECDSA_P256 , KeyType_ECDSA_P384 , KeyType_ECDSA_P521 :
var curveBits int
var curve elliptic . Curve
switch p . Type {
case KeyType_ECDSA_P384 :
curveBits = 384
curve = elliptic . P384 ( )
case KeyType_ECDSA_P521 :
curveBits = 521
curve = elliptic . P521 ( )
default :
curveBits = 256
curve = elliptic . P256 ( )
}
2016-09-21 14:29:42 +00:00
key := & ecdsa . PrivateKey {
PublicKey : ecdsa . PublicKey {
2019-10-03 16:32:43 +00:00
Curve : curve ,
2016-09-21 14:29:42 +00:00
X : keyParams . EC_X ,
Y : keyParams . EC_Y ,
} ,
D : keyParams . EC_D ,
}
2019-01-23 17:31:34 +00:00
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
}
2019-01-23 17:31:34 +00:00
switch marshaling {
case MarshalingTypeASN1 :
// This is used by openssl and X.509
sig , err = asn1 . Marshal ( ecdsaSignature {
R : r ,
S : s ,
} )
if err != nil {
return nil , err
}
case MarshalingTypeJWS :
// This is used by JWS
// First we have to get the length of the curve in bytes. Although
// we only support 256 now, we'll do this in an agnostic way so we
// can reuse this marshaling if we support e.g. 521. Getting the
// number of bytes without rounding up would be 65.125 so we need
// to add one in that case.
keyLen := curveBits / 8
if curveBits % 8 > 0 {
keyLen ++
}
// Now create the output array
sig = make ( [ ] byte , keyLen * 2 )
rb := r . Bytes ( )
sb := s . Bytes ( )
copy ( sig [ keyLen - len ( rb ) : ] , rb )
copy ( sig [ 2 * keyLen - len ( sb ) : ] , sb )
default :
return nil , errutil . UserError { Err : "requested marshaling type is invalid" }
2016-09-21 14:29:42 +00:00
}
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
2020-10-02 02:04:36 +00:00
key , err = p . GetKey ( 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 {
2020-10-07 13:21:31 +00:00
key = ed25519 . PrivateKey ( keyParams . 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
}
2020-02-15 22:40:50 +00:00
case KeyType_RSA2048 , KeyType_RSA3072 , KeyType_RSA4096 :
2020-10-07 13:21:31 +00:00
key := keyParams . RSAKey
2017-11-03 14:45:53 +00:00
var algo crypto . Hash
2018-03-15 16:17:02 +00:00
switch hashAlgorithm {
2019-02-07 23:31:31 +00:00
case HashTypeSHA1 :
algo = crypto . SHA1
2019-01-23 17:31:34 +00:00
case HashTypeSHA2224 :
2017-11-03 14:45:53 +00:00
algo = crypto . SHA224
2019-01-23 17:31:34 +00:00
case HashTypeSHA2256 :
2017-11-03 14:45:53 +00:00
algo = crypto . SHA256
2019-01-23 17:31:34 +00:00
case HashTypeSHA2384 :
2017-11-03 14:45:53 +00:00
algo = crypto . SHA384
2019-01-23 17:31:34 +00:00
case HashTypeSHA2512 :
2017-11-03 14:45:53 +00:00
algo = crypto . SHA512
2021-12-08 18:29:33 +00:00
case HashTypeSHA3224 :
algo = crypto . SHA3_224
case HashTypeSHA3256 :
algo = crypto . SHA3_256
case HashTypeSHA3384 :
algo = crypto . SHA3_384
case HashTypeSHA3512 :
algo = crypto . SHA3_512
2017-11-03 14:45:53 +00:00
default :
2019-01-23 17:31:34 +00:00
return nil , errutil . InternalError { Err : "unsupported hash algorithm" }
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
2019-01-23 17:31:34 +00:00
var encoded string
switch marshaling {
case MarshalingTypeASN1 :
encoded = base64 . StdEncoding . EncodeToString ( sig )
case MarshalingTypeJWS :
encoded = base64 . RawURLEncoding . 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
}
2019-01-23 17:31:34 +00:00
func ( p * Policy ) VerifySignature ( context , input [ ] byte , hashAlgorithm HashType , sigAlgorithm string , marshaling MarshalingType , sig 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 }
}
2019-01-23 17:31:34 +00:00
var sigBytes [ ] byte
switch marshaling {
case MarshalingTypeASN1 :
sigBytes , err = base64 . StdEncoding . DecodeString ( splitVerSig [ 1 ] )
case MarshalingTypeJWS :
sigBytes , err = base64 . RawURLEncoding . DecodeString ( splitVerSig [ 1 ] )
default :
return false , errutil . UserError { Err : "requested marshaling type is invalid" }
}
2017-06-05 19:00:39 +00:00
if err != nil {
return false , errutil . UserError { Err : "invalid base64 signature value" }
}
2016-09-21 14:29:42 +00:00
switch p . Type {
2019-10-03 16:32:43 +00:00
case KeyType_ECDSA_P256 , KeyType_ECDSA_P384 , KeyType_ECDSA_P521 :
var curve elliptic . Curve
switch p . Type {
case KeyType_ECDSA_P384 :
curve = elliptic . P384 ( )
case KeyType_ECDSA_P521 :
curve = elliptic . P521 ( )
default :
curve = elliptic . P256 ( )
}
2016-09-21 14:29:42 +00:00
var ecdsaSig ecdsaSignature
2019-01-23 17:31:34 +00:00
switch marshaling {
case MarshalingTypeASN1 :
rest , err := asn1 . Unmarshal ( sigBytes , & ecdsaSig )
if err != nil {
return false , errutil . UserError { Err : "supplied signature is invalid" }
}
if rest != nil && len ( rest ) != 0 {
return false , errutil . UserError { Err : "supplied signature contains extra data" }
}
case MarshalingTypeJWS :
paramLen := len ( sigBytes ) / 2
rb := sigBytes [ : paramLen ]
sb := sigBytes [ paramLen : ]
ecdsaSig . R = new ( big . Int )
ecdsaSig . R . SetBytes ( rb )
ecdsaSig . S = new ( big . Int )
ecdsaSig . S . SetBytes ( sb )
2016-09-21 14:29:42 +00:00
}
2020-10-07 13:21:31 +00:00
keyParams , err := p . safeGetKeyEntry ( ver )
if err != nil {
return false , err
}
2016-09-21 14:29:42 +00:00
key := & ecdsa . PublicKey {
2019-10-03 16:32:43 +00:00
Curve : curve ,
2016-09-21 14:29:42 +00:00
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
2020-10-02 02:04:36 +00:00
key , err = p . GetKey ( 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
2020-02-15 22:40:50 +00:00
case KeyType_RSA2048 , KeyType_RSA3072 , KeyType_RSA4096 :
2020-10-07 13:21:31 +00:00
keyEntry , err := p . safeGetKeyEntry ( ver )
if err != nil {
return false , err
}
key := keyEntry . RSAKey
2017-11-03 14:45:53 +00:00
var algo crypto . Hash
2018-03-15 16:17:02 +00:00
switch hashAlgorithm {
2019-02-07 23:31:31 +00:00
case HashTypeSHA1 :
algo = crypto . SHA1
2019-01-23 17:31:34 +00:00
case HashTypeSHA2224 :
2017-11-03 14:45:53 +00:00
algo = crypto . SHA224
2019-01-23 17:31:34 +00:00
case HashTypeSHA2256 :
2017-11-03 14:45:53 +00:00
algo = crypto . SHA256
2019-01-23 17:31:34 +00:00
case HashTypeSHA2384 :
2017-11-03 14:45:53 +00:00
algo = crypto . SHA384
2019-01-23 17:31:34 +00:00
case HashTypeSHA2512 :
2017-11-03 14:45:53 +00:00
algo = crypto . SHA512
2021-12-08 18:29:33 +00:00
case HashTypeSHA3224 :
algo = crypto . SHA3_224
case HashTypeSHA3256 :
algo = crypto . SHA3_256
case HashTypeSHA3384 :
algo = crypto . SHA3_384
case HashTypeSHA3512 :
algo = crypto . SHA3_512
2017-11-03 14:45:53 +00:00
default :
2019-01-23 17:31:34 +00:00
return false , errutil . InternalError { Err : "unsupported hash algorithm" }
2018-03-15 16:17:02 +00:00
}
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 ) }
}
}
2022-05-16 16:50:38 +00:00
func ( p * Policy ) Import ( ctx context . Context , storage logical . Storage , key [ ] byte , randReader io . Reader ) error {
now := time . Now ( )
entry := KeyEntry {
CreationTime : now ,
DeprecatedCreationTime : now . Unix ( ) ,
}
hmacKey , err := uuid . GenerateRandomBytesWithReader ( 32 , randReader )
if err != nil {
return err
}
entry . HMACKey = hmacKey
if ( p . Type == KeyType_AES128_GCM96 && len ( key ) != 16 ) ||
( ( p . Type == KeyType_AES256_GCM96 || p . Type == KeyType_ChaCha20_Poly1305 ) && len ( key ) != 32 ) {
return fmt . Errorf ( "invalid key size %d bytes for key type %s" , len ( key ) , p . Type )
}
if p . Type == KeyType_AES128_GCM96 || p . Type == KeyType_AES256_GCM96 || p . Type == KeyType_ChaCha20_Poly1305 {
entry . Key = key
} else {
parsedPrivateKey , err := x509 . ParsePKCS8PrivateKey ( key )
if err != nil {
2022-06-06 22:09:21 +00:00
if strings . Contains ( err . Error ( ) , "unknown elliptic curve" ) {
var edErr error
parsedPrivateKey , edErr = ParsePKCS8Ed25519PrivateKey ( key )
if edErr != nil {
return fmt . Errorf ( "error parsing asymmetric key:\n - assuming contents are an ed25519 private key: %s\n - original error: %v" , edErr , err )
}
// Parsing as Ed25519-in-PKCS8-ECPrivateKey succeeded!
} else {
return fmt . Errorf ( "error parsing asymmetric key: %s" , err )
}
2022-05-16 16:50:38 +00:00
}
switch parsedPrivateKey . ( type ) {
case * ecdsa . PrivateKey :
if p . Type != KeyType_ECDSA_P256 && p . Type != KeyType_ECDSA_P384 && p . Type != KeyType_ECDSA_P521 {
return fmt . Errorf ( "invalid key type: expected %s, got %T" , p . Type , parsedPrivateKey )
}
ecdsaKey := parsedPrivateKey . ( * ecdsa . PrivateKey )
curve := elliptic . P256 ( )
if p . Type == KeyType_ECDSA_P384 {
curve = elliptic . P384 ( )
} else if p . Type == KeyType_ECDSA_P521 {
curve = elliptic . P521 ( )
}
if ecdsaKey . Curve != curve {
return fmt . Errorf ( "invalid curve: expected %s, got %s" , curve . Params ( ) . Name , ecdsaKey . Curve . Params ( ) . Name )
}
entry . EC_D = ecdsaKey . D
entry . EC_X = ecdsaKey . X
entry . EC_Y = ecdsaKey . Y
derBytes , err := x509 . MarshalPKIXPublicKey ( ecdsaKey . Public ( ) )
if err != nil {
return errwrap . Wrapf ( "error marshaling public key: {{err}}" , 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 )
case ed25519 . PrivateKey :
if p . Type != KeyType_ED25519 {
return fmt . Errorf ( "invalid key type: expected %s, got %T" , p . Type , parsedPrivateKey )
}
privateKey := parsedPrivateKey . ( ed25519 . PrivateKey )
entry . Key = privateKey
publicKey := privateKey . Public ( ) . ( ed25519 . PublicKey )
entry . FormattedPublicKey = base64 . StdEncoding . EncodeToString ( publicKey )
case * rsa . PrivateKey :
if p . Type != KeyType_RSA2048 && p . Type != KeyType_RSA3072 && p . Type != KeyType_RSA4096 {
return fmt . Errorf ( "invalid key type: expected %s, got %T" , p . Type , parsedPrivateKey )
}
keyBytes := 256
if p . Type == KeyType_RSA3072 {
keyBytes = 384
} else if p . Type == KeyType_RSA4096 {
keyBytes = 512
}
rsaKey := parsedPrivateKey . ( * rsa . PrivateKey )
if rsaKey . Size ( ) != keyBytes {
return fmt . Errorf ( "invalid key size: expected %d bytes, got %d bytes" , keyBytes , rsaKey . Size ( ) )
}
entry . RSAKey = rsaKey
default :
return fmt . Errorf ( "invalid key type: expected %s, got %T" , p . Type , parsedPrivateKey )
}
}
p . LatestVersion += 1
if p . Keys == nil {
// 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.
p . Keys = keyEntryMap { }
}
p . Keys [ strconv . Itoa ( p . LatestVersion ) ] = entry
// 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
}
return p . Persist ( ctx , storage )
}
2021-02-22 19:09:13 +00:00
// Rotate rotates the policy and persists it to storage.
// If the rotation partially fails, the policy state will be restored.
2019-10-17 17:33:00 +00:00
func ( p * Policy ) Rotate ( ctx context . Context , storage logical . Storage , randReader io . Reader ) ( retErr error ) {
2018-02-12 22:27:28 +00:00
priorLatestVersion := p . LatestVersion
priorMinDecryptionVersion := p . MinDecryptionVersion
var priorKeys keyEntryMap
2022-05-16 16:50:38 +00:00
if p . Imported && ! p . AllowImportedKeyRotation {
return fmt . Errorf ( "imported key %s does not allow rotation within Vault" , p . Name )
}
2018-02-12 22:27:28 +00:00
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
}
} ( )
2021-02-22 19:09:13 +00:00
if err := p . RotateInMemory ( randReader ) ; err != nil {
return err
2015-09-14 20:28:46 +00:00
}
2022-05-16 16:50:38 +00:00
p . Imported = false
2021-02-22 19:09:13 +00:00
return p . Persist ( ctx , storage )
}
// RotateInMemory rotates the policy but does not persist it to storage.
func ( p * Policy ) RotateInMemory ( randReader io . Reader ) ( retErr error ) {
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
}
2019-10-17 17:33:00 +00:00
hmacKey , err := uuid . GenerateRandomBytesWithReader ( 32 , randReader )
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 {
2019-10-03 20:11:43 +00:00
case KeyType_AES128_GCM96 , KeyType_AES256_GCM96 , KeyType_ChaCha20_Poly1305 :
// Default to 256 bit key
numBytes := 32
if p . Type == KeyType_AES128_GCM96 {
numBytes = 16
}
2019-10-17 17:33:00 +00:00
newKey , err := uuid . GenerateRandomBytesWithReader ( numBytes , randReader )
2016-09-21 14:29:42 +00:00
if err != nil {
return err
}
2017-06-05 19:00:39 +00:00
entry . Key = newKey
2016-01-15 19:02:51 +00:00
2019-10-03 16:32:43 +00:00
case KeyType_ECDSA_P256 , KeyType_ECDSA_P384 , KeyType_ECDSA_P521 :
var curve elliptic . Curve
switch p . Type {
case KeyType_ECDSA_P384 :
curve = elliptic . P384 ( )
case KeyType_ECDSA_P521 :
curve = elliptic . P521 ( )
default :
curve = elliptic . P256 ( )
}
privKey , err := ecdsa . GenerateKey ( curve , rand . Reader )
2016-09-21 14:29:42 +00:00
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 :
2019-10-17 17:33:00 +00:00
pub , pri , err := ed25519 . GenerateKey ( randReader )
2017-06-05 19:00:39 +00:00
if err != nil {
return err
}
entry . Key = pri
entry . FormattedPublicKey = base64 . StdEncoding . EncodeToString ( pub )
2017-11-03 14:45:53 +00:00
2020-02-15 22:40:50 +00:00
case KeyType_RSA2048 , KeyType_RSA3072 , KeyType_RSA4096 :
2017-11-03 14:45:53 +00:00
bitSize := 2048
2020-02-15 22:40:50 +00:00
if p . Type == KeyType_RSA3072 {
bitSize = 3072
}
2017-11-03 14:45:53 +00:00
if p . Type == KeyType_RSA4096 {
bitSize = 4096
}
2019-10-17 17:33:00 +00:00
entry . RSAKey , err = rsa . GenerateKey ( randReader , bitSize )
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 p . ConvergentEncryption {
if p . ConvergentVersion == - 1 || p . ConvergentVersion > 1 {
entry . ConvergentVersion = currentConvergentVersion
}
}
2021-02-22 19:09:13 +00:00
p . LatestVersion += 1
if p . Keys == nil {
// 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.
p . Keys = keyEntryMap { }
}
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
}
2021-02-22 19:09:13 +00:00
return nil
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
}
2022-08-03 19:22:48 +00:00
prefix := strings . ReplaceAll ( template , "{{version}}" , strconv . Itoa ( ver ) )
2018-03-09 01:58:50 +00:00
p . versionPrefixCache . Store ( ver , prefix )
return prefix
}
2020-10-02 02:04:36 +00:00
// SymmetricOpts are the arguments to symmetric operations that are "optional", e.g.
// not always used. This improves the aesthetics of calls to those functions.
type SymmetricOpts struct {
// Whether to use convergent encryption
Convergent bool
// The version of the convergent encryption scheme
ConvergentVersion int
// The nonce, if not randomly generated
Nonce [ ] byte
// Additional data to include in AEAD authentication
AdditionalData [ ] byte
// The HMAC key, for generating IVs in convergent encryption
HMACKey [ ] byte
}
// Symmetrically encrypt a plaintext given the convergence configuration and appropriate keys
func ( p * Policy ) SymmetricEncryptRaw ( ver int , encKey , plaintext [ ] byte , opts SymmetricOpts ) ( [ ] byte , error ) {
var aead cipher . AEAD
var err error
nonce := opts . Nonce
switch p . Type {
case KeyType_AES128_GCM96 , KeyType_AES256_GCM96 :
// Setup the cipher
aesCipher , err := aes . NewCipher ( encKey )
if err != nil {
return nil , errutil . InternalError { Err : err . Error ( ) }
}
// Setup the GCM AEAD
gcm , err := cipher . NewGCM ( aesCipher )
if err != nil {
return nil , errutil . InternalError { Err : err . Error ( ) }
}
aead = gcm
case KeyType_ChaCha20_Poly1305 :
cha , err := chacha20poly1305 . New ( encKey )
if err != nil {
return nil , errutil . InternalError { Err : err . Error ( ) }
}
aead = cha
}
if opts . Convergent {
convergentVersion := p . convergentVersion ( ver )
switch convergentVersion {
case 1 :
if len ( opts . Nonce ) != aead . NonceSize ( ) {
return nil , errutil . UserError { Err : fmt . Sprintf ( "base64-decoded nonce must be %d bytes long when using convergent encryption with this key" , aead . NonceSize ( ) ) }
}
case 2 , 3 :
if len ( opts . HMACKey ) == 0 {
return nil , errutil . InternalError { Err : fmt . Sprintf ( "invalid hmac key length of zero" ) }
}
nonceHmac := hmac . New ( sha256 . New , opts . HMACKey )
nonceHmac . Write ( plaintext )
nonceSum := nonceHmac . Sum ( nil )
nonce = nonceSum [ : aead . NonceSize ( ) ]
default :
return nil , errutil . InternalError { Err : fmt . Sprintf ( "unhandled convergent version %d" , convergentVersion ) }
}
} else if len ( nonce ) == 0 {
// Compute random nonce
nonce , err = uuid . GenerateRandomBytes ( aead . NonceSize ( ) )
if err != nil {
return nil , errutil . InternalError { Err : err . Error ( ) }
}
2022-01-19 07:32:49 +00:00
} else if len ( nonce ) != aead . NonceSize ( ) {
return nil , errutil . UserError { Err : fmt . Sprintf ( "base64-decoded nonce must be %d bytes long but given %d bytes" , aead . NonceSize ( ) , len ( nonce ) ) }
2020-10-02 02:04:36 +00:00
}
// Encrypt and tag with AEAD
ciphertext := aead . Seal ( nil , nonce , plaintext , opts . AdditionalData )
// Place the encrypted data after the nonce
if ! opts . Convergent || p . convergentVersion ( ver ) > 1 {
ciphertext = append ( nonce , ciphertext ... )
}
return ciphertext , nil
}
// Symmetrically decrypt a ciphertext given the convergence configuration and appropriate keys
func ( p * Policy ) SymmetricDecryptRaw ( encKey , ciphertext [ ] byte , opts SymmetricOpts ) ( [ ] byte , error ) {
var aead cipher . AEAD
var nonce [ ] byte
switch p . Type {
case KeyType_AES128_GCM96 , KeyType_AES256_GCM96 :
// Setup the cipher
aesCipher , err := aes . NewCipher ( encKey )
if err != nil {
return nil , errutil . InternalError { Err : err . Error ( ) }
}
// Setup the GCM AEAD
gcm , err := cipher . NewGCM ( aesCipher )
if err != nil {
return nil , errutil . InternalError { Err : err . Error ( ) }
}
aead = gcm
case KeyType_ChaCha20_Poly1305 :
cha , err := chacha20poly1305 . New ( encKey )
if err != nil {
return nil , errutil . InternalError { Err : err . Error ( ) }
}
aead = cha
}
if len ( ciphertext ) < aead . NonceSize ( ) {
return nil , errutil . UserError { Err : "invalid ciphertext length" }
}
// Extract the nonce and ciphertext
var trueCT [ ] byte
if opts . Convergent && opts . ConvergentVersion == 1 {
trueCT = ciphertext
} else {
nonce = ciphertext [ : aead . NonceSize ( ) ]
trueCT = ciphertext [ aead . NonceSize ( ) : ]
}
// Verify and Decrypt
plain , err := aead . Open ( nil , nonce , trueCT , opts . AdditionalData )
if err != nil {
2021-11-17 16:40:43 +00:00
return nil , errutil . UserError { Err : err . Error ( ) }
2020-10-02 02:04:36 +00:00
}
return plain , nil
}