aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Biggers <ebiggers@google.com>2019-12-15 19:31:39 -0800
committerEric Biggers <ebiggers@google.com>2020-01-05 10:02:13 -0800
commit6ffc9457945a9484d2757cc4b01de35426502d0a (patch)
treee9838735ddb17c595123a1e30cee56fc534de4bc
parent462d166d5355d33a05271d24de4d52f30dd62f67 (diff)
keyring: support filesystem keyring with v1 encryption policies
Linux v5.4 and later allows fscrypt keys to be added/removed directly to/from the filesystem via the new ioctls FS_IOC_ADD_ENCRYPTION_KEY and FS_IOC_REMOVE_ENCRYPTION_KEY. Among other benefits, these fix the key visibility problems that many users have been running into, where system services and containers can't access encrypted files. Allow the user to opt-in to using these new ioctls for their existing encrypted directories by setting in their /etc/fscrypt.conf: "use_fs_keyring_for_v1_policies": true Note that it can't really be on by default, since for v1 policies the ioctls require root, whereas user keyrings don't. I.e., setting this to true means that users will need to use 'sudo fscrypt unlock', not 'fscrypt unlock'. v2 policies won't have this restriction.
-rw-r--r--actions/context.go13
-rw-r--r--actions/policy.go16
-rw-r--r--cmd/fscrypt/status.go18
-rw-r--r--keyring/fs_keyring.go211
-rw-r--r--keyring/keyring.go46
-rw-r--r--keyring/keyring_test.go132
-rw-r--r--keyring/user_keyring.go3
-rw-r--r--metadata/config_test.go3
-rw-r--r--metadata/metadata.pb.go131
-rw-r--r--metadata/metadata.proto1
10 files changed, 469 insertions, 105 deletions
diff --git a/actions/context.go b/actions/context.go
index 7703db5..f7e98cf 100644
--- a/actions/context.go
+++ b/actions/context.go
@@ -58,10 +58,11 @@ type Context struct {
// modified after being loaded to customise parameters.
Config *metadata.Config
// Mount is the filesystem relative to which all Protectors and Policies
- // are added, edited, removed, and applied.
+ // are added, edited, removed, and applied, and to which policies using
+ // the filesystem keyring are provisioned.
Mount *filesystem.Mount
- // TargetUser is the user for which protectors are created and to whose
- // keyring policies are provisioned.
+ // TargetUser is the user for whom protectors are created, and to whose
+ // keyring policies using the user keyring are provisioned.
TargetUser *user.User
}
@@ -148,8 +149,10 @@ func (ctx *Context) getService() string {
func (ctx *Context) getKeyringOptions() *keyring.Options {
return &keyring.Options{
- User: ctx.TargetUser,
- Service: ctx.getService(),
+ Mount: ctx.Mount,
+ User: ctx.TargetUser,
+ Service: ctx.getService(),
+ UseFsKeyringForV1Policies: ctx.Config.GetUseFsKeyringForV1Policies(),
}
}
diff --git a/actions/policy.go b/actions/policy.go
index 5bc2c5c..6ef83ce 100644
--- a/actions/policy.go
+++ b/actions/policy.go
@@ -44,8 +44,8 @@ var (
)
// PurgeAllPolicies removes all policy keys on the filesystem from the kernel
-// keyring. In order for this removal to have an effect, the filesystem should
-// also be unmounted.
+// keyring. In order for this to fully take effect, the filesystem may also need
+// to be unmounted or caches dropped.
func PurgeAllPolicies(ctx *Context) error {
if err := ctx.checkContext(); err != nil {
return err
@@ -60,6 +60,9 @@ func PurgeAllPolicies(ctx *Context) error {
switch errors.Cause(err) {
case nil, keyring.ErrKeyNotPresent:
// We don't care if the key has already been removed
+ case keyring.ErrKeyFilesOpen:
+ log.Printf("Key for policy %s couldn't be fully removed because some files are still in-use",
+ policyDescriptor)
default:
return err
}
@@ -379,6 +382,12 @@ func (policy *Policy) IsProvisioned() bool {
return policy.GetProvisioningStatus() == keyring.KeyPresent
}
+// IsFullyDeprovisioned returns true if the policy has been fully deprovisioned,
+// including all files protected by it having been closed.
+func (policy *Policy) IsFullyDeprovisioned() bool {
+ return policy.GetProvisioningStatus() == keyring.KeyAbsent
+}
+
// Provision inserts the Policy key into the kernel keyring. This allows reading
// and writing of files encrypted with this directory. Requires unlocked Policy.
func (policy *Policy) Provision() error {
@@ -390,7 +399,8 @@ func (policy *Policy) Provision() error {
}
// Deprovision removes the Policy key from the kernel keyring. This prevents
-// reading and writing to the directory once the caches are cleared.
+// reading and writing to the directory --- unless the target keyring is a user
+// keyring, in which case caches must be dropped too.
func (policy *Policy) Deprovision() error {
return keyring.RemoveEncryptionKey(policy.Descriptor(),
policy.Context.getKeyringOptions())
diff --git a/cmd/fscrypt/status.go b/cmd/fscrypt/status.go
index 375899b..3f7f577 100644
--- a/cmd/fscrypt/status.go
+++ b/cmd/fscrypt/status.go
@@ -31,6 +31,7 @@ import (
"github.com/google/fscrypt/actions"
"github.com/google/fscrypt/filesystem"
+ "github.com/google/fscrypt/keyring"
"github.com/google/fscrypt/metadata"
)
@@ -65,6 +66,19 @@ func yesNoString(b bool) string {
return "No"
}
+func policyUnlockedStatus(policy *actions.Policy) string {
+ switch policy.GetProvisioningStatus() {
+ case keyring.KeyPresent:
+ return "Yes"
+ case keyring.KeyAbsent:
+ return "No"
+ case keyring.KeyAbsentButFilesBusy:
+ return "Partially (incompletely locked)"
+ default:
+ return "Unknown"
+ }
+}
+
// writeGlobalStatus prints all the filesystems that use (or could use) fscrypt.
func writeGlobalStatus(w io.Writer) error {
mounts, err := filesystem.AllFilesystems()
@@ -160,7 +174,7 @@ func writeFilesystemStatus(w io.Writer, ctx *actions.Context) error {
continue
}
- fmt.Fprintf(t, "%s\t%s\t%s\n", descriptor, yesNoString(policy.IsProvisioned()),
+ fmt.Fprintf(t, "%s\t%s\t%s\n", descriptor, policyUnlockedStatus(policy),
strings.Join(policy.ProtectorDescriptors(), ", "))
}
return t.Flush()
@@ -180,7 +194,7 @@ func writePathStatus(w io.Writer, path string) error {
fmt.Fprintln(w)
fmt.Fprintf(w, "Policy: %s\n", policy.Descriptor())
fmt.Fprintf(w, "Options: %s\n", policy.Options())
- fmt.Fprintf(w, "Unlocked: %s\n", yesNoString(policy.IsProvisioned()))
+ fmt.Fprintf(w, "Unlocked: %s\n", policyUnlockedStatus(policy))
fmt.Fprintln(w)
options := policy.ProtectorOptions()
diff --git a/keyring/fs_keyring.go b/keyring/fs_keyring.go
new file mode 100644
index 0000000..bed23af
--- /dev/null
+++ b/keyring/fs_keyring.go
@@ -0,0 +1,211 @@
+/*
+ * fs_keyring.go - Add/remove encryption policy keys to/from filesystem
+ *
+ * Copyright 2019 Google LLC
+ * Author: Eric Biggers (ebiggers@google.com)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package keyring
+
+/*
+#include <string.h>
+*/
+import "C"
+
+import (
+ "encoding/hex"
+ "log"
+ "os"
+ "os/user"
+ "sync"
+ "unsafe"
+
+ "github.com/pkg/errors"
+ "golang.org/x/sys/unix"
+
+ "github.com/google/fscrypt/crypto"
+ "github.com/google/fscrypt/filesystem"
+)
+
+var (
+ fsKeyringSupported bool
+ fsKeyringSupportedKnown bool
+ fsKeyringSupportedLock sync.Mutex
+)
+
+func checkForFsKeyringSupport(mount *filesystem.Mount) bool {
+ dir, err := os.Open(mount.Path)
+ if err != nil {
+ log.Printf("Unexpected error opening %q. Assuming filesystem keyring is unsupported.",
+ mount.Path)
+ return false
+ }
+ defer dir.Close()
+
+ // FS_IOC_ADD_ENCRYPTION_KEY with a NULL argument will fail with ENOTTY
+ // if the ioctl isn't supported. Otherwise it should fail with EFAULT.
+ //
+ // Note that there's no need to check for FS_IOC_REMOVE_ENCRYPTION_KEY
+ // support separately, since it's guaranteed to be available if
+ // FS_IOC_ADD_ENCRYPTION_KEY is. There's also no need to check for
+ // support on every filesystem separately, since either the kernel
+ // supports the ioctls on all fscrypt-capable filesystems or it doesn't.
+ _, _, errno := unix.Syscall(unix.SYS_IOCTL, dir.Fd(), unix.FS_IOC_ADD_ENCRYPTION_KEY, 0)
+ if errno == unix.ENOTTY {
+ log.Printf("Kernel doesn't support filesystem keyring. Falling back to user keyring.")
+ return false
+ }
+ if errno == unix.EFAULT {
+ log.Printf("Detected support for filesystem keyring")
+ } else {
+ // EFAULT is expected, but as long as we didn't get ENOTTY the
+ // ioctl should be available.
+ log.Printf("Unexpected error from FS_IOC_ADD_ENCRYPTION_KEY(%q, NULL): %v", mount.Path, errno)
+ }
+ return true
+}
+
+// isFsKeyringSupported returns true if the kernel supports the ioctls to
+// add/remove fscrypt keys directly to/from the filesystem. For support to be
+// detected, the given Mount must be for a filesystem that supports fscrypt.
+func isFsKeyringSupported(mount *filesystem.Mount) bool {
+ fsKeyringSupportedLock.Lock()
+ defer fsKeyringSupportedLock.Unlock()
+ if !fsKeyringSupportedKnown {
+ fsKeyringSupported = checkForFsKeyringSupport(mount)
+ fsKeyringSupportedKnown = true
+ }
+ return fsKeyringSupported
+}
+
+// buildKeySpecifier converts the key descriptor string to an FscryptKeySpecifier.
+func buildKeySpecifier(spec *unix.FscryptKeySpecifier, descriptor string) error {
+ descriptorBytes, err := hex.DecodeString(descriptor)
+ if err != nil {
+ return errors.Errorf("key descriptor %q is invalid", descriptor)
+ }
+ switch len(descriptorBytes) {
+ case unix.FSCRYPT_KEY_DESCRIPTOR_SIZE:
+ spec.Type = unix.FSCRYPT_KEY_SPEC_TYPE_DESCRIPTOR
+ default:
+ return errors.Errorf("key descriptor %q has unknown length", descriptor)
+ }
+ copy(spec.U[:], descriptorBytes)
+ return nil
+}
+
+// fsAddEncryptionKey adds the specified encryption key to the specified filesystem.
+func fsAddEncryptionKey(key *crypto.Key, descriptor string,
+ mount *filesystem.Mount, user *user.User) error {
+
+ dir, err := os.Open(mount.Path)
+ if err != nil {
+ return err
+ }
+ defer dir.Close()
+
+ argKey, err := crypto.NewBlankKey(int(unsafe.Sizeof(unix.FscryptAddKeyArg{})) + key.Len())
+ if err != nil {
+ return err
+ }
+ defer argKey.Wipe()
+ arg := (*unix.FscryptAddKeyArg)(argKey.UnsafePtr())
+
+ if err = buildKeySpecifier(&arg.Key_spec, descriptor); err != nil {
+ return err
+ }
+
+ raw := unsafe.Pointer(uintptr(argKey.UnsafePtr()) + unsafe.Sizeof(*arg))
+ arg.Raw_size = uint32(key.Len())
+ C.memcpy(raw, key.UnsafePtr(), C.size_t(key.Len()))
+
+ _, _, errno := unix.Syscall(unix.SYS_IOCTL, dir.Fd(),
+ unix.FS_IOC_ADD_ENCRYPTION_KEY, uintptr(argKey.UnsafePtr()))
+ log.Printf("FS_IOC_ADD_ENCRYPTION_KEY(%q, %s, <raw>) = %v", mount.Path, descriptor, errno)
+ if errno != 0 {
+ return errors.Wrap(ErrKeyAdd, errno.Error())
+ }
+ return nil
+}
+
+// fsRemoveEncryptionKey removes the specified encryption key from the specified
+// filesystem.
+func fsRemoveEncryptionKey(descriptor string, mount *filesystem.Mount,
+ user *user.User) error {
+
+ dir, err := os.Open(mount.Path)
+ if err != nil {
+ return err
+ }
+ defer dir.Close()
+
+ var arg unix.FscryptRemoveKeyArg
+ if err = buildKeySpecifier(&arg.Key_spec, descriptor); err != nil {
+ return err
+ }
+
+ _, _, errno := unix.Syscall(unix.SYS_IOCTL, dir.Fd(),
+ unix.FS_IOC_REMOVE_ENCRYPTION_KEY, uintptr(unsafe.Pointer(&arg)))
+ log.Printf("FS_IOC_REMOVE_ENCRYPTION_KEY(%q, %s) = %v, removal_status_flags=0x%x",
+ mount.Path, descriptor, errno, arg.Removal_status_flags)
+ switch errno {
+ case 0:
+ if arg.Removal_status_flags&unix.FSCRYPT_KEY_REMOVAL_STATUS_FLAG_FILES_BUSY != 0 {
+ return ErrKeyFilesOpen
+ }
+ return nil
+ case unix.ENOKEY:
+ return ErrKeyNotPresent
+ default:
+ return errors.Wrap(ErrKeyRemove, errno.Error())
+ }
+}
+
+// fsGetEncryptionKeyStatus gets the status of the specified encryption key on
+// the specified filesystem.
+func fsGetEncryptionKeyStatus(descriptor string, mount *filesystem.Mount,
+ user *user.User) (KeyStatus, error) {
+
+ dir, err := os.Open(mount.Path)
+ if err != nil {
+ return KeyStatusUnknown, err
+ }
+ defer dir.Close()
+
+ var arg unix.FscryptGetKeyStatusArg
+ err = buildKeySpecifier(&arg.Key_spec, descriptor)
+ if err != nil {
+ return KeyStatusUnknown, err
+ }
+
+ _, _, errno := unix.Syscall(unix.SYS_IOCTL, dir.Fd(),
+ unix.FS_IOC_GET_ENCRYPTION_KEY_STATUS, uintptr(unsafe.Pointer(&arg)))
+ log.Printf("FS_IOC_GET_ENCRYPTION_KEY_STATUS(%q, %s) = %v, status=%d, status_flags=0x%x",
+ mount.Path, descriptor, errno, arg.Status, arg.Status_flags)
+ if errno != 0 {
+ return KeyStatusUnknown, errors.Wrap(ErrKeySearch, errno.Error())
+ }
+ switch arg.Status {
+ case unix.FSCRYPT_KEY_STATUS_ABSENT:
+ return KeyAbsent, nil
+ case unix.FSCRYPT_KEY_STATUS_PRESENT:
+ return KeyPresent, nil
+ case unix.FSCRYPT_KEY_STATUS_INCOMPLETELY_REMOVED:
+ return KeyAbsentButFilesBusy, nil
+ default:
+ return KeyStatusUnknown,
+ errors.Wrapf(ErrKeySearch, "unknown key status (%d)", arg.Status)
+ }
+}
diff --git a/keyring/keyring.go b/keyring/keyring.go
index 7a5fd64..f0bd1b7 100644
--- a/keyring/keyring.go
+++ b/keyring/keyring.go
@@ -19,7 +19,11 @@
// Package keyring manages adding, removing, and getting the status of
// encryption policy keys to/from the kernel. Most public functions are in
-// keyring.go, and they delegate to user_keyring.go.
+// keyring.go, and they delegate to either user_keyring.go or fs_keyring.go,
+// depending on whether a user keyring or a filesystem keyring is being used.
+//
+// v1 policies use the user keyring by default, but can be configured to use the
+// filesystem keyring instead (requires root and kernel v5.4+).
package keyring
import (
@@ -29,6 +33,7 @@ import (
"github.com/pkg/errors"
"github.com/google/fscrypt/crypto"
+ "github.com/google/fscrypt/filesystem"
"github.com/google/fscrypt/metadata"
"github.com/google/fscrypt/util"
)
@@ -38,6 +43,7 @@ var (
ErrKeyAdd = util.SystemError("could not add key to the keyring")
ErrKeyRemove = util.SystemError("could not remove key from the keyring")
ErrKeyNotPresent = errors.New("key not present or already removed")
+ ErrKeyFilesOpen = errors.New("some files using the key are still open")
ErrKeySearch = errors.New("could not find key with descriptor")
ErrSessionUserKeying = errors.New("user keyring not linked into session keyring")
ErrAccessUserKeyring = errors.New("could not access user keyring")
@@ -47,22 +53,47 @@ var (
// Options are the options which specify *which* keyring the key should be
// added/removed/gotten to, and how.
type Options struct {
+ // Mount is the filesystem to which the key should be
+ // added/removed/gotten.
+ Mount *filesystem.Mount
// User is the user for whom the key should be added/removed/gotten.
User *user.User
- // Service is the prefix to prepend to the description of the keys.
+ // Service is the prefix to prepend to the description of the keys in
+ // user keyrings. Not relevant for filesystem keyrings.
Service string
+ // UseFsKeyringForV1Policies is true if keys for v1 encryption policies
+ // should be put in the filesystem's keyring (if supported) rather than
+ // in the user's keyring. Note that this makes AddEncryptionKey and
+ // RemoveEncryptionKey require root privileges.
+ UseFsKeyringForV1Policies bool
}
-// AddEncryptionKey adds an encryption policy key to a kernel keyring.
+func shouldUseFsKeyring(descriptor string, options *Options) bool {
+ // Use the filesystem keyring if use_fs_keyring_for_v1_policies is set
+ // in /etc/fscrypt.conf and the kernel supports it.
+ return options.UseFsKeyringForV1Policies && isFsKeyringSupported(options.Mount)
+}
+
+// AddEncryptionKey adds an encryption policy key to a kernel keyring. It uses
+// either the filesystem keyring for the target Mount or the user keyring for
+// the target User.
func AddEncryptionKey(key *crypto.Key, descriptor string, options *Options) error {
if err := util.CheckValidLength(metadata.PolicyKeyLen, key.Len()); err != nil {
return errors.Wrap(err, "policy key")
}
+ if shouldUseFsKeyring(descriptor, options) {
+ return fsAddEncryptionKey(key, descriptor, options.Mount, options.User)
+ }
return userAddKey(key, options.Service+descriptor, options.User)
}
// RemoveEncryptionKey removes an encryption policy key from a kernel keyring.
+// It uses either the filesystem keyring for the target Mount or the user
+// keyring for the target User.
func RemoveEncryptionKey(descriptor string, options *Options) error {
+ if shouldUseFsKeyring(descriptor, options) {
+ return fsRemoveEncryptionKey(descriptor, options.Mount, options.User)
+ }
return userRemoveKey(options.Service+descriptor, options.User)
}
@@ -73,6 +104,7 @@ type KeyStatus int
const (
KeyStatusUnknown = 0 + iota
KeyAbsent
+ KeyAbsentButFilesBusy
KeyPresent
)
@@ -82,6 +114,8 @@ func (status KeyStatus) String() string {
return "Unknown"
case KeyAbsent:
return "Absent"
+ case KeyAbsentButFilesBusy:
+ return "AbsentButFilesBusy"
case KeyPresent:
return "Present"
default:
@@ -90,8 +124,12 @@ func (status KeyStatus) String() string {
}
// GetEncryptionKeyStatus gets the status of an encryption policy key in a
-// kernel keyring.
+// kernel keyring. It uses either the filesystem keyring for the target Mount
+// or the user keyring for the target User.
func GetEncryptionKeyStatus(descriptor string, options *Options) (KeyStatus, error) {
+ if shouldUseFsKeyring(descriptor, options) {
+ return fsGetEncryptionKeyStatus(descriptor, options.Mount, options.User)
+ }
_, err := userFindKey(options.Service+descriptor, options.User)
if err != nil {
return KeyAbsent, nil
diff --git a/keyring/keyring_test.go b/keyring/keyring_test.go
index 10ff874..9a4570b 100644
--- a/keyring/keyring_test.go
+++ b/keyring/keyring_test.go
@@ -24,6 +24,7 @@ import (
"golang.org/x/sys/unix"
"github.com/google/fscrypt/crypto"
+ "github.com/google/fscrypt/filesystem"
"github.com/google/fscrypt/metadata"
"github.com/google/fscrypt/util"
)
@@ -44,52 +45,125 @@ func makeKey(b byte, n int) (*crypto.Key, error) {
}
var (
- fakeValidDescriptor = "0123456789abcdef"
defaultService = unix.FSCRYPT_KEY_DESC_PREFIX
testUser, _ = util.EffectiveUser()
fakeValidPolicyKey, _ = makeKey(42, metadata.PolicyKeyLen)
fakeInvalidPolicyKey, _ = makeKey(42, metadata.PolicyKeyLen-1)
+ fakeV1Descriptor = "0123456789abcdef"
)
-// Adds and removes a key with various services.
-func TestAddRemoveKeys(t *testing.T) {
- for _, service := range []string{defaultService, "ext4:", "f2fs:"} {
- options := &Options{
- User: testUser,
- Service: service,
- }
- if err := AddEncryptionKey(fakeValidPolicyKey, fakeValidDescriptor, options); err != nil {
- t.Error(err)
- }
- if err := RemoveEncryptionKey(fakeValidDescriptor, options); err != nil {
- t.Error(err)
- }
+func assertKeyStatus(t *testing.T, descriptor string, options *Options,
+ expectedStatus KeyStatus) {
+ status, err := GetEncryptionKeyStatus(descriptor, options)
+ if err != nil {
+ t.Error(err)
+ }
+ if status != expectedStatus {
+ t.Errorf("Expected key status %v but got key status %v", expectedStatus, status)
}
}
-// Adds a key twice (both should succeed)
-func TestAddTwice(t *testing.T) {
- options := &Options{
- User: testUser,
- Service: defaultService,
+// getTestMount retrieves the Mount for a test filesystem, or skips the test if
+// no test filesystem is available.
+func getTestMount(t *testing.T) *filesystem.Mount {
+ root, err := util.TestRoot()
+ if err != nil {
+ t.Skip(err)
+ }
+ mount, err := filesystem.GetMount(root)
+ if err != nil {
+ t.Skip(err)
+ }
+ return mount
+}
+
+// getTestMountV2 is like getTestMount, but it also checks that the filesystem
+// keyring is supported.
+func getTestMountV2(t *testing.T) *filesystem.Mount {
+ mount := getTestMount(t)
+ if !isFsKeyringSupported(mount) {
+ t.Skip("No support for fs keyring, skipping test.")
+ }
+ return mount
+}
+
+func requireRoot(t *testing.T) {
+ if !util.IsUserRoot() {
+ t.Skip("Not root, skipping test.")
}
- if err := AddEncryptionKey(fakeValidPolicyKey, fakeValidDescriptor, options); err != nil {
+}
+
+// testAddAndRemoveKey does the common tests for adding+removing keys that are
+// run in multiple configurations (v1 policies with user keyring and v1 policies
+// with fs keyring).
+func testAddAndRemoveKey(t *testing.T, descriptor string, options *Options) {
+
+ // Basic add, get status, and remove
+ if err := AddEncryptionKey(fakeValidPolicyKey, descriptor, options); err != nil {
t.Error(err)
}
- if err := AddEncryptionKey(fakeValidPolicyKey, fakeValidDescriptor, options); err != nil {
+ assertKeyStatus(t, descriptor, options, KeyPresent)
+ if err := RemoveEncryptionKey(descriptor, options); err != nil {
+ t.Error(err)
+ }
+ assertKeyStatus(t, descriptor, options, KeyAbsent)
+ err := RemoveEncryptionKey(descriptor, options)
+ if err != ErrKeyNotPresent {
+ t.Error(err)
+ }
+
+ // Adding a key twice should succeed
+ if err := AddEncryptionKey(fakeValidPolicyKey, descriptor, options); err != nil {
+ t.Error(err)
+ }
+ if err := AddEncryptionKey(fakeValidPolicyKey, descriptor, options); err != nil {
t.Error("AddEncryptionKey should not fail if key already exists")
}
- RemoveEncryptionKey(fakeValidDescriptor, options)
+ RemoveEncryptionKey(descriptor, options)
+ assertKeyStatus(t, descriptor, options, KeyAbsent)
+
+ // Adding a key with wrong length should fail
+ if err := AddEncryptionKey(fakeInvalidPolicyKey, descriptor, options); err == nil {
+ RemoveEncryptionKey(descriptor, options)
+ t.Error("AddEncryptionKey should fail with wrong-length key")
+ }
+ assertKeyStatus(t, descriptor, options, KeyAbsent)
}
-// Makes sure trying to add a key of the wrong length fails
-func TestAddWrongLengthKey(t *testing.T) {
+func TestUserKeyringDefaultService(t *testing.T) {
options := &Options{
- User: testUser,
- Service: defaultService,
+ User: testUser,
+ Service: defaultService,
+ UseFsKeyringForV1Policies: false,
}
- if err := AddEncryptionKey(fakeInvalidPolicyKey, fakeValidDescriptor, options); err == nil {
- RemoveEncryptionKey(fakeValidDescriptor, options)
- t.Error("AddEncryptionKey should fail with wrong-length key")
+ testAddAndRemoveKey(t, fakeV1Descriptor, options)
+}
+
+func TestUserKeyringExt4Service(t *testing.T) {
+ options := &Options{
+ User: testUser,
+ Service: "ext4:",
+ UseFsKeyringForV1Policies: false,
+ }
+ testAddAndRemoveKey(t, fakeV1Descriptor, options)
+}
+
+func TestUserKeyringF2fsService(t *testing.T) {
+ options := &Options{
+ User: testUser,
+ Service: "f2fs:",
+ UseFsKeyringForV1Policies: false,
+ }
+ testAddAndRemoveKey(t, fakeV1Descriptor, options)
+}
+
+func TestFsKeyringV1PolicyKey(t *testing.T) {
+ requireRoot(t)
+ mount := getTestMountV2(t)
+ options := &Options{
+ Mount: mount,
+ User: testUser,
+ UseFsKeyringForV1Policies: true,
}
+ testAddAndRemoveKey(t, fakeV1Descriptor, options)
}
diff --git a/keyring/user_keyring.go b/keyring/user_keyring.go
index adac71a..71f519d 100644
--- a/keyring/user_keyring.go
+++ b/keyring/user_keyring.go
@@ -1,5 +1,6 @@
/*
- * user_keyring.go - Add/remove encryption policy keys to/from user keyrings
+ * user_keyring.go - Add/remove encryption policy keys to/from user keyrings.
+ * This is the deprecated mechanism; see fs_keyring.go for the new mechanism.
*
* Copyright 2017 Google Inc.
* Author: Joe Richey (joerichey@google.com)
diff --git a/metadata/config_test.go b/metadata/config_test.go
index d184a87..3c20c51 100644
--- a/metadata/config_test.go
+++ b/metadata/config_test.go
@@ -49,7 +49,8 @@ var testConfigString = `{
"padding": "32",
"contents": "AES_256_XTS",
"filenames": "AES_256_CTS"
- }
+ },
+ "use_fs_keyring_for_v1_policies": false
}
`
diff --git a/metadata/metadata.pb.go b/metadata/metadata.pb.go
index bd3ee2a..aa4eeff 100644
--- a/metadata/metadata.pb.go
+++ b/metadata/metadata.pb.go
@@ -45,7 +45,7 @@ func (x SourceType) String() string {
return proto.EnumName(SourceType_name, int32(x))
}
func (SourceType) EnumDescriptor() ([]byte, []int) {
- return fileDescriptor_metadata_fa046c95c3cd6aa1, []int{0}
+ return fileDescriptor_metadata_ff272c42a9f0f3d3, []int{0}
}
// Type of encryption; should match declarations of unix.FSCRYPT_MODE
@@ -87,7 +87,7 @@ func (x EncryptionOptions_Mode) String() string {
return proto.EnumName(EncryptionOptions_Mode_name, int32(x))
}
func (EncryptionOptions_Mode) EnumDescriptor() ([]byte, []int) {
- return fileDescriptor_metadata_fa046c95c3cd6aa1, []int{3, 0}
+ return fileDescriptor_metadata_ff272c42a9f0f3d3, []int{3, 0}
}
// Cost parameters to be used in our hashing functions.
@@ -104,7 +104,7 @@ func (m *HashingCosts) Reset() { *m = HashingCosts{} }
func (m *HashingCosts) String() string { return proto.CompactTextString(m) }
func (*HashingCosts) ProtoMessage() {}
func (*HashingCosts) Descriptor() ([]byte, []int) {
- return fileDescriptor_metadata_fa046c95c3cd6aa1, []int{0}
+ return fileDescriptor_metadata_ff272c42a9f0f3d3, []int{0}
}
func (m *HashingCosts) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_HashingCosts.Unmarshal(m, b)
@@ -159,7 +159,7 @@ func (m *WrappedKeyData) Reset() { *m = WrappedKeyData{} }
func (m *WrappedKeyData) String() string { return proto.CompactTextString(m) }
func (*WrappedKeyData) ProtoMessage() {}
func (*WrappedKeyData) Descriptor() ([]byte, []int) {
- return fileDescriptor_metadata_fa046c95c3cd6aa1, []int{1}
+ return fileDescriptor_metadata_ff272c42a9f0f3d3, []int{1}
}
func (m *WrappedKeyData) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_WrappedKeyData.Unmarshal(m, b)
@@ -219,7 +219,7 @@ func (m *ProtectorData) Reset() { *m = ProtectorData{} }
func (m *ProtectorData) String() string { return proto.CompactTextString(m) }
func (*ProtectorData) ProtoMessage() {}
func (*ProtectorData) Descriptor() ([]byte, []int) {
- return fileDescriptor_metadata_fa046c95c3cd6aa1, []int{2}
+ return fileDescriptor_metadata_ff272c42a9f0f3d3, []int{2}
}
func (m *ProtectorData) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ProtectorData.Unmarshal(m, b)
@@ -302,7 +302,7 @@ func (m *EncryptionOptions) Reset() { *m = EncryptionOptions{} }
func (m *EncryptionOptions) String() string { return proto.CompactTextString(m) }
func (*EncryptionOptions) ProtoMessage() {}
func (*EncryptionOptions) Descriptor() ([]byte, []int) {
- return fileDescriptor_metadata_fa046c95c3cd6aa1, []int{3}
+ return fileDescriptor_metadata_ff272c42a9f0f3d3, []int{3}
}
func (m *EncryptionOptions) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_EncryptionOptions.Unmarshal(m, b)
@@ -355,7 +355,7 @@ func (m *WrappedPolicyKey) Reset() { *m = WrappedPolicyKey{} }
func (m *WrappedPolicyKey) String() string { return proto.CompactTextString(m) }
func (*WrappedPolicyKey) ProtoMessage() {}
func (*WrappedPolicyKey) Descriptor() ([]byte, []int) {
- return fileDescriptor_metadata_fa046c95c3cd6aa1, []int{4}
+ return fileDescriptor_metadata_ff272c42a9f0f3d3, []int{4}
}
func (m *WrappedPolicyKey) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_WrappedPolicyKey.Unmarshal(m, b)
@@ -403,7 +403,7 @@ func (m *PolicyData) Reset() { *m = PolicyData{} }
func (m *PolicyData) String() string { return proto.CompactTextString(m) }
func (*PolicyData) ProtoMessage() {}
func (*PolicyData) Descriptor() ([]byte, []int) {
- return fileDescriptor_metadata_fa046c95c3cd6aa1, []int{5}
+ return fileDescriptor_metadata_ff272c42a9f0f3d3, []int{5}
}
func (m *PolicyData) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_PolicyData.Unmarshal(m, b)
@@ -446,20 +446,21 @@ func (m *PolicyData) GetWrappedPolicyKeys() []*WrappedPolicyKey {
// Data stored in the config file
type Config struct {
- Source SourceType `protobuf:"varint,1,opt,name=source,proto3,enum=metadata.SourceType" json:"source,omitempty"`
- HashCosts *HashingCosts `protobuf:"bytes,2,opt,name=hash_costs,json=hashCosts,proto3" json:"hash_costs,omitempty"`
- Compatibility string `protobuf:"bytes,3,opt,name=compatibility,proto3" json:"compatibility,omitempty"`
- Options *EncryptionOptions `protobuf:"bytes,4,opt,name=options,proto3" json:"options,omitempty"`
- XXX_NoUnkeyedLiteral struct{} `json:"-"`
- XXX_unrecognized []byte `json:"-"`
- XXX_sizecache int32 `json:"-"`
+ Source SourceType `protobuf:"varint,1,opt,name=source,proto3,enum=metadata.SourceType" json:"source,omitempty"`
+ HashCosts *HashingCosts `protobuf:"bytes,2,opt,name=hash_costs,json=hashCosts,proto3" json:"hash_costs,omitempty"`
+ Compatibility string `protobuf:"bytes,3,opt,name=compatibility,proto3" json:"compatibility,omitempty"`
+ Options *EncryptionOptions `protobuf:"bytes,4,opt,name=options,proto3" json:"options,omitempty"`
+ UseFsKeyringForV1Policies bool `protobuf:"varint,5,opt,name=use_fs_keyring_for_v1_policies,json=useFsKeyringForV1Policies,proto3" json:"use_fs_keyring_for_v1_policies,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
}
func (m *Config) Reset() { *m = Config{} }
func (m *Config) String() string { return proto.CompactTextString(m) }
func (*Config) ProtoMessage() {}
func (*Config) Descriptor() ([]byte, []int) {
- return fileDescriptor_metadata_fa046c95c3cd6aa1, []int{6}
+ return fileDescriptor_metadata_ff272c42a9f0f3d3, []int{6}
}
func (m *Config) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Config.Unmarshal(m, b)
@@ -507,6 +508,13 @@ func (m *Config) GetOptions() *EncryptionOptions {
return nil
}
+func (m *Config) GetUseFsKeyringForV1Policies() bool {
+ if m != nil {
+ return m.UseFsKeyringForV1Policies
+ }
+ return false
+}
+
func init() {
proto.RegisterType((*HashingCosts)(nil), "metadata.HashingCosts")
proto.RegisterType((*WrappedKeyData)(nil), "metadata.WrappedKeyData")
@@ -519,49 +527,52 @@ func init() {
proto.RegisterEnum("metadata.EncryptionOptions_Mode", EncryptionOptions_Mode_name, EncryptionOptions_Mode_value)
}
-func init() { proto.RegisterFile("metadata/metadata.proto", fileDescriptor_metadata_fa046c95c3cd6aa1) }
+func init() { proto.RegisterFile("metadata/metadata.proto", fileDescriptor_metadata_ff272c42a9f0f3d3) }
-var fileDescriptor_metadata_fa046c95c3cd6aa1 = []byte{
- // 656 bytes of a gzipped FileDescriptorProto
- 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x94, 0xef, 0x6a, 0xdb, 0x3c,
- 0x14, 0xc6, 0x5f, 0xdb, 0x69, 0xd2, 0x9c, 0xfc, 0x79, 0x5d, 0xb5, 0x6f, 0x5f, 0xb3, 0x7d, 0x09,
- 0xde, 0x06, 0x65, 0x94, 0x8e, 0x66, 0x74, 0x6c, 0x30, 0x06, 0x5d, 0x5a, 0xb6, 0xae, 0x94, 0x75,
- 0x4a, 0xe8, 0x36, 0x18, 0x04, 0xd5, 0x56, 0x1b, 0x51, 0xdb, 0x12, 0x96, 0x42, 0xf0, 0xb7, 0x7d,
- 0xdb, 0x05, 0xec, 0x5a, 0xb6, 0x8b, 0xd8, 0x55, 0x0d, 0xc9, 0xb1, 0xe3, 0xb4, 0x50, 0xba, 0x7d,
- 0x31, 0x47, 0x8f, 0xa4, 0xf3, 0x1c, 0xfd, 0xa4, 0x63, 0xf8, 0x3f, 0xa6, 0x8a, 0x84, 0x44, 0x91,
- 0x27, 0x45, 0xb0, 0x23, 0x52, 0xae, 0x38, 0x5a, 0x2d, 0xc6, 0xfe, 0x17, 0x68, 0xbf, 0x25, 0x72,
- 0xc2, 0x92, 0xcb, 0x01, 0x97, 0x4a, 0x22, 0x04, 0x35, 0xc5, 0x62, 0xea, 0xd9, 0x3d, 0x6b, 0xcb,
- 0xc1, 0x26, 0x46, 0x9b, 0x50, 0x8f, 0x69, 0xcc, 0xd3, 0xcc, 0x73, 0x8c, 0x3a, 0x1f, 0xa1, 0x1e,
- 0xb4, 0x04, 0x49, 0x49, 0x14, 0xd1, 0x88, 0xc9, 0xd8, 0xab, 0x99, 0xc9, 0xaa, 0xe4, 0x7f, 0x86,
- 0xee, 0xc7, 0x94, 0x08, 0x41, 0xc3, 0x63, 0x9a, 0x1d, 0x10, 0x45, 0x50, 0x17, 0xec, 0xa3, 0x33,
- 0xcf, 0xea, 0x59, 0x5b, 0x6d, 0x6c, 0x1f, 0x9d, 0xa1, 0x07, 0xd0, 0xa1, 0x49, 0x90, 0x66, 0x42,
- 0xd1, 0x70, 0x7c, 0x45, 0x33, 0x63, 0xdc, 0xc6, 0xed, 0x52, 0x3c, 0xa6, 0x99, 0x2e, 0x6a, 0x12,
- 0x93, 0xc0, 0xd8, 0xb7, 0xb1, 0x89, 0xfd, 0xef, 0x36, 0x74, 0x4e, 0x53, 0xae, 0x68, 0xa0, 0x78,
- 0x6a, 0x52, 0xef, 0xc2, 0x86, 0x28, 0x84, 0x71, 0x48, 0x65, 0x90, 0x32, 0xa1, 0x78, 0x6a, 0xcc,
- 0x9a, 0x78, 0xbd, 0x9c, 0x3b, 0x28, 0xa7, 0xd0, 0x36, 0xd4, 0x25, 0x9f, 0xa6, 0x41, 0x7e, 0xde,
- 0x6e, 0x7f, 0x63, 0xa7, 0x04, 0x35, 0x34, 0xfa, 0x28, 0x13, 0x14, 0xcf, 0xd7, 0xe8, 0x32, 0x12,
- 0x12, 0x53, 0x53, 0x46, 0x13, 0x9b, 0x18, 0x6d, 0xc3, 0x4a, 0xa0, 0xc1, 0x99, 0xd3, 0xb7, 0xfa,
- 0x9b, 0x8b, 0x04, 0x55, 0xac, 0x38, 0x5f, 0xa4, 0x33, 0x48, 0x12, 0x29, 0x6f, 0x25, 0x3f, 0x88,
- 0x8e, 0x91, 0x0b, 0xce, 0x94, 0x85, 0x5e, 0xdd, 0xd0, 0xd3, 0x21, 0x7a, 0x01, 0xad, 0x59, 0x4e,
- 0xcd, 0x10, 0x69, 0x98, 0xcc, 0xde, 0x22, 0xf3, 0x32, 0x52, 0x0c, 0xb3, 0x72, 0xec, 0xff, 0xb0,
- 0x61, 0xed, 0x30, 0x47, 0xc7, 0x78, 0xf2, 0xde, 0x7c, 0x25, 0xf2, 0xa0, 0x21, 0x48, 0x18, 0xb2,
- 0xe4, 0xd2, 0xc0, 0x70, 0x70, 0x31, 0x44, 0x2f, 0x61, 0x35, 0xe0, 0x89, 0xa2, 0x89, 0x92, 0x73,
- 0x04, 0xbd, 0x85, 0xcf, 0x8d, 0x44, 0x3b, 0x27, 0x3c, 0xa4, 0xb8, 0xdc, 0x81, 0x5e, 0x41, 0xf3,
- 0x82, 0x45, 0x54, 0x83, 0x90, 0x86, 0xca, 0x5d, 0xb6, 0x2f, 0xb6, 0xf8, 0xdf, 0x2c, 0xa8, 0x69,
- 0x0d, 0xb5, 0xa0, 0x11, 0xd2, 0x0b, 0x32, 0x8d, 0x94, 0xfb, 0x0f, 0xfa, 0x17, 0x5a, 0xfb, 0x87,
- 0xc3, 0x71, 0x7f, 0xef, 0xd9, 0xf8, 0xd3, 0x68, 0xe8, 0x5a, 0x55, 0xe1, 0xcd, 0xe0, 0xc4, 0xb5,
- 0xab, 0xc2, 0xe0, 0xf5, 0xc0, 0x75, 0x96, 0x84, 0xd1, 0xd0, 0xad, 0x15, 0xc2, 0x6e, 0xff, 0xb9,
- 0x59, 0xb1, 0xb2, 0x24, 0x8c, 0x86, 0x6e, 0x1d, 0xb5, 0x61, 0x75, 0x3f, 0x64, 0x24, 0x51, 0xd3,
- 0xd8, 0x6d, 0xfa, 0x5f, 0x2d, 0x70, 0xe7, 0x58, 0x4f, 0x79, 0xc4, 0x82, 0x4c, 0x3f, 0xbb, 0xbf,
- 0x78, 0x50, 0xd7, 0xae, 0xce, 0xfe, 0x83, 0xab, 0xfb, 0x69, 0x01, 0xe4, 0xde, 0xe6, 0x35, 0x3f,
- 0x82, 0xee, 0x15, 0xcd, 0x6e, 0xda, 0x76, 0xae, 0x68, 0x56, 0x31, 0xdc, 0x83, 0x06, 0xcf, 0xe9,
- 0xce, 0xcd, 0xee, 0xdf, 0x72, 0x01, 0xb8, 0x58, 0x8b, 0xde, 0xc1, 0x7a, 0x51, 0xa7, 0x30, 0x9e,
- 0xba, 0x5c, 0x7d, 0x87, 0xce, 0x56, 0xab, 0x7f, 0xef, 0x46, 0xbd, 0x25, 0x13, 0xbc, 0x36, 0xbb,
- 0xa6, 0x48, 0xff, 0x97, 0x05, 0xf5, 0x01, 0x4f, 0x2e, 0xd8, 0x65, 0xa5, 0x9f, 0xac, 0x3b, 0xf4,
- 0xd3, 0x1e, 0xc0, 0x84, 0xc8, 0xc9, 0x38, 0x6f, 0x20, 0xfb, 0xd6, 0x06, 0x6a, 0xea, 0x95, 0xf9,
- 0x2f, 0xea, 0x21, 0x74, 0x02, 0x1e, 0x0b, 0xa2, 0xd8, 0x39, 0x8b, 0x98, 0xca, 0xe6, 0xfd, 0xb8,
- 0x2c, 0x56, 0xc1, 0xd4, 0xee, 0x0e, 0xe6, 0xf1, 0x07, 0x80, 0x45, 0xa5, 0xcb, 0xef, 0x12, 0x41,
- 0x57, 0x90, 0x78, 0x2c, 0x88, 0x94, 0x62, 0x92, 0x12, 0x49, 0x5d, 0x0b, 0xfd, 0x07, 0x6b, 0xc1,
- 0x54, 0x2a, 0xbe, 0x24, 0xdb, 0x7a, 0x5f, 0x4a, 0x66, 0x9a, 0xa9, 0xeb, 0x9c, 0xd7, 0xcd, 0x3f,
- 0xf7, 0xe9, 0xef, 0x00, 0x00, 0x00, 0xff, 0xff, 0x4b, 0xbe, 0x84, 0xbc, 0x8e, 0x05, 0x00, 0x00,
+var fileDescriptor_metadata_ff272c42a9f0f3d3 = []byte{
+ // 693 bytes of a gzipped FileDescriptorProto
+ 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x94, 0xdf, 0x6b, 0x13, 0x41,
+ 0x10, 0xc7, 0xbd, 0x4b, 0x9a, 0x1f, 0x93, 0x1f, 0x5e, 0xb7, 0xb5, 0x9e, 0x0a, 0x12, 0xa2, 0x42,
+ 0x91, 0x52, 0x49, 0xa4, 0xa2, 0x20, 0x42, 0x4d, 0x5b, 0xad, 0xa5, 0x58, 0x2f, 0xa1, 0x2a, 0x08,
+ 0xc7, 0xf6, 0x6e, 0x93, 0x2c, 0xbd, 0xbb, 0x5d, 0x76, 0x37, 0x86, 0x7b, 0xf3, 0xcd, 0x27, 0x9f,
+ 0xfc, 0x5b, 0xf4, 0xef, 0x93, 0xdd, 0xcb, 0xcf, 0x16, 0x4a, 0xeb, 0xcb, 0x31, 0xfb, 0xdd, 0xd9,
+ 0x99, 0xd9, 0xcf, 0xce, 0x1c, 0xdc, 0x8d, 0x89, 0xc2, 0x21, 0x56, 0xf8, 0xd9, 0xd4, 0xd8, 0xe6,
+ 0x82, 0x29, 0x86, 0x4a, 0xd3, 0x75, 0xf3, 0x1b, 0x54, 0xdf, 0x63, 0x39, 0xa4, 0xc9, 0xa0, 0xc3,
+ 0xa4, 0x92, 0x08, 0x41, 0x5e, 0xd1, 0x98, 0xb8, 0x76, 0xc3, 0xda, 0xcc, 0x79, 0xc6, 0x46, 0x1b,
+ 0x50, 0x88, 0x49, 0xcc, 0x44, 0xea, 0xe6, 0x8c, 0x3a, 0x59, 0xa1, 0x06, 0x54, 0x38, 0x16, 0x38,
+ 0x8a, 0x48, 0x44, 0x65, 0xec, 0xe6, 0xcd, 0xe6, 0xa2, 0xd4, 0xfc, 0x0a, 0xf5, 0xcf, 0x02, 0x73,
+ 0x4e, 0xc2, 0x23, 0x92, 0xee, 0x61, 0x85, 0x51, 0x1d, 0xec, 0xc3, 0x53, 0xd7, 0x6a, 0x58, 0x9b,
+ 0x55, 0xcf, 0x3e, 0x3c, 0x45, 0x8f, 0xa0, 0x46, 0x92, 0x40, 0xa4, 0x5c, 0x91, 0xd0, 0x3f, 0x27,
+ 0xa9, 0x49, 0x5c, 0xf5, 0xaa, 0x33, 0xf1, 0x88, 0xa4, 0xba, 0xa8, 0x61, 0x8c, 0x03, 0x93, 0xbe,
+ 0xea, 0x19, 0xbb, 0xf9, 0xdb, 0x86, 0xda, 0x89, 0x60, 0x8a, 0x04, 0x8a, 0x09, 0x13, 0xba, 0x05,
+ 0xeb, 0x7c, 0x2a, 0xf8, 0x21, 0x91, 0x81, 0xa0, 0x5c, 0x31, 0x61, 0x92, 0x95, 0xbd, 0xb5, 0xd9,
+ 0xde, 0xde, 0x6c, 0x0b, 0x6d, 0x41, 0x41, 0xb2, 0x91, 0x08, 0xb2, 0xfb, 0xd6, 0xdb, 0xeb, 0xdb,
+ 0x33, 0x50, 0x5d, 0xa3, 0xf7, 0x52, 0x4e, 0xbc, 0x89, 0x8f, 0x2e, 0x23, 0xc1, 0x31, 0x31, 0x65,
+ 0x94, 0x3d, 0x63, 0xa3, 0x2d, 0x58, 0x09, 0x34, 0x38, 0x73, 0xfb, 0x4a, 0x7b, 0x63, 0x1e, 0x60,
+ 0x11, 0xab, 0x97, 0x39, 0xe9, 0x08, 0x12, 0x47, 0xca, 0x5d, 0xc9, 0x2e, 0xa2, 0x6d, 0xe4, 0x40,
+ 0x6e, 0x44, 0x43, 0xb7, 0x60, 0xe8, 0x69, 0x13, 0xbd, 0x82, 0xca, 0x38, 0xa3, 0x66, 0x88, 0x14,
+ 0x4d, 0x64, 0x77, 0x1e, 0x79, 0x19, 0xa9, 0x07, 0xe3, 0xd9, 0xba, 0xf9, 0xc7, 0x86, 0xd5, 0xfd,
+ 0x0c, 0x1d, 0x65, 0xc9, 0x47, 0xf3, 0x95, 0xc8, 0x85, 0x22, 0xc7, 0x61, 0x48, 0x93, 0x81, 0x81,
+ 0x91, 0xf3, 0xa6, 0x4b, 0xf4, 0x1a, 0x4a, 0x01, 0x4b, 0x14, 0x49, 0x94, 0x9c, 0x20, 0x68, 0xcc,
+ 0xf3, 0x5c, 0x0a, 0xb4, 0x7d, 0xcc, 0x42, 0xe2, 0xcd, 0x4e, 0xa0, 0x37, 0x50, 0xee, 0xd3, 0x88,
+ 0x68, 0x10, 0xd2, 0x50, 0xb9, 0xce, 0xf1, 0xf9, 0x91, 0xe6, 0x4f, 0x0b, 0xf2, 0x5a, 0x43, 0x15,
+ 0x28, 0x86, 0xa4, 0x8f, 0x47, 0x91, 0x72, 0x6e, 0xa1, 0xdb, 0x50, 0xd9, 0xdd, 0xef, 0xfa, 0xed,
+ 0x9d, 0x17, 0xfe, 0x97, 0x5e, 0xd7, 0xb1, 0x16, 0x85, 0x77, 0x9d, 0x63, 0xc7, 0x5e, 0x14, 0x3a,
+ 0x6f, 0x3b, 0x4e, 0x6e, 0x49, 0xe8, 0x75, 0x9d, 0xfc, 0x54, 0x68, 0xb5, 0x5f, 0x1a, 0x8f, 0x95,
+ 0x25, 0xa1, 0xd7, 0x75, 0x0a, 0xa8, 0x0a, 0xa5, 0xdd, 0x90, 0xe2, 0x44, 0x8d, 0x62, 0xa7, 0xdc,
+ 0xfc, 0x61, 0x81, 0x33, 0xc1, 0x7a, 0xc2, 0x22, 0x1a, 0xa4, 0xba, 0xed, 0xfe, 0xa3, 0xa1, 0x2e,
+ 0x3c, 0x9d, 0x7d, 0x83, 0xa7, 0xfb, 0x6b, 0x01, 0x64, 0xb9, 0x4d, 0x37, 0x3f, 0x81, 0xfa, 0x39,
+ 0x49, 0x2f, 0xa7, 0xad, 0x9d, 0x93, 0x74, 0x21, 0xe1, 0x0e, 0x14, 0x59, 0x46, 0x77, 0x92, 0xec,
+ 0xc1, 0x15, 0x0f, 0xe0, 0x4d, 0x7d, 0xd1, 0x07, 0x58, 0x9b, 0xd6, 0xc9, 0x4d, 0x4e, 0x5d, 0xae,
+ 0x7e, 0xc3, 0xdc, 0x66, 0xa5, 0x7d, 0xff, 0x52, 0xbd, 0x33, 0x26, 0xde, 0xea, 0xf8, 0x82, 0x22,
+ 0x9b, 0xbf, 0x6c, 0x28, 0x74, 0x58, 0xd2, 0xa7, 0x83, 0x85, 0x79, 0xb2, 0xae, 0x31, 0x4f, 0x3b,
+ 0x00, 0x43, 0x2c, 0x87, 0x7e, 0x36, 0x40, 0xf6, 0x95, 0x03, 0x54, 0xd6, 0x9e, 0xd9, 0x2f, 0xea,
+ 0x31, 0xd4, 0x02, 0x16, 0x73, 0xac, 0xe8, 0x19, 0x8d, 0xa8, 0x4a, 0x27, 0xf3, 0xb8, 0x2c, 0x2e,
+ 0x82, 0xc9, 0xdf, 0x00, 0xcc, 0x2e, 0x3c, 0x1c, 0x49, 0xe2, 0xf7, 0xa5, 0x06, 0x22, 0x68, 0x32,
+ 0xf0, 0xfb, 0x4c, 0xf8, 0xdf, 0x5b, 0x19, 0x26, 0x4a, 0xa4, 0x99, 0xdd, 0x92, 0x77, 0x6f, 0x24,
+ 0xc9, 0x81, 0x3c, 0xca, 0x7c, 0x0e, 0x98, 0x38, 0x6d, 0x9d, 0x4c, 0x1c, 0x9e, 0x7e, 0x02, 0x98,
+ 0x5f, 0x76, 0xb9, 0xb5, 0x11, 0xd4, 0x39, 0x8e, 0x7d, 0x8e, 0xa5, 0xe4, 0x43, 0x81, 0x25, 0x71,
+ 0x2c, 0x74, 0x07, 0x56, 0x83, 0x91, 0x54, 0x6c, 0x49, 0xb6, 0xf5, 0x39, 0x81, 0xc7, 0xba, 0x0a,
+ 0x27, 0x77, 0x56, 0x30, 0xbf, 0xed, 0xe7, 0xff, 0x02, 0x00, 0x00, 0xff, 0xff, 0xd3, 0x31, 0x82,
+ 0x34, 0xd1, 0x05, 0x00, 0x00,
}
diff --git a/metadata/metadata.proto b/metadata/metadata.proto
index 735181e..e682212 100644
--- a/metadata/metadata.proto
+++ b/metadata/metadata.proto
@@ -97,4 +97,5 @@ message Config {
HashingCosts hash_costs = 2;
string compatibility = 3;
EncryptionOptions options = 4;
+ bool use_fs_keyring_for_v1_policies = 5;
}