1#[cfg(feature = "keydb")]
6use crate::util::get_last_error;
7use crate::{
8 error::*,
9 pk11::{context::HashAlgorithm, slot, types::SymKey},
10 util::{assert_nss_initialized, map_nss_secstatus, sec_item_as_slice, ScopedPtr},
11};
12#[cfg(feature = "keydb")]
13use std::ffi::{c_char, CString};
14use std::{
15 mem,
16 os::raw::{c_uchar, c_uint, c_ulong},
17 ptr,
18};
19
20pub fn hkdf_expand(
21 digest_alg: &HashAlgorithm,
22 key_bytes: &[u8],
23 info: &[u8],
24 len: usize,
25) -> Result<Vec<u8>> {
26 assert_nss_initialized();
27 let mech = digest_alg.as_hkdf_mechanism();
28 let mut hkdf_params = nss_sys::CK_NSS_HKDFParams {
32 bExtract: nss_sys::CK_FALSE,
33 pSalt: ptr::null_mut(),
34 ulSaltLen: 0,
35 bExpand: nss_sys::CK_TRUE,
36 pInfo: info.as_ptr() as *mut u8,
37 ulInfoLen: c_ulong::try_from(info.len())?,
38 };
39 let mut params = nss_sys::SECItem {
40 type_: nss_sys::SECItemType::siBuffer as u32,
41 data: &mut hkdf_params as *mut _ as *mut c_uchar,
42 len: u32::try_from(mem::size_of::<nss_sys::CK_NSS_HKDFParams>())?,
43 };
44 let base_key = import_sym_key(mech.into(), nss_sys::CKA_WRAP.into(), key_bytes)?;
45 let derived_len = i32::try_from(len)?;
46 let sym_key = unsafe {
47 SymKey::from_ptr(
48 nss_sys::PK11_Derive(
51 base_key.as_mut_ptr(),
52 mech.into(),
53 &mut params,
54 nss_sys::CKM_SHA512_HMAC.into(),
55 nss_sys::CKA_SIGN.into(),
56 derived_len,
57 ),
58 )?
59 };
60 map_nss_secstatus(|| unsafe { nss_sys::PK11_ExtractKeyValue(sym_key.as_mut_ptr()) })?;
61 let mut key_data = unsafe { *nss_sys::PK11_GetKeyData(sym_key.as_mut_ptr()) };
64 if u32::try_from(len)? > key_data.len {
65 return Err(ErrorKind::InternalError.into());
66 }
67 let buf = unsafe { sec_item_as_slice(&mut key_data)? };
68 Ok(buf.to_vec())
69}
70
71pub(crate) fn import_sym_key(
75 mechanism: nss_sys::CK_MECHANISM_TYPE,
76 operation: nss_sys::CK_ATTRIBUTE_TYPE,
77 buf: &[u8],
78) -> Result<SymKey> {
79 assert_nss_initialized();
80 let mut item = nss_sys::SECItem {
81 type_: nss_sys::SECItemType::siBuffer as u32,
82 data: buf.as_ptr() as *mut c_uchar,
83 len: c_uint::try_from(buf.len())?,
84 };
85 let slot = slot::get_internal_slot()?;
86 unsafe {
87 SymKey::from_ptr(nss_sys::PK11_ImportSymKey(
88 slot.as_mut_ptr(),
89 mechanism,
90 nss_sys::PK11Origin::PK11_OriginUnwrap as u32,
91 operation,
92 &mut item,
93 ptr::null_mut(),
94 ))
95 }
96}
97
98#[cfg(feature = "keydb")]
101pub fn authentication_with_primary_password_is_needed() -> Result<bool> {
102 let slot = slot::get_internal_key_slot()?;
103
104 unsafe {
105 Ok(
106 nss_sys::PK11_NeedLogin(slot.as_mut_ptr()) == nss_sys::PR_TRUE
107 && nss_sys::PK11_IsLoggedIn(slot.as_mut_ptr(), ptr::null_mut()) != nss_sys::PR_TRUE,
108 )
109 }
110}
111
112#[cfg(feature = "keydb")]
115pub fn authenticate_with_primary_password(primary_password: &str) -> Result<bool> {
116 let slot = slot::get_internal_key_slot()?;
117
118 let password_cstr = CString::new(primary_password).map_err(|_| ErrorKind::NulError)?;
119 unsafe {
120 Ok(
121 nss_sys::PK11_CheckUserPassword(slot.as_mut_ptr(), password_cstr.as_ptr())
122 == nss_sys::SECStatus::SECSuccess,
123 )
124 }
125}
126
127#[cfg(feature = "keydb")]
131pub fn get_or_create_aes256_key(name: &str) -> Result<Vec<u8>> {
132 let sym_key = match get_aes256_key(name) {
133 Ok(sym_key) => sym_key,
134 Err(_) => create_aes256_key(name)?,
135 };
136 let mut key_data = unsafe { *nss_sys::PK11_GetKeyData(sym_key.as_mut_ptr()) };
137 if key_data.len != nss_sys::AES_256_KEY_LENGTH {
138 return Err(ErrorKind::InvalidKeyLength.into());
139 }
140 let buf = unsafe { sec_item_as_slice(&mut key_data)? };
141 Ok(buf.to_vec())
144}
145
146#[cfg(feature = "keydb")]
147fn get_aes256_key(name: &str) -> Result<SymKey> {
148 let slot = slot::get_internal_key_slot()?;
149 let name = CString::new(name).map_err(|_| ErrorKind::NulError)?;
150 let sym_key = unsafe {
151 SymKey::from_ptr(nss_sys::PK11_ListFixedKeysInSlot(
152 slot.as_mut_ptr(),
153 name.as_ptr() as *mut c_char,
154 ptr::null_mut(),
155 ))
156 };
157 match sym_key {
158 Ok(sym_key) => {
159 let wrapping_key = unsafe {
165 SymKey::from_ptr(nss_sys::PK11_KeyGen(
166 slot.as_mut_ptr(),
167 nss_sys::CKM_AES_KEY_GEN,
168 ptr::null_mut(),
169 16,
170 ptr::null_mut(),
171 ))
172 .map_err(|_| get_last_error())?
173 };
174 let mut wrap_len = nss_sys::SECItem {
175 type_: nss_sys::SECItemType::siBuffer as u32,
176 data: ptr::null_mut(),
177 len: 0,
178 };
179 map_nss_secstatus(|| unsafe {
180 nss_sys::PK11_WrapSymKey(
181 nss_sys::CKM_AES_KEY_WRAP_KWP,
182 ptr::null_mut(),
183 wrapping_key.as_mut_ptr(),
184 sym_key.as_mut_ptr(),
185 &mut wrap_len,
186 )
187 })
188 .map_err(|_| get_last_error())?;
189 if wrap_len.len > u32::MAX - 8 {
191 return Err(ErrorKind::InvalidKeyLength.into());
192 }
193 let wrapped_key = unsafe {
195 nss_sys::SECITEM_AllocItem(ptr::null_mut(), ptr::null_mut(), wrap_len.len + 8)
196 };
197 map_nss_secstatus(|| unsafe {
198 nss_sys::PK11_WrapSymKey(
199 nss_sys::CKM_AES_KEY_WRAP_KWP,
200 ptr::null_mut(),
201 wrapping_key.as_mut_ptr(),
202 sym_key.as_mut_ptr(),
203 wrapped_key,
204 )
205 })
206 .map_err(|_| get_last_error())?;
207 let sym_key = unsafe {
208 SymKey::from_ptr(nss_sys::PK11_UnwrapSymKey(
209 wrapping_key.as_mut_ptr(),
210 nss_sys::CKM_AES_KEY_WRAP_KWP,
211 ptr::null_mut(),
212 wrapped_key,
213 nss_sys::CKM_AES_GCM.into(),
214 (nss_sys::CKA_ENCRYPT | nss_sys::CKA_DECRYPT).into(),
215 wrap_len.len as i32,
216 ))
217 }
218 .map_err(|_| get_last_error())?;
219
220 map_nss_secstatus(|| unsafe { nss_sys::PK11_ExtractKeyValue(sym_key.as_mut_ptr()) })?;
221 Ok(sym_key)
222 }
223 Err(e) => Err(e),
224 }
225}
226
227#[cfg(feature = "keydb")]
228fn create_aes256_key(name: &str) -> Result<SymKey> {
229 let mut key_bytes: [u8; nss_sys::AES_256_KEY_LENGTH as usize] =
230 [0; nss_sys::AES_256_KEY_LENGTH as usize];
231 map_nss_secstatus(|| unsafe {
232 nss_sys::PK11_GenerateRandom(key_bytes.as_mut_ptr(), nss_sys::AES_256_KEY_LENGTH as i32)
233 })?;
234 match import_and_persist_sym_key(
235 nss_sys::CKM_AES_GCM.into(),
236 nss_sys::PK11Origin::PK11_OriginGenerated,
237 (nss_sys::CKA_ENCRYPT | nss_sys::CKA_DECRYPT).into(),
238 &key_bytes,
239 ) {
240 Ok(sym_key) => {
241 let name = CString::new(name).map_err(|_| ErrorKind::NulError)?;
242 unsafe { nss_sys::PK11_SetSymKeyNickname(sym_key.as_mut_ptr(), name.as_ptr()) };
243 Ok(sym_key)
244 }
245 Err(e) => Err(e),
246 }
247}
248
249#[cfg(feature = "keydb")]
253fn import_and_persist_sym_key(
254 mechanism: nss_sys::CK_MECHANISM_TYPE,
255 origin: nss_sys::PK11Origin,
256 operation: nss_sys::CK_ATTRIBUTE_TYPE,
257 buf: &[u8],
258) -> Result<SymKey> {
259 let mut item = nss_sys::SECItem {
260 type_: nss_sys::SECItemType::siBuffer as u32,
261 data: buf.as_ptr() as *mut c_uchar,
262 len: c_uint::try_from(buf.len())?,
263 };
264 let slot = slot::get_internal_key_slot()?;
265 unsafe {
266 SymKey::from_ptr(nss_sys::PK11_ImportSymKeyWithFlags(
267 slot.as_mut_ptr(),
268 mechanism,
269 origin as u32,
270 operation,
271 &mut item,
272 nss_sys::CK_FLAGS::default(),
273 nss_sys::PR_TRUE,
274 ptr::null_mut(),
275 ))
276 }
277}