diff --git a/libcitadel/src/keyring.rs b/libcitadel/src/keyring.rs index ba25d13..6844520 100644 --- a/libcitadel/src/keyring.rs +++ b/libcitadel/src/keyring.rs @@ -21,7 +21,7 @@ use sodiumoxide::crypto::{ }, }; -use crate::{Result,Error}; +use crate::{Result,Error,KeyPair}; #[derive(Serialize,Deserialize,Debug)] pub struct KeyRing { @@ -38,7 +38,7 @@ impl KeyRing { pub fn load>(path: P, passphrase: &str) -> Result { let mut sbox = SecretBox::new(path.as_ref()); - sbox.read()?; + sbox.read().map_err(|e| format_err!("Error reading keyring file: {}", e))?; let mut bytes = sbox.open(passphrase)?; let keyring = toml::from_slice::(&bytes)?; bytes.iter_mut().for_each(|b| *b = 0); @@ -51,7 +51,7 @@ impl KeyRing { } fn get_cryptsetup_passphrase() -> Result { - let key = KernelKey::request_key("user", "cryptsetup")?; + let key = KeyRing::get_key("cryptsetup")?; info!("Got key {}", key.0); let buf = key.read()?; match buf.split(|b| *b == 0).map(|bs| String::from_utf8_lossy(bs).to_string()).last() { @@ -60,14 +60,38 @@ impl KeyRing { } } + fn get_key(name: &str) -> Result { + if let Ok(key) = KernelKey::user_keyring().search(name) { + debug!("Found {} key in user keyring: (keyid: {:08x})", name, key.0); + if let Err(e) = key.read() { + info!("err tho on read: {}", e); + } else { + return Ok(key); + } + } + if let Ok(key) = KernelKey::request_key("user", name) { + info!("Found {} key with request_key", name); + return Ok(key); + } + return Err(format_err!("kernel key '{}' not found", name)) + } + pub fn add_keys_to_kernel(&self) -> Result<()> { for (k,v) in self.keypairs.iter() { info!("Adding {} to kernel keystore", k.as_str()); - let _key = KernelKey::add_key("user", k.as_str(), v.as_bytes(), KEY_SPEC_USER_KEYRING)?; + let bytes = hex::decode(v)?; + let key = KernelKey::add_key("user", k.as_str(), &bytes, KEY_SPEC_USER_KEYRING)?; + key.set_perm(0x3f030000)?; } Ok(()) } + pub fn get_kernel_keypair(name: &str) -> Result { + let key = KeyRing::get_key(name)?; + let data = key.read()?; + KeyPair::from_bytes(&data) + } + pub fn write>(&self, path: P, passphrase: &str) -> Result<()> { let salt = pwhash::gen_salt(); let nonce = secretbox::gen_nonce(); @@ -143,13 +167,23 @@ impl SecretBox { } +const KEYCTL_GET_KEYRING_ID : c_int = 0; // ask for a keyring's ID +const KEYCTL_SETPERM : c_int = 5; // set perms on a key +const KEYCTL_DESCRIBE : c_int = 6; // describe a key +const KEYCTL_SEARCH : c_int = 10; // search for a key in a keyring const KEYCTL_READ : c_int = 11; // read a key or keyring's contents + const KEY_SPEC_USER_KEYRING : c_int = -4; // - key ID for UID-specific keyring pub struct KernelKey(int32_t); impl KernelKey { + + pub fn user_keyring() -> KernelKey { + KernelKey(KEY_SPEC_USER_KEYRING) + } + pub fn request_key(key_type: &str, description: &str) -> Result { let key_type = CString::new(key_type).unwrap(); let description = CString::new(description).unwrap(); @@ -164,11 +198,40 @@ impl KernelKey { Ok(KernelKey(serial as i32)) } + pub fn get_keyring_id(&self, create: bool) -> Result { + let serial = keyctl2(KEYCTL_GET_KEYRING_ID, self.id(), create as u64)?; + Ok(KernelKey(serial as i32)) + } + + pub fn set_perm(&self, perm: u32) -> Result<()> { + keyctl2(KEYCTL_SETPERM, self.id(), perm as u64)?; + Ok(()) + } + + pub fn describe(&self) -> Result { + let mut size = 0; + loop { + size = match self.buffer_request(KEYCTL_DESCRIBE, size) { + BufferResult::Err(err) => return Err(format_err!("Error calling KEYCTL_DESCRIBE on key: {}", err)), + BufferResult::Ok(vec) => return Ok(String::from_utf8(vec).expect("KEYCTL_DESCRIBE returned bad utf8")), + BufferResult::TooSmall(sz) => sz, + } + } + } + + pub fn search(&self, description: &str) -> Result { + let key_type = CString::new("user").unwrap(); + let description = CString::new(description).unwrap(); + + let serial = keyctl4(KEYCTL_SEARCH, self.id(), key_type.as_ptr() as u64, description.as_ptr() as u64, 0)?; + Ok(KernelKey(serial as i32)) + } + pub fn read(&self) -> Result> { let mut size = 0; loop { size = match self.buffer_request(KEYCTL_READ, size) { - BufferResult::Err(err) => return Err(err), + BufferResult::Err(err) => return Err(format_err!("Error reading key: {}", err)), BufferResult::Ok(buffer) => return Ok(buffer), BufferResult::TooSmall(sz) => sz + 1, } @@ -212,14 +275,22 @@ enum BufferResult { fn keyctl1(command: c_int, arg2: c_ulong) -> Result { - _keyctl(command, arg2, 0, 0, 0) + sys_keyctl(command, arg2, 0, 0, 0) +} + +fn keyctl2(command: c_int, arg2: c_ulong, arg3: c_ulong) -> Result { + sys_keyctl(command, arg2, arg3, 0, 0) } fn keyctl3(command: c_int, arg2: c_ulong, arg3: c_ulong, arg4: c_ulong) -> Result { - _keyctl(command, arg2, arg3, arg4, 0) + sys_keyctl(command, arg2, arg3, arg4, 0) } -fn _keyctl(command: c_int, arg2: c_ulong, arg3: c_ulong, arg4: c_ulong, arg5: c_ulong) -> Result { +fn keyctl4(command: c_int, arg2: c_ulong, arg3: c_ulong, arg4: c_ulong, arg5: c_ulong) -> Result { + sys_keyctl(command, arg2, arg3, arg4, arg5) +} + +fn sys_keyctl(command: c_int, arg2: c_ulong, arg3: c_ulong, arg4: c_ulong, arg5: c_ulong) -> Result { unsafe { let r = libc::syscall(libc::SYS_keyctl, command, arg2, arg3, arg4, arg5); if r == -1 { @@ -250,4 +321,4 @@ fn _add_key(key_type: *const c_char, description: *const c_char, payload: *const Ok(r) } } -} \ No newline at end of file +}