Skip to content

Commit

Permalink
support keydb feature
Browse files Browse the repository at this point in the history
This adds a feature `keydb` to rc_crypto`s nss create, which enables the
`ensure_initialized_with_profile_dir` initialize function. This
configures NSS to use a profile and persist keys into key4.db.
  • Loading branch information
jo committed Jan 3, 2025
1 parent d5dd8d4 commit 3ab93b5
Show file tree
Hide file tree
Showing 5 changed files with 74 additions and 0 deletions.
1 change: 1 addition & 0 deletions components/support/rc_crypto/nss/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,4 @@ serde_derive = "1"
[features]
default = []
gecko = ["nss_sys/gecko"]
keydb = []
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ extern "C" {
pub fn PK11_FreeSlot(slot: *mut PK11SlotInfo);
pub fn PK11_GetInternalSlot() -> *mut PK11SlotInfo;
pub fn PK11_GetInternalKeySlot() -> *mut PK11SlotInfo;
pub fn PK11_NeedUserInit(slot: *mut PK11SlotInfo) -> PRBool;
pub fn PK11_GenerateRandom(data: *mut c_uchar, len: c_int) -> SECStatus;
pub fn PK11_FreeSymKey(key: *mut PK11SymKey);
pub fn PK11_InitPin(
Expand Down
3 changes: 3 additions & 0 deletions components/support/rc_crypto/nss/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,6 @@ pub mod pkixc;
pub mod secport;
pub use crate::error::{Error, ErrorKind, Result};
pub use util::ensure_nss_initialized as ensure_initialized;

#[cfg(feature = "keydb")]
pub use util::ensure_nss_initialized_with_profile_dir as ensure_initialized_with_profile_dir;
8 changes: 8 additions & 0 deletions components/support/rc_crypto/nss/src/pk11/slot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,11 @@ pub fn generate_random(data: &mut [u8]) -> Result<()> {
pub(crate) fn get_internal_slot() -> Result<Slot> {
unsafe { Slot::from_ptr(nss_sys::PK11_GetInternalSlot()) }
}

/// Safe wrapper around `PK11_GetInternalKeySlot` that
/// de-allocates memory when the slot goes out of
/// scope.
#[cfg(feature = "keydb")]
pub(crate) fn get_internal_key_slot() -> Result<Slot> {
unsafe { Slot::from_ptr(nss_sys::PK11_GetInternalKeySlot()) }
}
61 changes: 61 additions & 0 deletions components/support/rc_crypto/nss/src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@ use crate::error::*;
use nss_sys::*;
use std::{ffi::CString, os::raw::c_char, sync::Once};

#[cfg(feature = "keydb")]
use crate::pk11::slot;
#[cfg(feature = "keydb")]
use std::fs;
#[cfg(feature = "keydb")]
use std::path::Path;

// This is the NSS version that this crate is claiming to be compatible with.
// We check it at runtime using `NSS_VersionCheck`.
pub const COMPATIBLE_NSS_VERSION: &str = "3.26";
Expand Down Expand Up @@ -41,6 +48,60 @@ pub fn ensure_nss_initialized() {
})
}

#[cfg(feature = "keydb")]
pub fn ensure_nss_initialized_with_profile_dir(path: impl AsRef<Path>) {
NSS_INIT.call_once(|| {
let version_ptr = CString::new(COMPATIBLE_NSS_VERSION).unwrap();
if unsafe { NSS_VersionCheck(version_ptr.as_ptr()) == PR_FALSE } {
panic!("Incompatible NSS version!")
}
let c_path: CString = CString::new(path.as_ref().to_str().unwrap()).unwrap();
if !fs::metadata(path).is_ok() {
panic!(
"Could not initialize NSS: missing profile dir: {:?}",
c_path
);
}

let empty = CString::default();
let flags = NSS_INIT_FORCEOPEN | NSS_INIT_OPTIMIZESPACE;

let context = unsafe {
NSS_InitContext(
c_path.as_ptr(),
empty.as_ptr(),
empty.as_ptr(),
empty.as_ptr(),
std::ptr::null_mut(),
flags,
)
};
if context.is_null() {
let error = get_last_error();
panic!("Could not initialize NSS: {}", error);
}

let Ok(slot) = slot::get_internal_key_slot() else {
let error = get_last_error();
panic!("Could not get internal key slot: {}", error);
};

if unsafe { PK11_NeedUserInit(slot.as_mut_ptr()) } == nss_sys::PR_TRUE {
let result = unsafe {
PK11_InitPin(
slot.as_mut_ptr(),
std::ptr::null_mut(),
std::ptr::null_mut(),
)
};
if result != SECStatus::SECSuccess {
let error = get_last_error();
panic!("Could not initialize internal key slot: {}", error);
}
}
})
}

pub fn map_nss_secstatus<F>(callback: F) -> Result<()>
where
F: FnOnce() -> SECStatus,
Expand Down

0 comments on commit 3ab93b5

Please sign in to comment.