diff --git a/src/api.rs b/src/api.rs index 39ca0d0..606ca48 100644 --- a/src/api.rs +++ b/src/api.rs @@ -640,7 +640,8 @@ impl KeyctlHash { } /// Options for output from public key functions (encryption, decryption, signing, and verifying). -#[derive(Debug, Clone)] +#[derive(Debug, Default, Clone)] +// #[non_exhaustive] pub struct PublicKeyOptions { /// The encoding of the encrypted blob or the signature. pub encoding: Option, diff --git a/src/tests/mod.rs b/src/tests/mod.rs index 740048b..013a6f0 100644 --- a/src/tests/mod.rs +++ b/src/tests/mod.rs @@ -37,6 +37,7 @@ mod keytype; mod link; mod newring; mod permitting; +mod pkey; mod reading; mod revoke; mod search; diff --git a/src/tests/pkey.rs b/src/tests/pkey.rs new file mode 100644 index 0000000..7113859 --- /dev/null +++ b/src/tests/pkey.rs @@ -0,0 +1,205 @@ +// Copyright (c) 2020, Ben Boeckel +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of this project nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +use crate::keytypes::User; + +use super::utils; +use super::utils::kernel::*; + +#[test] +fn invalid_keyring_query() { + let keyring = utils::invalid_keyring(); + let key = utils::keyring_as_key(&keyring); + let err = key.pkey_query_support(&Default::default()).unwrap_err(); + assert_eq!(err, errno::Errno(libc::EINVAL)); +} + +#[test] +fn invalid_key_query() { + let key = utils::invalid_key(); + let err = key.pkey_query_support(&Default::default()).unwrap_err(); + assert_eq!(err, errno::Errno(libc::EINVAL)); +} + +#[test] +fn pkey_query_keyring() { + let keyring = utils::new_test_keyring(); + let key = utils::keyring_as_key(&keyring); + let err = key.pkey_query_support(&Default::default()).unwrap_err(); + + if *HAVE_PKEY { + assert_eq!(err, errno::Errno(libc::EOPNOTSUPP)); + } else { + assert_eq!(err, errno::Errno(libc::ENOSYS)); + } +} + +#[test] +fn pkey_query_user() { + let mut keyring = utils::new_test_keyring(); + let payload = &b"payload"[..]; + let key = keyring + .add_key::("pkey_query_user", payload) + .unwrap(); + + let err = key.pkey_query_support(&Default::default()).unwrap_err(); + + if *HAVE_PKEY { + assert_eq!(err, errno::Errno(libc::EOPNOTSUPP)); + } else { + assert_eq!(err, errno::Errno(libc::ENOSYS)); + } +} + +#[test] +fn pkey_encrypt_keyring() { + let keyring = utils::new_test_keyring(); + let key = utils::keyring_as_key(&keyring); + let data = &b"data"[..]; + let err = key.encrypt(&Default::default(), data).unwrap_err(); + + if *HAVE_PKEY { + assert_eq!(err, errno::Errno(libc::EOPNOTSUPP)); + } else { + assert_eq!(err, errno::Errno(libc::ENOSYS)); + } +} + +#[test] +fn pkey_encrypt_user() { + let mut keyring = utils::new_test_keyring(); + let payload = &b"payload"[..]; + let key = keyring + .add_key::("pkey_encrypt_user", payload) + .unwrap(); + + let data = &b"data"[..]; + let err = key.encrypt(&Default::default(), data).unwrap_err(); + + if *HAVE_PKEY { + assert_eq!(err, errno::Errno(libc::EOPNOTSUPP)); + } else { + assert_eq!(err, errno::Errno(libc::ENOSYS)); + } +} + +#[test] +fn pkey_decrypt_keyring() { + let keyring = utils::new_test_keyring(); + let key = utils::keyring_as_key(&keyring); + let data = &b"data"[..]; + let err = key.decrypt(&Default::default(), data).unwrap_err(); + + if *HAVE_PKEY { + assert_eq!(err, errno::Errno(libc::EOPNOTSUPP)); + } else { + assert_eq!(err, errno::Errno(libc::ENOSYS)); + } +} + +#[test] +fn pkey_decrypt_user() { + let mut keyring = utils::new_test_keyring(); + let payload = &b"payload"[..]; + let key = keyring + .add_key::("pkey_decrypt_user", payload) + .unwrap(); + + let data = &b"data"[..]; + let err = key.decrypt(&Default::default(), data).unwrap_err(); + + if *HAVE_PKEY { + assert_eq!(err, errno::Errno(libc::EOPNOTSUPP)); + } else { + assert_eq!(err, errno::Errno(libc::ENOSYS)); + } +} + +#[test] +fn pkey_sign_keyring() { + let keyring = utils::new_test_keyring(); + let key = utils::keyring_as_key(&keyring); + let data = &b"data"[..]; + let err = key.sign(&Default::default(), data).unwrap_err(); + + if *HAVE_PKEY { + assert_eq!(err, errno::Errno(libc::EOPNOTSUPP)); + } else { + assert_eq!(err, errno::Errno(libc::ENOSYS)); + } +} + +#[test] +fn pkey_sign_user() { + let mut keyring = utils::new_test_keyring(); + let payload = &b"payload"[..]; + let key = keyring + .add_key::("pkey_sign_user", payload) + .unwrap(); + + let data = &b"data"[..]; + let err = key.sign(&Default::default(), data).unwrap_err(); + + if *HAVE_PKEY { + assert_eq!(err, errno::Errno(libc::EOPNOTSUPP)); + } else { + assert_eq!(err, errno::Errno(libc::ENOSYS)); + } +} + +#[test] +fn pkey_verify_keyring() { + let keyring = utils::new_test_keyring(); + let key = utils::keyring_as_key(&keyring); + let data = &b"data"[..]; + let sig = &b"sig"[..]; + let err = key.verify(&Default::default(), data, sig).unwrap_err(); + + if *HAVE_PKEY { + assert_eq!(err, errno::Errno(libc::EOPNOTSUPP)); + } else { + assert_eq!(err, errno::Errno(libc::ENOSYS)); + } +} + +#[test] +fn pkey_verify_user() { + let mut keyring = utils::new_test_keyring(); + let payload = &b"payload"[..]; + let key = keyring + .add_key::("pkey_verify_user", payload) + .unwrap(); + + let data = &b"data"[..]; + let sig = &b"sig"[..]; + let err = key.verify(&Default::default(), data, sig).unwrap_err(); + + if *HAVE_PKEY { + assert_eq!(err, errno::Errno(libc::EOPNOTSUPP)); + } else { + assert_eq!(err, errno::Errno(libc::ENOSYS)); + } +} diff --git a/src/tests/utils/kernel.rs b/src/tests/utils/kernel.rs index ec55816..6e900aa 100644 --- a/src/tests/utils/kernel.rs +++ b/src/tests/utils/kernel.rs @@ -38,6 +38,7 @@ lazy_static! { pub static ref KERNEL_VERSION: String = kernel_version(); pub static ref SEMVER_KERNEL_VERSION: &'static str = semver_kernel_version(); pub static ref HAVE_INVALIDATE: bool = have_invalidate(); + pub static ref HAVE_PKEY: bool = have_pkey(); pub static ref PAGE_SIZE: usize = page_size(); pub static ref UID: libc::uid_t = getuid(); pub static ref GID: libc::gid_t = getgid(); @@ -82,6 +83,23 @@ fn have_invalidate() -> bool { } } +// Whether the kernel supports the `pkey` APIs on a key. +fn have_pkey() -> bool { + match Version::parse(dbg!(*SEMVER_KERNEL_VERSION)) { + Ok(ver) => { + let minver = VersionReq::parse(">=4.20").unwrap(); + minver.matches(&ver) + }, + Err(err) => { + eprintln!( + "failed to parse kernel version `{}` ({}): assuming incompatibility", + *SEMVER_KERNEL_VERSION, err + ); + false + }, + } +} + fn page_size() -> usize { errno::set_errno(errno::Errno(0)); let ret = unsafe { libc::sysconf(libc::_SC_PAGESIZE) };