aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crypto/crypto_test.go28
-rw-r--r--crypto/key.go69
-rw-r--r--metadata/policy.go3
-rw-r--r--metadata/policy_test.go4
4 files changed, 99 insertions, 5 deletions
diff --git a/crypto/crypto_test.go b/crypto/crypto_test.go
index d76381e..025b5b9 100644
--- a/crypto/crypto_test.go
+++ b/crypto/crypto_test.go
@@ -40,6 +40,12 @@ func makeKey(b byte, n int) (*Key, error) {
return NewFixedLengthKeyFromReader(ConstReader(b), n)
}
+var fakeValidDescriptor = "0123456789abcdef"
+var fakeInvalidDescriptor = "123456789abcdef"
+
+var fakeValidPolicyKey, _ = makeKey(42, PolicyKeyLen)
+var fakeInvalidPolicyKey, _ = makeKey(42, PolicyKeyLen-1)
+
// Tests the two ways of making keys
func TestMakeKeys(t *testing.T) {
data := []byte("1234\n6789")
@@ -111,3 +117,25 @@ func TestLongLength(t *testing.T) {
t.Error("Key contained incorrect data")
}
}
+
+// Adds a key with and without legacy (check keyctl to see the key identifiers).
+func TestAddKeys(t *testing.T) {
+ for _, service := range []string{ServiceDefault, ServiceExt4, ServiceF2FS} {
+ if err := InsertPolicyKey(fakeValidPolicyKey, fakeValidDescriptor, service); err != nil {
+ t.Error(err)
+ }
+ }
+}
+
+// Makes sure a key fails with bad descriptor, policy, or service
+func TestBadAddKeys(t *testing.T) {
+ if InsertPolicyKey(fakeInvalidPolicyKey, fakeValidDescriptor, ServiceDefault) == nil {
+ t.Error("InsertPolicyKey should fail with bad policy key")
+ }
+ if InsertPolicyKey(fakeValidPolicyKey, fakeInvalidDescriptor, ServiceDefault) == nil {
+ t.Error("InsertPolicyKey should fail with bad descriptor")
+ }
+ if InsertPolicyKey(fakeValidPolicyKey, fakeValidDescriptor, "ext4") == nil {
+ t.Error("InsertPolicyKey should fail with bad service")
+ }
+}
diff --git a/crypto/key.go b/crypto/key.go
index 88b5a2c..31d4667 100644
--- a/crypto/key.go
+++ b/crypto/key.go
@@ -27,15 +27,31 @@ import (
"golang.org/x/sys/unix"
+ "fscrypt/metadata"
"fscrypt/util"
)
+// Service Prefixes for keyring keys. As of kernel v4.8, all filesystems
+// supporting encryption will use FS_KEY_DESC_PREFIX to indicate that a key in
+// the keyring should be used with filesystem encryption. However, we also
+// include the older service prefixes for legacy compatibility.
+const (
+ ServiceDefault = unix.FS_KEY_DESC_PREFIX
+ // ServiceExt4 was used before v4.8 for ext4 filesystem encryption.
+ ServiceExt4 = "ext4:"
+ // ServiceExt4 was used before v4.6 for F2FS filesystem encryption.
+ ServiceF2FS = "f2fs:"
+)
+
+// PolicyKeyLen is the length of all keys passed directly to the Keyring
+const PolicyKeyLen = unix.FS_MAX_KEY_SIZE
+
/*
UseMlock determines whether we should use the mlock/munlock syscalls to
prevent sensitive data like keys and passphrases from being paged to disk.
UseMlock defaults to true, but can be set to false if the application calling
-into this library has insufficient privileges to lock memory. A package could
-also bind this setting to a flag by using:
+into this library has insufficient privileges to lock memory. Code using this
+package could also bind this setting to a flag by using:
flag.BoolVar(&crypto.UseMlock, "lock-memory", true, "lock keys in memory")
*/
@@ -201,3 +217,52 @@ func NewFixedLengthKeyFromReader(reader io.Reader, length int) (*Key, error) {
}
return key, nil
}
+
+// addPayloadToSessionKeyring adds the payload to the current session keyring as
+// type logon, returning the key's new ID.
+func addPayloadToSessionKeyring(payload []byte, description string) (int, error) {
+ // We cannot add directly to KEY_SPEC_SESSION_KEYRING, as that will make
+ // a new session keyring if one does not exist, which will be garbage
+ // collected when the process terminates. Instead, we first get the ID
+ // of the KEY_SPEC_SESSION_KEYRING, which will return the user session
+ // keyring if a session keyring does not exist.
+ keyringID, err := unix.KeyctlGetKeyringID(unix.KEY_SPEC_SESSION_KEYRING, 0)
+ if err != nil {
+ return 0, err
+ }
+
+ return unix.AddKey("logon", description, payload, keyringID)
+}
+
+// InsertPolicyKey puts the provided policy key into the kernel keyring with the
+// provided descriptor, provided service prefix, and type logon. The key and
+// descriptor must have the appropriate lengths.
+func InsertPolicyKey(key *Key, descriptor string, service string) error {
+ if key.Len() != PolicyKeyLen {
+ return util.InvalidLengthError("Policy Key", PolicyKeyLen, key.Len())
+ }
+
+ if len(descriptor) != metadata.DescriptorLen {
+ return util.InvalidLengthError("Descriptor", metadata.DescriptorLen, len(descriptor))
+ }
+
+ // Create our payload (containing an FscryptKey)
+ payload, err := newBlankKey(unix.SizeofFscryptKey)
+ if err != nil {
+ return err
+ }
+ defer payload.Wipe()
+
+ // Cast the payload to an FscryptKey so we can initialize the fields.
+ fscryptKey := (*unix.FscryptKey)(util.Ptr(payload.data))
+ // Mode is ignored by the kernel
+ fscryptKey.Mode = 0
+ fscryptKey.Size = PolicyKeyLen
+ copy(fscryptKey.Raw[:], key.data)
+
+ if _, err := addPayloadToSessionKeyring(payload.data, service+descriptor); err != nil {
+ return util.SystemErrorF("inserting key - %s: %v", descriptor, err)
+ }
+
+ return nil
+}
diff --git a/metadata/policy.go b/metadata/policy.go
index ae8b869..8c67f52 100644
--- a/metadata/policy.go
+++ b/metadata/policy.go
@@ -120,12 +120,13 @@ func GetPolicy(path string) (*PolicyData, error) {
// policy. Returns an error if we cannot set the policy for any reason (not a
// directory, invalid options or KeyDescriptor, etc).
func SetPolicy(path string, data *PolicyData) error {
- // Convert the padding value to a flag and the policyID to a byte array
+ // Convert the padding value to a flag
paddingFlag, ok := util.Lookup(data.Options.Padding, paddingArray, flagsArray)
if !ok {
return util.InvalidInputF("padding of %d", data.Options.Padding)
}
+ // Convert the policyDescriptor to a byte array
if len(data.KeyDescriptor) != DescriptorLen {
return util.InvalidLengthError("policy descriptor", DescriptorLen, len(data.KeyDescriptor))
}
diff --git a/metadata/policy_test.go b/metadata/policy_test.go
index 7f8a48b..593f3da 100644
--- a/metadata/policy_test.go
+++ b/metadata/policy_test.go
@@ -110,7 +110,7 @@ func TestSetPolicyFile(t *testing.T) {
}
// Tests that we fail when using bad policies
-func TestSetPolicyBadIDs(t *testing.T) {
+func TestSetPolicyBadDescriptors(t *testing.T) {
// Policies that are too short, have invalid chars, or are too long
badDescriptors := []string{"123456789abcde", "xxxxxxxxxxxxxxxx", "0123456789abcdef00"}
for _, badDescriptor := range badDescriptors {
@@ -121,7 +121,7 @@ func TestSetPolicyBadIDs(t *testing.T) {
}
if err = SetPolicy(directory, badPolicy); err == nil {
- t.Errorf("id %q should have made SetPolicy fail", badDescriptor)
+ t.Errorf("descriptor %q should have made SetPolicy fail", badDescriptor)
}
os.RemoveAll(directory)
}