1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
use crate::error::*;
use nss_sys::*;
use std::{convert::TryFrom, ffi::CString, os::raw::c_char, sync::Once};
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())
}
#[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;
}
#[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)
}