/rust/git/checkouts/nss-rs-71e20fe79ef91440/9b94ca3/src/util.rs
Line | Count | Source |
1 | | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or |
2 | | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license |
3 | | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your |
4 | | // option. This file may not be copied, modified, or distributed |
5 | | // except according to those terms. |
6 | | |
7 | | use std::{ |
8 | | convert::TryFrom as _, marker::PhantomData, os::raw::c_uint, ptr::null_mut, slice::Iter, |
9 | | }; |
10 | | |
11 | | use crate::{Res, nss_prelude::*, null_safe_slice}; |
12 | | |
13 | | /// Implement a smart pointer for NSS objects. |
14 | | /// |
15 | | /// Most of the time the pointer is like a `Box`, but there are exceptions (e.g. |
16 | | /// `PK11SymKey` is internally reference counted so its pointer is like an `Arc`.) |
17 | | /// |
18 | | /// Named "scoped" because that is what NSS calls its `unique_ptr` typedefs. |
19 | | #[macro_export] |
20 | | macro_rules! scoped_ptr { |
21 | | ($name:ident, $target:ty, $dtor:path) => { |
22 | | pub struct $name { |
23 | | ptr: *mut $target, |
24 | | } |
25 | | |
26 | | impl $name { |
27 | | /// Create a new instance of `$name` from a pointer. |
28 | | /// |
29 | | /// # Errors |
30 | | /// When passed a null pointer generates an error. |
31 | 128k | pub fn from_ptr(raw: *mut $target) -> Result<Self, $crate::err::Error> { |
32 | 128k | let ptr = $crate::err::into_result(raw)?; |
33 | 128k | Ok(Self { ptr }) |
34 | 128k | } <nss_rs::p11::Certificate>::from_ptr Line | Count | Source | 31 | 1.28k | pub fn from_ptr(raw: *mut $target) -> Result<Self, $crate::err::Error> { | 32 | 1.28k | let ptr = $crate::err::into_result(raw)?; | 33 | 1.28k | Ok(Self { ptr }) | 34 | 1.28k | } |
<nss_rs::p11::Context>::from_ptr Line | Count | Source | 31 | 32.4k | pub fn from_ptr(raw: *mut $target) -> Result<Self, $crate::err::Error> { | 32 | 32.4k | let ptr = $crate::err::into_result(raw)?; | 33 | 32.4k | Ok(Self { ptr }) | 34 | 32.4k | } |
<nss_rs::replay::AntiReplayContext>::from_ptr Line | Count | Source | 31 | 1.28k | pub fn from_ptr(raw: *mut $target) -> Result<Self, $crate::err::Error> { | 32 | 1.28k | let ptr = $crate::err::into_result(raw)?; | 33 | 1.28k | Ok(Self { ptr }) | 34 | 1.28k | } |
Unexecuted instantiation: <nss_rs::util::ScopedSECItem>::from_ptr Unexecuted instantiation: <nss_rs::p11::CertList>::from_ptr Unexecuted instantiation: <nss_rs::util::ScopedSECItemArray>::from_ptr Unexecuted instantiation: <nss_rs::p11::SubjectPublicKeyInfo>::from_ptr Unexecuted instantiation: <nss_rs::p11::PublicKey>::from_ptr <nss_rs::p11::PrivateKey>::from_ptr Line | Count | Source | 31 | 1.28k | pub fn from_ptr(raw: *mut $target) -> Result<Self, $crate::err::Error> { | 32 | 1.28k | let ptr = $crate::err::into_result(raw)?; | 33 | 1.28k | Ok(Self { ptr }) | 34 | 1.28k | } |
<nss_rs::p11::Slot>::from_ptr Line | Count | Source | 31 | 19.2k | pub fn from_ptr(raw: *mut $target) -> Result<Self, $crate::err::Error> { | 32 | 19.2k | let ptr = $crate::err::into_result(raw)?; | 33 | 19.2k | Ok(Self { ptr }) | 34 | 19.2k | } |
<nss_rs::p11::SymKey>::from_ptr Line | Count | Source | 31 | 72.7k | pub fn from_ptr(raw: *mut $target) -> Result<Self, $crate::err::Error> { | 32 | 72.7k | let ptr = $crate::err::into_result(raw)?; | 33 | 72.7k | Ok(Self { ptr }) | 34 | 72.7k | } |
|
35 | | } |
36 | | |
37 | | impl $crate::err::IntoResult for *mut $target { |
38 | | type Ok = $name; |
39 | | |
40 | 0 | fn into_result(self) -> Result<Self::Ok, $crate::err::Error> { |
41 | 0 | $name::from_ptr(self) |
42 | 0 | } Unexecuted instantiation: <*mut nss_rs::replay::SSLAntiReplayContext as nss_rs::err::IntoResult>::into_result Unexecuted instantiation: <*mut nss_rs::p11::nss_p11::CERTCertificateStr as nss_rs::err::IntoResult>::into_result Unexecuted instantiation: <*mut nss_rs::p11::nss_p11::PK11ContextStr as nss_rs::err::IntoResult>::into_result Unexecuted instantiation: <*mut nss_rs::nss_prelude::SECItemStr as nss_rs::err::IntoResult>::into_result Unexecuted instantiation: <*mut nss_rs::p11::nss_p11::CERTCertListStr as nss_rs::err::IntoResult>::into_result Unexecuted instantiation: <*mut nss_rs::nss_prelude::SECItemArrayStr as nss_rs::err::IntoResult>::into_result Unexecuted instantiation: <*mut nss_rs::p11::nss_p11::CERTSubjectPublicKeyInfoStr as nss_rs::err::IntoResult>::into_result Unexecuted instantiation: <*mut nss_rs::p11::nss_p11::SECKEYPublicKeyStr as nss_rs::err::IntoResult>::into_result Unexecuted instantiation: <*mut nss_rs::p11::nss_p11::SECKEYPrivateKeyStr as nss_rs::err::IntoResult>::into_result Unexecuted instantiation: <*mut nss_rs::p11::nss_p11::PK11SlotInfoStr as nss_rs::err::IntoResult>::into_result Unexecuted instantiation: <*mut nss_rs::p11::nss_p11::PK11SymKeyStr as nss_rs::err::IntoResult>::into_result |
43 | | } |
44 | | |
45 | | impl std::ops::Deref for $name { |
46 | | type Target = *mut $target; |
47 | | |
48 | 150k | fn deref(&self) -> &*mut $target { |
49 | 150k | &self.ptr |
50 | 150k | } <nss_rs::p11::Certificate as core::ops::deref::Deref>::deref Line | Count | Source | 48 | 2.57k | fn deref(&self) -> &*mut $target { | 49 | 2.57k | &self.ptr | 50 | 2.57k | } |
<nss_rs::p11::PrivateKey as core::ops::deref::Deref>::deref Line | Count | Source | 48 | 1.28k | fn deref(&self) -> &*mut $target { | 49 | 1.28k | &self.ptr | 50 | 1.28k | } |
<nss_rs::replay::AntiReplayContext as core::ops::deref::Deref>::deref Line | Count | Source | 48 | 1.28k | fn deref(&self) -> &*mut $target { | 49 | 1.28k | &self.ptr | 50 | 1.28k | } |
<nss_rs::p11::SymKey as core::ops::deref::Deref>::deref Line | Count | Source | 48 | 117k | fn deref(&self) -> &*mut $target { | 49 | 117k | &self.ptr | 50 | 117k | } |
<nss_rs::p11::Context as core::ops::deref::Deref>::deref Line | Count | Source | 48 | 8.76k | fn deref(&self) -> &*mut $target { | 49 | 8.76k | &self.ptr | 50 | 8.76k | } |
Unexecuted instantiation: <nss_rs::p11::SubjectPublicKeyInfo as core::ops::deref::Deref>::deref Unexecuted instantiation: <nss_rs::p11::PublicKey as core::ops::deref::Deref>::deref <nss_rs::p11::Slot as core::ops::deref::Deref>::deref Line | Count | Source | 48 | 19.2k | fn deref(&self) -> &*mut $target { | 49 | 19.2k | &self.ptr | 50 | 19.2k | } |
Unexecuted instantiation: <nss_rs::util::ScopedSECItem as core::ops::deref::Deref>::deref Unexecuted instantiation: <nss_rs::p11::CertList as core::ops::deref::Deref>::deref Unexecuted instantiation: <nss_rs::util::ScopedSECItemArray as core::ops::deref::Deref>::deref |
51 | | } |
52 | | |
53 | | // Original implements DerefMut, but is that really a good idea? |
54 | | |
55 | | impl Drop for $name { |
56 | 150k | fn drop(&mut self) { |
57 | 150k | unsafe { _ = $dtor(self.ptr) }; |
58 | 150k | } <nss_rs::replay::AntiReplayContext as core::ops::drop::Drop>::drop Line | Count | Source | 56 | 1.28k | fn drop(&mut self) { | 57 | 1.28k | unsafe { _ = $dtor(self.ptr) }; | 58 | 1.28k | } |
<nss_rs::p11::SymKey as core::ops::drop::Drop>::drop Line | Count | Source | 56 | 94.8k | fn drop(&mut self) { | 57 | 94.8k | unsafe { _ = $dtor(self.ptr) }; | 58 | 94.8k | } |
<nss_rs::p11::Context as core::ops::drop::Drop>::drop Line | Count | Source | 56 | 32.4k | fn drop(&mut self) { | 57 | 32.4k | unsafe { _ = $dtor(self.ptr) }; | 58 | 32.4k | } |
<nss_rs::p11::Certificate as core::ops::drop::Drop>::drop Line | Count | Source | 56 | 1.28k | fn drop(&mut self) { | 57 | 1.28k | unsafe { _ = $dtor(self.ptr) }; | 58 | 1.28k | } |
Unexecuted instantiation: <nss_rs::util::ScopedSECItem as core::ops::drop::Drop>::drop Unexecuted instantiation: <nss_rs::p11::CertList as core::ops::drop::Drop>::drop Unexecuted instantiation: <nss_rs::util::ScopedSECItemArray as core::ops::drop::Drop>::drop Unexecuted instantiation: <nss_rs::p11::SubjectPublicKeyInfo as core::ops::drop::Drop>::drop Unexecuted instantiation: <nss_rs::p11::PublicKey as core::ops::drop::Drop>::drop <nss_rs::p11::PrivateKey as core::ops::drop::Drop>::drop Line | Count | Source | 56 | 1.28k | fn drop(&mut self) { | 57 | 1.28k | unsafe { _ = $dtor(self.ptr) }; | 58 | 1.28k | } |
<nss_rs::p11::Slot as core::ops::drop::Drop>::drop Line | Count | Source | 56 | 19.2k | fn drop(&mut self) { | 57 | 19.2k | unsafe { _ = $dtor(self.ptr) }; | 58 | 19.2k | } |
|
59 | | } |
60 | | }; |
61 | | } |
62 | | |
63 | | macro_rules! impl_clone { |
64 | | ($name:ty, $nss_fn:path) => { |
65 | | impl Clone for $name { |
66 | 0 | fn clone(&self) -> Self { |
67 | 0 | let ptr = unsafe { $nss_fn(self.ptr) }; |
68 | 0 | assert!(!ptr.is_null()); |
69 | 0 | Self { ptr } |
70 | 0 | } Unexecuted instantiation: <nss_rs::p11::SymKey as core::clone::Clone>::clone Unexecuted instantiation: <nss_rs::p11::PublicKey as core::clone::Clone>::clone Unexecuted instantiation: <nss_rs::p11::PrivateKey as core::clone::Clone>::clone |
71 | | } |
72 | | }; |
73 | | } |
74 | | |
75 | | impl SECItem { |
76 | | /// Return contents as a slice. |
77 | | /// |
78 | | /// Unsafe due to calling `from_raw_parts`, or if 'a outlives &self. This |
79 | | /// unsafety is encapsulated by the `as_slice` method of `SECItemBorrowed` |
80 | | /// and `SECItemMut`. |
81 | | /// |
82 | | /// Note that safe code can construct a `SECItem` pointing to anything. The |
83 | | /// same is not true of the safe wrappers `SECItemMut` and `SECItemBorrowed` |
84 | | /// because their inner `SECItem` is private. |
85 | | #[must_use] |
86 | 0 | pub unsafe fn as_slice<'a>(&self) -> &'a [u8] { |
87 | | // Sanity check the type, as some types don't count bytes in `Item::len`. |
88 | 0 | assert_eq!(self.type_, SECItemType::siBuffer); |
89 | | // Note: `from_raw_parts` requires non-null `data` even for zero-length |
90 | | // slices. |
91 | 0 | if self.len != 0 { |
92 | | unsafe { |
93 | 0 | null_safe_slice( |
94 | 0 | self.data, |
95 | 0 | usize::try_from(self.len).expect("Buffer too long"), |
96 | 0 | ) |
97 | | } |
98 | | } else { |
99 | 0 | &[] |
100 | | } |
101 | 0 | } |
102 | | } |
103 | | |
104 | 0 | unsafe fn destroy_secitem(item: *mut SECItem) { |
105 | 0 | unsafe { |
106 | 0 | SECITEM_FreeItem(item, PRBool::from(true)); |
107 | 0 | } |
108 | 0 | } |
109 | | scoped_ptr!(ScopedSECItem, SECItem, destroy_secitem); |
110 | | |
111 | | impl ScopedSECItem { |
112 | | /// This dereferences the pointer held by the item and makes a copy of the |
113 | | /// content that is referenced there. |
114 | | /// |
115 | | /// # Safety |
116 | | /// This dereferences two pointers. It doesn't get much less safe. |
117 | | #[must_use] |
118 | 0 | pub unsafe fn into_vec(self) -> Vec<u8> { |
119 | 0 | let b = unsafe { self.ptr.as_ref().expect("Null pointer") }; |
120 | | // Sanity check the type, as some types don't count bytes in `Item::len`. |
121 | 0 | assert_eq!(b.type_, SECItemType::siBuffer); |
122 | 0 | let slc = |
123 | 0 | unsafe { null_safe_slice(b.data, usize::try_from(b.len).expect("Buffer too long")) }; |
124 | 0 | Vec::from(slc) |
125 | 0 | } |
126 | | } |
127 | | |
128 | 0 | unsafe fn destroy_secitem_array(array: *mut SECItemArray) { |
129 | 0 | unsafe { |
130 | 0 | SECITEM_FreeArray(array, PRBool::from(true)); |
131 | 0 | } |
132 | 0 | } |
133 | | scoped_ptr!(ScopedSECItemArray, SECItemArray, destroy_secitem_array); |
134 | | |
135 | | #[expect(clippy::into_iter_without_iter)] |
136 | | impl<'a> IntoIterator for &'a ScopedSECItemArray { |
137 | | type Item = &'a [u8]; |
138 | | type IntoIter = ScopedSECItemArrayIterator<'a>; |
139 | 0 | fn into_iter(self) -> Self::IntoIter { |
140 | 0 | Self::IntoIter { |
141 | 0 | iter: AsRef::<[SECItem]>::as_ref(self).iter(), |
142 | 0 | } |
143 | 0 | } |
144 | | } |
145 | | |
146 | | impl AsRef<[SECItem]> for ScopedSECItemArray { |
147 | 0 | fn as_ref(&self) -> &[SECItem] { |
148 | 0 | unsafe { null_safe_slice((*self.ptr).items, (*self.ptr).len) } |
149 | 0 | } |
150 | | } |
151 | | |
152 | | pub struct ScopedSECItemArrayIterator<'a> { |
153 | | iter: Iter<'a, SECItem>, |
154 | | } |
155 | | |
156 | | impl<'a> Iterator for ScopedSECItemArrayIterator<'a> { |
157 | | type Item = &'a [u8]; |
158 | 0 | fn next(&mut self) -> Option<&'a [u8]> { |
159 | 0 | let item = self.iter.next()?; |
160 | 0 | unsafe { Some(item.as_slice()) } |
161 | 0 | } |
162 | | } |
163 | | |
164 | | /// An owned `SECItem`. |
165 | | /// |
166 | | /// The `SECItem` structure is allocated by Rust. The buffer referenced by the |
167 | | /// `SECItem` is allocated by NSS. `SECITEM_FreeItem` will be called to free the |
168 | | /// buffer when the `SECItemMut` is dropped. |
169 | | /// |
170 | | /// This is used with NSS functions that return a variable amount of data. |
171 | | #[repr(transparent)] |
172 | | pub struct SECItemMut { |
173 | | inner: SECItem, |
174 | | } |
175 | | |
176 | | impl Drop for SECItemMut { |
177 | 0 | fn drop(&mut self) { |
178 | | // FreeItem unconditionally frees the buffer referenced by the SECItem. |
179 | | // If the second argument is true, it also frees the SECItem itself, |
180 | | // which we don't want to do, because rust owns that memory. |
181 | 0 | unsafe { |
182 | 0 | SECITEM_FreeItem(&raw mut self.inner, PRBool::from(false)); |
183 | 0 | } |
184 | 0 | } |
185 | | } |
186 | | |
187 | | impl AsRef<SECItem> for SECItemMut { |
188 | 0 | fn as_ref(&self) -> &SECItem { |
189 | 0 | &self.inner |
190 | 0 | } |
191 | | } |
192 | | |
193 | | impl AsMut<SECItem> for SECItemMut { |
194 | 0 | fn as_mut(&mut self) -> &mut SECItem { |
195 | 0 | &mut self.inner |
196 | 0 | } |
197 | | } |
198 | | |
199 | | impl SECItemMut { |
200 | | /// Return contents as a slice. |
201 | | #[must_use] |
202 | 0 | pub fn as_slice(&self) -> &[u8] { |
203 | 0 | unsafe { self.inner.as_slice() } |
204 | 0 | } |
205 | | |
206 | | /// Make an empty `SECItemMut` for passing as a mutable `*SECItem` argument. |
207 | | #[must_use] |
208 | 0 | pub const fn make_empty() -> Self { |
209 | 0 | Self { |
210 | 0 | inner: SECItem { |
211 | 0 | type_: SECItemType::siBuffer, |
212 | 0 | data: null_mut(), |
213 | 0 | len: 0, |
214 | 0 | }, |
215 | 0 | } |
216 | 0 | } |
217 | | } |
218 | | |
219 | | /// A borrowed `SECItem`. |
220 | | /// |
221 | | /// The `SECItem` structure is allocated by Rust. The buffer referenced by the |
222 | | /// `SECItem` may be allocated either by Rust or NSS. The `SECItem` does not own the |
223 | | /// buffer and will not free it when dropped. |
224 | | /// |
225 | | /// This is usually used to pass a reference to some borrowed rust memory to |
226 | | /// NSS. It is occasionally used to accept non-owned output data from NSS. |
227 | | #[repr(transparent)] |
228 | | pub struct SECItemBorrowed<'a> { |
229 | | inner: SECItem, |
230 | | phantom_data: PhantomData<&'a u8>, |
231 | | } |
232 | | |
233 | | impl AsRef<SECItem> for SECItemBorrowed<'_> { |
234 | 32.4k | fn as_ref(&self) -> &SECItem { |
235 | 32.4k | &self.inner |
236 | 32.4k | } |
237 | | } |
238 | | |
239 | | impl AsMut<SECItem> for SECItemBorrowed<'_> { |
240 | | /// Get a mutable reference to the underlying `SECItem` struct. |
241 | | /// |
242 | | /// Note that even if the `SECItem` struct is mutable, the buffer it |
243 | | /// references may not be. Take care not to pass the mutable |
244 | | /// `SECItem` to NSS routines that will violate mutability rules. |
245 | | // |
246 | | // TODO: Should we make the danger more obvious, by using a non-trait method |
247 | | // with "unsafe" in the name, or an unsafe method? |
248 | 19.2k | fn as_mut(&mut self) -> &mut SECItem { |
249 | 19.2k | &mut self.inner |
250 | 19.2k | } |
251 | | } |
252 | | |
253 | | impl<'a> SECItemBorrowed<'a> { |
254 | | /// Return contents as a slice. |
255 | | #[must_use] |
256 | 0 | pub fn as_slice(&self) -> &'a [u8] { |
257 | 0 | unsafe { self.inner.as_slice() } |
258 | 0 | } |
259 | | |
260 | | /// Create an empty `SECItemBorrowed`. |
261 | | /// |
262 | | /// This can be used (1) to pass an empty item as an argument, and (2) as an |
263 | | /// output parameter when NSS returns a pointer to NSS-owned memory that |
264 | | /// should not be freed when the `SECItem` is dropped. If the memory should |
265 | | /// be freed when the `SECItem` is dropped, use `SECItemMut`. |
266 | | /// |
267 | | /// It is safe to let the caller specify any lifetime here because no |
268 | | /// borrowing is actually taking place. However, if the pointer in the |
269 | | /// returned item is modified, care must be taken that the specified |
270 | | /// lifetime accurately reflects the data referenced by the pointer. |
271 | | #[must_use] |
272 | 10.6k | pub const fn make_empty() -> Self { |
273 | 10.6k | SECItemBorrowed { |
274 | 10.6k | inner: SECItem { |
275 | 10.6k | type_: SECItemType::siBuffer, |
276 | 10.6k | data: null_mut(), |
277 | 10.6k | len: 0, |
278 | 10.6k | }, |
279 | 10.6k | phantom_data: PhantomData, |
280 | 10.6k | } |
281 | 10.6k | } |
282 | | |
283 | | /// Create a `SECItemBorrowed` wrapping a slice. |
284 | | /// |
285 | | /// Creating this object is technically safe, but using it is extremely dangerous. |
286 | | /// Minimally, it can only be passed as a `const SECItem*` argument to functions, |
287 | | /// or those that treat their argument as `const`. |
288 | 41.0k | pub fn wrap(buf: &'a [u8]) -> Res<Self> { |
289 | | Ok(Self { |
290 | | inner: SECItem { |
291 | | type_: SECItemType::siBuffer, |
292 | 41.0k | data: buf.as_ptr().cast_mut(), |
293 | 41.0k | len: c_uint::try_from(buf.len())?, |
294 | | }, |
295 | 41.0k | phantom_data: PhantomData, |
296 | | }) |
297 | 41.0k | } |
298 | | |
299 | | /// Create a `SECItemBorrowed` wrapping a struct. |
300 | | /// |
301 | | /// Creating this object is technically safe, but using it is extremely dangerous. |
302 | | /// Minimally, it can only be passed as a `const SECItem*` argument to functions, |
303 | | /// or those that treat their argument as `const`. |
304 | 0 | pub fn wrap_struct<T>(v: &'a T) -> Res<Self> { |
305 | 0 | let data: *const T = v; |
306 | | Ok(Self { |
307 | | inner: SECItem { |
308 | | type_: SECItemType::siBuffer, |
309 | 0 | data: data.cast_mut().cast(), |
310 | 0 | len: c_uint::try_from(size_of::<T>())?, |
311 | | }, |
312 | 0 | phantom_data: PhantomData, |
313 | | }) |
314 | 0 | } |
315 | | } |