use std::borrow::{Borrow, Cow};
use std::convert::TryInto;
use std::mem;
use std::result;
use std::str;
use std::time::Duration;
use keyutils_raw::*;
use log::error;
use uninit::extension_traits::VecCapacity;
use crate::constants::{KeyctlSupportFlags, Permission, SpecialKeyring};
use crate::keytype::*;
use crate::keytypes;
pub type Error = errno::Errno;
pub type Result<T> = result::Result<T, Error>;
fn request_impl<K: KeyType>(
description: &str,
info: Option<&str>,
id: Option<KeyringSerial>,
) -> Result<KeyringSerial> {
request_key(K::name(), description, info, id)
}
fn read_impl(id: KeyringSerial) -> Result<Vec<u8>> {
let mut sz = keyctl_read(id, None)?;
let mut buffer = vec![0; sz];
loop {
let write_buffer = buffer.get_backing_buffer();
sz = keyctl_read(id, Some(write_buffer))?;
if sz <= buffer.capacity() {
break;
}
buffer.resize(sz, 0);
}
buffer.truncate(sz);
Ok(buffer)
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Keyring {
id: KeyringSerial,
}
impl Keyring {
pub unsafe fn new(id: KeyringSerial) -> Self {
Keyring {
id,
}
}
fn new_impl(id: KeyringSerial) -> Self {
Keyring {
id,
}
}
pub(crate) fn serial(&self) -> KeyringSerial {
self.id
}
pub fn set_default(keyring: DefaultKeyring) -> Result<DefaultKeyring> {
keyctl_set_reqkey_keyring(keyring)
}
pub fn request<'s, 'a, D, I, T>(description: D, info: I, target: T) -> Result<Self>
where
D: AsRef<str>,
I: Into<Option<&'s str>>,
T: Into<Option<TargetKeyring<'a>>>,
{
request_impl::<keytypes::Keyring>(
description.as_ref(),
info.into().as_ref().copied(),
target.into().map(TargetKeyring::serial),
)
.map(Self::new_impl)
}
fn get_keyring(id: SpecialKeyring, create: bool) -> Result<Keyring> {
keyctl_get_keyring_id(id.serial(), create).map(Self::new_impl)
}
pub fn attach(id: SpecialKeyring) -> Result<Self> {
Self::get_keyring(id, false)
}
pub fn attach_or_create(id: SpecialKeyring) -> Result<Self> {
Self::get_keyring(id, true)
}
pub fn join_anonymous_session() -> Result<Self> {
keyctl_join_session_keyring(None).map(Self::new_impl)
}
pub fn join_session<N>(name: N) -> Result<Self>
where
N: AsRef<str>,
{
keyctl_join_session_keyring(Some(name.as_ref())).map(Self::new_impl)
}
pub fn clear(&mut self) -> Result<()> {
keyctl_clear(self.id)
}
pub fn link_key(&mut self, key: &Key) -> Result<()> {
keyctl_link(key.id, self.id)
}
pub fn unlink_key(&mut self, key: &Key) -> Result<()> {
keyctl_unlink(key.id, self.id)
}
pub fn link_keyring(&mut self, keyring: &Keyring) -> Result<()> {
keyctl_link(keyring.id, self.id)
}
pub fn unlink_keyring(&mut self, keyring: &Keyring) -> Result<()> {
keyctl_unlink(keyring.id, self.id)
}
fn search_impl<K>(
&self,
description: &str,
destination: Option<&mut Keyring>,
) -> Result<KeyringSerial>
where
K: KeyType,
{
keyctl_search(
self.id,
K::name(),
description,
destination.map(|dest| dest.id),
)
}
pub fn search_for_key<'a, K, D, DK>(&self, description: D, destination: DK) -> Result<Key>
where
K: KeyType,
D: Borrow<K::Description>,
DK: Into<Option<&'a mut Keyring>>,
{
self.search_impl::<K>(&description.borrow().description(), destination.into())
.map(Key::new_impl)
}
pub fn search_for_keyring<'a, D, DK>(&self, description: D, destination: DK) -> Result<Self>
where
D: Borrow<<keytypes::Keyring as KeyType>::Description>,
DK: Into<Option<&'a mut Keyring>>,
{
self.search_impl::<keytypes::Keyring>(
&description.borrow().description(),
destination.into(),
)
.map(Self::new_impl)
}
pub fn read(&self) -> Result<(Vec<Key>, Vec<Keyring>)> {
if self.id.get() == 0 {
return Err(errno::Errno(libc::ENOKEY));
}
let desc = self.description()?;
if desc.type_ != keytypes::Keyring::name() {
return Err(errno::Errno(libc::ENOTDIR));
}
let buffer = read_impl(self.id)?;
let keyring_children = {
let chunk_size = mem::size_of::<KeyringSerial>();
let chunks = buffer.chunks(chunk_size);
chunks.map(|chunk| {
let bytes = chunk.try_into().map_err(|err| {
error!(
"A keyring did not have the right number of bytes for a child key or \
keyring ID: {}",
err,
);
errno::Errno(libc::EINVAL)
})?;
let id = i32::from_ne_bytes(bytes);
let serial = KeyringSerial::new(id).ok_or_else(|| {
error!("A keyring had a child key or keyring ID of 0");
errno::Errno(libc::EINVAL)
})?;
Ok(Key::new_impl(serial))
})
};
let mut keys = Vec::new();
let mut keyrings = Vec::new();
for key in keyring_children {
let key = key?;
match key.description() {
Ok(description) => {
if description.type_ == keytypes::Keyring::name() {
keyrings.push(Keyring::new_impl(key.id))
} else {
keys.push(key)
}
},
Err(errno::Errno(libc::ENOKEY)) => {},
Err(e) => return Err(e),
}
}
Ok((keys, keyrings))
}
pub fn attach_persistent(&mut self) -> Result<Self> {
keyctl_get_persistent(!0, self.id).map(Self::new_impl)
}
pub fn add_key<K, D, P>(&mut self, description: D, payload: P) -> Result<Key>
where
K: KeyType,
D: Borrow<K::Description>,
P: Borrow<K::Payload>,
{
self.add_key_impl::<K>(description.borrow(), payload.borrow())
.map(Key::new_impl)
}
fn add_key_impl<K>(
&mut self,
description: &K::Description,
payload: &K::Payload,
) -> Result<KeyringSerial>
where
K: KeyType,
{
add_key(
K::name(),
&description.description(),
&payload.payload(),
self.id,
)
}
pub fn add_keyring<D>(&mut self, description: D) -> Result<Self>
where
D: Borrow<<keytypes::Keyring as KeyType>::Description>,
{
self.add_key_impl::<keytypes::Keyring>(description.borrow(), &())
.map(Self::new_impl)
}
pub fn revoke(self) -> Result<()> {
keyctl_revoke(self.id)
}
pub fn chown(&mut self, uid: libc::uid_t) -> Result<()> {
keyctl_chown(self.id, Some(uid), None)
}
pub fn chgrp(&mut self, gid: libc::gid_t) -> Result<()> {
keyctl_chown(self.id, None, Some(gid))
}
pub fn set_permissions(&mut self, perms: Permission) -> Result<()> {
keyctl_setperm(self.id, perms.bits())
}
#[cfg(test)]
pub(crate) fn set_permissions_raw(&mut self, perms: KeyPermissions) -> Result<()> {
keyctl_setperm(self.id, perms)
}
pub fn restrict_all(&mut self) -> Result<()> {
keyctl_restrict_keyring(self.id, Restriction::AllLinks)
}
pub fn restrict_by_type<K, R>(&mut self, restriction: R) -> Result<()>
where
K: RestrictableKeyType,
R: Borrow<K::Restriction>,
{
keyctl_restrict_keyring(
self.id,
Restriction::ByType {
type_: K::name(),
restriction: &restriction.borrow().restriction(),
},
)
}
fn description_raw(&self) -> Result<String> {
let mut sz = keyctl_describe(self.id, None)?;
let mut buffer = vec![0; sz];
loop {
let write_buffer = buffer.get_backing_buffer();
sz = keyctl_describe(self.id, Some(write_buffer))?;
if sz <= buffer.capacity() {
break;
}
buffer.resize(sz, 0);
}
buffer.truncate(sz.saturating_sub(1));
let str_slice = str::from_utf8(&buffer[..]).unwrap();
Ok(str_slice.to_owned())
}
pub fn description(&self) -> Result<Description> {
self.description_raw()
.and_then(|desc| Description::parse(&desc).ok_or(errno::Errno(libc::EINVAL)))
}
pub fn set_timeout(&mut self, timeout: Duration) -> Result<()> {
keyctl_set_timeout(self.id, timeout.as_secs() as TimeoutSeconds)
}
pub fn security(&self) -> Result<String> {
let mut sz = keyctl_get_security(self.id, None)?;
let mut buffer = vec![0; sz];
loop {
let write_buffer = buffer.get_backing_buffer();
sz = keyctl_get_security(self.id, Some(write_buffer))?;
if sz <= buffer.capacity() {
break;
}
buffer.resize(sz, 0);
}
buffer.truncate(sz.saturating_sub(1));
let str_slice = str::from_utf8(&buffer[..]).unwrap();
Ok(str_slice.to_owned())
}
pub fn invalidate(self) -> Result<()> {
keyctl_invalidate(self.id)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Key {
id: KeyringSerial,
}
#[derive(Debug, Clone, Copy)]
pub struct KeySupportInfo {
pub supported_ops: KeyctlSupportFlags,
pub key_size: u32,
pub max_data_size: u16,
pub max_sig_size: u16,
pub max_enc_size: u16,
pub max_dec_size: u16,
}
impl KeySupportInfo {
fn from_c(c_info: PKeyQuery) -> Self {
KeySupportInfo {
supported_ops: c_info.supported_ops,
key_size: c_info.key_size,
max_data_size: c_info.max_data_size,
max_sig_size: c_info.max_sig_size,
max_enc_size: c_info.max_enc_size,
max_dec_size: c_info.max_dec_size,
}
}
}
#[derive(Debug, Clone)]
pub enum KeyctlEncoding {
RsassaPkcs1V15,
RsaesPkcs1V15,
RsassaPss,
RsaesOaep,
OtherEncoding(Cow<'static, str>),
}
impl KeyctlEncoding {
fn encoding(&self) -> &str {
match *self {
KeyctlEncoding::RsassaPkcs1V15 => "pkcs1",
KeyctlEncoding::RsaesPkcs1V15 => "pkcs1",
KeyctlEncoding::RsassaPss => "pss",
KeyctlEncoding::RsaesOaep => "oaep",
KeyctlEncoding::OtherEncoding(ref s) => s,
}
}
}
#[derive(Debug, Clone)]
pub enum KeyctlHash {
Md4,
Md5,
Sha1,
Sha224,
Sha256,
Sha384,
Sha512,
RipeMd128,
RipeMd160,
RipeMd256,
RipeMd320,
Wp256,
Wp384,
Wp512,
Tgr128,
Tgr160,
Tgr192,
Sm3_256,
OtherEncoding(Cow<'static, str>),
}
impl KeyctlHash {
fn hash(&self) -> &str {
match *self {
KeyctlHash::Md4 => "md4",
KeyctlHash::Md5 => "md5",
KeyctlHash::Sha1 => "sha1",
KeyctlHash::Sha224 => "sha224",
KeyctlHash::Sha256 => "sha256",
KeyctlHash::Sha384 => "sha384",
KeyctlHash::Sha512 => "sha512",
KeyctlHash::RipeMd128 => "rmd128",
KeyctlHash::RipeMd160 => "rmd160",
KeyctlHash::RipeMd256 => "rmd256",
KeyctlHash::RipeMd320 => "rmd320",
KeyctlHash::Wp256 => "wp256",
KeyctlHash::Wp384 => "wp384",
KeyctlHash::Wp512 => "wp512",
KeyctlHash::Tgr128 => "tgr128",
KeyctlHash::Tgr160 => "tgr160",
KeyctlHash::Tgr192 => "tgr192",
KeyctlHash::Sm3_256 => "sm3-256",
KeyctlHash::OtherEncoding(ref s) => s,
}
}
}
#[derive(Debug, Clone)]
pub struct PublicKeyOptions {
pub encoding: Option<KeyctlEncoding>,
pub hash: Option<KeyctlHash>,
}
impl PublicKeyOptions {
fn info(&self) -> String {
let options = [
("enc", self.encoding.as_ref().map(KeyctlEncoding::encoding)),
("hash", self.hash.as_ref().map(KeyctlHash::hash)),
]
.iter()
.map(|&(key, value)| value.map_or_else(String::new, |v| format!("{}={}", key, v)))
.collect::<Vec<_>>();
options.join(" ").trim().to_owned()
}
}
impl Key {
pub unsafe fn new(id: KeyringSerial) -> Self {
Self::new_impl(id)
}
fn new_impl(id: KeyringSerial) -> Self {
Key {
id,
}
}
pub(crate) fn serial(&self) -> KeyringSerial {
self.id
}
pub fn request<'s, 'a, K, D, I, T>(description: D, info: I, target: T) -> Result<Self>
where
K: KeyType,
D: Borrow<K::Description>,
I: Into<Option<&'s str>>,
T: Into<Option<TargetKeyring<'a>>>,
{
request_impl::<K>(
&description.borrow().description(),
info.into().as_ref().copied(),
target.into().map(TargetKeyring::serial),
)
.map(Self::new_impl)
}
pub fn is_keytype<K>(&self) -> Result<bool>
where
K: KeyType,
{
let desc = self.description()?;
Ok(desc.type_ == K::name())
}
pub fn update<K, P>(&mut self, payload: P) -> Result<()>
where
K: KeyType,
P: Borrow<K::Payload>,
{
keyctl_update(self.id, &payload.borrow().payload())
}
pub fn revoke(self) -> Result<()> {
Keyring::new_impl(self.id).revoke()
}
pub fn chown(&mut self, uid: libc::uid_t) -> Result<()> {
Keyring::new_impl(self.id).chown(uid)
}
pub fn chgrp(&mut self, gid: libc::gid_t) -> Result<()> {
Keyring::new_impl(self.id).chgrp(gid)
}
pub fn set_permissions(&mut self, perms: Permission) -> Result<()> {
Keyring::new_impl(self.id).set_permissions(perms)
}
#[cfg(test)]
pub(crate) fn set_permissions_raw(&mut self, perms: KeyPermissions) -> Result<()> {
Keyring::new_impl(self.id).set_permissions_raw(perms)
}
pub fn description(&self) -> Result<Description> {
Keyring::new_impl(self.id).description()
}
pub fn read(&self) -> Result<Vec<u8>> {
read_impl(self.id)
}
pub fn set_timeout(&mut self, timeout: Duration) -> Result<()> {
Keyring::new_impl(self.id).set_timeout(timeout)
}
pub fn security(&self) -> Result<String> {
Keyring::new_impl(self.id).security()
}
pub fn invalidate(self) -> Result<()> {
Keyring::new_impl(self.id).invalidate()
}
pub fn manage(&mut self) -> Result<KeyManager> {
keyctl_assume_authority(Some(self.id))?;
Ok(KeyManager::new(Key::new_impl(self.id)))
}
pub fn compute_dh(private: &Key, prime: &Key, base: &Key) -> Result<Vec<u8>> {
let mut sz = keyctl_dh_compute(private.id, prime.id, base.id, None)?;
let mut buffer = vec![0; sz];
loop {
let write_buffer = buffer.get_backing_buffer();
sz = keyctl_dh_compute(private.id, prime.id, base.id, Some(write_buffer))?;
if sz <= buffer.capacity() {
break;
}
buffer.resize(sz, 0);
}
buffer.truncate(sz);
Ok(buffer)
}
pub fn compute_dh_kdf<O>(
private: &Key,
prime: &Key,
base: &Key,
hash: KeyctlHash,
other: Option<O>,
) -> Result<Vec<u8>>
where
O: AsRef<[u8]>,
{
Self::compute_dh_kdf_impl(
private,
prime,
base,
hash,
other.as_ref().map(AsRef::as_ref),
)
}
fn compute_dh_kdf_impl(
private: &Key,
prime: &Key,
base: &Key,
hash: KeyctlHash,
other: Option<&[u8]>,
) -> Result<Vec<u8>> {
let mut sz =
keyctl_dh_compute_kdf(private.id, prime.id, base.id, hash.hash(), other, None)?;
let mut buffer = vec![0; sz];
loop {
let write_buffer = buffer.get_backing_buffer();
sz = keyctl_dh_compute_kdf(
private.id,
prime.id,
base.id,
hash.hash(),
other,
Some(write_buffer),
)?;
if sz <= buffer.capacity() {
break;
}
buffer.resize(sz, 0);
}
buffer.truncate(sz);
Ok(buffer)
}
fn pkey_query_support_impl(&self, info: &str) -> Result<PKeyQuery> {
keyctl_pkey_query(self.id, info)
}
pub fn pkey_query_support(&self, query: &PublicKeyOptions) -> Result<KeySupportInfo> {
let info = query.info();
self.pkey_query_support_impl(&info)
.map(KeySupportInfo::from_c)
}
pub fn encrypt(&self, options: &PublicKeyOptions, data: &[u8]) -> Result<Vec<u8>> {
let info = options.info();
let support = self.pkey_query_support_impl(&info)?;
let mut buffer = Vec::with_capacity(support.max_enc_size as usize);
let write_buffer = buffer.get_backing_buffer();
let sz = keyctl_pkey_encrypt(self.id, &info, data, write_buffer)?;
buffer.truncate(sz);
Ok(buffer)
}
pub fn decrypt(&self, options: &PublicKeyOptions, data: &[u8]) -> Result<Vec<u8>> {
let info = options.info();
let support = self.pkey_query_support_impl(&info)?;
let mut buffer = Vec::with_capacity(support.max_dec_size as usize);
let write_buffer = buffer.get_backing_buffer();
let sz = keyctl_pkey_decrypt(self.id, &info, data, write_buffer)?;
buffer.truncate(sz);
Ok(buffer)
}
pub fn sign(&self, options: &PublicKeyOptions, data: &[u8]) -> Result<Vec<u8>> {
let info = options.info();
let support = self.pkey_query_support_impl(&info)?;
let mut buffer = Vec::with_capacity(support.max_sig_size as usize);
let write_buffer = buffer.get_backing_buffer();
let sz = keyctl_pkey_sign(self.id, &info, data, write_buffer)?;
buffer.truncate(sz);
Ok(buffer)
}
pub fn verify(
&self,
options: &PublicKeyOptions,
data: &[u8],
signature: &[u8],
) -> Result<bool> {
keyctl_pkey_verify(self.id, &options.info(), data, signature)
}
}
#[derive(Debug, Clone)]
pub struct Description {
pub type_: String,
pub uid: libc::uid_t,
pub gid: libc::gid_t,
pub perms: Permission,
pub description: String,
}
impl Description {
fn parse(desc: &str) -> Option<Description> {
let mut pieces = desc.split(';').collect::<Vec<_>>();
pieces.reverse();
let len = pieces.len();
if len < 5 {
None
} else {
if len > 5 {
error!(
"New fields detected! Please report this upstream to \
https://github.com/mathstuf/rust-keyutils: {}",
desc,
);
}
let bits = KeyPermissions::from_str_radix(pieces[1], 16).unwrap();
if Permission::from_bits(bits).is_none() {
error!(
"New permission bits detected! Please report this upstream to \
https://github.com/mathstuf/rust-keyutils: {}",
bits,
);
}
Some(Description {
type_: pieces[4].to_owned(),
uid: pieces[3].parse::<libc::uid_t>().unwrap(),
gid: pieces[2].parse::<libc::gid_t>().unwrap(),
perms: Permission::from_bits_truncate(bits),
description: pieces[0].to_owned(),
})
}
}
}
#[derive(Debug)]
pub enum TargetKeyring<'a> {
Special(SpecialKeyring),
Keyring(&'a mut Keyring),
}
impl<'a> TargetKeyring<'a> {
fn serial(self) -> KeyringSerial {
match self {
TargetKeyring::Special(special) => special.serial(),
TargetKeyring::Keyring(keyring) => keyring.id,
}
}
}
impl<'a> From<SpecialKeyring> for TargetKeyring<'a> {
fn from(special: SpecialKeyring) -> Self {
TargetKeyring::Special(special)
}
}
impl<'a> From<&'a mut Keyring> for TargetKeyring<'a> {
fn from(keyring: &'a mut Keyring) -> Self {
TargetKeyring::Keyring(keyring)
}
}
impl<'a> From<SpecialKeyring> for Option<TargetKeyring<'a>> {
fn from(special: SpecialKeyring) -> Self {
Some(special.into())
}
}
impl<'a> From<&'a mut Keyring> for Option<TargetKeyring<'a>> {
fn from(keyring: &'a mut Keyring) -> Self {
Some(keyring.into())
}
}
#[derive(Debug, PartialEq, Eq)]
pub struct KeyManager {
key: Key,
}
impl KeyManager {
fn new(key: Key) -> Self {
KeyManager {
key,
}
}
#[cfg(test)]
pub(crate) fn test_new(key: Key) -> Self {
Self::new(key)
}
pub fn request_key_auth_key(create: bool) -> Result<Key> {
keyctl_get_keyring_id(KEY_SPEC_REQKEY_AUTH_KEY, create).map(Key::new_impl)
}
pub fn drop_authority() -> Result<()> {
keyctl_assume_authority(None)
}
pub fn instantiate<'a, T, P>(self, keyring: T, payload: P) -> Result<()>
where
T: Into<Option<TargetKeyring<'a>>>,
P: AsRef<[u8]>,
{
keyctl_instantiate(
self.key.id,
payload.as_ref(),
keyring.into().map(TargetKeyring::serial),
)
}
pub fn reject<'a, T>(self, keyring: T, timeout: Duration, error: errno::Errno) -> Result<()>
where
T: Into<Option<TargetKeyring<'a>>>,
{
keyctl_reject(
self.key.id,
timeout.as_secs() as TimeoutSeconds,
error,
keyring.into().map(TargetKeyring::serial),
)
}
pub fn negate<'a, T>(self, keyring: T, timeout: Duration) -> Result<()>
where
T: Into<Option<TargetKeyring<'a>>>,
{
keyctl_negate(
self.key.id,
timeout.as_secs() as TimeoutSeconds,
keyring.into().map(TargetKeyring::serial),
)
}
}