2016-10-26 23:57:28 +00:00
package keysutil
2016-01-26 17:23:42 +00:00
import (
2018-01-19 06:44:44 +00:00
"context"
2016-01-26 17:23:42 +00:00
"reflect"
2017-12-06 23:24:00 +00:00
"strconv"
2016-01-26 17:23:42 +00:00
"testing"
2017-12-06 23:24:00 +00:00
"time"
2016-01-26 17:23:42 +00:00
2017-12-06 23:24:00 +00:00
"github.com/hashicorp/vault/helper/jsonutil"
2016-01-26 17:23:42 +00:00
"github.com/hashicorp/vault/logical"
2018-02-12 22:27:28 +00:00
"github.com/mitchellh/copystructure"
2016-01-26 17:23:42 +00:00
)
2017-12-06 23:24:00 +00:00
func TestPolicy_KeyEntryMapUpgrade ( t * testing . T ) {
now := time . Now ( )
old := map [ int ] KeyEntry {
1 : {
Key : [ ] byte ( "samplekey" ) ,
HMACKey : [ ] byte ( "samplehmackey" ) ,
CreationTime : now ,
FormattedPublicKey : "sampleformattedpublickey" ,
} ,
2 : {
Key : [ ] byte ( "samplekey2" ) ,
HMACKey : [ ] byte ( "samplehmackey2" ) ,
CreationTime : now . Add ( 10 * time . Second ) ,
FormattedPublicKey : "sampleformattedpublickey2" ,
} ,
}
oldEncoded , err := jsonutil . EncodeJSON ( old )
if err != nil {
t . Fatal ( err )
}
var new keyEntryMap
err = jsonutil . DecodeJSON ( oldEncoded , & new )
if err != nil {
t . Fatal ( err )
}
newEncoded , err := jsonutil . EncodeJSON ( & new )
if err != nil {
t . Fatal ( err )
}
if string ( oldEncoded ) != string ( newEncoded ) {
t . Fatalf ( "failed to upgrade key entry map;\nold: %q\nnew: %q" , string ( oldEncoded ) , string ( newEncoded ) )
}
}
2016-01-27 01:21:58 +00:00
func Test_KeyUpgrade ( t * testing . T ) {
2016-10-26 23:57:28 +00:00
testKeyUpgradeCommon ( t , NewLockManager ( false ) )
testKeyUpgradeCommon ( t , NewLockManager ( true ) )
2016-04-21 20:32:06 +00:00
}
2016-10-26 23:57:28 +00:00
func testKeyUpgradeCommon ( t * testing . T , lm * LockManager ) {
2018-01-19 06:44:44 +00:00
ctx := context . Background ( )
2016-01-27 01:21:58 +00:00
storage := & logical . InmemStorage { }
2018-01-19 06:44:44 +00:00
p , lock , upserted , err := lm . GetPolicyUpsert ( ctx , PolicyRequest {
2016-10-26 23:52:31 +00:00
Storage : storage ,
2016-10-26 23:57:28 +00:00
KeyType : KeyType_AES256_GCM96 ,
2016-10-26 23:52:31 +00:00
Name : "test" ,
2016-09-21 14:29:42 +00:00
} )
2016-05-03 04:19:18 +00:00
if lock != nil {
defer lock . RUnlock ( )
}
2016-01-27 01:21:58 +00:00
if err != nil {
t . Fatal ( err )
}
2016-04-26 15:39:19 +00:00
if p == nil {
t . Fatal ( "nil policy" )
2016-01-27 01:21:58 +00:00
}
2016-04-26 15:39:19 +00:00
if ! upserted {
t . Fatal ( "expected an upsert" )
}
2016-01-27 21:24:11 +00:00
2017-12-06 23:24:00 +00:00
testBytes := make ( [ ] byte , len ( p . Keys [ "1" ] . Key ) )
copy ( testBytes , p . Keys [ "1" ] . Key )
2016-01-27 01:21:58 +00:00
2017-12-06 23:24:00 +00:00
p . Key = p . Keys [ "1" ] . Key
2016-04-26 15:39:19 +00:00
p . Keys = nil
2016-10-26 23:52:31 +00:00
p . MigrateKeyToKeysMap ( )
2016-04-26 15:39:19 +00:00
if p . Key != nil {
2016-01-27 01:21:58 +00:00
t . Fatal ( "policy.Key is not nil" )
}
2016-04-26 15:39:19 +00:00
if len ( p . Keys ) != 1 {
2016-01-27 01:21:58 +00:00
t . Fatal ( "policy.Keys is the wrong size" )
}
2017-12-06 23:24:00 +00:00
if ! reflect . DeepEqual ( testBytes , p . Keys [ "1" ] . Key ) {
2016-01-27 01:21:58 +00:00
t . Fatal ( "key mismatch" )
}
}
2016-01-27 17:02:32 +00:00
func Test_ArchivingUpgrade ( t * testing . T ) {
2016-10-26 23:57:28 +00:00
testArchivingUpgradeCommon ( t , NewLockManager ( false ) )
testArchivingUpgradeCommon ( t , NewLockManager ( true ) )
2016-04-21 20:32:06 +00:00
}
2016-10-26 23:57:28 +00:00
func testArchivingUpgradeCommon ( t * testing . T , lm * LockManager ) {
2018-01-19 06:44:44 +00:00
ctx := context . Background ( )
2016-01-27 17:02:32 +00:00
// First, we generate a policy and rotate it a number of times. Each time
// we'll ensure that we have the expected number of keys in the archive and
// the main keys object, which without changing the min version should be
// zero and latest, respectively
storage := & logical . InmemStorage { }
2018-01-19 06:44:44 +00:00
p , lock , _ , err := lm . GetPolicyUpsert ( ctx , PolicyRequest {
2016-10-26 23:52:31 +00:00
Storage : storage ,
2016-10-26 23:57:28 +00:00
KeyType : KeyType_AES256_GCM96 ,
2016-10-26 23:52:31 +00:00
Name : "test" ,
2016-09-21 14:29:42 +00:00
} )
2016-01-27 17:02:32 +00:00
if err != nil {
t . Fatal ( err )
}
2016-05-03 04:19:18 +00:00
if p == nil || lock == nil {
t . Fatal ( "nil policy or lock" )
2016-04-21 20:32:06 +00:00
}
2016-05-03 04:19:18 +00:00
lock . RUnlock ( )
2016-01-27 21:24:11 +00:00
2016-01-27 17:02:32 +00:00
// Store the initial key in the archive
2018-02-12 16:04:58 +00:00
keysArchive := [ ] KeyEntry { KeyEntry { } , p . Keys [ "1" ] }
checkKeys ( t , ctx , p , storage , keysArchive , "initial" , 1 , 1 , 1 )
2016-01-27 17:02:32 +00:00
for i := 2 ; i <= 10 ; i ++ {
2018-01-19 06:44:44 +00:00
err = p . Rotate ( ctx , storage )
2016-01-27 17:02:32 +00:00
if err != nil {
t . Fatal ( err )
}
2017-12-06 23:24:00 +00:00
keysArchive = append ( keysArchive , p . Keys [ strconv . Itoa ( i ) ] )
2018-02-12 16:04:58 +00:00
checkKeys ( t , ctx , p , storage , keysArchive , "rotate" , i , i , i )
2016-01-27 17:02:32 +00:00
}
// Now, wipe the archive and set the archive version to zero
2018-01-19 06:44:44 +00:00
err = storage . Delete ( ctx , "archive/test" )
2016-01-27 17:02:32 +00:00
if err != nil {
t . Fatal ( err )
}
2016-04-26 15:39:19 +00:00
p . ArchiveVersion = 0
2016-01-27 17:02:32 +00:00
// Store it, but without calling persist, so we don't trigger
// handleArchiving()
2016-04-26 15:39:19 +00:00
buf , err := p . Serialize ( )
2016-01-27 17:02:32 +00:00
if err != nil {
t . Fatal ( err )
}
// Write the policy into storage
2018-01-19 06:44:44 +00:00
err = storage . Put ( ctx , & logical . StorageEntry {
2016-04-26 15:39:19 +00:00
Key : "policy/" + p . Name ,
2016-01-27 17:02:32 +00:00
Value : buf ,
} )
if err != nil {
t . Fatal ( err )
}
2016-04-26 15:39:19 +00:00
// If we're caching, expire from the cache since we modified it
2016-04-21 20:32:06 +00:00
// under-the-hood
2016-04-26 15:39:19 +00:00
if lm . CacheActive ( ) {
2016-10-27 00:03:51 +00:00
delete ( lm . cache , "test" )
2016-04-21 20:32:06 +00:00
}
2016-01-27 21:24:11 +00:00
2016-01-27 17:02:32 +00:00
// Now get the policy again; the upgrade should happen automatically
2018-01-19 06:44:44 +00:00
p , lock , err = lm . GetPolicyShared ( ctx , storage , "test" )
2016-01-27 17:02:32 +00:00
if err != nil {
t . Fatal ( err )
}
2016-05-03 04:19:18 +00:00
if p == nil || lock == nil {
t . Fatal ( "nil policy or lock" )
2016-01-27 17:02:32 +00:00
}
2016-05-03 04:19:18 +00:00
lock . RUnlock ( )
2016-01-27 17:02:32 +00:00
2018-02-12 16:04:58 +00:00
checkKeys ( t , ctx , p , storage , keysArchive , "upgrade" , 10 , 10 , 10 )
2016-05-03 04:19:18 +00:00
// Let's check some deletion logic while we're at it
// The policy should be in there
2016-10-27 00:03:51 +00:00
if lm . CacheActive ( ) && lm . cache [ "test" ] == nil {
2016-05-03 04:19:18 +00:00
t . Fatal ( "nil policy in cache" )
}
// First we'll do this wrong, by not setting the deletion flag
2018-01-19 06:44:44 +00:00
err = lm . DeletePolicy ( ctx , storage , "test" )
2016-05-03 04:19:18 +00:00
if err == nil {
t . Fatal ( "got nil error, but should not have been able to delete since we didn't set the deletion flag on the policy" )
}
// The policy should still be in there
2016-10-27 00:03:51 +00:00
if lm . CacheActive ( ) && lm . cache [ "test" ] == nil {
2016-05-03 04:19:18 +00:00
t . Fatal ( "nil policy in cache" )
}
2018-01-19 06:44:44 +00:00
p , lock , err = lm . GetPolicyShared ( ctx , storage , "test" )
2016-05-03 04:19:18 +00:00
if err != nil {
t . Fatal ( err )
}
if p == nil || lock == nil {
t . Fatal ( "policy or lock nil after bad delete" )
}
lock . RUnlock ( )
// Now do it properly
p . DeletionAllowed = true
2018-01-19 06:44:44 +00:00
err = p . Persist ( ctx , storage )
2016-05-03 04:19:18 +00:00
if err != nil {
t . Fatal ( err )
}
2018-01-19 06:44:44 +00:00
err = lm . DeletePolicy ( ctx , storage , "test" )
2016-05-03 04:19:18 +00:00
if err != nil {
t . Fatal ( err )
}
// The policy should *not* be in there
2016-10-27 00:03:51 +00:00
if lm . CacheActive ( ) && lm . cache [ "test" ] != nil {
2016-05-03 04:19:18 +00:00
t . Fatal ( "non-nil policy in cache" )
}
2018-01-19 06:44:44 +00:00
p , lock , err = lm . GetPolicyShared ( ctx , storage , "test" )
2016-05-03 04:19:18 +00:00
if err != nil {
t . Fatal ( err )
}
if p != nil || lock != nil {
t . Fatal ( "policy or lock not nil after delete" )
}
2016-01-27 17:02:32 +00:00
}
2016-01-26 17:23:42 +00:00
func Test_Archiving ( t * testing . T ) {
2016-10-26 23:57:28 +00:00
testArchivingCommon ( t , NewLockManager ( false ) )
testArchivingCommon ( t , NewLockManager ( true ) )
2016-04-21 20:32:06 +00:00
}
2016-10-26 23:57:28 +00:00
func testArchivingCommon ( t * testing . T , lm * LockManager ) {
2018-01-19 06:44:44 +00:00
ctx := context . Background ( )
2017-06-05 19:00:39 +00:00
// First, we generate a policy and rotate it a number of times. Each time
// we'll ensure that we have the expected number of keys in the archive and
2016-01-26 17:23:42 +00:00
// the main keys object, which without changing the min version should be
// zero and latest, respectively
storage := & logical . InmemStorage { }
2018-01-19 06:44:44 +00:00
p , lock , _ , err := lm . GetPolicyUpsert ( ctx , PolicyRequest {
2016-10-26 23:52:31 +00:00
Storage : storage ,
2016-10-26 23:57:28 +00:00
KeyType : KeyType_AES256_GCM96 ,
2016-10-26 23:52:31 +00:00
Name : "test" ,
2016-09-21 14:29:42 +00:00
} )
2016-01-26 17:23:42 +00:00
if err != nil {
t . Fatal ( err )
}
2018-02-12 22:27:28 +00:00
if p == nil || lock == nil {
t . Fatal ( "nil policy or lock" )
2016-04-21 20:32:06 +00:00
}
2018-02-12 22:27:28 +00:00
lock . RUnlock ( )
2016-01-27 21:24:11 +00:00
2016-01-26 17:23:42 +00:00
// Store the initial key in the archive
2018-02-12 16:04:58 +00:00
keysArchive := [ ] KeyEntry { KeyEntry { } , p . Keys [ "1" ] }
checkKeys ( t , ctx , p , storage , keysArchive , "initial" , 1 , 1 , 1 )
2016-01-26 17:23:42 +00:00
for i := 2 ; i <= 10 ; i ++ {
2018-01-19 06:44:44 +00:00
err = p . Rotate ( ctx , storage )
2016-01-26 17:23:42 +00:00
if err != nil {
t . Fatal ( err )
}
2017-12-06 23:24:00 +00:00
keysArchive = append ( keysArchive , p . Keys [ strconv . Itoa ( i ) ] )
2018-02-12 16:04:58 +00:00
checkKeys ( t , ctx , p , storage , keysArchive , "rotate" , i , i , i )
2016-01-26 17:23:42 +00:00
}
// Move the min decryption version up
for i := 1 ; i <= 10 ; i ++ {
2016-04-26 15:39:19 +00:00
p . MinDecryptionVersion = i
2016-01-26 17:23:42 +00:00
2018-01-19 06:44:44 +00:00
err = p . Persist ( ctx , storage )
2016-01-26 17:23:42 +00:00
if err != nil {
t . Fatal ( err )
}
// We expect to find:
2016-01-26 22:14:21 +00:00
// * The keys in archive are the same as the latest version
2016-01-26 17:23:42 +00:00
// * The latest version is constant
// * The number of keys in the policy itself is from the min
// decryption version up to the latest version, so for e.g. 7 and
// 10, you'd need 7, 8, 9, and 10 -- IOW, latest version - min
// decryption version plus 1 (the min decryption version key
// itself)
2018-02-12 16:04:58 +00:00
checkKeys ( t , ctx , p , storage , keysArchive , "minadd" , 10 , 10 , p . LatestVersion - p . MinDecryptionVersion + 1 )
2016-01-26 17:23:42 +00:00
}
// Move the min decryption version down
for i := 10 ; i >= 1 ; i -- {
2016-04-26 15:39:19 +00:00
p . MinDecryptionVersion = i
2016-01-26 17:23:42 +00:00
2018-01-19 06:44:44 +00:00
err = p . Persist ( ctx , storage )
2016-01-26 17:23:42 +00:00
if err != nil {
t . Fatal ( err )
}
// We expect to find:
2016-01-26 22:14:21 +00:00
// * The keys in archive are never removed so same as the latest version
2016-01-26 17:23:42 +00:00
// * The latest version is constant
// * The number of keys in the policy itself is from the min
// decryption version up to the latest version, so for e.g. 7 and
// 10, you'd need 7, 8, 9, and 10 -- IOW, latest version - min
// decryption version plus 1 (the min decryption version key
// itself)
2018-02-12 16:04:58 +00:00
checkKeys ( t , ctx , p , storage , keysArchive , "minsub" , 10 , 10 , p . LatestVersion - p . MinDecryptionVersion + 1 )
2016-01-26 17:23:42 +00:00
}
}
func checkKeys ( t * testing . T ,
2018-01-19 06:44:44 +00:00
ctx context . Context ,
2016-10-26 23:57:28 +00:00
p * Policy ,
2016-01-26 17:23:42 +00:00
storage logical . Storage ,
2018-02-12 16:04:58 +00:00
keysArchive [ ] KeyEntry ,
2016-01-26 22:14:21 +00:00
action string ,
2016-01-26 17:23:42 +00:00
archiveVer , latestVer , keysSize int ) {
// Sanity check
if len ( keysArchive ) != latestVer + 1 {
t . Fatalf ( "latest expected key version is %d, expected test keys archive size is %d, " +
"but keys archive is of size %d" , latestVer , latestVer + 1 , len ( keysArchive ) )
}
2018-01-19 06:44:44 +00:00
archive , err := p . LoadArchive ( ctx , storage )
2016-01-26 17:23:42 +00:00
if err != nil {
t . Fatal ( err )
}
badArchiveVer := false
if archiveVer == 0 {
2016-09-01 15:57:28 +00:00
if len ( archive . Keys ) != 0 || p . ArchiveVersion != 0 {
2016-01-26 17:23:42 +00:00
badArchiveVer = true
}
} else {
// We need to subtract one because we have the indexes match key
// versions, which start at 1. So for an archive version of 1, we
// actually have two entries -- a blank 0 entry, and the key at spot 1
2016-09-01 15:57:28 +00:00
if archiveVer != len ( archive . Keys ) - 1 || archiveVer != p . ArchiveVersion {
2016-01-26 17:23:42 +00:00
badArchiveVer = true
}
}
if badArchiveVer {
t . Fatalf (
"expected archive version %d, found length of archive keys %d and policy archive version %d" ,
2016-09-01 15:57:28 +00:00
archiveVer , len ( archive . Keys ) , p . ArchiveVersion ,
2016-01-26 17:23:42 +00:00
)
}
2016-09-01 15:57:28 +00:00
if latestVer != p . LatestVersion {
2016-01-26 17:23:42 +00:00
t . Fatalf (
"expected latest version %d, found %d" ,
2016-09-01 15:57:28 +00:00
latestVer , p . LatestVersion ,
2016-01-26 17:23:42 +00:00
)
}
2016-09-01 15:57:28 +00:00
if keysSize != len ( p . Keys ) {
2016-01-26 17:23:42 +00:00
t . Fatalf (
2016-01-26 22:14:21 +00:00
"expected keys size %d, found %d, action is %s, policy is \n%#v\n" ,
2016-09-01 15:57:28 +00:00
keysSize , len ( p . Keys ) , action , p ,
2016-01-26 17:23:42 +00:00
)
}
2016-09-01 15:57:28 +00:00
for i := p . MinDecryptionVersion ; i <= p . LatestVersion ; i ++ {
2017-12-06 23:24:00 +00:00
if _ , ok := p . Keys [ strconv . Itoa ( i ) ] ; ! ok {
2016-01-26 17:23:42 +00:00
t . Fatalf (
"expected key %d, did not find it in policy keys" , i ,
)
}
}
2016-09-01 15:57:28 +00:00
for i := p . MinDecryptionVersion ; i <= p . LatestVersion ; i ++ {
2017-12-06 23:24:00 +00:00
ver := strconv . Itoa ( i )
2017-06-05 19:00:39 +00:00
// Travis has weird time zone issues and gets super unhappy
2017-12-06 23:24:00 +00:00
if ! p . Keys [ ver ] . CreationTime . Equal ( keysArchive [ i ] . CreationTime ) {
t . Fatalf ( "key %d not equivalent between policy keys and test keys archive; policy keys:\n%#v\ntest keys archive:\n%#v\n" , i , p . Keys [ ver ] , keysArchive [ i ] )
2017-06-05 19:00:39 +00:00
}
2017-12-06 23:24:00 +00:00
polKey := p . Keys [ ver ]
2017-06-05 19:00:39 +00:00
polKey . CreationTime = keysArchive [ i ] . CreationTime
2017-12-06 23:24:00 +00:00
p . Keys [ ver ] = polKey
if ! reflect . DeepEqual ( p . Keys [ ver ] , keysArchive [ i ] ) {
t . Fatalf ( "key %d not equivalent between policy keys and test keys archive; policy keys:\n%#v\ntest keys archive:\n%#v\n" , i , p . Keys [ ver ] , keysArchive [ i ] )
2016-01-26 17:23:42 +00:00
}
}
for i := 1 ; i < len ( archive . Keys ) ; i ++ {
2017-06-05 19:00:39 +00:00
if ! reflect . DeepEqual ( archive . Keys [ i ] . Key , keysArchive [ i ] . Key ) {
t . Fatalf ( "key %d not equivalent between policy archive and test keys archive; policy archive:\n%#v\ntest keys archive:\n%#v\n" , i , archive . Keys [ i ] . Key , keysArchive [ i ] . Key )
2016-01-26 17:23:42 +00:00
}
}
}
2018-02-12 22:27:28 +00:00
func Test_StorageErrorSafety ( t * testing . T ) {
ctx := context . Background ( )
lm := NewLockManager ( false )
storage := & logical . InmemStorage { }
p , lock , _ , err := lm . GetPolicyUpsert ( ctx , PolicyRequest {
Storage : storage ,
KeyType : KeyType_AES256_GCM96 ,
Name : "test" ,
} )
if err != nil {
t . Fatal ( err )
}
if p == nil || lock == nil {
t . Fatal ( "nil policy or lock" )
}
lock . RUnlock ( )
// Store the initial key in the archive
keysArchive := [ ] KeyEntry { KeyEntry { } , p . Keys [ "1" ] }
checkKeys ( t , ctx , p , storage , keysArchive , "initial" , 1 , 1 , 1 )
// We use checkKeys here just for sanity; it doesn't really handle cases of
// errors below so we do more targeted testing later
for i := 2 ; i <= 5 ; i ++ {
err = p . Rotate ( ctx , storage )
if err != nil {
t . Fatal ( err )
}
keysArchive = append ( keysArchive , p . Keys [ strconv . Itoa ( i ) ] )
checkKeys ( t , ctx , p , storage , keysArchive , "rotate" , i , i , i )
}
underlying := storage . Underlying ( )
underlying . FailPut ( true )
priorLen := len ( p . Keys )
err = p . Rotate ( ctx , storage )
if err == nil {
t . Fatal ( "expected error" )
}
if len ( p . Keys ) != priorLen {
t . Fatal ( "length of keys should not have changed" )
}
}
func Test_BadUpgrade ( t * testing . T ) {
ctx := context . Background ( )
lm := NewLockManager ( false )
storage := & logical . InmemStorage { }
p , lock , _ , err := lm . GetPolicyUpsert ( ctx , PolicyRequest {
Storage : storage ,
KeyType : KeyType_AES256_GCM96 ,
Name : "test" ,
} )
if err != nil {
t . Fatal ( err )
}
if p == nil || lock == nil {
t . Fatal ( "nil policy or lock" )
}
lock . RUnlock ( )
orig , err := copystructure . Copy ( p )
if err != nil {
t . Fatal ( err )
}
p . Key = p . Keys [ "1" ] . Key
p . Keys = nil
p . MinDecryptionVersion = 0
if err := p . Upgrade ( ctx , storage ) ; err != nil {
t . Fatal ( err )
}
k := p . Keys [ "1" ]
o := orig . ( * Policy ) . Keys [ "1" ]
k . CreationTime = o . CreationTime
k . HMACKey = o . HMACKey
p . Keys [ "1" ] = k
if ! reflect . DeepEqual ( orig , p ) {
t . Fatalf ( "not equal:\n%#v\n%#v" , orig , p )
}
// Do it again with a failing storage call
underlying := storage . Underlying ( )
underlying . FailPut ( true )
p . Key = p . Keys [ "1" ] . Key
p . Keys = nil
p . MinDecryptionVersion = 0
if err := p . Upgrade ( ctx , storage ) ; err == nil {
t . Fatal ( "expected error" )
}
if p . MinDecryptionVersion == 1 {
t . Fatal ( "min decryption version was changed" )
}
if p . Keys != nil {
t . Fatal ( "found upgraded keys" )
}
if p . Key == nil {
t . Fatal ( "non-upgraded key not found" )
}
}
func Test_BadArchive ( t * testing . T ) {
ctx := context . Background ( )
lm := NewLockManager ( false )
storage := & logical . InmemStorage { }
p , lock , _ , err := lm . GetPolicyUpsert ( ctx , PolicyRequest {
Storage : storage ,
KeyType : KeyType_AES256_GCM96 ,
Name : "test" ,
} )
if err != nil {
t . Fatal ( err )
}
if p == nil || lock == nil {
t . Fatal ( "nil policy or lock" )
}
lock . RUnlock ( )
for i := 2 ; i <= 10 ; i ++ {
err = p . Rotate ( ctx , storage )
if err != nil {
t . Fatal ( err )
}
}
p . MinDecryptionVersion = 5
if err := p . Persist ( ctx , storage ) ; err != nil {
t . Fatal ( err )
}
if p . ArchiveVersion != 10 {
t . Fatalf ( "unexpected archive version %d" , p . ArchiveVersion )
}
if len ( p . Keys ) != 6 {
t . Fatalf ( "unexpected key length %d" , len ( p . Keys ) )
}
// Set back
p . MinDecryptionVersion = 1
if err := p . Persist ( ctx , storage ) ; err != nil {
t . Fatal ( err )
}
if p . ArchiveVersion != 10 {
t . Fatalf ( "unexpected archive version %d" , p . ArchiveVersion )
}
if len ( p . Keys ) != 10 {
t . Fatalf ( "unexpected key length %d" , len ( p . Keys ) )
}
// Run it again but we'll turn off storage along the way
p . MinDecryptionVersion = 5
if err := p . Persist ( ctx , storage ) ; err != nil {
t . Fatal ( err )
}
if p . ArchiveVersion != 10 {
t . Fatalf ( "unexpected archive version %d" , p . ArchiveVersion )
}
if len ( p . Keys ) != 6 {
t . Fatalf ( "unexpected key length %d" , len ( p . Keys ) )
}
underlying := storage . Underlying ( )
underlying . FailPut ( true )
// Set back, which should cause p.Keys to be changed if the persist works,
// but it doesn't
p . MinDecryptionVersion = 1
if err := p . Persist ( ctx , storage ) ; err == nil {
t . Fatal ( "expected error during put" )
}
if p . ArchiveVersion != 10 {
t . Fatalf ( "unexpected archive version %d" , p . ArchiveVersion )
}
// Here's the expected change
if len ( p . Keys ) != 6 {
t . Fatalf ( "unexpected key length %d" , len ( p . Keys ) )
}
}