Skip to content

Commit 3a72e06

Browse files
committed
pkey: add support for pkey APIs
1 parent 170b6c5 commit 3a72e06

File tree

4 files changed

+341
-1
lines changed

4 files changed

+341
-1
lines changed

keyutils-raw/src/constants.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,11 @@ pub const KEY_SPEC_USER_SESSION_KEYRING: KeyringSerial = unsafe { KeyringSeri
4040
pub const KEY_SPEC_GROUP_KEYRING: KeyringSerial = unsafe { KeyringSerial::new_unchecked(-6) };
4141
pub const KEY_SPEC_REQKEY_AUTH_KEY: KeyringSerial = unsafe { KeyringSerial::new_unchecked(-7) };
4242

43+
pub const KEYCTL_SUPPORTS_ENCRYPT: u32 = 0x01;
44+
pub const KEYCTL_SUPPORTS_DECRYPT: u32 = 0x02;
45+
pub const KEYCTL_SUPPORTS_SIGN: u32 = 0x04;
46+
pub const KEYCTL_SUPPORTS_VERIFY: u32 = 0x08;
47+
4348
pub const KEY_POS_VIEW: KeyPermissions = 0x0100_0000; /* possessor can view a key's attributes */
4449
pub const KEY_POS_READ: KeyPermissions = 0x0200_0000; /* possessor can read key payload / view keyring */
4550
pub const KEY_POS_WRITE: KeyPermissions = 0x0400_0000; /* possessor can update key payload / add link to keyring */

keyutils-raw/src/functions.rs

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -472,3 +472,172 @@ pub fn keyctl_restrict_keyring(keyring: KeyringSerial, restriction: Restriction)
472472
}
473473
.map(ignore)
474474
}
475+
476+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
477+
// #[non_exhaustive]
478+
pub struct PKeyQuery {
479+
pub supported_ops: u32,
480+
pub key_size: u32,
481+
pub max_data_size: u16,
482+
pub max_sig_size: u16,
483+
pub max_enc_size: u16,
484+
pub max_dec_size: u16,
485+
}
486+
487+
#[repr(C)]
488+
pub struct PKeyQueryKernel {
489+
supported_ops: u32,
490+
key_size: u32,
491+
max_data_size: u16,
492+
max_sig_size: u16,
493+
max_enc_size: u16,
494+
max_dec_size: u16,
495+
_spare: [u32; 10],
496+
}
497+
498+
impl PKeyQueryKernel {
499+
fn zeroed() -> Self {
500+
PKeyQueryKernel {
501+
supported_ops: 0,
502+
key_size: 0,
503+
max_data_size: 0,
504+
max_sig_size: 0,
505+
max_enc_size: 0,
506+
max_dec_size: 0,
507+
_spare: [0; 10],
508+
}
509+
}
510+
}
511+
512+
impl From<PKeyQueryKernel> for PKeyQuery {
513+
fn from(kernel: PKeyQueryKernel) -> Self {
514+
PKeyQuery {
515+
supported_ops: kernel.supported_ops,
516+
key_size: kernel.key_size,
517+
max_data_size: kernel.max_data_size,
518+
max_sig_size: kernel.max_sig_size,
519+
max_enc_size: kernel.max_enc_size,
520+
max_dec_size: kernel.max_dec_size,
521+
}
522+
}
523+
}
524+
525+
pub fn keyctl_pkey_query(key: KeyringSerial, info: &str) -> Result<PKeyQuery> {
526+
let mut query = PKeyQueryKernel::zeroed();
527+
let info_cstr = cstring(info);
528+
unsafe {
529+
keyctl!(
530+
libc::KEYCTL_PKEY_QUERY,
531+
key.get(),
532+
0,
533+
info_cstr.as_ptr(),
534+
&mut query as *mut PKeyQueryKernel,
535+
)
536+
}
537+
.map(ignore)?;
538+
539+
Ok(query.into())
540+
}
541+
542+
#[repr(C)]
543+
struct PKeyOpParamsKernel {
544+
key_id: i32,
545+
in_len: u32,
546+
out_len: u32,
547+
in2_len: u32,
548+
}
549+
550+
pub fn keyctl_pkey_encrypt(
551+
key: KeyringSerial,
552+
info: &str,
553+
data: &[u8],
554+
mut buffer: Out<[u8]>,
555+
) -> Result<usize> {
556+
let params = PKeyOpParamsKernel {
557+
key_id: key.get(),
558+
in_len: safe_len(data.len())?,
559+
out_len: safe_len(buffer.len())?,
560+
in2_len: 0,
561+
};
562+
let info_cstr = cstring(info);
563+
unsafe {
564+
keyctl!(
565+
libc::KEYCTL_PKEY_ENCRYPT,
566+
&params as *const PKeyOpParamsKernel,
567+
info_cstr.as_ptr(),
568+
data.as_ptr(),
569+
buffer.as_mut_ptr(),
570+
)
571+
}
572+
.map(size)
573+
}
574+
575+
pub fn keyctl_pkey_decrypt(
576+
key: KeyringSerial,
577+
info: &str,
578+
data: &[u8],
579+
mut buffer: Out<[u8]>,
580+
) -> Result<usize> {
581+
let params = PKeyOpParamsKernel {
582+
key_id: key.get(),
583+
in_len: safe_len(data.len())?,
584+
out_len: safe_len(buffer.len())?,
585+
in2_len: 0,
586+
};
587+
let info_cstr = cstring(info);
588+
unsafe {
589+
keyctl!(
590+
libc::KEYCTL_PKEY_DECRYPT,
591+
&params as *const PKeyOpParamsKernel,
592+
info_cstr.as_ptr(),
593+
data.as_ptr(),
594+
buffer.as_mut_ptr(),
595+
)
596+
}
597+
.map(size)
598+
}
599+
600+
pub fn keyctl_pkey_sign(
601+
key: KeyringSerial,
602+
info: &str,
603+
data: &[u8],
604+
mut buffer: Out<[u8]>,
605+
) -> Result<usize> {
606+
let params = PKeyOpParamsKernel {
607+
key_id: key.get(),
608+
in_len: safe_len(data.len())?,
609+
out_len: safe_len(buffer.len())?,
610+
in2_len: 0,
611+
};
612+
let info_cstr = cstring(info);
613+
unsafe {
614+
keyctl!(
615+
libc::KEYCTL_PKEY_SIGN,
616+
&params as *const PKeyOpParamsKernel,
617+
info_cstr.as_ptr(),
618+
data.as_ptr(),
619+
buffer.as_mut_ptr(),
620+
)
621+
}
622+
.map(size)
623+
}
624+
625+
pub fn keyctl_pkey_verify(key: KeyringSerial, info: &str, data: &[u8], sig: &[u8]) -> Result<bool> {
626+
let params = PKeyOpParamsKernel {
627+
key_id: key.get(),
628+
in_len: safe_len(data.len())?,
629+
out_len: 0,
630+
in2_len: safe_len(sig.len())?,
631+
};
632+
let info_cstr = cstring(info);
633+
unsafe {
634+
keyctl!(
635+
libc::KEYCTL_PKEY_VERIFY,
636+
&params as *const PKeyOpParamsKernel,
637+
info_cstr.as_ptr(),
638+
data.as_ptr(),
639+
sig.as_ptr(),
640+
)
641+
}
642+
.map(|res| res == 0)
643+
}

src/api.rs

Lines changed: 135 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ use keyutils_raw::*;
3535
use log::error;
3636
use uninit::extension_traits::VecCapacity;
3737

38-
use crate::constants::{Permission, SpecialKeyring};
38+
use crate::constants::{KeyctlSupportFlags, Permission, SpecialKeyring};
3939
use crate::keytype::*;
4040
use crate::keytypes;
4141

@@ -511,6 +511,64 @@ pub struct Key {
511511
id: KeyringSerial,
512512
}
513513

514+
/// Structure to store results from a query on optional feature support for a key.
515+
#[derive(Debug, Clone, Copy)]
516+
pub struct KeySupportInfo {
517+
/// Features supported by the key.
518+
pub supported_ops: KeyctlSupportFlags,
519+
/// The size of the key (in bits).
520+
pub key_size: u32,
521+
/// The maximum size of a data blob which may be signed.
522+
pub max_data_size: u16,
523+
/// The maximum size of a signature blob.
524+
pub max_sig_size: u16,
525+
/// The maximum size of a blob to be encrypted.
526+
pub max_enc_size: u16,
527+
/// The maximum size of a blob to be decrypted.
528+
pub max_dec_size: u16,
529+
}
530+
531+
impl KeySupportInfo {
532+
fn from_c(c_info: PKeyQuery) -> Self {
533+
KeySupportInfo {
534+
supported_ops: c_info.supported_ops,
535+
key_size: c_info.key_size,
536+
max_data_size: c_info.max_data_size,
537+
max_sig_size: c_info.max_sig_size,
538+
max_enc_size: c_info.max_enc_size,
539+
max_dec_size: c_info.max_dec_size,
540+
}
541+
}
542+
}
543+
544+
/// Encodings supported by the kernel.
545+
#[derive(Debug, Clone)]
546+
// #[non_exhaustive]
547+
pub enum KeyctlEncoding {
548+
/// The RSASSA-PKCS1-v1.5 encoding.
549+
RsassaPkcs1V15,
550+
/// The RSAES-PKCS1-v1.5 encoding.
551+
RsaesPkcs1V15,
552+
/// The RSASSA-PSS encoding.
553+
RsassaPss,
554+
/// The RSAES-OAEP encoding.
555+
RsaesOaep,
556+
/// For extensibility.
557+
OtherEncoding(Cow<'static, str>),
558+
}
559+
560+
impl KeyctlEncoding {
561+
fn encoding(&self) -> &str {
562+
match *self {
563+
KeyctlEncoding::RsassaPkcs1V15 => "pkcs1",
564+
KeyctlEncoding::RsaesPkcs1V15 => "pkcs1",
565+
KeyctlEncoding::RsassaPss => "pss",
566+
KeyctlEncoding::RsaesOaep => "oaep",
567+
KeyctlEncoding::OtherEncoding(ref s) => &s,
568+
}
569+
}
570+
}
571+
514572
/// Hashes supported by the kernel.
515573
#[derive(Debug, Clone)]
516574
// #[non_exhaustive]
@@ -581,6 +639,28 @@ impl KeyctlHash {
581639
}
582640
}
583641

642+
/// Options for output from public key functions (encryption, decryption, signing, and verifying).
643+
#[derive(Debug, Clone)]
644+
pub struct PublicKeyOptions {
645+
/// The encoding of the encrypted blob or the signature.
646+
pub encoding: Option<KeyctlEncoding>,
647+
/// Hash algorithm to use (if the encoding uses it).
648+
pub hash: Option<KeyctlHash>,
649+
}
650+
651+
impl PublicKeyOptions {
652+
fn info(&self) -> String {
653+
let options = [
654+
("enc", self.encoding.as_ref().map(KeyctlEncoding::encoding)),
655+
("hash", self.hash.as_ref().map(KeyctlHash::hash)),
656+
]
657+
.iter()
658+
.map(|&(key, value)| value.map_or_else(String::new, |v| format!("{}={}", key, v)))
659+
.collect::<Vec<_>>();
660+
options.join(" ").trim().to_owned()
661+
}
662+
}
663+
584664
impl Key {
585665
/// Instantiate a key from an ID.
586666
///
@@ -814,6 +894,60 @@ impl Key {
814894
buffer.truncate(sz);
815895
Ok(buffer)
816896
}
897+
898+
fn pkey_query_support_impl(&self, info: &str) -> Result<PKeyQuery> {
899+
keyctl_pkey_query(self.id, info)
900+
}
901+
902+
/// Query which optionally supported features may be used by the key.
903+
pub fn pkey_query_support(&self, query: &PublicKeyOptions) -> Result<KeySupportInfo> {
904+
let info = query.info();
905+
self.pkey_query_support_impl(&info)
906+
.map(KeySupportInfo::from_c)
907+
}
908+
909+
/// Encrypt data using the key.
910+
pub fn encrypt(&self, options: &PublicKeyOptions, data: &[u8]) -> Result<Vec<u8>> {
911+
let info = options.info();
912+
let support = self.pkey_query_support_impl(&info)?;
913+
let mut buffer = Vec::with_capacity(support.max_enc_size as usize);
914+
let write_buffer = buffer.get_backing_buffer();
915+
let sz = keyctl_pkey_encrypt(self.id, &info, data, write_buffer)?;
916+
buffer.truncate(sz);
917+
Ok(buffer)
918+
}
919+
920+
/// Decrypt data using the key.
921+
pub fn decrypt(&self, options: &PublicKeyOptions, data: &[u8]) -> Result<Vec<u8>> {
922+
let info = options.info();
923+
let support = self.pkey_query_support_impl(&info)?;
924+
let mut buffer = Vec::with_capacity(support.max_dec_size as usize);
925+
let write_buffer = buffer.get_backing_buffer();
926+
let sz = keyctl_pkey_decrypt(self.id, &info, data, write_buffer)?;
927+
buffer.truncate(sz);
928+
Ok(buffer)
929+
}
930+
931+
/// Sign data using the key.
932+
pub fn sign(&self, options: &PublicKeyOptions, data: &[u8]) -> Result<Vec<u8>> {
933+
let info = options.info();
934+
let support = self.pkey_query_support_impl(&info)?;
935+
let mut buffer = Vec::with_capacity(support.max_sig_size as usize);
936+
let write_buffer = buffer.get_backing_buffer();
937+
let sz = keyctl_pkey_sign(self.id, &info, data, write_buffer)?;
938+
buffer.truncate(sz);
939+
Ok(buffer)
940+
}
941+
942+
/// Verify a signature of the data using the key.
943+
pub fn verify(
944+
&self,
945+
options: &PublicKeyOptions,
946+
data: &[u8],
947+
signature: &[u8],
948+
) -> Result<bool> {
949+
keyctl_pkey_verify(self.id, &options.info(), data, signature)
950+
}
817951
}
818952

819953
/// Structure representing the metadata about a key or keyring.

src/constants.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,21 @@ bitflags! {
146146
}
147147
}
148148

149+
/// They kernel type for representing support for optional features.
150+
///
151+
/// Asymmetric keys might only support a limited set of operations. These flags indicate which
152+
/// operations are available.
153+
pub type KeyctlSupportFlags = u32;
154+
155+
bitflags! {
156+
struct KeyctlSupportFlag: KeyctlSupportFlags {
157+
const SUPPORTS_ENCRYPT = 0x01;
158+
const SUPPORTS_DECRYPT = 0x02;
159+
const SUPPORTS_SIGN = 0x04;
160+
const SUPPORTS_VERIFY = 0x08;
161+
}
162+
}
163+
149164
#[test]
150165
fn test_keyring_ids() {
151166
assert_eq!(SpecialKeyring::Thread.serial(), KEY_SPEC_THREAD_KEYRING);
@@ -202,3 +217,20 @@ fn test_other_permission_bits() {
202217
assert_eq!(Permission::OTHER_SET_ATTRIBUTE.bits, KEY_OTH_SETATTR);
203218
assert_eq!(Permission::OTHER_ALL.bits, KEY_OTH_ALL);
204219
}
220+
221+
#[test]
222+
fn test_support_flags() {
223+
assert_eq!(
224+
KeyctlSupportFlag::SUPPORTS_ENCRYPT.bits,
225+
KEYCTL_SUPPORTS_ENCRYPT,
226+
);
227+
assert_eq!(
228+
KeyctlSupportFlag::SUPPORTS_DECRYPT.bits,
229+
KEYCTL_SUPPORTS_DECRYPT,
230+
);
231+
assert_eq!(KeyctlSupportFlag::SUPPORTS_SIGN.bits, KEYCTL_SUPPORTS_SIGN);
232+
assert_eq!(
233+
KeyctlSupportFlag::SUPPORTS_VERIFY.bits,
234+
KEYCTL_SUPPORTS_VERIFY,
235+
);
236+
}

0 commit comments

Comments
 (0)