Skip to content

Commit 8f8dc36

Browse files
committed
WIP: api: bind the public key API
1 parent 1826533 commit 8f8dc36

File tree

3 files changed

+270
-1
lines changed

3 files changed

+270
-1
lines changed

src/api.rs

Lines changed: 172 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,128 @@ pub struct Key {
344344
id: KeyringSerial,
345345
}
346346

347+
/// Structure to store results from a query on optional feature support for a key.
348+
pub struct KeySupportInfo {
349+
/// Features supported by the key.
350+
pub supported_ops: KeyctlSupportFlags,
351+
/// The size of the key (in bits).
352+
pub key_size: u32,
353+
/// The maximum size of a data blob which may be signed.
354+
pub max_data_size: u16,
355+
/// The maximum size of a signature blob.
356+
pub max_sig_size: u16,
357+
/// The maximum size of a blob to be encrypted.
358+
pub max_enc_size: u16,
359+
/// The maximum size of a blob to be decrypted.
360+
pub max_dec_size: u16,
361+
}
362+
363+
impl KeySupportInfo {
364+
fn from_c(c_info: keyctl_pkey_query) -> Self {
365+
KeySupportInfo {
366+
supported_ops: c_info.supported_ops,
367+
key_size: c_info.key_size,
368+
max_data_size: c_info.max_data_size,
369+
max_sig_size: c_info.max_sig_size,
370+
max_enc_size: c_info.max_enc_size,
371+
max_dec_size: c_info.max_dec_size,
372+
}
373+
}
374+
}
375+
376+
/// Encodings supported by the kernel.
377+
pub enum KeyctlEncoding {
378+
RSASSA_PKCS1_v1_5,
379+
RSAES_PKCS1_v1_5,
380+
RSASSA_PSS,
381+
RSAES_OAEP,
382+
/// For extensibility.
383+
OtherEncoding(String),
384+
}
385+
386+
impl KeyctlEncoding {
387+
fn encoding(&self) -> &str {
388+
match *self {
389+
KeyctlEncoding::RSASSA_PKCS1_v1_5 => "pkcs1",
390+
KeyctlEncoding::RSAES_PKCS1_v1_5 => "pkcs1",
391+
KeyctlEncoding::RSASSA_PSS => "pss",
392+
KeyctlEncoding::RSAES_OAEP => "oaep",
393+
KeyctlEncoding::OtherEncoding(ref s) => &s,
394+
}
395+
}
396+
}
397+
398+
/// Hashes supported by the kernel.
399+
pub enum KeyctlHash {
400+
MD4,
401+
MD5,
402+
SHA1,
403+
SHA224,
404+
SHA256,
405+
SHA384,
406+
SHA512,
407+
RIPE_MD_128,
408+
RIPE_MD_160,
409+
RIPE_MD_256,
410+
RIPE_MD_320,
411+
WP_256,
412+
WP_384,
413+
WP_512,
414+
TGR_128,
415+
TGR_160,
416+
TGR_192,
417+
SM3_256,
418+
/// For extensibility.
419+
OtherEncoding(String),
420+
}
421+
422+
impl KeyctlHash {
423+
fn hash(&self) -> &str {
424+
match *self {
425+
KeyctlHash::MD4 => "md4",
426+
KeyctlHash::MD5 => "md5",
427+
KeyctlHash::SHA1 => "sha1",
428+
KeyctlHash::SHA224 => "sha224",
429+
KeyctlHash::SHA256 => "sha256",
430+
KeyctlHash::SHA384 => "sha384",
431+
KeyctlHash::SHA512 => "sha512",
432+
KeyctlHash::RIPE_MD_128 => "rmd128",
433+
KeyctlHash::RIPE_MD_160 => "rmd160",
434+
KeyctlHash::RIPE_MD_256 => "rmd256",
435+
KeyctlHash::RIPE_MD_320 => "rmd320",
436+
KeyctlHash::WP_256 => "wp256",
437+
KeyctlHash::WP_384 => "wp384",
438+
KeyctlHash::WP_512 => "wp512",
439+
KeyctlHash::TGR_128 => "tgr128",
440+
KeyctlHash::TGR_160 => "tgr160",
441+
KeyctlHash::TGR_192 => "tgr192",
442+
KeyctlHash::SM3_256 => "sm3-256",
443+
KeyctlHash::OtherEncoding(ref s) => &s,
444+
}
445+
}
446+
}
447+
448+
/// Options for output from public key functions (encryption, decryption, signing, and verifying).
449+
pub struct PublicKeyOptions {
450+
/// The encoding of the encrypted blob or the signature.
451+
pub encoding: Option<KeyctlEncoding>,
452+
/// Hash algorithm to use (if the encoding uses it).
453+
pub hash: Option<KeyctlHash>,
454+
}
455+
456+
impl PublicKeyOptions {
457+
fn info(&self) -> String {
458+
let options = [
459+
("enc", self.encoding.as_ref().map(KeyctlEncoding::encoding)),
460+
("hash", self.hash.as_ref().map(KeyctlHash::hash)),
461+
].iter().map(|&(key, value)| {
462+
value.map_or_else(String::new,
463+
|v| format!("{}={}", key, v))
464+
}).collect::<Vec<_>>();
465+
options.join(" ").trim().to_owned()
466+
}
467+
}
468+
347469
impl Key {
348470
/// Requests a key with the given description by searching the thread, process, and session
349471
/// keyrings.
@@ -445,12 +567,61 @@ impl Key {
445567

446568
/// Compute a Diffie-Hellman prime for use as a shared secret or public key.
447569
pub fn compute_dh(private: &Key, prime: &Key, base: &Key) -> Result<Vec<u8>> {
448-
let sz = try!(check_call_ret(unsafe { keyctl_dh_compute(private.id, prime.id, base.id, ptr::null() as *mut libc::c_char, 0) }));
570+
let sz = try!(check_call_ret(unsafe { keyctl_dh_compute(private.id, prime.id, base.id, ptr::null_mut() as *mut libc::c_char, 0) }));
449571
let mut buffer = Vec::with_capacity(sz as usize);
450572
let actual_sz = try!(check_call_ret(unsafe { keyctl_dh_compute(private.id, prime.id, base.id, buffer.as_mut_ptr() as *mut libc::c_char, sz as usize) }));
451573
unsafe { buffer.set_len(actual_sz as usize) };
452574
Ok(buffer)
453575
}
576+
577+
/// Query which optionally supported features may be used by the key.
578+
pub fn query_support(&self, password: &Option<Key>) -> Result<KeySupportInfo> {
579+
let mut info = keyctl_pkey_query::new();
580+
let password_id = password.as_ref().map_or(0, |pass| pass.id);
581+
try!(check_call_ret(unsafe { keyctl_pkey_query(self.id, password_id, &mut info) }));
582+
Ok(KeySupportInfo::from_c(info))
583+
}
584+
585+
/// Encrypt data using the key.
586+
pub fn encrypt(&self, password: &Option<Key>, options: &PublicKeyOptions, data: &[u8]) -> Result<Vec<u8>> {
587+
let password_id = password.as_ref().map_or(0, |pass| pass.id);
588+
let info_cstr = CString::new(options.info()).unwrap();
589+
let sz = try!(self.query_support(password)).max_enc_size;
590+
let mut buffer = Vec::with_capacity(sz as usize);
591+
let actual_sz = try!(check_call_ret(unsafe { keyctl_pkey_encrypt(self.id, password_id, info_cstr.as_ptr(), data.as_ptr() as *const libc::c_void, data.len(), buffer.as_mut_ptr() as *mut libc::c_void, buffer.len()) }));
592+
unsafe { buffer.set_len(actual_sz as usize) };
593+
Ok(buffer)
594+
}
595+
596+
/// Decrypt data using the key.
597+
pub fn decrypt(&self, password: &Option<Key>, options: &PublicKeyOptions, data: &[u8]) -> Result<Vec<u8>> {
598+
let password_id = password.as_ref().map_or(0, |pass| pass.id);
599+
let info_cstr = CString::new(options.info()).unwrap();
600+
let sz = try!(self.query_support(password)).max_dec_size;
601+
let mut buffer = Vec::with_capacity(sz as usize);
602+
let actual_sz = try!(check_call_ret(unsafe { keyctl_pkey_decrypt(self.id, password_id, info_cstr.as_ptr(), data.as_ptr() as *const libc::c_void, data.len(), buffer.as_mut_ptr() as *mut libc::c_void, buffer.len()) }));
603+
unsafe { buffer.set_len(actual_sz as usize) };
604+
Ok(buffer)
605+
}
606+
607+
/// Sign data using the key.
608+
pub fn sign(&self, password: &Option<Key>, options: &PublicKeyOptions, data: &[u8]) -> Result<Vec<u8>> {
609+
let password_id = password.as_ref().map_or(0, |pass| pass.id);
610+
let info_cstr = CString::new(options.info()).unwrap();
611+
let sz = try!(self.query_support(password)).max_sig_size;
612+
let mut buffer = Vec::with_capacity(sz as usize);
613+
let actual_sz = try!(check_call_ret(unsafe { keyctl_pkey_sign(self.id, password_id, info_cstr.as_ptr(), data.as_ptr() as *const libc::c_void, data.len(), buffer.as_mut_ptr() as *mut libc::c_void, buffer.len()) }));
614+
unsafe { buffer.set_len(actual_sz as usize) };
615+
Ok(buffer)
616+
}
617+
618+
/// Verify a signature of the data using the key.
619+
pub fn verify(&self, password: &Option<Key>, options: &PublicKeyOptions, data: &[u8], signature: &[u8]) -> Result<bool> {
620+
let password_id = password.as_ref().map_or(0, |pass| pass.id);
621+
let info_cstr = CString::new(options.info()).unwrap();
622+
let res = try!(check_call_ret(unsafe { keyctl_pkey_sign(self.id, password_id, info_cstr.as_ptr(), data.as_ptr() as *const libc::c_void, data.len(), signature.as_ptr() as *mut libc::c_void, signature.len()) }));
623+
Ok(res == 0)
624+
}
454625
}
455626

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

src/constants.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,20 @@ bitflags! {
182182
}
183183
}
184184

185+
/// They kernel type for representing support for optional features.
186+
///
187+
/// TODO: explain more
188+
pub type KeyctlSupportFlags = u32;
189+
190+
bitflags! {
191+
flags KeyctlSupportFlag: KeyctlSupportFlags {
192+
const SUPPORTS_ENCRYPT = 0x01,
193+
const SUPPORTS_DECRYPT = 0x02,
194+
const SUPPORTS_SIGN = 0x04,
195+
const SUPPORTS_VERIFY = 0x08,
196+
}
197+
}
198+
185199
#[test]
186200
fn test_keyring_ids() {
187201
assert_eq!(SpecialKeyring::ThreadKeyring.serial(),
@@ -250,3 +264,11 @@ fn test_permission_bits() {
250264
assert_eq!(OTHER_SET_ATTRIBUTE.bits, KEY_OTH_SETATTR);
251265
assert_eq!(OTHER_ALL.bits, KEY_OTH_ALL);
252266
}
267+
268+
#[test]
269+
fn test_support_flags() {
270+
assert_eq!(SUPPORTS_ENCRYPT.bits, KEYCTL_SUPPORTS_ENCRYPT);
271+
assert_eq!(SUPPORTS_DECRYPT.bits, KEYCTL_SUPPORTS_DECRYPT);
272+
assert_eq!(SUPPORTS_SIGN.bits, KEYCTL_SUPPORTS_SIGN);
273+
assert_eq!(SUPPORTS_VERIFY.bits, KEYCTL_SUPPORTS_VERIFY);
274+
}

src/ffi.rs

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,41 @@ pub const KEY_OTH_LINK: key_perm_t = 0x00000010;
5858
pub const KEY_OTH_SETATTR: key_perm_t = 0x00000020;
5959
pub const KEY_OTH_ALL: key_perm_t = 0x0000003f;
6060

61+
// No actual type in the API, but create one for simplicity.
62+
#[allow(non_camel_case_types)]
63+
pub type _keyctl_support_t = libc::uint32_t;
64+
65+
pub const KEYCTL_SUPPORTS_ENCRYPT: _keyctl_support_t = 0x01;
66+
pub const KEYCTL_SUPPORTS_DECRYPT: _keyctl_support_t = 0x02;
67+
pub const KEYCTL_SUPPORTS_SIGN: _keyctl_support_t = 0x04;
68+
pub const KEYCTL_SUPPORTS_VERIFY: _keyctl_support_t = 0x08;
69+
70+
#[repr(C)]
71+
#[allow(non_camel_case_types)]
72+
pub struct keyctl_pkey_query {
73+
pub supported_ops: libc::uint32_t,
74+
pub key_size: libc::uint32_t,
75+
pub max_data_size: libc::uint16_t,
76+
pub max_sig_size: libc::uint16_t,
77+
pub max_enc_size: libc::uint16_t,
78+
pub max_dec_size: libc::uint16_t,
79+
__spare: [libc::uint32_t; 10],
80+
}
81+
82+
impl keyctl_pkey_query {
83+
pub fn new() -> Self {
84+
keyctl_pkey_query {
85+
supported_ops: 0,
86+
key_size: 0,
87+
max_data_size: 0,
88+
max_sig_size: 0,
89+
max_enc_size: 0,
90+
max_dec_size: 0,
91+
__spare: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
92+
}
93+
}
94+
}
95+
6196
#[link(name = "keyutils")]
6297
extern "C" {
6398
pub fn add_key(
@@ -173,4 +208,45 @@ extern "C" {
173208
buffer: *mut libc::c_char,
174209
buflen: libc::size_t)
175210
-> libc::c_long;
211+
pub fn keyctl_pkey_query(
212+
key: key_serial_t,
213+
password: key_serial_t,
214+
info: *mut keyctl_pkey_query)
215+
-> libc::c_long;
216+
pub fn keyctl_pkey_encrypt(
217+
key: key_serial_t,
218+
password: key_serial_t,
219+
info: *const libc::c_char,
220+
data: *const libc::c_void,
221+
data_len: libc::size_t,
222+
enc: *mut libc::c_void,
223+
enc_len: libc::size_t)
224+
-> libc::c_long;
225+
pub fn keyctl_pkey_decrypt(
226+
key: key_serial_t,
227+
password: key_serial_t,
228+
info: *const libc::c_char,
229+
enc: *const libc::c_void,
230+
enc_len: libc::size_t,
231+
data: *mut libc::c_void,
232+
data_len: libc::size_t)
233+
-> libc::c_long;
234+
pub fn keyctl_pkey_sign(
235+
key: key_serial_t,
236+
password: key_serial_t,
237+
info: *const libc::c_char,
238+
data: *const libc::c_void,
239+
data_len: libc::size_t,
240+
sig: *mut libc::c_void,
241+
sig_len: libc::size_t)
242+
-> libc::c_long;
243+
pub fn keyctl_pkey_verify(
244+
key: key_serial_t,
245+
password: key_serial_t,
246+
info: *const libc::c_char,
247+
data: *const libc::c_void,
248+
data_len: libc::size_t,
249+
sig: *const libc::c_void,
250+
sig_len: libc::size_t)
251+
-> libc::c_long;
176252
}

0 commit comments

Comments
 (0)