rama_boring/ssl/
credential.rs1use crate::error::ErrorStack;
2use crate::ex_data::Index;
3use crate::pkey::{PKeyRef, Private};
4use crate::ssl::callbacks;
5use crate::ssl::PrivateKeyMethod;
6use crate::{cvt_0i, cvt_n};
7use crate::{ffi, free_data_box};
8use foreign_types::{ForeignType, ForeignTypeRef};
9use openssl_macros::corresponds;
10use std::any::TypeId;
11use std::collections::HashMap;
12use std::ffi::{c_int, c_void};
13use std::mem;
14use std::ptr;
15use std::sync::{LazyLock, Mutex};
16
17static SSL_CREDENTIAL_INDEXES: LazyLock<Mutex<HashMap<TypeId, c_int>>> =
18 LazyLock::new(|| Mutex::new(HashMap::new()));
19
20foreign_type_and_impl_send_sync! {
21 type CType = ffi::SSL_CREDENTIAL;
22 fn drop = ffi::SSL_CREDENTIAL_free;
23
24 pub struct SslCredential;
26}
27
28impl SslCredential {
29 #[corresponds(SSL_C_get_ex_new_index)]
34 pub fn new_ex_index<T>() -> Result<Index<Self, T>, ErrorStack>
35 where
36 T: 'static + Sync + Send,
37 {
38 unsafe {
39 ffi::init();
40 let idx = cvt_n(get_new_ssl_credential_idx(Some(free_data_box::<T>)))?;
41 Ok(Index::from_raw(idx))
42 }
43 }
44
45 pub(crate) fn cached_ex_index<T>() -> Index<Self, T>
47 where
48 T: 'static + Sync + Send,
49 {
50 unsafe {
51 let idx = *SSL_CREDENTIAL_INDEXES
52 .lock()
53 .unwrap_or_else(|e| e.into_inner())
54 .entry(TypeId::of::<T>())
55 .or_insert_with(|| Self::new_ex_index::<T>().unwrap().as_raw());
56 Index::from_raw(idx)
57 }
58 }
59}
60
61impl SslCredentialRef {
62 #[corresponds(SSL_CREDENTIAL_get_ex_data)]
64 #[must_use]
65 pub fn ex_data<T>(&self, index: Index<SslCredential, T>) -> Option<&T> {
66 unsafe {
67 let data = ffi::SSL_CREDENTIAL_get_ex_data(self.as_ptr(), index.as_raw());
68 if data.is_null() {
69 None
70 } else {
71 Some(&*(data as *const T))
72 }
73 }
74 }
75
76 #[corresponds(SSL_CREDENTIAL_get_ex_data)]
79 pub(crate) unsafe fn ex_data_mut<T>(
80 &mut self,
81 index: Index<SslCredential, T>,
82 ) -> Option<&mut T> {
83 let data = ffi::SSL_CREDENTIAL_get_ex_data(self.as_ptr(), index.as_raw());
84 if data.is_null() {
85 None
86 } else {
87 Some(&mut *(data as *mut T))
88 }
89 }
90
91 #[corresponds(SSL_CREDENTIAL_set_ex_data)]
94 pub(crate) unsafe fn replace_ex_data<T>(
95 &mut self,
96 index: Index<SslCredential, T>,
97 data: T,
98 ) -> Option<T> {
99 if let Some(old) = self.ex_data_mut(index) {
100 return Some(mem::replace(old, data));
101 }
102
103 unsafe {
104 let data = Box::into_raw(Box::new(data)) as *mut c_void;
105 ffi::SSL_CREDENTIAL_set_ex_data(self.as_ptr(), index.as_raw(), data);
106 }
107
108 None
109 }
110}
111
112pub struct SslCredentialBuilder(SslCredential);
114
115impl SslCredentialBuilder {
116 #[corresponds(SSL_CREDENTIAL_set_ex_data)]
123 pub fn replace_ex_data<T>(&mut self, index: Index<SslCredential, T>, data: T) -> Option<T> {
124 unsafe { self.0.replace_ex_data(index, data) }
125 }
126
127 #[corresponds(SSL_CREDENTIAL_set1_private_key)]
129 pub fn set_private_key(&mut self, private_key: &PKeyRef<Private>) -> Result<(), ErrorStack> {
130 unsafe {
131 cvt_0i(ffi::SSL_CREDENTIAL_set1_private_key(
132 self.0.as_ptr(),
133 private_key.as_ptr(),
134 ))
135 .map(|_| ())
136 }
137 }
138
139 #[corresponds(SSL_CREDENTIAL_set_private_key_method)]
143 pub fn set_private_key_method<M>(&mut self, method: M) -> Result<(), ErrorStack>
144 where
145 M: PrivateKeyMethod,
146 {
147 unsafe {
148 self.replace_ex_data(SslCredential::cached_ex_index::<M>(), method);
149
150 cvt_0i(ffi::SSL_CREDENTIAL_set_private_key_method(
151 self.0.as_ptr(),
152 &ffi::SSL_PRIVATE_KEY_METHOD {
153 sign: Some(callbacks::raw_sign::<M>),
154 decrypt: Some(callbacks::raw_decrypt::<M>),
155 complete: Some(callbacks::raw_complete::<M>),
156 },
157 ))
158 .map(|_| ())
159 }
160 }
161
162 #[must_use]
163 pub fn build(self) -> SslCredential {
164 self.0
165 }
166}
167
168unsafe fn get_new_ssl_credential_idx(f: ffi::CRYPTO_EX_free) -> c_int {
169 ffi::SSL_CREDENTIAL_get_ex_new_index(0, ptr::null_mut(), ptr::null_mut(), None, f)
170}