implemented some extra functionality

This commit is contained in:
Bruce Leidl 2019-04-02 15:14:41 -04:00
parent 533ed4b8be
commit e493e5180d

View File

@ -21,7 +21,7 @@ use sodiumoxide::crypto::{
}, },
}; };
use crate::{Result,Error}; use crate::{Result,Error,KeyPair};
#[derive(Serialize,Deserialize,Debug)] #[derive(Serialize,Deserialize,Debug)]
pub struct KeyRing { pub struct KeyRing {
@ -38,7 +38,7 @@ impl KeyRing {
pub fn load<P: AsRef<Path>>(path: P, passphrase: &str) -> Result<KeyRing> { pub fn load<P: AsRef<Path>>(path: P, passphrase: &str) -> Result<KeyRing> {
let mut sbox = SecretBox::new(path.as_ref()); 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 mut bytes = sbox.open(passphrase)?;
let keyring = toml::from_slice::<KeyRing>(&bytes)?; let keyring = toml::from_slice::<KeyRing>(&bytes)?;
bytes.iter_mut().for_each(|b| *b = 0); bytes.iter_mut().for_each(|b| *b = 0);
@ -51,7 +51,7 @@ impl KeyRing {
} }
fn get_cryptsetup_passphrase() -> Result<String> { fn get_cryptsetup_passphrase() -> Result<String> {
let key = KernelKey::request_key("user", "cryptsetup")?; let key = KeyRing::get_key("cryptsetup")?;
info!("Got key {}", key.0); info!("Got key {}", key.0);
let buf = key.read()?; let buf = key.read()?;
match buf.split(|b| *b == 0).map(|bs| String::from_utf8_lossy(bs).to_string()).last() { 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<KernelKey> {
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<()> { pub fn add_keys_to_kernel(&self) -> Result<()> {
for (k,v) in self.keypairs.iter() { for (k,v) in self.keypairs.iter() {
info!("Adding {} to kernel keystore", k.as_str()); 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(()) Ok(())
} }
pub fn get_kernel_keypair(name: &str) -> Result<KeyPair> {
let key = KeyRing::get_key(name)?;
let data = key.read()?;
KeyPair::from_bytes(&data)
}
pub fn write<P: AsRef<Path>>(&self, path: P, passphrase: &str) -> Result<()> { pub fn write<P: AsRef<Path>>(&self, path: P, passphrase: &str) -> Result<()> {
let salt = pwhash::gen_salt(); let salt = pwhash::gen_salt();
let nonce = secretbox::gen_nonce(); 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 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 const KEY_SPEC_USER_KEYRING : c_int = -4; // - key ID for UID-specific keyring
pub struct KernelKey(int32_t); pub struct KernelKey(int32_t);
impl KernelKey { impl KernelKey {
pub fn user_keyring() -> KernelKey {
KernelKey(KEY_SPEC_USER_KEYRING)
}
pub fn request_key(key_type: &str, description: &str) -> Result<KernelKey> { pub fn request_key(key_type: &str, description: &str) -> Result<KernelKey> {
let key_type = CString::new(key_type).unwrap(); let key_type = CString::new(key_type).unwrap();
let description = CString::new(description).unwrap(); let description = CString::new(description).unwrap();
@ -164,11 +198,40 @@ impl KernelKey {
Ok(KernelKey(serial as i32)) Ok(KernelKey(serial as i32))
} }
pub fn get_keyring_id(&self, create: bool) -> Result<KernelKey> {
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<String> {
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<KernelKey> {
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<Vec<u8>> { pub fn read(&self) -> Result<Vec<u8>> {
let mut size = 0; let mut size = 0;
loop { loop {
size = match self.buffer_request(KEYCTL_READ, size) { 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::Ok(buffer) => return Ok(buffer),
BufferResult::TooSmall(sz) => sz + 1, BufferResult::TooSmall(sz) => sz + 1,
} }
@ -212,14 +275,22 @@ enum BufferResult {
fn keyctl1(command: c_int, arg2: c_ulong) -> Result<c_long> { fn keyctl1(command: c_int, arg2: c_ulong) -> Result<c_long> {
_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<c_long> {
sys_keyctl(command, arg2, arg3, 0, 0)
} }
fn keyctl3(command: c_int, arg2: c_ulong, arg3: c_ulong, arg4: c_ulong) -> Result<c_long> { fn keyctl3(command: c_int, arg2: c_ulong, arg3: c_ulong, arg4: c_ulong) -> Result<c_long> {
_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<c_long> { fn keyctl4(command: c_int, arg2: c_ulong, arg3: c_ulong, arg4: c_ulong, arg5: c_ulong) -> Result<c_long> {
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<c_long> {
unsafe { unsafe {
let r = libc::syscall(libc::SYS_keyctl, command, arg2, arg3, arg4, arg5); let r = libc::syscall(libc::SYS_keyctl, command, arg2, arg3, arg4, arg5);
if r == -1 { if r == -1 {