// If we abort in the middle of writing the key and cert, such that only the key is written
// to the final location, when we read we can still read the cert from the temporary
// location.
func TestTwoPhaseReadWrite(t *testing.T) {
	cert1, _, err := testutils.CreateRootCertAndKey("cn")
	require.NoError(t, err)

	cert2, key2, err := testutils.CreateRootCertAndKey("cn")
	require.NoError(t, err)

	tempdir, err := ioutil.TempDir("", "KeyReadWriter")
	require.NoError(t, err)
	defer os.RemoveAll(tempdir)

	path := ca.NewConfigPaths(filepath.Join(tempdir))
	krw := ca.NewKeyReadWriter(path.Node, nil, nil)

	// put a directory in the location where the cert goes, so we can't actually move
	// the cert from the temporary location to the final location.
	require.NoError(t, os.Mkdir(filepath.Join(path.Node.Cert), 0755))
	require.Error(t, krw.Write(cert2, key2, nil))

	// the temp cert file should exist
	tempCertPath := filepath.Join(filepath.Dir(path.Node.Cert), "."+filepath.Base(path.Node.Cert))
	readCert, err := ioutil.ReadFile(tempCertPath)
	require.NoError(t, err)
	require.Equal(t, cert2, readCert)

	// remove the directory, to simulate it failing to write the first time
	os.RemoveAll(path.Node.Cert)
	readCert, readKey, err := krw.Read()
	require.NoError(t, err)
	require.Equal(t, cert2, readCert)
	require.Equal(t, key2, readKey)
	// the cert should have been moved to its proper location
	_, err = os.Stat(tempCertPath)
	require.True(t, os.IsNotExist(err))

	// If the cert in the proper location doesn't match the key, the temp location is checked
	require.NoError(t, ioutil.WriteFile(tempCertPath, cert2, 0644))
	require.NoError(t, ioutil.WriteFile(path.Node.Cert, cert1, 0644))
	readCert, readKey, err = krw.Read()
	require.NoError(t, err)
	require.Equal(t, cert2, readCert)
	require.Equal(t, key2, readKey)
	// the cert should have been moved to its proper location
	_, err = os.Stat(tempCertPath)
	require.True(t, os.IsNotExist(err))

	// If the cert in the temp location also doesn't match, the failure matching the
	// correctly-located cert is returned
	require.NoError(t, os.Remove(path.Node.Cert))
	require.NoError(t, ioutil.WriteFile(tempCertPath, cert1, 0644)) // mismatching cert
	_, _, err = krw.Read()
	require.True(t, os.IsNotExist(err))
	// the cert should have been removed
	_, err = os.Stat(tempCertPath)
	require.True(t, os.IsNotExist(err))
}
func TestKeyReadWriterMigrate(t *testing.T) {
	cert, key, err := testutils.CreateRootCertAndKey("cn")
	require.NoError(t, err)

	tempdir, err := ioutil.TempDir("", "KeyReadWriter")
	require.NoError(t, err)
	defer os.RemoveAll(tempdir)

	path := ca.NewConfigPaths(filepath.Join(tempdir))

	// if the key exists in an old location, migrate it from there.
	tempKeyPath := filepath.Join(filepath.Dir(path.Node.Key), "."+filepath.Base(path.Node.Key))
	require.NoError(t, ioutil.WriteFile(path.Node.Cert, cert, 0644))
	require.NoError(t, ioutil.WriteFile(tempKeyPath, key, 0600))

	krw := ca.NewKeyReadWriter(path.Node, nil, nil)
	require.NoError(t, krw.Migrate())
	_, err = os.Stat(tempKeyPath)
	require.True(t, os.IsNotExist(err)) // it's been moved to the right place
	_, _, err = krw.Read()
	require.NoError(t, err)

	// migrate does not affect any existing files
	dirList, err := ioutil.ReadDir(filepath.Dir(path.Node.Key))
	require.NoError(t, err)
	require.NoError(t, krw.Migrate())
	dirList2, err := ioutil.ReadDir(filepath.Dir(path.Node.Key))
	require.NoError(t, err)
	require.Equal(t, dirList, dirList2)
	_, _, err = krw.Read()
	require.NoError(t, err)
}
Exemple #3
0
func TestDecrypt(t *testing.T) {
	tempdir, err := ioutil.TempDir("", "rafttool")
	require.NoError(t, err)
	defer os.RemoveAll(tempdir)

	kek := []byte("kek")
	dek := []byte("dek")
	unlockKey := encryption.HumanReadableKey(kek)

	// write a key to disk, else we won't be able to decrypt anything
	paths := certPaths(tempdir)
	krw := ca.NewKeyReadWriter(paths.Node, kek,
		manager.RaftDEKData{EncryptionKeys: raft.EncryptionKeys{CurrentDEK: dek}})
	cert, key, err := testutils.CreateRootCertAndKey("not really a root, just need cert and key")
	require.NoError(t, err)
	require.NoError(t, krw.Write(cert, key, nil))

	// create the encrypted v3 directory
	origSnapshot := raftpb.Snapshot{
		Data: []byte("snapshot"),
		Metadata: raftpb.SnapshotMetadata{
			Index: 1,
			Term:  1,
		},
	}
	e, d := encryption.Defaults(dek)
	writeFakeRaftData(t, tempdir, &origSnapshot, storage.NewWALFactory(e, d), storage.NewSnapFactory(e, d))

	outdir := filepath.Join(tempdir, "outdir")
	// if we use the wrong unlock key, we can't actually decrypt anything.  The output directory won't get created.
	err = decryptRaftData(tempdir, outdir, "")
	require.IsType(t, ca.ErrInvalidKEK{}, err)
	require.False(t, fileutil.Exist(outdir))

	// Using the right unlock key, we produce data that is unencrypted
	require.NoError(t, decryptRaftData(tempdir, outdir, unlockKey))
	require.True(t, fileutil.Exist(outdir))

	// The snapshot directory is readable by the regular snapshotter
	snapshot, err := storage.OriginalSnap.New(filepath.Join(outdir, "snap-decrypted")).Load()
	require.NoError(t, err)
	require.NotNil(t, snapshot)
	require.Equal(t, origSnapshot, *snapshot)

	// The wals are readable by the regular wal
	walreader, err := storage.OriginalWAL.Open(filepath.Join(outdir, "wal-decrypted"), walpb.Snapshot{Index: 1, Term: 1})
	require.NoError(t, err)
	metadata, _, entries, err := walreader.ReadAll()
	require.NoError(t, err)
	require.Equal(t, []byte("v3metadata"), metadata)
	require.Len(t, entries, 5)
}
func TestKeyReadWriterViewAndRotateKEK(t *testing.T) {
	cert, key, err := testutils.CreateRootCertAndKey("cn")
	require.NoError(t, err)

	tempdir, err := ioutil.TempDir("", "KeyReadWriter")
	require.NoError(t, err)
	defer os.RemoveAll(tempdir)

	path := ca.NewConfigPaths(filepath.Join(tempdir))

	// write a key with headers to the key to make sure it gets passed when reading/writing headers
	keyBlock, _ := pem.Decode(key)
	require.NotNil(t, keyBlock)
	keyBlock.Headers = map[string]string{"hello": "world"}
	key = pem.EncodeToMemory(keyBlock)
	require.NoError(t, ca.NewKeyReadWriter(path.Node, nil, nil).Write(cert, key, nil))

	// if if getting new kek and headers fail, rotating a KEK fails, and the kek does not rotate
	k := ca.NewKeyReadWriter(path.Node, nil, nil)
	require.Error(t, k.ViewAndRotateKEK(func(k ca.KEKData, h ca.PEMKeyHeaders) (ca.KEKData, ca.PEMKeyHeaders, error) {
		require.Equal(t, ca.KEKData{}, k)
		require.Nil(t, h)
		return ca.KEKData{}, nil, fmt.Errorf("Nope")
	}))

	// writing new headers will write a key that has the headers returned by the header update function
	k = ca.NewKeyReadWriter(path.Node, []byte("oldKEK"), nil)
	require.NoError(t, k.ViewAndRotateKEK(func(k ca.KEKData, h ca.PEMKeyHeaders) (ca.KEKData, ca.PEMKeyHeaders, error) {
		require.Equal(t, ca.KEKData{KEK: []byte("oldKEK")}, k)
		require.Nil(t, h)
		return ca.KEKData{KEK: []byte("newKEK"), Version: uint64(2)},
			testHeaders{newHeaders: func(kek ca.KEKData) (map[string]string, error) {
				require.Equal(t, []byte("newKEK"), kek.KEK)
				return map[string]string{"updated": "headers"}, nil
			}}, nil
	}))

	// ensure the key has been re-encrypted and we can read it
	k = ca.NewKeyReadWriter(path.Node, nil, nil)
	_, _, err = k.Read()
	require.Error(t, err)

	var headers map[string]string

	k = ca.NewKeyReadWriter(path.Node, []byte("newKEK"), testHeaders{setHeaders: func(h map[string]string, _ ca.KEKData) (ca.PEMKeyHeaders, error) {
		headers = h
		return testHeaders{}, nil
	}})
	_, _, err = k.Read()
	require.NoError(t, err)
	require.Equal(t, map[string]string{"updated": "headers"}, headers)
}
Exemple #5
0
func TestRaftDEKManagerUpdateKeys(t *testing.T) {
	tempDir, err := ioutil.TempDir("", "manager-update-keys-")
	require.NoError(t, err)
	defer os.RemoveAll(tempDir)

	paths := ca.NewConfigPaths(tempDir)
	cert, key, err := cautils.CreateRootCertAndKey("cn")
	require.NoError(t, err)

	keys := raft.EncryptionKeys{
		CurrentDEK: []byte("key1"),
		PendingDEK: []byte("key2"),
	}
	krw := ca.NewKeyReadWriter(paths.Node, nil, RaftDEKData{
		EncryptionKeys: keys,
		NeedsRotation:  true,
	})
	require.NoError(t, krw.Write(cert, key, nil))

	dekManager, err := NewRaftDEKManager(krw)
	require.NoError(t, err)

	newKeys := raft.EncryptionKeys{
		CurrentDEK: []byte("new current"),
	}
	require.NoError(t, dekManager.UpdateKeys(newKeys))
	// don't run GetKeys, because NeedsRotation is true and it'd just generate a new one

	h, _ := krw.GetCurrentState()
	dekData, ok := h.(RaftDEKData)
	require.True(t, ok)
	require.True(t, dekData.NeedsRotation)

	// UpdateKeys so there is no CurrentDEK: all the headers should be wiped out
	require.NoError(t, dekManager.UpdateKeys(raft.EncryptionKeys{}))
	require.Equal(t, raft.EncryptionKeys{}, dekManager.GetKeys())
	require.False(t, dekManager.NeedsRotation())

	h, _ = krw.GetCurrentState()
	require.Nil(t, h)

	keyBytes, err := ioutil.ReadFile(paths.Node.Key)
	require.NoError(t, err)
	keyBlock, _ := pem.Decode(keyBytes)
	require.NotNil(t, keyBlock)

	// the only header remaining should be the kek version
	require.Len(t, keyBlock.Headers, 1)
	require.Contains(t, keyBlock.Headers, "kek-version")
}
Exemple #6
0
// NewRaftDEKManager creates a key if one doesn't exist
func TestNewRaftDEKManager(t *testing.T) {
	tempDir, err := ioutil.TempDir("", "manager-new-dek-manager-")
	require.NoError(t, err)
	defer os.RemoveAll(tempDir)

	paths := ca.NewConfigPaths(tempDir)
	cert, key, err := cautils.CreateRootCertAndKey("cn")
	require.NoError(t, err)

	krw := ca.NewKeyReadWriter(paths.Node, nil, nil)
	require.NoError(t, krw.Write(cert, key, nil))

	keyBytes, err := ioutil.ReadFile(paths.Node.Key)
	require.NoError(t, err)
	require.NotContains(t, string(keyBytes), pemHeaderRaftDEK) // headers are not written

	dekManager, err := NewRaftDEKManager(krw) // this should create a new DEK and write it to the file
	require.NoError(t, err)

	keyBytes, err = ioutil.ReadFile(paths.Node.Key)
	require.NoError(t, err)
	require.Contains(t, string(keyBytes), pemHeaderRaftDEK) // header is written now

	keys := dekManager.GetKeys()
	require.NotNil(t, keys.CurrentDEK)
	require.Nil(t, keys.PendingDEK)
	require.False(t, dekManager.NeedsRotation())

	// If one exists, nothing is updated
	dekManager, err = NewRaftDEKManager(krw) // this should create a new DEK and write it to the file
	require.NoError(t, err)

	keyBytes2, err := ioutil.ReadFile(paths.Node.Key)
	require.NoError(t, err)
	require.Equal(t, keyBytes, keyBytes2)

	require.Equal(t, keys, dekManager.GetKeys())
	require.False(t, dekManager.NeedsRotation())
}
func TestKeyReadWriterViewAndUpdateHeaders(t *testing.T) {
	cert, key, err := testutils.CreateRootCertAndKey("cn")
	require.NoError(t, err)

	tempdir, err := ioutil.TempDir("", "KeyReadWriter")
	require.NoError(t, err)
	defer os.RemoveAll(tempdir)

	path := ca.NewConfigPaths(filepath.Join(tempdir))

	// write a key with headers to the key to make sure it gets passed when reading/writing headers
	keyBlock, _ := pem.Decode(key)
	require.NotNil(t, keyBlock)
	keyBlock.Headers = map[string]string{"hello": "world"}
	key = pem.EncodeToMemory(keyBlock)
	require.NoError(t, ioutil.WriteFile(path.Node.Cert, cert, 0644))
	require.NoError(t, ioutil.WriteFile(path.Node.Key, key, 0600))

	// if the update headers callback function fails, updating headers fails
	k := ca.NewKeyReadWriter(path.Node, nil, nil)
	err = k.ViewAndUpdateHeaders(func(h ca.PEMKeyHeaders) (ca.PEMKeyHeaders, error) {
		require.Nil(t, h)
		return nil, fmt.Errorf("nope")
	})
	require.Error(t, err)
	require.Equal(t, "nope", err.Error())

	// updating headers succeed and is called with the latest kek data
	err = k.ViewAndUpdateHeaders(func(h ca.PEMKeyHeaders) (ca.PEMKeyHeaders, error) {
		require.Nil(t, h)
		return testHeaders{newHeaders: func(kek ca.KEKData) (map[string]string, error) {
			return map[string]string{"updated": "headers"}, nil
		}}, nil
	})
	require.NoError(t, err)

	k = ca.NewKeyReadWriter(path.Node, nil, testHeaders{setHeaders: func(h map[string]string, k ca.KEKData) (ca.PEMKeyHeaders, error) {
		require.Equal(t, map[string]string{"updated": "headers"}, h)
		require.Equal(t, ca.KEKData{}, k)
		return testHeaders{}, nil
	}})
	_, _, err = k.Read()
	require.NoError(t, err)

	// we can also update headers on an encrypted key
	k = ca.NewKeyReadWriter(path.Node, []byte("kek"), nil)
	require.NoError(t, k.Write(cert, key, nil))

	err = k.ViewAndUpdateHeaders(func(h ca.PEMKeyHeaders) (ca.PEMKeyHeaders, error) {
		require.Nil(t, h)
		return testHeaders{newHeaders: func(kek ca.KEKData) (map[string]string, error) {
			require.Equal(t, ca.KEKData{KEK: []byte("kek")}, kek)
			return map[string]string{"updated": "headers"}, nil
		}}, nil
	})
	require.NoError(t, err)

	k = ca.NewKeyReadWriter(path.Node, []byte("kek"), testHeaders{setHeaders: func(h map[string]string, k ca.KEKData) (ca.PEMKeyHeaders, error) {
		require.Equal(t, map[string]string{"updated": "headers"}, h)
		require.Equal(t, ca.KEKData{KEK: []byte("kek")}, k)
		return testHeaders{}, nil
	}})
	_, _, err = k.Read()
	require.NoError(t, err)
}
// can read and write tls keys that aren't encrypted, and that are encrypted.  without
// a pem header manager, the headers are all preserved and not overwritten
func TestKeyReadWriter(t *testing.T) {
	cert, key, err := testutils.CreateRootCertAndKey("cn")
	require.NoError(t, err)

	expectedKey := key

	tempdir, err := ioutil.TempDir("", "KeyReadWriter")
	require.NoError(t, err)
	defer os.RemoveAll(tempdir)

	path := ca.NewConfigPaths(filepath.Join(tempdir, "subdir")) // to make sure subdirectories are created

	checkCanReadWithKEK := func(kek []byte) *ca.KeyReadWriter {
		k := ca.NewKeyReadWriter(path.Node, kek, nil)
		readCert, readKey, err := k.Read()
		require.NoError(t, err)
		require.Equal(t, cert, readCert)
		require.Equal(t, expectedKey, readKey, "Expected %s, Got %s", string(expectedKey), string(readKey))
		return k
	}

	k := ca.NewKeyReadWriter(path.Node, nil, nil)

	// can't read things that don't exist
	_, _, err = k.Read()
	require.Error(t, err)

	// can write an unencrypted key with no updates
	require.NoError(t, k.Write(cert, expectedKey, nil))

	// can read unencrypted
	k = checkCanReadWithKEK(nil)
	_, kekData := k.GetCurrentState()
	require.EqualValues(t, 0, kekData.Version) // the first version was 0

	// write a key with headers to the key to make sure they're cleaned
	keyBlock, _ := pem.Decode(expectedKey)
	require.NotNil(t, keyBlock)
	keyBlock.Headers = map[string]string{"hello": "world"}
	expectedKey = pem.EncodeToMemory(keyBlock)
	// write a version, but that's not what we'd expect back once we read
	keyBlock.Headers["kek-version"] = "8"
	require.NoError(t, ioutil.WriteFile(path.Node.Key, pem.EncodeToMemory(keyBlock), 0600))

	// if a kek is provided, we can still read unencrypted keys, and read
	// the provided version
	k = checkCanReadWithKEK([]byte("original kek"))
	_, kekData = k.GetCurrentState()
	require.EqualValues(t, 8, kekData.Version)

	// we can update the kek and write at the same time
	require.NoError(t, k.Write(cert, key, &ca.KEKData{KEK: []byte("new kek!"), Version: 3}))

	// the same kek can still read, and will continue to write with this key if
	// no further kek updates are provided
	_, _, err = k.Read()
	require.NoError(t, err)
	require.NoError(t, k.Write(cert, expectedKey, nil))

	expectedKey = key

	// without the right kek, we can't read
	k = ca.NewKeyReadWriter(path.Node, []byte("original kek"), nil)
	_, _, err = k.Read()
	require.Error(t, err)

	// same new key, just for sanity
	k = checkCanReadWithKEK([]byte("new kek!"))
	_, kekData = k.GetCurrentState()
	require.EqualValues(t, 3, kekData.Version)

	// we can also change the kek back to nil, which means the key is unencrypted
	require.NoError(t, k.Write(cert, key, &ca.KEKData{KEK: nil}))
	k = checkCanReadWithKEK(nil)
	_, kekData = k.GetCurrentState()
	require.EqualValues(t, 0, kekData.Version)
}
// KeyReaderWriter makes a call to a get headers updater, if write is called,
// and set headers, if read is called.  The KEK version header is always preserved
// no matter what.
func TestKeyReadWriterWithPemHeaderManager(t *testing.T) {
	cert, key, err := testutils.CreateRootCertAndKey("cn")
	require.NoError(t, err)

	// write a key with headers to the key to make sure it gets overwritten
	keyBlock, _ := pem.Decode(key)
	require.NotNil(t, keyBlock)
	keyBlock.Headers = map[string]string{"hello": "world"}
	key = pem.EncodeToMemory(keyBlock)

	tempdir, err := ioutil.TempDir("", "KeyReadWriter")
	require.NoError(t, err)
	defer os.RemoveAll(tempdir)

	path := ca.NewConfigPaths(filepath.Join(tempdir, "subdir")) // to make sure subdirectories are created

	// if if getting new headers fail, writing a key fails, and the key does not rotate
	var count int
	badKEKData := ca.KEKData{KEK: []byte("failed kek"), Version: 3}
	k := ca.NewKeyReadWriter(path.Node, nil, testHeaders{newHeaders: func(k ca.KEKData) (map[string]string, error) {
		if count == 0 {
			count++
			require.Equal(t, badKEKData, k)
			return nil, fmt.Errorf("fail")
		}
		require.Equal(t, ca.KEKData{}, k)
		return nil, nil
	}})
	// first write will fail
	require.Error(t, k.Write(cert, key, &badKEKData))
	// the stored kek data will be not be updated because the write failed
	_, kekData := k.GetCurrentState()
	require.Equal(t, ca.KEKData{}, kekData)
	// second write will succeed, using the original kek (nil)
	require.NoError(t, k.Write(cert, key, nil))

	var (
		headers map[string]string
		kek     ca.KEKData
	)

	// if setting headers fail, reading fails
	k = ca.NewKeyReadWriter(path.Node, nil, testHeaders{setHeaders: func(map[string]string, ca.KEKData) (ca.PEMKeyHeaders, error) {
		return nil, fmt.Errorf("nope")
	}})
	_, _, err = k.Read()
	require.Error(t, err)

	k = ca.NewKeyReadWriter(path.Node, nil, testHeaders{setHeaders: func(h map[string]string, k ca.KEKData) (ca.PEMKeyHeaders, error) {
		headers = h
		kek = k
		return testHeaders{}, nil
	}})

	_, _, err = k.Read()
	require.NoError(t, err)
	require.Equal(t, ca.KEKData{}, kek)
	require.Equal(t, keyBlock.Headers, headers)

	// writing new headers is called with existing headers, and will write a key that has the headers
	// returned by the header update function
	k = ca.NewKeyReadWriter(path.Node, []byte("oldKek"), testHeaders{newHeaders: func(kek ca.KEKData) (map[string]string, error) {
		require.Equal(t, []byte("newKEK"), kek.KEK)
		return map[string]string{"updated": "headers"}, nil
	}})
	require.NoError(t, k.Write(cert, key, &ca.KEKData{KEK: []byte("newKEK"), Version: 2}))

	// make sure headers were correctly set
	k = ca.NewKeyReadWriter(path.Node, []byte("newKEK"), testHeaders{setHeaders: func(h map[string]string, k ca.KEKData) (ca.PEMKeyHeaders, error) {
		headers = h
		kek = k
		return testHeaders{}, nil
	}})
	_, _, err = k.Read()
	require.NoError(t, err)
	require.Equal(t, ca.KEKData{KEK: []byte("newKEK"), Version: 2}, kek)

	_, kekData = k.GetCurrentState()
	require.Equal(t, kek, kekData)
	require.Equal(t, map[string]string{"updated": "headers"}, headers)
}
Exemple #10
0
func TestRaftDEKManagerMaybeUpdateKEK(t *testing.T) {
	tempDir, err := ioutil.TempDir("", "manager-maybe-update-kek-")
	require.NoError(t, err)
	defer os.RemoveAll(tempDir)

	paths := ca.NewConfigPaths(tempDir)
	cert, key, err := cautils.CreateRootCertAndKey("cn")
	require.NoError(t, err)

	keys := raft.EncryptionKeys{CurrentDEK: []byte("current dek")}

	// trying to update a KEK will error if the version is the same but the kek is different
	krw := ca.NewKeyReadWriter(paths.Node, nil, RaftDEKData{EncryptionKeys: keys})
	require.NoError(t, krw.Write(cert, key, nil))
	dekManager, err := NewRaftDEKManager(krw)
	require.NoError(t, err)

	keyBytes, err := ioutil.ReadFile(paths.Node.Key)
	require.NoError(t, err)

	_, _, err = dekManager.MaybeUpdateKEK(ca.KEKData{KEK: []byte("locked now")})
	require.Error(t, err)
	require.False(t, dekManager.NeedsRotation())

	keyBytes2, err := ioutil.ReadFile(paths.Node.Key)
	require.NoError(t, err)
	require.Equal(t, keyBytes, keyBytes2)

	// trying to update a KEK from unlocked to lock will set NeedsRotation to true, as well as encrypt the TLS key
	updated, unlockedToLocked, err := dekManager.MaybeUpdateKEK(ca.KEKData{KEK: []byte("locked now"), Version: 1})
	require.NoError(t, err)
	require.True(t, updated)
	require.True(t, unlockedToLocked)
	// don't run GetKeys, because NeedsRotation is true and it'd just generate a new one
	h, _ := krw.GetCurrentState()
	dekData, ok := h.(RaftDEKData)
	require.True(t, ok)
	require.Equal(t, keys, dekData.EncryptionKeys)
	require.True(t, dekData.NeedsRotation)
	require.NotNil(t, <-dekManager.RotationNotify()) // we are notified of a new pending key

	keyBytes2, err = ioutil.ReadFile(paths.Node.Key)
	require.NoError(t, err)
	require.NotEqual(t, keyBytes, keyBytes2)
	keyBytes = keyBytes2

	readKRW := ca.NewKeyReadWriter(paths.Node, []byte("locked now"), RaftDEKData{})
	_, _, err = readKRW.Read()
	require.NoError(t, err)

	// trying to update a KEK of a lower version will not update anything, but will not error
	updated, unlockedToLocked, err = dekManager.MaybeUpdateKEK(ca.KEKData{})
	require.NoError(t, err)
	require.False(t, unlockedToLocked)
	require.False(t, updated)
	// don't run GetKeys, because NeedsRotation is true and it'd just generate a new one
	h, _ = krw.GetCurrentState()
	dekData, ok = h.(RaftDEKData)
	require.True(t, ok)
	require.Equal(t, keys, dekData.EncryptionKeys)
	require.True(t, dekData.NeedsRotation)

	keyBytes2, err = ioutil.ReadFile(paths.Node.Key)
	require.NoError(t, err)
	require.Equal(t, keyBytes, keyBytes2, string(keyBytes), string(keyBytes2))

	// updating a kek to a higher version, but with the same kek, will also neither update anything nor error
	updated, unlockedToLocked, err = dekManager.MaybeUpdateKEK(ca.KEKData{KEK: []byte("locked now"), Version: 100})
	require.NoError(t, err)
	require.False(t, unlockedToLocked)
	require.False(t, updated)
	// don't run GetKeys, because NeedsRotation is true and it'd just generate a new one
	h, _ = krw.GetCurrentState()
	dekData, ok = h.(RaftDEKData)
	require.True(t, ok)
	require.Equal(t, keys, dekData.EncryptionKeys)
	require.True(t, dekData.NeedsRotation)

	keyBytes2, err = ioutil.ReadFile(paths.Node.Key)
	require.NoError(t, err)
	require.Equal(t, keyBytes, keyBytes2)

	// going from locked to unlock does not result in the NeedsRotation flag, but does result in
	// the key being decrypted
	krw = ca.NewKeyReadWriter(paths.Node, []byte("kek"), RaftDEKData{EncryptionKeys: keys})
	require.NoError(t, krw.Write(cert, key, nil))
	dekManager, err = NewRaftDEKManager(krw)
	require.NoError(t, err)

	keyBytes, err = ioutil.ReadFile(paths.Node.Key)
	require.NoError(t, err)

	updated, unlockedToLocked, err = dekManager.MaybeUpdateKEK(ca.KEKData{Version: 2})
	require.NoError(t, err)
	require.False(t, unlockedToLocked)
	require.True(t, updated)
	require.Equal(t, keys, dekManager.GetKeys())
	require.False(t, dekManager.NeedsRotation())

	keyBytes2, err = ioutil.ReadFile(paths.Node.Key)
	require.NoError(t, err)
	require.NotEqual(t, keyBytes, keyBytes2)

	readKRW = ca.NewKeyReadWriter(paths.Node, nil, RaftDEKData{})
	_, _, err = readKRW.Read()
	require.NoError(t, err)
}
Exemple #11
0
// NeedsRotate returns true if there is a PendingDEK or a NeedsRotation flag
func TestRaftDEKManagerNeedsRotateGetKeys(t *testing.T) {
	tempDir, err := ioutil.TempDir("", "manager-maybe-get-data-")
	require.NoError(t, err)
	defer os.RemoveAll(tempDir)

	paths := ca.NewConfigPaths(tempDir)

	// if there is no PendingDEK, and no NeedsRotation flag:  NeedsRotation=false
	keys := raft.EncryptionKeys{CurrentDEK: []byte("hello")}
	dekManager, err := NewRaftDEKManager(
		ca.NewKeyReadWriter(paths.Node, nil, RaftDEKData{EncryptionKeys: keys}))
	require.NoError(t, err)

	require.False(t, dekManager.NeedsRotation())
	require.Equal(t, keys, dekManager.GetKeys())

	// if there is a PendingDEK, and no NeedsRotation flag:  NeedsRotation=true
	keys = raft.EncryptionKeys{CurrentDEK: []byte("hello"), PendingDEK: []byte("another")}
	dekManager, err = NewRaftDEKManager(
		ca.NewKeyReadWriter(paths.Node, nil, RaftDEKData{EncryptionKeys: keys}))
	require.NoError(t, err)

	require.True(t, dekManager.NeedsRotation())
	require.Equal(t, keys, dekManager.GetKeys())

	// if there is a PendingDEK, and a NeedsRotation flag:  NeedsRotation=true
	keys = raft.EncryptionKeys{CurrentDEK: []byte("hello"), PendingDEK: []byte("another")}
	dekManager, err = NewRaftDEKManager(
		ca.NewKeyReadWriter(paths.Node, nil, RaftDEKData{
			EncryptionKeys: keys,
			NeedsRotation:  true,
		}))
	require.NoError(t, err)

	require.True(t, dekManager.NeedsRotation())
	require.Equal(t, keys, dekManager.GetKeys())

	// if there no PendingDEK, and a NeedsRotation flag:  NeedsRotation=true and
	// GetKeys attempts to create a pending key and write it to disk.  However, writing
	// will error (because there is no key on disk atm), and then the original keys will
	// be returned.
	keys = raft.EncryptionKeys{CurrentDEK: []byte("hello")}
	krw := ca.NewKeyReadWriter(paths.Node, nil, RaftDEKData{
		EncryptionKeys: keys,
		NeedsRotation:  true,
	})
	dekManager, err = NewRaftDEKManager(krw)
	require.NoError(t, err)

	require.True(t, dekManager.NeedsRotation())
	require.Equal(t, keys, dekManager.GetKeys())
	h, _ := krw.GetCurrentState()
	dekData, ok := h.(RaftDEKData)
	require.True(t, ok)
	require.True(t, dekData.NeedsRotation)

	// if there no PendingDEK, and a NeedsRotation flag:  NeedsRotation=true and
	// GetKeys attempts to create a pending key and write it to disk.  If successful,
	// it returns the new keys
	keys = raft.EncryptionKeys{CurrentDEK: []byte("hello")}
	krw = ca.NewKeyReadWriter(paths.Node, nil, RaftDEKData{
		EncryptionKeys: keys,
		NeedsRotation:  true,
	})
	dekManager, err = NewRaftDEKManager(krw)

	require.NoError(t, err)
	cert, key, err := cautils.CreateRootCertAndKey("cn")
	require.NoError(t, err)
	require.NoError(t, krw.Write(cert, key, nil))

	require.True(t, dekManager.NeedsRotation())
	updatedKeys := dekManager.GetKeys()
	require.Equal(t, keys.CurrentDEK, updatedKeys.CurrentDEK)
	require.NotNil(t, updatedKeys.PendingDEK)
	require.True(t, dekManager.NeedsRotation())

	h, _ = krw.GetCurrentState()
	dekData, ok = h.(RaftDEKData)
	require.True(t, ok)
	require.False(t, dekData.NeedsRotation)
}