From 9759cdfb7985b127e1939baad44afd98389d4c61 Mon Sep 17 00:00:00 2001 From: Bradley Landherr <12598313+landhb@users.noreply.github.com> Date: Sun, 9 Oct 2022 23:27:33 -0400 Subject: [PATCH] Provide `Key::read_to_vec` (#6) * Add `Key::read_to_vec` for easier reading into a vec * Don't rely on libc for KEYCTL constants * Update tests * Bump version Co-authored-by: landhb --- Cargo.toml | 2 +- src/errors.rs | 3 +++ src/ffi/types.rs | 64 ++++++++++++++++++++++++------------------------ src/key.rs | 45 +++++++++++++++++++++++++++++++++- 4 files changed, 80 insertions(+), 34 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 5e75228..631f09e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "linux-keyutils" -version = "0.2.0" +version = "0.2.1" edition = "2021" authors = ["landhb "] description = """ diff --git a/src/errors.rs b/src/errors.rs index dd3dfc5..8d9e530 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -51,6 +51,9 @@ pub enum KeyError { /// Operation not supported OperationNotSupported, + /// Write to destination failed + WriteError, + /// Unknown - catch all, return this instead of panicing Unknown(i32), } diff --git a/src/ffi/types.rs b/src/ffi/types.rs index 875659b..5aa38d0 100644 --- a/src/ffi/types.rs +++ b/src/ffi/types.rs @@ -63,69 +63,69 @@ pub enum DefaultKeyring { #[repr(u32)] pub enum KeyCtlOperation { /// Ask for a keyring's ID - GetKeyRingId = libc::KEYCTL_GET_KEYRING_ID, + GetKeyRingId = 0, /// Join or start named session keyring - JoinSessionKeyRing = libc::KEYCTL_JOIN_SESSION_KEYRING, + JoinSessionKeyRing = 1, /// Update a key - Update = libc::KEYCTL_UPDATE, + Update = 2, /// Revoke a key - Revoke = libc::KEYCTL_REVOKE, + Revoke = 3, /// Set ownership of a key - Chown = libc::KEYCTL_CHOWN, + Chown = 4, /// Set permissions of a key - SetPerm = libc::KEYCTL_SETPERM, + SetPerm = 5, /// Describe a key - Describe = libc::KEYCTL_DESCRIBE, + Describe = 6, /// Clear contents of a keyring - Clear = libc::KEYCTL_CLEAR, + Clear = 7, /// Link a key into a keyring - Link = libc::KEYCTL_LINK, + Link = 8, /// Unlink a key from a keyring - Unlink = libc::KEYCTL_UNLINK, + Unlink = 9, /// Search for a key in a keyring - Search = libc::KEYCTL_SEARCH, + Search = 10, /// Read a key or keyring's contents - Read = libc::KEYCTL_READ, + Read = 11, /// Instantiate a partially constructed key - Instantiate = libc::KEYCTL_INSTANTIATE, + Instantiate = 12, /// Negate a partially constructed key - Negate = libc::KEYCTL_NEGATE, + Negate = 13, /// Set default request-key keyring - SetRequestKeyKeyring = libc::KEYCTL_SET_REQKEY_KEYRING, + SetRequestKeyKeyring = 14, /// Set timeout on a key - SetTimeout = libc::KEYCTL_SET_TIMEOUT, + SetTimeout = 15, /// Assume authority to instantiate key - AssumeAuthority = libc::KEYCTL_ASSUME_AUTHORITY, + AssumeAuthority = 16, /// Get key security label - GetSecurityLabel = libc::KEYCTL_GET_SECURITY, + GetSecurityLabel = 17, /// Set my session keyring on my parent process - SessionToParent = libc::KEYCTL_SESSION_TO_PARENT, + SessionToParent = 18, /// Reject a partially constructed key - Reject = libc::KEYCTL_REJECT, + Reject = 19, /// Instantiate a partially constructed key - InstantiageIov = libc::KEYCTL_INSTANTIATE_IOV, + InstantiageIov = 20, /// Invalidate a key - Invalidate = libc::KEYCTL_INVALIDATE, + Invalidate = 21, /// Get a user's persistent keyring - GetPersistent = libc::KEYCTL_GET_PERSISTENT, + GetPersistent = 22, /// Compute Diffie-Hellman values - DiffieHellmanCompute = libc::KEYCTL_DH_COMPUTE, + DiffieHellmanCompute = 23, /// Query public key parameters - PubkeyQuery = libc::KEYCTL_PKEY_QUERY, + PubkeyQuery = 24, /// Encrypt a blob using a public key - PubkeyEncrypt = libc::KEYCTL_PKEY_ENCRYPT, + PubkeyEncrypt = 25, /// Decrypt a blob using a public key - PubkeyDecrypt = libc::KEYCTL_PKEY_DECRYPT, + PubkeyDecrypt = 26, /// Create a public key signature - PubkeySign = libc::KEYCTL_PKEY_SIGN, + PubkeySign = 27, /// Verify a public key signature - PubkeyVerify = libc::KEYCTL_PKEY_VERIFY, + PubkeyVerify = 28, /// Restrict keys allowed to link to a keyring - RestrictKeyring = libc::KEYCTL_RESTRICT_KEYRING, + RestrictKeyring = 29, /// Move keys between keyrings - Move = libc::KEYCTL_MOVE, + Move = 30, /// Find capabilities of keyrings subsystem - Capabilities = libc::KEYCTL_CAPABILITIES, + Capabilities = 31, /// Watch a key or ring of keys for changes WatchKey = 32, } diff --git a/src/key.rs b/src/key.rs index f01f90e..d949819 100644 --- a/src/key.rs +++ b/src/key.rs @@ -1,4 +1,5 @@ use crate::ffi::{self, KeyCtlOperation, KeySerialId}; +use crate::utils::Vec; use crate::{KeyError, KeyPermissions, Metadata}; use core::fmt; @@ -57,7 +58,9 @@ impl Key { Metadata::from_id(self.0) } - /// Read the payload data of a key. + /// Read the payload data of a key into a provided mutable slice. + /// + /// The returned usize is the number of bytes read into the slice. /// /// The key must either grant the caller read permission, or grant /// the caller search permission when searched for from the process @@ -73,6 +76,30 @@ impl Key { Ok(len) } + /// Read the payload data of a key, returning a newly allocated vector. + /// + /// The key must either grant the caller read permission, or grant + /// the caller search permission when searched for from the process + /// keyrings (i.e., the key is possessed). + pub fn read_to_vec(&self) -> Result, KeyError> { + // Ensure we have enough room to write up to the maximum for a UserKey + let mut buffer = Vec::with_capacity(65536); + + // Obtain the key + let len = ffi::keyctl!( + KeyCtlOperation::Read, + self.0.as_raw_id() as libc::c_ulong, + buffer.as_mut_ptr() as _, + buffer.capacity() as _ + )? as usize; + + // Update length + unsafe { + buffer.set_len(len); + } + Ok(buffer) + } + /// Update a key's data payload. /// /// The caller must have write permission on the key specified and the key @@ -229,6 +256,22 @@ mod tests { key.invalidate().unwrap() } + #[test] + fn test_read_into_vec() { + let secret = "Test Data"; + + // Obtain the default User keyring + let ring = KeyRing::from_special_id(KeyRingIdentifier::Session, false).unwrap(); + + // Create the key + let key = ring.add_key("vec-read-key", secret).unwrap(); + + // Verify the payload + let payload = key.read_to_vec().unwrap(); + assert_eq!(secret.as_bytes(), &payload); + key.invalidate().unwrap(); + } + #[test] fn test_user_keyring_add_key() { let secret = "Test Data";