use super::err::{secstatus_to_res, Error};
use crate::err::Res;
use std::convert::TryFrom;
use std::marker::PhantomData;
use std::mem;
use std::os::raw::{c_int, c_uint};
use std::ptr::null_mut;
#[allow(
clippy::pedantic,
clippy::upper_case_acronyms,
dead_code,
deref_nullptr,
non_camel_case_types,
non_snake_case,
non_upper_case_globals
)]
pub mod sys {
include!(concat!(env!("OUT_DIR"), "/nss_p11.rs"));
}
use sys::{
PK11ObjectType, PK11SlotInfo, PK11SymKey, PK11_ExtractKeyValue, PK11_FreeSlot, PK11_FreeSymKey,
PK11_GenerateRandom, PK11_GetInternalSlot, PK11_GetKeyData, PK11_ReadRawAttribute,
PK11_ReferenceSymKey, PRBool, SECITEM_FreeItem, SECItem, SECItemType, SECKEYPrivateKey,
SECKEYPublicKey, SECKEY_DestroyPrivateKey, SECKEY_DestroyPublicKey, CKA_VALUE,
CK_ATTRIBUTE_TYPE,
};
macro_rules! scoped_ptr {
($scoped:ident, $target:ty, $dtor:path) => {
pub struct $scoped {
ptr: *mut $target,
}
impl $scoped {
pub fn from_ptr(ptr: *mut $target) -> Result<Self, crate::err::Error> {
if ptr.is_null() {
Err(crate::nss::err::Error::last())
} else {
Ok(Self { ptr })
}
}
}
impl std::ops::Deref for $scoped {
type Target = *mut $target;
#[must_use]
fn deref(&self) -> &*mut $target {
&self.ptr
}
}
impl std::ops::DerefMut for $scoped {
fn deref_mut(&mut self) -> &mut *mut $target {
&mut self.ptr
}
}
impl Drop for $scoped {
fn drop(&mut self) {
let _ = unsafe { $dtor(self.ptr) };
}
}
};
}
scoped_ptr!(PrivateKey, SECKEYPrivateKey, SECKEY_DestroyPrivateKey);
impl PrivateKey {
pub fn key_data(&self) -> Res<Vec<u8>> {
let mut key_item = SECItem {
type_: SECItemType::siBuffer,
data: null_mut(),
len: 0,
};
secstatus_to_res(unsafe {
PK11_ReadRawAttribute(
PK11ObjectType::PK11_TypePrivKey,
(**self).cast(),
CK_ATTRIBUTE_TYPE::from(CKA_VALUE),
&mut key_item,
)
})?;
let slc = unsafe {
std::slice::from_raw_parts(key_item.data, usize::try_from(key_item.len).unwrap())
};
let key = Vec::from(slc);
unsafe {
SECITEM_FreeItem(&mut key_item, PRBool::from(false));
}
Ok(key)
}
}
unsafe impl Send for PrivateKey {}
impl Clone for PrivateKey {
#[must_use]
fn clone(&self) -> Self {
let ptr = unsafe { sys::SECKEY_CopyPrivateKey(self.ptr) };
assert!(!ptr.is_null());
Self { ptr }
}
}
impl std::fmt::Debug for PrivateKey {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
if let Ok(b) = self.key_data() {
write!(f, "PrivateKey {}", hex::encode(b))
} else {
write!(f, "Opaque PrivateKey")
}
}
}
scoped_ptr!(PublicKey, SECKEYPublicKey, SECKEY_DestroyPublicKey);
impl PublicKey {
pub fn key_data(&self) -> Res<Vec<u8>> {
let mut buf = vec![0; 100];
let mut len: c_uint = 0;
secstatus_to_res(unsafe {
sys::PK11_HPKE_Serialize(
**self,
buf.as_mut_ptr(),
&mut len,
c_uint::try_from(buf.len()).unwrap(),
)
})?;
buf.truncate(usize::try_from(len).unwrap());
Ok(buf)
}
}
unsafe impl Send for PublicKey {}
impl Clone for PublicKey {
#[must_use]
fn clone(&self) -> Self {
let ptr = unsafe { sys::SECKEY_CopyPublicKey(self.ptr) };
assert!(!ptr.is_null());
Self { ptr }
}
}
impl std::fmt::Debug for PublicKey {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
if let Ok(b) = self.key_data() {
write!(f, "PublicKey {}", hex::encode(b))
} else {
write!(f, "Opaque PublicKey")
}
}
}
scoped_ptr!(Slot, PK11SlotInfo, PK11_FreeSlot);
impl Slot {
pub(crate) fn internal() -> Res<Self> {
let p = unsafe { PK11_GetInternalSlot() };
Slot::from_ptr(p)
}
}
scoped_ptr!(SymKey, PK11SymKey, PK11_FreeSymKey);
impl SymKey {
pub fn key_data(&self) -> Res<&[u8]> {
secstatus_to_res(unsafe { PK11_ExtractKeyValue(self.ptr) })?;
let key_item = unsafe { PK11_GetKeyData(self.ptr) };
match unsafe { key_item.as_mut() } {
None => Err(Error::last()),
Some(key) => Ok(unsafe { std::slice::from_raw_parts(key.data, key.len as usize) }),
}
}
}
impl Clone for SymKey {
#[must_use]
fn clone(&self) -> Self {
let ptr = unsafe { PK11_ReferenceSymKey(self.ptr) };
assert!(!ptr.is_null());
Self { ptr }
}
}
impl std::fmt::Debug for SymKey {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
if let Ok(b) = self.key_data() {
write!(f, "SymKey {}", hex::encode(b))
} else {
write!(f, "Opaque SymKey")
}
}
}
unsafe impl Send for SymKey {}
#[must_use]
pub fn random(size: usize) -> Vec<u8> {
let mut buf = vec![0; size];
secstatus_to_res(unsafe {
PK11_GenerateRandom(buf.as_mut_ptr(), c_int::try_from(buf.len()).unwrap())
})
.unwrap();
buf
}
pub(crate) struct ParamItem<'a, T: 'a> {
item: SECItem,
marker: PhantomData<&'a T>,
}
impl<'a, T: Sized + 'a> ParamItem<'a, T> {
pub fn new(v: &'a mut T) -> Self {
let item = SECItem {
type_: SECItemType::siBuffer,
data: (v as *mut T).cast::<u8>(),
len: c_uint::try_from(mem::size_of::<T>()).unwrap(),
};
Self {
item,
marker: PhantomData::default(),
}
}
pub fn ptr(&mut self) -> *mut SECItem {
std::ptr::addr_of_mut!(self.item)
}
}
unsafe fn destroy_secitem(item: *mut SECItem) {
SECITEM_FreeItem(item, PRBool::from(true));
}
scoped_ptr!(Item, SECItem, destroy_secitem);
impl Item {
pub(crate) fn wrap(buf: &[u8]) -> SECItem {
SECItem {
type_: SECItemType::siBuffer,
data: buf.as_ptr() as *mut u8,
len: c_uint::try_from(buf.len()).unwrap(),
}
}
pub(crate) unsafe fn into_vec(self) -> Vec<u8> {
let b = self.ptr.as_ref().unwrap();
assert_eq!(b.type_, SECItemType::siBuffer);
let slc = std::slice::from_raw_parts(b.data, usize::try_from(b.len).unwrap());
Vec::from(slc)
}
}
#[cfg(test)]
mod test {
use super::random;
use crate::init;
#[test]
fn randomness() {
init();
assert_ne!(random(16), random(16));
}
}