#[must_use] pubfn hex_with_len<B: AsRef<[u8]>>(buf: B) -> String { use std::fmt::Write as _; let buf = buf.as_ref(); letmut ret = String::with_capacity(10 + buf.len() * 2);
write!(&mut ret, "[{}]: ", buf.len()).unwrap(); for b in buf {
write!(&mut ret, "{b:02x}").unwrap();
}
ret
}
impl PublicKey { /// Get the HPKE serialization of the public key. /// /// # Errors /// /// When the key cannot be exported, which can be because the type is not supported. /// /// # Panics /// /// When keys are too large to fit in `c_uint/usize`. So only on programming error. pubfn key_data(&self) -> Res<Vec<u8>> { letmut buf = vec![0; 100]; letmut len: c_uint = 0;
secstatus_to_res(unsafe {
PK11_HPKE_Serialize(
**self,
buf.as_mut_ptr(),
&raw mut len,
c_uint::try_from(buf.len()).map_err(|_| Error::IntegerOverflow)?,
)
})?;
buf.truncate(usize::try_from(len).map_err(|_| Error::IntegerOverflow)?);
Ok(buf)
}
impl PrivateKey { /// Get the bits of the private key. /// /// # Errors /// /// When the key cannot be exported, which can be because the type is not supported /// or because the key data cannot be extracted from the PKCS#11 module. /// /// # Panics /// /// When the values are too large to fit. So never. pubfn key_data(&self) -> Res<Vec<u8>> { letmut key_item = SECItemMut::make_empty();
secstatus_to_res(unsafe {
PK11_ReadRawAttribute(
PK11ObjectType::PK11_TypePrivKey,
(**self).cast(),
CKA_VALUE,
key_item.as_mut(),
)
})?; let slc = unsafe { null_safe_slice(key_item.as_ref().data, key_item.as_ref().len) }; let key = Vec::from(slc); // The data that `key_item` refers to needs to be freed, but we can't // use the scoped `Item` implementation. This is OK as long as nothing // panics between `PK11_ReadRawAttribute` succeeding and here. unsafe {
SECITEM_FreeItem(key_item.as_mut(), PRBool::from(false));
}
Ok(key)
}
} unsafeimpl Send for PrivateKey {}
/// Check a user-supplied password against this slot. /// /// **Note:** This internally logs out before re-authenticating. /// A failed check leaves the slot in a logged-out state. pubfn check_user_password(&self, password: &str) -> Res<()> { let c_password = std::ffi::CString::new(password)?;
secstatus_to_res(unsafe { PK11_CheckUserPassword(self.ptr, c_password.as_ptr()) })
}
/// Find a persistent symmetric key on this slot by nickname. /// Returns `None` if no key with the given nickname exists. #[must_use] pubfn find_key_by_nickname(&self, nickname: &str) -> Option<SymKey> { let c_nickname = std::ffi::CString::new(nickname).ok()?; let ptr = unsafe {
PK11_ListFixedKeysInSlot(self.ptr, c_nickname.as_ptr().cast_mut(), null_mut())
}; if ptr.is_null() {
None
} else {
SymKey::from_ptr(ptr).ok()
}
}
/// Generate a persistent symmetric key on this slot with a nickname. pubfn generate_token_key(
&self,
mechanism: CK_MECHANISM_TYPE,
key_size: usize,
nickname: &str,
) -> Res<SymKey> { let key = unsafe {
SymKey::from_ptr(PK11_TokenKeyGenWithFlags( self.ptr,
mechanism,
null_mut(),
c_int::try_from(key_size).map_err(|_| Error::IntegerOverflow)?,
null_mut(),
CK_FLAGS::from(CKF_ENCRYPT | CKF_DECRYPT),
PK11AttrFlags::from(PK11_ATTR_TOKEN | PK11_ATTR_PRIVATE | PK11_ATTR_SENSITIVE),
null_mut(),
))
}?; let c_nickname = std::ffi::CString::new(nickname).map_err(|_| Error::InvalidInput)?;
secstatus_to_res(unsafe { PK11_SetSymKeyNickname(*key, c_nickname.as_ptr()) })?;
Ok(key)
}
}
/// Returns all available token slots for the given mechanism. #[must_use] pubfn all_token_slots(mechanism: CK_MECHANISM_TYPE) -> Vec<Slot> { let list = unsafe {
PK11_GetAllTokens(
mechanism,
PRBool::from(false),
PRBool::from(false),
null_mut(),
)
}; if list.is_null() { return Vec::new();
} letmut result = Vec::new(); unsafe { letmut elem = (*list).head; while !elem.is_null() { let slot_ptr = (*elem).slot; if !slot_ptr.is_null() {
PK11_ReferenceSlot(slot_ptr); iflet Ok(slot) = Slot::from_ptr(slot_ptr) {
result.push(slot);
}
}
elem = (*elem).next;
}
PK11_FreeSlotList(list);
}
result
}
impl SymKey { /// You really don't want to use this. /// /// # Errors /// /// Internal errors in case of failures in NSS. pubfn key_data(&self) -> Res<&[u8]> {
secstatus_to_res(unsafe { PK11_ExtractKeyValue(**self) })?;
let key_item = unsafe { PK11_GetKeyData(**self) }; // This is accessing a value attached to the key, so we can treat this as a borrow. matchunsafe { key_item.as_mut() } {
None => Err(Error::Internal),
Some(key) => Ok(unsafe { null_safe_slice(key.data, key.len) }),
}
}
#[cfg(feature = "disable-random")] /// Fill a buffer with a predictable sequence of bytes. pubfn randomize<B: AsMut<[u8]>>(mut buf: B) -> B { let m_buf = buf.as_mut(); for v in m_buf.iter_mut() {
*v = CURRENT_VALUE.get();
CURRENT_VALUE.set(v.wrapping_add(1));
}
buf
}
/// Fill a buffer with randomness. /// /// # Panics /// /// When `size` is too large or NSS fails. #[cfg(not(feature = "disable-random"))] pubfn randomize<B: AsMut<[u8]>>(mut buf: B) -> B { let m_buf = buf.as_mut(); let len = c_int::try_from(m_buf.len()).expect("usize fits into c_int");
secstatus_to_res(unsafe { PK11_GenerateRandom(m_buf.as_mut_ptr(), len) }).expect("NSS failed");
buf
}
fixture_init(); // If any of these ever fail, there is either a bug, or it's time to buy a lottery ticket.
assert_ne!(random::<16>(), randomize([0; 16]));
assert_ne!([0; 16], random::<16>());
assert_ne!([0; 64], random::<64>());
}
for _ in0..100 { let len = loop { let len = usize::from(random::<1>()[0] & mask) + 1; if len <= RandomCache::CUTOFF { break len;
}
};
buf.fill(0); if len >= 16 {
assert_ne!(&cache.randomize(&mut buf[..len])[..len], &ZERO[..len]);
}
}
}
fixture_init(); let (sk, pk) = generate_keys().unwrap();
// Test key_data serialization - X25519 keys are 32 bytes
assert_eq!(pk.key_data().unwrap().len(), 32);
// Test Debug formatting let pk_dbg = format!("{pk:?}");
assert_eq!(&pk_dbg[..9], "PublicKey"); let sk_dbg = format!("{sk:?}"); // Private key debug output depends on whether key extraction is allowed by NSS. // It could be either "PrivateKey [hex]" or "Opaque PrivateKey".
assert!(
sk_dbg.starts_with("PrivateKey") || sk_dbg.starts_with("Opaque"), "unexpected private key debug format: {sk_dbg}"
);
// Test cloning let pk2 = pk.clone(); let sk2 = sk.clone();
assert_eq!(pk.key_data().unwrap(), pk2.key_data().unwrap());
assert_eq!(format!("{sk:?}"), format!("{sk2:?}"));
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.