use crate::{
error::*,
pk11::slot::{generate_random, get_internal_slot},
util::{map_nss_secstatus, ScopedPtr},
};
use std::{
ops::Deref,
os::raw::{c_int, c_uchar, c_uint, c_void},
ptr,
};
scoped_ptr!(SymKey, nss_sys::PK11SymKey, nss_sys::PK11_FreeSymKey);
scoped_ptr!(
PrivateKey,
nss_sys::SECKEYPrivateKey,
nss_sys::SECKEY_DestroyPrivateKey
);
scoped_ptr!(
PublicKey,
nss_sys::SECKEYPublicKey,
nss_sys::SECKEY_DestroyPublicKey
);
scoped_ptr!(
GenericObject,
nss_sys::PK11GenericObject,
nss_sys::PK11_DestroyGenericObject
);
scoped_ptr!(
Certificate,
nss_sys::CERTCertificate,
nss_sys::CERT_DestroyCertificate
);
scoped_ptr!(Context, nss_sys::PK11Context, pk11_destroy_context_true);
scoped_ptr!(Slot, nss_sys::PK11SlotInfo, nss_sys::PK11_FreeSlot);
scoped_ptr!(
AlgorithmID,
nss_sys::SECAlgorithmID,
secoid_destroy_algorithm_id_true
);
#[inline]
unsafe fn secoid_destroy_algorithm_id_true(alg_id: *mut nss_sys::SECAlgorithmID) {
nss_sys::SECOID_DestroyAlgorithmID(alg_id, nss_sys::PR_TRUE);
}
#[inline]
unsafe fn pk11_destroy_context_true(context: *mut nss_sys::PK11Context) {
nss_sys::PK11_DestroyContext(context, nss_sys::PR_TRUE);
}
pub(crate) unsafe trait Pkcs11Object: ScopedPtr {
const PK11_OBJECT_TYPE: nss_sys::PK11ObjectType;
fn read_raw_attribute(
&self,
attribute_type: nss_sys::CK_ATTRIBUTE_TYPE,
) -> Result<ScopedSECItem> {
let mut out_sec = ScopedSECItem::empty(nss_sys::SECItemType::siBuffer);
map_nss_secstatus(|| unsafe {
nss_sys::PK11_ReadRawAttribute(
Self::PK11_OBJECT_TYPE as u32,
self.as_mut_ptr() as *mut c_void,
attribute_type,
out_sec.as_mut_ref(),
)
})?;
Ok(out_sec)
}
}
unsafe impl Pkcs11Object for GenericObject {
const PK11_OBJECT_TYPE: nss_sys::PK11ObjectType = nss_sys::PK11ObjectType::PK11_TypeGeneric;
}
unsafe impl Pkcs11Object for PrivateKey {
const PK11_OBJECT_TYPE: nss_sys::PK11ObjectType = nss_sys::PK11ObjectType::PK11_TypePrivKey;
}
unsafe impl Pkcs11Object for PublicKey {
const PK11_OBJECT_TYPE: nss_sys::PK11ObjectType = nss_sys::PK11ObjectType::PK11_TypePubKey;
}
unsafe impl Pkcs11Object for SymKey {
const PK11_OBJECT_TYPE: nss_sys::PK11ObjectType = nss_sys::PK11ObjectType::PK11_TypeSymKey;
}
unsafe impl Send for PrivateKey {}
unsafe impl Send for PublicKey {}
impl PrivateKey {
pub fn convert_to_public_key(&self) -> Result<PublicKey> {
Ok(unsafe { PublicKey::from_ptr(nss_sys::SECKEY_ConvertToPublicKey(self.as_mut_ptr()))? })
}
pub(crate) fn from_private_key_template(
mut template: Vec<nss_sys::CK_ATTRIBUTE>,
) -> Result<Self> {
let mut obj_id_buf = vec![0u8; 160 / 8];
generate_random(&mut obj_id_buf)?;
let mut obj_id = nss_sys::SECItem {
type_: nss_sys::SECItemType::siBuffer as u32,
data: obj_id_buf.as_ptr() as *mut c_uchar,
len: c_uint::try_from(obj_id_buf.len())?,
};
let slot = get_internal_slot()?;
let mut pre_existing_key = unsafe {
nss_sys::PK11_FindKeyByKeyID(slot.as_mut_ptr(), &mut obj_id, std::ptr::null_mut())
};
if !pre_existing_key.is_null() {
unsafe {
destroy_private_key_without_destroying_pkcs11_object(pre_existing_key);
}
generate_random(&mut obj_id_buf)?;
pre_existing_key = unsafe {
nss_sys::PK11_FindKeyByKeyID(slot.as_mut_ptr(), &mut obj_id, std::ptr::null_mut())
};
if !pre_existing_key.is_null() {
unsafe {
destroy_private_key_without_destroying_pkcs11_object(pre_existing_key);
}
return Err(ErrorKind::InternalError.into());
}
}
let template_len = c_int::try_from(template.len())?;
let id_attr: &mut nss_sys::CK_ATTRIBUTE = template
.iter_mut()
.find(|&&mut attr| {
attr.type_ == (nss_sys::CKA_ID as nss_sys::CK_ATTRIBUTE_TYPE)
&& attr.pValue.is_null()
&& attr.ulValueLen == 0
})
.ok_or(ErrorKind::InternalError)?;
id_attr.pValue = obj_id_buf.as_mut_ptr() as *mut c_void;
id_attr.ulValueLen = nss_sys::CK_ULONG::try_from(obj_id_buf.len())?;
let _obj = unsafe {
GenericObject::from_ptr(nss_sys::PK11_CreateGenericObject(
slot.as_mut_ptr(),
template.as_mut_ptr(),
template_len,
nss_sys::PR_FALSE,
))?
};
Ok(unsafe {
PrivateKey::from_ptr(nss_sys::PK11_FindKeyByKeyID(
slot.as_mut_ptr(),
&mut obj_id,
std::ptr::null_mut(),
))?
})
}
}
pub(crate) struct ScopedSECItem {
wrapped: nss_sys::SECItem,
}
impl ScopedSECItem {
pub(crate) fn empty(r#type: nss_sys::SECItemType) -> Self {
ScopedSECItem {
wrapped: nss_sys::SECItem {
type_: r#type as u32,
data: ptr::null_mut(),
len: 0,
},
}
}
pub(crate) fn as_mut_ref(&mut self) -> &mut nss_sys::SECItem {
&mut self.wrapped
}
}
impl Deref for ScopedSECItem {
type Target = nss_sys::SECItem;
#[inline]
fn deref(&self) -> &nss_sys::SECItem {
&self.wrapped
}
}
impl Drop for ScopedSECItem {
fn drop(&mut self) {
unsafe {
nss_sys::SECITEM_FreeItem(&mut self.wrapped, nss_sys::PR_FALSE);
}
}
}
unsafe fn destroy_private_key_without_destroying_pkcs11_object(
key: *mut nss_sys::SECKEYPrivateKey,
) {
assert!(!key.is_null());
nss_sys::PK11_FreeSlot((*key).pkcs11Slot);
nss_sys::PORT_FreeArena((*key).arena, nss_sys::PR_TRUE);
}