win_crypto_ng/helpers/
mod.rs

1use crate::property::Property;
2use crate::{Error, Result};
3use std::mem::MaybeUninit;
4use std::ptr::{null, null_mut};
5use winapi::shared::bcrypt::*;
6use winapi::shared::ntdef::{LPCWSTR, PUCHAR, ULONG, VOID};
7
8mod bytes;
9pub use bytes::{AsBytes, FromBytes, Pod};
10mod blob;
11pub use blob::{Blob, BlobLayout};
12mod windows_string;
13pub use windows_string::WindowsString;
14
15pub trait Handle: Send {
16    fn as_ptr(&self) -> BCRYPT_HANDLE;
17    fn as_mut_ptr(&mut self) -> *mut BCRYPT_HANDLE;
18
19    fn set_property<T: Property>(&self, value: &T::Value) -> Result<()> {
20        let property = WindowsString::from(T::IDENTIFIER);
21        unsafe {
22            Error::check(BCryptSetProperty(
23                self.as_ptr(),
24                property.as_ptr(),
25                value as *const _ as PUCHAR,
26                std::mem::size_of_val(value) as ULONG,
27                0,
28            ))
29        }
30    }
31
32    fn get_property<T: Property>(&self) -> Result<T::Value>
33    where
34        T::Value: Sized,
35    {
36        let property = WindowsString::from(T::IDENTIFIER);
37        // Determine how much data we need to allocate for the return value
38        let mut size = get_property_size(self.as_ptr(), property.as_ptr())?;
39        assert_eq!(
40            size as usize,
41            std::mem::size_of::<T::Value>(),
42            "CNG property needs to allocate extra data in sized get_property variant"
43        );
44
45        // We are not expected to allocate extra trailing data, so construct the
46        // value and return it inline (especially important for `Copy` types)
47        let mut result = MaybeUninit::<T::Value>::uninit();
48
49        unsafe {
50            Error::check(BCryptGetProperty(
51                self.as_ptr(),
52                property.as_ptr(),
53                result.as_mut_ptr() as *mut _,
54                size,
55                &mut size,
56                0,
57            ))?;
58        }
59        // SAFETY: Verify that the API call has written the exact amount of
60        // bytes, so that we can conclude it's been entirely initialized
61        assert_eq!(size as usize, std::mem::size_of::<T::Value>());
62
63        Ok(unsafe { result.assume_init() })
64    }
65
66    fn get_property_unsized<T: Property>(&self) -> Result<Box<T::Value>> {
67        let property = WindowsString::from(T::IDENTIFIER);
68
69        let mut size = get_property_size(self.as_ptr(), property.as_ptr())?;
70        let mut result = vec![0u8; size as usize].into_boxed_slice();
71
72        unsafe {
73            Error::check(BCryptGetProperty(
74                self.as_ptr(),
75                property.as_ptr(),
76                result.as_mut_ptr(),
77                size,
78                &mut size,
79                0,
80            ))?;
81        }
82        // SAFETY: Verify that the API call has written the exact amount of
83        // bytes, so that we can conclude it's been entirely initialized
84        assert_eq!(size as usize, result.len());
85
86        Ok(FromBytes::from_boxed(result))
87    }
88}
89
90fn get_property_size(handle: BCRYPT_HANDLE, prop: LPCWSTR) -> Result<ULONG> {
91    let mut size: ULONG = 0;
92    unsafe {
93        Error::check(BCryptGetProperty(handle, prop, null_mut(), 0, &mut size, 0))?;
94    }
95    Ok(size)
96}
97
98pub struct AlgoHandle {
99    handle: BCRYPT_ALG_HANDLE,
100}
101
102unsafe impl Send for AlgoHandle {}
103
104impl AlgoHandle {
105    pub fn open(id: &str) -> Result<Self> {
106        let mut handle = null_mut::<VOID>();
107        unsafe {
108            let id_str = WindowsString::from(id);
109            Error::check(BCryptOpenAlgorithmProvider(
110                &mut handle,
111                id_str.as_ptr(),
112                null(),
113                0,
114            ))
115            .map(|_| Self { handle })
116        }
117    }
118}
119
120impl Drop for AlgoHandle {
121    fn drop(&mut self) {
122        if !self.handle.is_null() {
123            unsafe {
124                BCryptCloseAlgorithmProvider(self.handle, 0);
125            }
126        }
127    }
128}
129
130impl Handle for AlgoHandle {
131    fn as_ptr(&self) -> BCRYPT_ALG_HANDLE {
132        self.handle
133    }
134
135    fn as_mut_ptr(&mut self) -> *mut BCRYPT_ALG_HANDLE {
136        &mut self.handle
137    }
138}
139
140/// Cryptographic key handle
141pub struct KeyHandle {
142    pub(crate) handle: BCRYPT_KEY_HANDLE,
143}
144
145unsafe impl Send for KeyHandle {}
146
147impl KeyHandle {
148    pub fn new() -> Self {
149        Self { handle: null_mut() }
150    }
151}
152
153impl Drop for KeyHandle {
154    fn drop(&mut self) {
155        if !self.handle.is_null() {
156            unsafe {
157                BCryptDestroyKey(self.handle);
158            }
159        }
160    }
161}
162
163impl Default for KeyHandle {
164    fn default() -> Self {
165        KeyHandle::new()
166    }
167}
168
169impl Handle for KeyHandle {
170    fn as_ptr(&self) -> BCRYPT_KEY_HANDLE {
171        self.handle
172    }
173
174    fn as_mut_ptr(&mut self) -> *mut BCRYPT_KEY_HANDLE {
175        &mut self.handle
176    }
177}
178
179#[cfg(test)]
180pub(crate) fn assert_send<T: Send>() {}
181
182#[cfg(test)]
183mod tests {
184    use super::*;
185
186    #[test]
187    fn send() {
188        assert_send::<AlgoHandle>();
189        assert_send::<KeyHandle>();
190    }
191}