1use super::mut_only::MutOnly;
2use super::{
3 ClientHello, GetSessionPendingError, PrivateKeyMethod, PrivateKeyMethodError, SelectCertError,
4 Ssl, SslAlert, SslContextBuilder, SslRef, SslSession, SslSignatureAlgorithm, SslVerifyError,
5 SslVerifyMode,
6};
7#[cfg(feature = "credential")]
8use crate::error::ErrorStack;
9use crate::ex_data::Index;
10#[cfg(feature = "credential")]
11use crate::ssl::SslCredentialBuilder;
12use std::convert::identity;
13use std::future::Future;
14use std::pin::Pin;
15use std::sync::LazyLock;
16use std::task::{ready, Context, Poll, Waker};
17
18pub type BoxSelectCertFuture = ExDataFuture<Result<BoxSelectCertFinish, AsyncSelectCertError>>;
20
21pub type BoxSelectCertFinish = Box<dyn FnOnce(ClientHello<'_>) -> Result<(), AsyncSelectCertError>>;
23
24pub type BoxPrivateKeyMethodFuture =
26 ExDataFuture<Result<BoxPrivateKeyMethodFinish, AsyncPrivateKeyMethodError>>;
27
28pub type BoxPrivateKeyMethodFinish =
30 Box<dyn FnOnce(&mut SslRef, &mut [u8]) -> Result<usize, AsyncPrivateKeyMethodError>>;
31
32pub type BoxGetSessionFuture = ExDataFuture<Option<BoxGetSessionFinish>>;
34
35pub type BoxGetSessionFinish = Box<dyn FnOnce(&mut SslRef, &[u8]) -> Option<SslSession>>;
37
38pub type BoxCustomVerifyFuture = ExDataFuture<Result<BoxCustomVerifyFinish, SslAlert>>;
40
41pub type BoxCustomVerifyFinish = Box<dyn FnOnce(&mut SslRef) -> Result<(), SslAlert>>;
43
44pub type ExDataFuture<T> = Pin<Box<dyn Future<Output = T> + Send>>;
48
49pub(crate) static TASK_WAKER_INDEX: LazyLock<Index<Ssl, Option<Waker>>> =
50 LazyLock::new(|| Ssl::new_ex_index().unwrap());
51pub(crate) static SELECT_CERT_FUTURE_INDEX: LazyLock<
52 Index<Ssl, MutOnly<Option<BoxSelectCertFuture>>>,
53> = LazyLock::new(|| Ssl::new_ex_index().unwrap());
54pub(crate) static SELECT_PRIVATE_KEY_METHOD_FUTURE_INDEX: LazyLock<
55 Index<Ssl, MutOnly<Option<BoxPrivateKeyMethodFuture>>>,
56> = LazyLock::new(|| Ssl::new_ex_index().unwrap());
57pub(crate) static SELECT_GET_SESSION_FUTURE_INDEX: LazyLock<
58 Index<Ssl, MutOnly<Option<BoxGetSessionFuture>>>,
59> = LazyLock::new(|| Ssl::new_ex_index().unwrap());
60pub(crate) static SELECT_CUSTOM_VERIFY_FUTURE_INDEX: LazyLock<
61 Index<Ssl, MutOnly<Option<BoxCustomVerifyFuture>>>,
62> = LazyLock::new(|| Ssl::new_ex_index().unwrap());
63
64impl SslContextBuilder {
65 pub fn set_async_select_certificate_callback<F>(&mut self, callback: F)
79 where
80 F: Fn(&mut ClientHello<'_>) -> Result<BoxSelectCertFuture, AsyncSelectCertError>
81 + Send
82 + Sync
83 + 'static,
84 {
85 self.set_select_certificate_callback(move |mut client_hello| {
86 let fut_poll_result = with_ex_data_future(
87 &mut client_hello,
88 *SELECT_CERT_FUTURE_INDEX,
89 ClientHello::ssl_mut,
90 &callback,
91 identity,
92 );
93
94 let fut_result = match fut_poll_result {
95 Poll::Ready(fut_result) => fut_result,
96 Poll::Pending => return Err(SelectCertError::RETRY),
97 };
98
99 let finish = fut_result.or(Err(SelectCertError::ERROR))?;
100
101 finish(client_hello).or(Err(SelectCertError::ERROR))
102 });
103 }
104
105 pub fn set_async_private_key_method(&mut self, method: impl AsyncPrivateKeyMethod) {
112 self.set_private_key_method(AsyncPrivateKeyMethodBridge(Box::new(method)));
113 }
114
115 pub unsafe fn set_async_get_session_callback<F>(&mut self, callback: F)
132 where
133 F: Fn(&mut SslRef, &[u8]) -> Option<BoxGetSessionFuture> + Send + Sync + 'static,
134 {
135 let async_callback = move |ssl: &mut SslRef, id: &[u8]| {
136 let fut_poll_result = with_ex_data_future(
137 &mut *ssl,
138 *SELECT_GET_SESSION_FUTURE_INDEX,
139 |ssl| ssl,
140 |ssl| callback(ssl, id).ok_or(()),
141 |option| option.ok_or(()),
142 );
143
144 match fut_poll_result {
145 Poll::Ready(Err(())) => Ok(None),
146 Poll::Ready(Ok(finish)) => Ok(finish(ssl, id)),
147 Poll::Pending => Err(GetSessionPendingError),
148 }
149 };
150
151 unsafe {
152 self.set_get_session_callback(async_callback);
153 }
154 }
155
156 pub fn set_async_custom_verify_callback<F>(&mut self, mode: SslVerifyMode, callback: F)
173 where
174 F: Fn(&mut SslRef) -> Result<BoxCustomVerifyFuture, SslAlert> + Send + Sync + 'static,
175 {
176 self.set_custom_verify_callback(mode, async_custom_verify_callback(callback));
177 }
178}
179
180#[cfg(feature = "credential")]
181impl SslCredentialBuilder {
182 pub fn set_async_private_key_method(
189 &mut self,
190 method: impl AsyncPrivateKeyMethod,
191 ) -> Result<(), ErrorStack> {
192 self.set_private_key_method(AsyncPrivateKeyMethodBridge(Box::new(method)))
193 }
194}
195
196impl SslRef {
197 pub fn set_async_custom_verify_callback<F>(&mut self, mode: SslVerifyMode, callback: F)
198 where
199 F: Fn(&mut SslRef) -> Result<BoxCustomVerifyFuture, SslAlert> + Send + Sync + 'static,
200 {
201 self.set_custom_verify_callback(mode, async_custom_verify_callback(callback));
202 }
203
204 pub fn set_task_waker(&mut self, waker: Option<Waker>) {
206 self.replace_ex_data(*TASK_WAKER_INDEX, waker);
207 }
208}
209
210fn async_custom_verify_callback<F>(
211 callback: F,
212) -> impl Fn(&mut SslRef) -> Result<(), SslVerifyError>
213where
214 F: Fn(&mut SslRef) -> Result<BoxCustomVerifyFuture, SslAlert> + Send + Sync + 'static,
215{
216 move |ssl| {
217 let fut_poll_result = with_ex_data_future(
218 &mut *ssl,
219 *SELECT_CUSTOM_VERIFY_FUTURE_INDEX,
220 |ssl| ssl,
221 &callback,
222 identity,
223 );
224
225 match fut_poll_result {
226 Poll::Ready(Err(alert)) => Err(SslVerifyError::Invalid(alert)),
227 Poll::Ready(Ok(finish)) => Ok(finish(ssl).map_err(SslVerifyError::Invalid)?),
228 Poll::Pending => Err(SslVerifyError::Retry),
229 }
230 }
231}
232
233#[derive(Debug, Copy, Clone, PartialEq, Eq)]
235pub struct AsyncSelectCertError;
236
237pub trait AsyncPrivateKeyMethod: Send + Sync + 'static {
245 fn sign(
253 &self,
254 ssl: &mut SslRef,
255 input: &[u8],
256 signature_algorithm: SslSignatureAlgorithm,
257 output: &mut [u8],
258 ) -> Result<BoxPrivateKeyMethodFuture, AsyncPrivateKeyMethodError>;
259
260 fn decrypt(
268 &self,
269 ssl: &mut SslRef,
270 input: &[u8],
271 output: &mut [u8],
272 ) -> Result<BoxPrivateKeyMethodFuture, AsyncPrivateKeyMethodError>;
273}
274
275#[derive(Debug, Copy, Clone, PartialEq, Eq)]
277pub struct AsyncPrivateKeyMethodError;
278
279struct AsyncPrivateKeyMethodBridge(Box<dyn AsyncPrivateKeyMethod>);
280
281impl PrivateKeyMethod for AsyncPrivateKeyMethodBridge {
282 fn sign(
283 &self,
284 ssl: &mut SslRef,
285 input: &[u8],
286 signature_algorithm: SslSignatureAlgorithm,
287 output: &mut [u8],
288 ) -> Result<usize, PrivateKeyMethodError> {
289 with_private_key_method(ssl, output, |ssl, output| {
290 <dyn AsyncPrivateKeyMethod>::sign(&*self.0, ssl, input, signature_algorithm, output)
291 })
292 }
293
294 fn decrypt(
295 &self,
296 ssl: &mut SslRef,
297 input: &[u8],
298 output: &mut [u8],
299 ) -> Result<usize, PrivateKeyMethodError> {
300 with_private_key_method(ssl, output, |ssl, output| {
301 <dyn AsyncPrivateKeyMethod>::decrypt(&*self.0, ssl, input, output)
302 })
303 }
304
305 fn complete(
306 &self,
307 ssl: &mut SslRef,
308 output: &mut [u8],
309 ) -> Result<usize, PrivateKeyMethodError> {
310 with_private_key_method(ssl, output, |_, _| {
311 if cfg!(debug_assertions) {
316 panic!("BUG: boring called complete without a pending operation");
317 }
318
319 Err(AsyncPrivateKeyMethodError)
320 })
321 }
322}
323
324fn with_private_key_method(
331 ssl: &mut SslRef,
332 output: &mut [u8],
333 create_fut: impl FnOnce(
334 &mut SslRef,
335 &mut [u8],
336 ) -> Result<BoxPrivateKeyMethodFuture, AsyncPrivateKeyMethodError>,
337) -> Result<usize, PrivateKeyMethodError> {
338 let fut_poll_result = with_ex_data_future(
339 ssl,
340 *SELECT_PRIVATE_KEY_METHOD_FUTURE_INDEX,
341 |ssl| ssl,
342 |ssl| create_fut(ssl, output),
343 identity,
344 );
345
346 let fut_result = match fut_poll_result {
347 Poll::Ready(fut_result) => fut_result,
348 Poll::Pending => return Err(PrivateKeyMethodError::RETRY),
349 };
350
351 let finish = fut_result.or(Err(PrivateKeyMethodError::FAILURE))?;
352
353 finish(ssl, output).or(Err(PrivateKeyMethodError::FAILURE))
354}
355
356fn with_ex_data_future<H, R, T, E>(
361 ssl_handle: &mut H,
362 index: Index<Ssl, MutOnly<Option<ExDataFuture<R>>>>,
363 get_ssl_mut: impl Fn(&mut H) -> &mut SslRef,
364 create_fut: impl FnOnce(&mut H) -> Result<ExDataFuture<R>, E>,
365 into_result: impl Fn(R) -> Result<T, E>,
366) -> Poll<Result<T, E>> {
367 let ssl = get_ssl_mut(ssl_handle);
368 let waker = ssl
369 .ex_data(*TASK_WAKER_INDEX)
370 .cloned()
371 .flatten()
372 .expect("task waker should be set");
373
374 let mut ctx = Context::from_waker(&waker);
375
376 if let Some(data @ Some(_)) = ssl.ex_data_mut(index).map(MutOnly::get_mut) {
377 let fut_result = into_result(ready!(data.as_mut().unwrap().as_mut().poll(&mut ctx)));
378
379 *data = None;
380
381 Poll::Ready(fut_result)
382 } else {
383 let mut fut = create_fut(ssl_handle)?;
384
385 match fut.as_mut().poll(&mut ctx) {
386 Poll::Ready(fut_result) => Poll::Ready(into_result(fut_result)),
387 Poll::Pending => {
388 get_ssl_mut(ssl_handle).replace_ex_data(index, MutOnly::new(Some(fut)));
389
390 Poll::Pending
391 }
392 }
393 }
394}