From ea3e258610340de0dd585c221f4e18a199f16bca Mon Sep 17 00:00:00 2001 From: "Joe Richey joerichey@google.com" Date: Thu, 8 Jun 2017 10:51:04 -0700 Subject: [PATCH] crypto: add in additional keyring functionality This commit adds in the FindPolicyKey and RemovePolicyKey functions to complement the InsertPolicyKey function. The existing functions were also refactored slightly. Change-Id: Iabd275f2186a9e3023d5efd44c772966123e3657 --- crypto/crypto.go | 2 ++ crypto/crypto_test.go | 10 ++++++++-- crypto/key.go | 45 +++++++++++++++++++++++++++++++++++++------ 3 files changed, 49 insertions(+), 8 deletions(-) diff --git a/crypto/crypto.go b/crypto/crypto.go index a226f26..c6d6619 100644 --- a/crypto/crypto.go +++ b/crypto/crypto.go @@ -63,6 +63,8 @@ var ( ErrKeyFree = util.SystemError("could not free memory of key") ErrKeyringLocate = util.SystemError("could not locate the session keyring") ErrKeyringInsert = util.SystemError("could not insert key into the session keyring") + ErrKeyringSearch = util.SystemError("could not find key in the session keyring") + ErrKeyringDelete = util.SystemError("could not delete key from the session keyring") ErrRecoveryCode = errors.New("provided recovery code had incorrect format") ErrLowEntropy = util.SystemError("insufficient entropy in pool to generate random bytes") ErrRandNotSupported = util.SystemError("getrandom() not implemented; kernel must be v3.17 or later") diff --git a/crypto/crypto_test.go b/crypto/crypto_test.go index 674baeb..2141fb8 100644 --- a/crypto/crypto_test.go +++ b/crypto/crypto_test.go @@ -234,24 +234,30 @@ func TestKeyLargeResize(t *testing.T) { } } -// Adds a key with and without legacy (check keyctl to see the key identifiers). -func TestAddKeys(t *testing.T) { +// Adds and removes a key with various services. +func TestAddRemoveKeys(t *testing.T) { for _, service := range []string{ServiceDefault, ServiceExt4, ServiceF2FS} { if err := InsertPolicyKey(fakeValidPolicyKey, fakeValidDescriptor, service); err != nil { t.Error(err) } + if err := RemovePolicyKey(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 { + RemovePolicyKey(fakeValidDescriptor, ServiceDefault) t.Error("InsertPolicyKey should fail with bad policy key") } if InsertPolicyKey(fakeValidPolicyKey, fakeInvalidDescriptor, ServiceDefault) == nil { + RemovePolicyKey(fakeInvalidDescriptor, ServiceDefault) t.Error("InsertPolicyKey should fail with bad descriptor") } if InsertPolicyKey(fakeValidPolicyKey, fakeValidDescriptor, "ext4") == nil { + RemovePolicyKey(fakeValidDescriptor, "ext4") t.Error("InsertPolicyKey should fail with bad service") } } diff --git a/crypto/key.go b/crypto/key.go index bc5ec0f..eefe08a 100644 --- a/crypto/key.go +++ b/crypto/key.go @@ -45,6 +45,8 @@ const ( ServiceExt4 = "ext4:" // ServiceExt4 was used before v4.6 for F2FS filesystem encryption. ServiceF2FS = "f2fs:" + // keyType is always logon as required by filesystem encryption + keyType = "logon" ) /* @@ -237,24 +239,55 @@ func addPayloadToSessionKeyring(payload []byte, description string) error { // 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) + log.Printf("unix.KeyctlGetKeyringID(KEY_SPEC_SESSION_KEYRING) = %d, %v", keyringID, err) if err != nil { - log.Printf("unix.KeyctlGetKeyringID failed: %v", err) - log.Print("could not get keyring ID of KEY_SPEC_SESSION_KEYRING") return ErrKeyringLocate } - if _, err = unix.AddKey("logon", description, payload, keyringID); err != nil { - log.Printf("unix.AddKey failed: %v", err) - log.Printf("could not insert %q into keyring (ID = %d)", description, keyringID) + keyID, err := unix.AddKey(keyType, description, payload, keyringID) + log.Printf("unix.AddKey(%s, %s, , %d) = %d, %v", + keyType, description, keyringID, keyID, err) + if err != nil { return ErrKeyringInsert } return nil } +// FindPolicyKey tries to locate a policy key in the kernel keyring with the +// provided descriptor and service. The key id is returned if we can find the +// key. An error is returned if the key does not exist. +func FindPolicyKey(descriptor, service string) (int, error) { + description := service + descriptor + keyID, err := unix.KeyctlSearch(unix.KEY_SPEC_SESSION_KEYRING, keyType, description, 0) + log.Printf("unix.KeyctlSearch(KEY_SPEC_SESSION_KEYRING, %s, %s, 0) = %d, %v", + keyType, description, keyID, err) + if err != nil { + return 0, ErrKeyringSearch + } + return keyID, nil +} + +// RemovePolicyKey tries to remove a policy key from the kernel keyring with the +// provided descriptor and service. An error is returned if the key does not +// exist. +func RemovePolicyKey(descriptor, service string) error { + keyID, err := FindPolicyKey(descriptor, service) + if err != nil { + return err + } + + err = unix.KeyctlUnlink(keyID, unix.KEY_SPEC_SESSION_KEYRING) + log.Printf("unix.KeyctlUnlink(%d, KEY_SPEC_SESSION_KEYRING) = %v", keyID, err) + if err != nil { + return ErrKeyringDelete + } + return nil +} + // 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 { +func InsertPolicyKey(key *Key, descriptor, service string) error { if key.Len() != metadata.PolicyKeyLen { return util.InvalidLengthError("Policy Key", metadata.PolicyKeyLen, key.Len()) } -- 2.39.5