summaryrefslogtreecommitdiffstats
path: root/third_party/rust/nss/src/util.rs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
commit2aa4a82499d4becd2284cdb482213d541b8804dd (patch)
treeb80bf8bf13c3766139fbacc530efd0dd9d54394c /third_party/rust/nss/src/util.rs
parentInitial commit. (diff)
downloadfirefox-upstream.tar.xz
firefox-upstream.zip
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/nss/src/util.rs')
-rw-r--r--third_party/rust/nss/src/util.rs129
1 files changed, 129 insertions, 0 deletions
diff --git a/third_party/rust/nss/src/util.rs b/third_party/rust/nss/src/util.rs
new file mode 100644
index 0000000000..39bf26c622
--- /dev/null
+++ b/third_party/rust/nss/src/util.rs
@@ -0,0 +1,129 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+use crate::error::*;
+use nss_sys::*;
+use std::{convert::TryFrom, ffi::CString, os::raw::c_char, sync::Once};
+
+// 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";
+
+static NSS_INIT: Once = Once::new();
+
+pub fn ensure_nss_initialized() {
+ 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 empty = CString::default();
+ let flags = NSS_INIT_READONLY
+ | NSS_INIT_NOCERTDB
+ | NSS_INIT_NOMODDB
+ | NSS_INIT_FORCEOPEN
+ | NSS_INIT_OPTIMIZESPACE;
+ let context = unsafe {
+ NSS_InitContext(
+ empty.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);
+ }
+ })
+}
+
+pub fn map_nss_secstatus<F>(callback: F) -> Result<()>
+where
+ F: FnOnce() -> SECStatus,
+{
+ if callback() == SECStatus::SECSuccess {
+ return Ok(());
+ }
+ Err(get_last_error())
+}
+
+/// Retrieve and wrap the last NSS/NSPR error in the current thread.
+#[cold]
+pub fn get_last_error() -> Error {
+ let error_code = unsafe { PR_GetError() };
+ let error_text: String = usize::try_from(unsafe { PR_GetErrorTextLength() })
+ .map(|error_text_len| {
+ let mut out_str = vec![0u8; error_text_len + 1];
+ unsafe { PR_GetErrorText(out_str.as_mut_ptr() as *mut c_char) };
+ CString::new(&out_str[0..error_text_len])
+ .unwrap_or_else(|_| CString::default())
+ .to_str()
+ .unwrap_or_else(|_| "")
+ .to_owned()
+ })
+ .unwrap_or_else(|_| "".to_string());
+ ErrorKind::NSSError(error_code, error_text).into()
+}
+
+pub(crate) trait ScopedPtr
+where
+ Self: std::marker::Sized,
+{
+ type RawType;
+ unsafe fn from_ptr(ptr: *mut Self::RawType) -> Result<Self>;
+ fn as_ptr(&self) -> *const Self::RawType;
+ fn as_mut_ptr(&self) -> *mut Self::RawType;
+}
+
+// The macro defines a wrapper around pointers refering to types allocated by NSS,
+// calling their NSS destructor method when they go out of scope to avoid memory leaks.
+// The `as_ptr`/`as_mut_ptr` are provided to retrieve the raw pointers to pass to
+// NSS functions that consume them.
+#[macro_export]
+macro_rules! scoped_ptr {
+ ($scoped:ident, $target:ty, $dtor:path) => {
+ pub struct $scoped {
+ ptr: *mut $target,
+ }
+
+ impl crate::util::ScopedPtr for $scoped {
+ type RawType = $target;
+
+ #[allow(dead_code)]
+ unsafe fn from_ptr(ptr: *mut $target) -> crate::error::Result<$scoped> {
+ if !ptr.is_null() {
+ Ok($scoped { ptr })
+ } else {
+ Err(crate::error::ErrorKind::InternalError.into())
+ }
+ }
+
+ #[inline]
+ fn as_ptr(&self) -> *const $target {
+ self.ptr
+ }
+
+ #[inline]
+ fn as_mut_ptr(&self) -> *mut $target {
+ self.ptr
+ }
+ }
+
+ impl Drop for $scoped {
+ fn drop(&mut self) {
+ assert!(!self.ptr.is_null());
+ unsafe { $dtor(self.ptr) };
+ }
+ }
+ };
+}
+
+pub(crate) unsafe fn sec_item_as_slice(sec_item: &mut SECItem) -> Result<&mut [u8]> {
+ let sec_item_buf_len = usize::try_from(sec_item.len)?;
+ let buf = std::slice::from_raw_parts_mut(sec_item.data, sec_item_buf_len);
+ Ok(buf)
+}