Skip to content

Commit 971f213

Browse files
authored
Merge pull request #49 from mathstuf/add-dh-kdf-compute
keyctl_dh_compute_kdf: expose the KDF support
2 parents 92f6288 + 39d9252 commit 971f213

File tree

2 files changed

+183
-2
lines changed

2 files changed

+183
-2
lines changed

keyutils-raw/src/functions.rs

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,13 @@ fn ignore(res: libc::c_long) {
103103
assert_eq!(res, 0);
104104
}
105105

106+
fn safe_len<T>(len: usize) -> Result<T>
107+
where
108+
usize: TryInto<T>,
109+
{
110+
len.try_into().map_err(|_| errno::Errno(libc::EINVAL))
111+
}
112+
106113
macro_rules! syscall {
107114
( $( $arg:expr, )* ) => {
108115
check_syscall(libc::syscall($( $arg, )*))
@@ -366,6 +373,14 @@ struct DhComputeParamsKernel {
366373
base: i32,
367374
}
368375

376+
#[repr(C)]
377+
struct DhKdfParamsKernel {
378+
hashname: *const libc::c_char,
379+
otherinfo: *const libc::c_void,
380+
otherinfolen: u32,
381+
_spare: [u32; 8],
382+
}
383+
369384
pub fn keyctl_dh_compute(
370385
private: KeyringSerial,
371386
prime: KeyringSerial,
@@ -384,7 +399,40 @@ pub fn keyctl_dh_compute(
384399
&params as *const DhComputeParamsKernel,
385400
buffer.as_mut().map_or(ptr::null(), |b| b.as_mut_ptr()),
386401
capacity,
387-
0,
402+
ptr::null() as *const DhKdfParamsKernel,
403+
)
404+
}
405+
.map(size)
406+
}
407+
408+
pub fn keyctl_dh_compute_kdf(
409+
private: KeyringSerial,
410+
prime: KeyringSerial,
411+
base: KeyringSerial,
412+
hashname: &str,
413+
otherinfo: Option<&[u8]>,
414+
mut buffer: Option<Out<[u8]>>,
415+
) -> Result<usize> {
416+
let params = DhComputeParamsKernel {
417+
priv_: private.get(),
418+
prime: prime.get(),
419+
base: base.get(),
420+
};
421+
let hash_cstr = cstring(hashname);
422+
let kdf_params = DhKdfParamsKernel {
423+
hashname: hash_cstr.as_ptr(),
424+
otherinfo: otherinfo.map_or(ptr::null(), |d| d.as_ptr()) as *const libc::c_void,
425+
otherinfolen: safe_len(otherinfo.map_or(0, |d| d.len()))?,
426+
_spare: [0; 8],
427+
};
428+
let capacity = buffer.as_mut().map_or(0, |b| b.len());
429+
unsafe {
430+
keyctl!(
431+
libc::KEYCTL_DH_COMPUTE,
432+
&params as *const DhComputeParamsKernel,
433+
buffer.as_mut().map_or(ptr::null(), |b| b.as_mut_ptr()),
434+
capacity,
435+
&kdf_params as *const DhKdfParamsKernel,
388436
)
389437
}
390438
.map(size)

src/api.rs

Lines changed: 134 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
2525
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2626

27-
use std::borrow::Borrow;
27+
use std::borrow::{Borrow, Cow};
2828
use std::convert::TryInto;
2929
use std::mem;
3030
use std::result;
@@ -511,6 +511,76 @@ pub struct Key {
511511
id: KeyringSerial,
512512
}
513513

514+
/// Hashes supported by the kernel.
515+
#[derive(Debug, Clone)]
516+
// #[non_exhaustive]
517+
pub enum KeyctlHash {
518+
/// The MD4 hash.
519+
Md4,
520+
/// The MD5 hash.
521+
Md5,
522+
/// The SHA1 hash.
523+
Sha1,
524+
/// The sha224 hash.
525+
Sha224,
526+
/// The sha256 hash.
527+
Sha256,
528+
/// The sha384 hash.
529+
Sha384,
530+
/// The sha512 hash.
531+
Sha512,
532+
/// The rmd128 hash.
533+
RipeMd128,
534+
/// The rmd160 hash.
535+
RipeMd160,
536+
/// The rmd256 hash.
537+
RipeMd256,
538+
/// The rmd320 hash.
539+
RipeMd320,
540+
/// The wp256 hash.
541+
Wp256,
542+
/// The wp384 hash.
543+
Wp384,
544+
/// The wp512 hash.
545+
Wp512,
546+
/// The tgr128 hash.
547+
Tgr128,
548+
/// The tgr160 hash.
549+
Tgr160,
550+
/// The tgr192 hash.
551+
Tgr192,
552+
/// The sm3-256 hash.
553+
Sm3_256,
554+
/// For extensibility.
555+
OtherEncoding(Cow<'static, str>),
556+
}
557+
558+
impl KeyctlHash {
559+
fn hash(&self) -> &str {
560+
match *self {
561+
KeyctlHash::Md4 => "md4",
562+
KeyctlHash::Md5 => "md5",
563+
KeyctlHash::Sha1 => "sha1",
564+
KeyctlHash::Sha224 => "sha224",
565+
KeyctlHash::Sha256 => "sha256",
566+
KeyctlHash::Sha384 => "sha384",
567+
KeyctlHash::Sha512 => "sha512",
568+
KeyctlHash::RipeMd128 => "rmd128",
569+
KeyctlHash::RipeMd160 => "rmd160",
570+
KeyctlHash::RipeMd256 => "rmd256",
571+
KeyctlHash::RipeMd320 => "rmd320",
572+
KeyctlHash::Wp256 => "wp256",
573+
KeyctlHash::Wp384 => "wp384",
574+
KeyctlHash::Wp512 => "wp512",
575+
KeyctlHash::Tgr128 => "tgr128",
576+
KeyctlHash::Tgr160 => "tgr160",
577+
KeyctlHash::Tgr192 => "tgr192",
578+
KeyctlHash::Sm3_256 => "sm3-256",
579+
KeyctlHash::OtherEncoding(ref s) => &s,
580+
}
581+
}
582+
}
583+
514584
impl Key {
515585
/// Instantiate a key from an ID.
516586
///
@@ -681,6 +751,69 @@ impl Key {
681751
buffer.truncate(sz);
682752
Ok(buffer)
683753
}
754+
755+
/// Compute a key from a Diffie-Hellman shared secret.
756+
///
757+
/// The `base` key contains the remote public key to create a share secret which is then
758+
/// processed using `hash`.
759+
///
760+
/// See [SP800-56A][] for details.
761+
///
762+
/// [SP800-56A]: https://csrc.nist.gov/publications/detail/sp/800-56a/revised/archive/2007-03-14
763+
pub fn compute_dh_kdf<O>(
764+
private: &Key,
765+
prime: &Key,
766+
base: &Key,
767+
hash: KeyctlHash,
768+
other: Option<O>,
769+
) -> Result<Vec<u8>>
770+
where
771+
O: AsRef<[u8]>,
772+
{
773+
Self::compute_dh_kdf_impl(
774+
private,
775+
prime,
776+
base,
777+
hash,
778+
other.as_ref().map(AsRef::as_ref),
779+
)
780+
}
781+
782+
fn compute_dh_kdf_impl(
783+
private: &Key,
784+
prime: &Key,
785+
base: &Key,
786+
hash: KeyctlHash,
787+
other: Option<&[u8]>,
788+
) -> Result<Vec<u8>> {
789+
// Get the size of the description.
790+
let mut sz =
791+
keyctl_dh_compute_kdf(private.id, prime.id, base.id, hash.hash(), other, None)?;
792+
// Allocate this description.
793+
let mut buffer = vec![0; sz];
794+
loop {
795+
let write_buffer = buffer.get_backing_buffer();
796+
// Fetch the description.
797+
sz = keyctl_dh_compute_kdf(
798+
private.id,
799+
prime.id,
800+
base.id,
801+
hash.hash(),
802+
other,
803+
Some(write_buffer),
804+
)?;
805+
806+
// If we got everything, exit.
807+
if sz <= buffer.capacity() {
808+
break;
809+
}
810+
811+
// Resize for the additional capacity we need.
812+
buffer.resize(sz, 0);
813+
}
814+
buffer.truncate(sz);
815+
Ok(buffer)
816+
}
684817
}
685818

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

0 commit comments

Comments
 (0)