Skip to main content

s2n_tls/
connection.rs

1// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2// SPDX-License-Identifier: Apache-2.0
3
4#![allow(clippy::missing_safety_doc)] // TODO add safety docs
5
6#[cfg(feature = "unstable-cert_authorities")]
7use crate::cert_authorities::CertRequestState;
8#[cfg(feature = "unstable-renegotiate")]
9use crate::renegotiate::RenegotiateState;
10use crate::{
11    callbacks::*,
12    cert_chain::{CertificateChain, CertificateChainHandle},
13    config::Config,
14    enums::*,
15    error::{Error, Fallible, Pollable},
16    psk::Psk,
17    security,
18    utilities::cstr_to_str,
19};
20
21use core::{
22    convert::TryInto,
23    fmt,
24    mem::{self, ManuallyDrop, MaybeUninit},
25    pin::Pin,
26    ptr::NonNull,
27    task::{Poll, Waker},
28    time::Duration,
29};
30use libc::c_void;
31use s2n_tls_sys::*;
32use std::{
33    any::{Any, TypeId},
34    collections::HashMap,
35    ffi::CStr,
36};
37
38mod builder;
39pub use builder::*;
40
41/// return a &str scoped to the lifetime of the surrounding function
42///
43/// SAFETY: must be called on a null terminated string
44///
45/// SAFETY: the underlying data must live at least as long as the surrounding scope
46// We use a macro instead of a function so that the lifetime of the output is
47// automatically inferred to match the surrounding scope.
48macro_rules! const_str {
49    ($c_chars:expr) => {
50        CStr::from_ptr($c_chars)
51            .to_str()
52            .map_err(|_| Error::INVALID_INPUT)
53    };
54}
55
56#[non_exhaustive]
57#[derive(Debug, PartialEq)]
58/// s2n-tls only tracks up to u8::MAX (255) key updates. If any of the fields show
59/// 255 updates, then more than 255 updates may have occurred.
60pub struct KeyUpdateCount {
61    pub send_key_updates: u8,
62    pub recv_key_updates: u8,
63}
64
65/// Corresponds to [`s2n_connection`].
66pub struct Connection {
67    connection: NonNull<s2n_connection>,
68}
69
70impl fmt::Debug for Connection {
71    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
72        let mut debug = f.debug_struct("Connection");
73        if let Ok(handshake) = self.handshake_type() {
74            debug.field("handshake_type", &handshake);
75        }
76        if let Ok(cipher) = self.cipher_suite() {
77            debug.field("cipher_suite", &cipher);
78        }
79        if let Ok(version) = self.actual_protocol_version() {
80            debug.field("actual_protocol_version", &version);
81        }
82        if let Some(group_name) = self.selected_key_exchange_group() {
83            debug.field("selected_key_exchange_group", &group_name);
84        }
85        debug.finish_non_exhaustive()
86    }
87}
88
89/// # Safety
90///
91/// s2n_connection objects can be sent across threads
92unsafe impl Send for Connection {}
93
94/// # Sync
95///
96/// Although NonNull isn't Sync and allows access to mutable pointers even from
97/// immutable references, the Connection interface enforces that all mutating
98/// methods correctly require &mut self.
99///
100/// Developers and reviewers MUST ensure that new methods correctly use
101/// either &self or &mut self depending on their behavior. No mechanism enforces this.
102///
103/// Note: Although non-mutating methods like getters should be thread-safe by definition,
104/// technically the only thread safety guarantee provided by the underlying C library
105/// is that s2n_send and s2n_recv can be called concurrently.
106///
107unsafe impl Sync for Connection {}
108
109impl Connection {
110    /// # Warning
111    ///
112    /// The newly created connection uses the default security policy.
113    /// Consider changing this depending on your security and compatibility requirements
114    /// by calling [`Connection::set_security_policy`].
115    /// Alternatively, you can use [`crate::config::Builder`], [`crate::config::Builder::set_security_policy`],
116    /// and [`Connection::set_config`] to set the policy on the Config instead of on the Connection.
117    /// See the s2n-tls usage guide:
118    /// <https://aws.github.io/s2n-tls/usage-guide/ch06-security-policies.html>
119    ///
120    /// Corresponds to [`s2n_connection_new`].
121    pub fn new(mode: Mode) -> Self {
122        crate::init::init();
123
124        let connection = unsafe { s2n_connection_new(mode.into()).into_result() }.unwrap();
125
126        unsafe {
127            debug_assert! {
128                s2n_connection_get_config(connection.as_ptr(), &mut core::ptr::null_mut())
129                    .into_result()
130                    .is_err()
131            }
132        }
133
134        let mut connection = Self { connection };
135        connection.init_context(mode);
136        connection
137    }
138
139    fn init_context(&mut self, mode: Mode) {
140        let context = Box::new(Context::new(mode));
141        let context = Box::into_raw(context) as *mut c_void;
142        // allocate a new context object
143        unsafe {
144            // There should never be an existing context
145            debug_assert!(s2n_connection_get_ctx(self.connection.as_ptr())
146                .into_result()
147                .is_err());
148
149            s2n_connection_set_ctx(self.connection.as_ptr(), context)
150                .into_result()
151                .unwrap();
152        }
153    }
154
155    pub fn new_client() -> Self {
156        Self::new(Mode::Client)
157    }
158
159    pub fn new_server() -> Self {
160        Self::new(Mode::Server)
161    }
162
163    pub(crate) fn as_ptr(&mut self) -> *mut s2n_connection {
164        self.connection.as_ptr()
165    }
166
167    /// Returns the underlying `s2n_tls_sys::s2n_connection` pointer associated with the
168    /// `Connection`.
169    ///
170    /// #### Warning:
171    /// This API is unstable, and may be removed in a future s2n-tls release. Applications should
172    /// use the higher level s2n-tls bindings rather than calling the low-level `s2n_tls_sys` APIs
173    /// directly.
174    #[cfg(s2n_tls_external_build)]
175    pub fn unstable_as_ptr(&mut self) -> *mut s2n_connection {
176        self.as_ptr()
177    }
178
179    /// # Safety
180    ///
181    /// Caller must ensure s2n_connection is a valid reference to a [`s2n_connection`] object
182    pub(crate) unsafe fn from_raw(connection: NonNull<s2n_connection>) -> Self {
183        Self { connection }
184    }
185
186    pub(crate) fn mode(&self) -> Mode {
187        self.context().mode
188    }
189
190    /// can be used to configure s2n to either use built-in blinding (set blinding
191    /// to Blinding::BuiltIn) or self-service blinding (set blinding to
192    /// Blinding::SelfService).
193    ///
194    /// Corresponds to [`s2n_connection_set_blinding`].
195    pub fn set_blinding(&mut self, blinding: Blinding) -> Result<&mut Self, Error> {
196        unsafe {
197            s2n_connection_set_blinding(self.connection.as_ptr(), blinding.into()).into_result()
198        }?;
199        Ok(self)
200    }
201
202    /// Reports the remaining nanoseconds before the connection may be gracefully shutdown.
203    ///
204    /// This method is expected to succeed, but could fail if the
205    /// [underlying C call](`s2n_connection_get_delay`) encounters errors.
206    /// Failure indicates that calls to [`Self::poll_shutdown`] will also fail and
207    /// that a graceful two-way shutdown of the connection will not be possible.
208    ///
209    /// Corresponds to [`s2n_connection_get_delay`].
210    pub fn remaining_blinding_delay(&self) -> Result<Duration, Error> {
211        let nanos = unsafe { s2n_connection_get_delay(self.connection.as_ptr()).into_result() }?;
212        Ok(Duration::from_nanos(nanos))
213    }
214
215    /// Sets whether or not a Client Certificate should be required to complete the TLS Connection.
216    ///
217    /// If this is set to ClientAuthType::Optional the server will request a client certificate
218    /// but allow the client to not provide one. Rejecting a client certificate when using
219    /// ClientAuthType::Optional will terminate the handshake.
220    ///
221    /// Corresponds to [`s2n_connection_set_client_auth_type`].
222    pub fn set_client_auth_type(
223        &mut self,
224        client_auth_type: ClientAuthType,
225    ) -> Result<&mut Self, Error> {
226        unsafe {
227            s2n_connection_set_client_auth_type(self.connection.as_ptr(), client_auth_type.into())
228                .into_result()
229        }?;
230        Ok(self)
231    }
232
233    /// Attempts to drop the config on the connection.
234    ///
235    /// # Safety
236    ///
237    /// The caller must ensure the config associated with the connection was created
238    /// with a [`config::Builder`].
239    unsafe fn drop_config(&mut self) -> Result<(), Error> {
240        let mut prev_config = core::ptr::null_mut();
241
242        // A valid non-null pointer is returned only if the application previously called
243        // [`Self::set_config()`].
244        if s2n_connection_get_config(self.connection.as_ptr(), &mut prev_config)
245            .into_result()
246            .is_ok()
247        {
248            let prev_config = NonNull::new(prev_config).expect(
249                "config should exist since the call to s2n_connection_get_config was successful",
250            );
251            drop(Config::from_raw(prev_config));
252        }
253
254        Ok(())
255    }
256
257    /// Associates a configuration object with a connection.
258    ///
259    /// Corresponds to [`s2n_connection_set_config`].
260    pub fn set_config(&mut self, mut config: Config) -> Result<&mut Self, Error> {
261        unsafe {
262            // attempt to drop the currently set config
263            self.drop_config()?;
264
265            s2n_connection_set_config(self.connection.as_ptr(), config.as_mut_ptr())
266                .into_result()?;
267
268            debug_assert! {
269                s2n_connection_get_config(self.connection.as_ptr(), &mut core::ptr::null_mut()).into_result().is_ok(),
270                "s2n_connection_set_config was successful"
271            };
272
273            // Setting the config on the connection creates one additional reference to the config
274            // so do not drop so prevent Rust from calling `drop()` at the end of this function.
275            mem::forget(config);
276        }
277
278        Ok(self)
279    }
280
281    pub(crate) fn config(&self) -> Option<Config> {
282        let mut raw = core::ptr::null_mut();
283        let config = unsafe {
284            s2n_connection_get_config(self.connection.as_ptr(), &mut raw)
285                .into_result()
286                .ok()?;
287            let raw = NonNull::new(raw)?;
288            Config::from_raw(raw)
289        };
290        // Because the config pointer is still set on the connection, this is a copy,
291        // not the original config. This is fine -- Configs are immutable.
292        let _ = ManuallyDrop::new(config.clone());
293        Some(config)
294    }
295
296    /// Corresponds to [`s2n_connection_set_cipher_preferences`].
297    pub fn set_security_policy(&mut self, policy: &security::Policy) -> Result<&mut Self, Error> {
298        unsafe {
299            s2n_connection_set_cipher_preferences(
300                self.connection.as_ptr(),
301                policy.as_cstr().as_ptr(),
302            )
303            .into_result()
304        }?;
305        Ok(self)
306    }
307
308    /// provides a smooth transition from s2n_connection_prefer_low_latency to s2n_connection_prefer_throughput.
309    ///
310    /// s2n_send uses small TLS records that fit into a single TCP segment for the resize_threshold
311    /// bytes (cap to 8M) of data and reset record size back to a single segment after timeout_threshold
312    /// seconds of inactivity.
313    ///
314    /// Corresponds to [`s2n_connection_set_dynamic_record_threshold`].
315    pub fn set_dynamic_record_threshold(
316        &mut self,
317        resize_threshold: u32,
318        timeout_threshold: u16,
319    ) -> Result<&mut Self, Error> {
320        unsafe {
321            s2n_connection_set_dynamic_record_threshold(
322                self.connection.as_ptr(),
323                resize_threshold,
324                timeout_threshold,
325            )
326            .into_result()
327        }?;
328        Ok(self)
329    }
330
331    /// Signals the connection to do a key_update at the next possible opportunity.
332    /// Note that the resulting key update message will not be sent until `send` is
333    /// called on the connection.
334    ///
335    /// `peer_request` indicates if a key update should also be requested
336    /// of the peer. When set to `KeyUpdateNotRequested`, then only the sending
337    /// key of the connection will be updated. If set to `KeyUpdateRequested`, then
338    /// the sending key of conn will be updated AND the peer will be requested to
339    /// update their sending key. Note that s2n-tls currently only supports
340    /// `peer_request` being set to `KeyUpdateNotRequested` and will return an error
341    /// if any other value is used.
342    ///
343    /// Corresponds to [`s2n_connection_request_key_update`].
344    pub fn request_key_update(&mut self, peer_request: PeerKeyUpdate) -> Result<&mut Self, Error> {
345        unsafe {
346            s2n_connection_request_key_update(self.connection.as_ptr(), peer_request.into())
347                .into_result()
348        }?;
349        Ok(self)
350    }
351
352    /// Reports the number of times sending and receiving keys have been updated.
353    ///
354    /// This only applies to TLS1.3. Earlier versions do not support key updates.
355    ///
356    /// Corresponds to [`s2n_connection_get_key_update_counts`].
357    #[cfg(feature = "unstable-ktls")]
358    pub fn key_update_counts(&self) -> Result<KeyUpdateCount, Error> {
359        let mut send_key_updates = 0;
360        let mut recv_key_updates = 0;
361        unsafe {
362            s2n_connection_get_key_update_counts(
363                self.connection.as_ptr(),
364                &mut send_key_updates,
365                &mut recv_key_updates,
366            )
367            .into_result()?;
368        }
369        Ok(KeyUpdateCount {
370            send_key_updates,
371            recv_key_updates,
372        })
373    }
374
375    /// sets the application protocol preferences on an s2n_connection object.
376    ///
377    /// protocols is a list in order of preference, with most preferred protocol first, and of
378    /// length protocol_count. When acting as a client the protocol list is included in the
379    /// Client Hello message as the ALPN extension. As a server, the list is used to negotiate
380    /// a mutual application protocol with the client. After the negotiation for the connection has
381    /// completed, the agreed upon protocol can be retrieved with s2n_get_application_protocol
382    ///
383    /// Corresponds to [`s2n_connection_set_protocol_preferences`].
384    pub fn set_application_protocol_preference<P: IntoIterator<Item = I>, I: AsRef<[u8]>>(
385        &mut self,
386        protocols: P,
387    ) -> Result<&mut Self, Error> {
388        // reset the list
389        unsafe {
390            s2n_connection_set_protocol_preferences(self.connection.as_ptr(), core::ptr::null(), 0)
391                .into_result()
392        }?;
393
394        for protocol in protocols {
395            self.append_application_protocol_preference(protocol.as_ref())?;
396        }
397
398        Ok(self)
399    }
400
401    /// Corresponds to [`s2n_connection_append_protocol_preference`].
402    pub fn append_application_protocol_preference(
403        &mut self,
404        protocol: &[u8],
405    ) -> Result<&mut Self, Error> {
406        unsafe {
407            s2n_connection_append_protocol_preference(
408                self.connection.as_ptr(),
409                protocol.as_ptr(),
410                protocol
411                    .len()
412                    .try_into()
413                    .map_err(|_| Error::INVALID_INPUT)?,
414            )
415            .into_result()
416        }?;
417        Ok(self)
418    }
419
420    /// may be used to receive data with callbacks defined by the user.
421    ///
422    /// Corresponds to [`s2n_connection_set_recv_cb`].
423    pub fn set_receive_callback(&mut self, callback: s2n_recv_fn) -> Result<&mut Self, Error> {
424        unsafe { s2n_connection_set_recv_cb(self.connection.as_ptr(), callback).into_result() }?;
425        Ok(self)
426    }
427
428    /// # Safety
429    ///
430    /// The `context` pointer must live at least as long as the connection
431    ///
432    /// Corresponds to [`s2n_connection_set_recv_ctx`].
433    pub unsafe fn set_receive_context(&mut self, context: *mut c_void) -> Result<&mut Self, Error> {
434        s2n_connection_set_recv_ctx(self.connection.as_ptr(), context).into_result()?;
435        Ok(self)
436    }
437
438    /// may be used to receive data with callbacks defined by the user.
439    ///
440    /// Corresponds to [`s2n_connection_set_send_cb`].
441    pub fn set_send_callback(&mut self, callback: s2n_send_fn) -> Result<&mut Self, Error> {
442        unsafe { s2n_connection_set_send_cb(self.connection.as_ptr(), callback).into_result() }?;
443        Ok(self)
444    }
445
446    /// # Safety
447    ///
448    /// The `context` pointer must live at least as long as the connection
449    ///
450    /// Corresponds to [`s2n_connection_set_send_ctx`].
451    pub unsafe fn set_send_context(&mut self, context: *mut c_void) -> Result<&mut Self, Error> {
452        s2n_connection_set_send_ctx(self.connection.as_ptr(), context).into_result()?;
453        Ok(self)
454    }
455
456    /// Sets the callback to use for verifying that a hostname from an X.509 certificate is
457    /// trusted.
458    ///
459    /// The callback may be called more than once during certificate validation as each SAN on
460    /// the certificate will be checked.
461    ///
462    /// Corresponds to [`s2n_connection_set_verify_host_callback`].
463    pub fn set_verify_host_callback<T: 'static + VerifyHostNameCallback>(
464        &mut self,
465        handler: T,
466    ) -> Result<&mut Self, Error> {
467        unsafe extern "C" fn verify_host_cb_fn(
468            host_name: *const ::libc::c_char,
469            host_name_len: usize,
470            context: *mut ::libc::c_void,
471        ) -> u8 {
472            let context = &mut *(context as *mut Context);
473            let handler = context.verify_host_callback.as_mut().unwrap();
474            verify_host(host_name, host_name_len, handler)
475        }
476
477        self.context_mut().verify_host_callback = Some(Box::new(handler));
478        unsafe {
479            s2n_connection_set_verify_host_callback(
480                self.connection.as_ptr(),
481                Some(verify_host_cb_fn),
482                self.context_mut() as *mut Context as *mut c_void,
483            )
484            .into_result()
485        }?;
486        Ok(self)
487    }
488
489    /// Connections preferring low latency will be encrypted using small record sizes that
490    /// can be decrypted sooner by the recipient.
491    ///
492    /// Corresponds to [`s2n_connection_prefer_low_latency`].
493    pub fn prefer_low_latency(&mut self) -> Result<&mut Self, Error> {
494        unsafe { s2n_connection_prefer_low_latency(self.connection.as_ptr()).into_result() }?;
495        Ok(self)
496    }
497
498    /// Connections preferring throughput will use large record sizes that minimize overhead.
499    ///
500    /// Corresponds to [`s2n_connection_prefer_throughput`].
501    pub fn prefer_throughput(&mut self) -> Result<&mut Self, Error> {
502        unsafe { s2n_connection_prefer_throughput(self.connection.as_ptr()).into_result() }?;
503        Ok(self)
504    }
505
506    /// Configure the connection to reduce potentially expensive calls to recv.
507    ///
508    /// Corresponds to [`s2n_connection_set_recv_buffering`].
509    pub fn set_receive_buffering(&mut self, enabled: bool) -> Result<&mut Self, Error> {
510        unsafe {
511            s2n_connection_set_recv_buffering(self.connection.as_ptr(), enabled).into_result()
512        }?;
513        Ok(self)
514    }
515
516    /// wipes and free the in and out buffers associated with a connection.
517    ///
518    /// This function may be called when a connection is in keep-alive or idle state to
519    /// reduce memory overhead of long lived connections.
520    ///
521    /// Corresponds to [`s2n_connection_release_buffers`].
522    pub fn release_buffers(&mut self) -> Result<&mut Self, Error> {
523        unsafe { s2n_connection_release_buffers(self.connection.as_ptr()).into_result() }?;
524        Ok(self)
525    }
526
527    /// Corresponds to [`s2n_connection_use_corked_io`].
528    pub fn use_corked_io(&mut self) -> Result<&mut Self, Error> {
529        unsafe { s2n_connection_use_corked_io(self.connection.as_ptr()).into_result() }?;
530        Ok(self)
531    }
532
533    pub(crate) fn wipe_method<F, T>(&mut self, wipe: F) -> Result<(), Error>
534    where
535        F: FnOnce(&mut Self) -> Result<T, Error>,
536    {
537        let mode = self.mode();
538
539        // Safety:
540        // We re-init the context after the wipe
541        unsafe { self.drop_context()? };
542
543        let result = wipe(self);
544        // We must initialize the context again whether or not wipe succeeds.
545        // A connection without a context is invalid and has undefined behavior.
546        self.init_context(mode);
547        result?;
548
549        Ok(())
550    }
551
552    /// wipes an existing connection and allows it to be reused.
553    ///
554    /// This method erases all data associated with a connection including pending reads.
555    /// This function should be called after all I/O is completed and s2n_shutdown has been
556    /// called. Reusing the same connection handle(s) is more performant than repeatedly
557    /// calling s2n_connection_new and s2n_connection_free
558    ///
559    /// Corresponds to [`s2n_connection_wipe`].
560    pub fn wipe(&mut self) -> Result<&mut Self, Error> {
561        self.wipe_method(|conn| unsafe { s2n_connection_wipe(conn.as_ptr()).into_result() })?;
562        Ok(self)
563    }
564
565    fn trigger_initializer(&mut self) {
566        if !core::mem::replace(&mut self.context_mut().connection_initialized, true) {
567            if let Some(config) = self.config() {
568                if let Some(callback) = config.context().connection_initializer.as_ref() {
569                    let future = callback.initialize_connection(self);
570                    AsyncCallback::trigger(future, self);
571                }
572            }
573        }
574    }
575
576    // Poll the connection future if it exists.
577    //
578    // If the future returns Pending, then re-set it back on the Connection.
579    fn poll_async_task(&mut self) -> Option<Poll<Result<(), Error>>> {
580        self.take_async_callback().map(|mut callback| {
581            let waker = self.waker().ok_or(Error::MISSING_WAKER)?.clone();
582            let mut ctx = core::task::Context::from_waker(&waker);
583            match Pin::new(&mut callback).poll(self, &mut ctx) {
584                Poll::Ready(result) => Poll::Ready(result),
585                Poll::Pending => {
586                    // replace the future if it hasn't completed yet
587                    self.set_async_callback(callback);
588                    Poll::Pending
589                }
590            }
591        })
592    }
593
594    pub(crate) fn poll_negotiate_method<F, T>(
595        &mut self,
596        mut negotiate: F,
597    ) -> Poll<Result<(), Error>>
598    where
599        F: FnMut(&mut Connection) -> Poll<Result<T, Error>>,
600    {
601        self.trigger_initializer();
602
603        loop {
604            // Check whether renegotiate is blocked by any async callbacks
605            match self.poll_async_task().unwrap_or(Poll::Ready(Ok(()))) {
606                Poll::Ready(Err(err)) => return Poll::Ready(Err(err)),
607                Poll::Pending => return Poll::Pending,
608                Poll::Ready(Ok(_)) => {}
609            };
610
611            match negotiate(self) {
612                Poll::Ready(res) => return Poll::Ready(res.map(|_| ())),
613                Poll::Pending => {
614                    // If `negotiate` returned `Pending` it could be blocked on a connection future
615                    // (i.e. not socket IO) so before we return, we need to make sure we poll
616                    // the associated future at least once. Otherwise, we will violate the waker contract.
617                    //
618                    // See https://github.com/aws/s2n-quic/pull/2248
619                    if self.context_mut().async_callback.is_some() {
620                        // continuing in the loop will poll the task
621                        continue;
622                    }
623
624                    // we don't have anything else to poll so return `Pending`
625                    return Poll::Pending;
626                }
627            }
628        }
629    }
630
631    /// Performs the TLS handshake to completion
632    ///
633    /// Multiple callbacks can be configured for a connection and config, but
634    /// [`Self::poll_negotiate()`] can only execute and block on one callback at a time.
635    /// The handshake is sequential, not concurrent, and stops execution when
636    /// it encounters an async callback.
637    ///
638    /// The handshake does not continue execution (and therefore can't call
639    /// any other callbacks) until the blocking async task reports completion.
640    ///
641    /// Corresponds to [`s2n_negotiate`].
642    pub fn poll_negotiate(&mut self) -> Poll<Result<&mut Self, Error>> {
643        let mut blocked = s2n_blocked_status::NOT_BLOCKED;
644        self.poll_negotiate_method(|conn| unsafe {
645            s2n_negotiate(conn.as_ptr(), &mut blocked).into_poll()
646        })
647        .map_ok(|_| self)
648    }
649
650    /// Encrypts and sends data on a connection where
651    /// [negotiate](`Self::poll_negotiate`) has succeeded.
652    ///
653    /// Returns the number of bytes written, and may indicate a partial write.
654    ///
655    /// Corresponds to [`s2n_send`].
656    #[cfg(not(feature = "unstable-renegotiate"))]
657    pub fn poll_send(&mut self, buf: &[u8]) -> Poll<Result<usize, Error>> {
658        let mut blocked = s2n_blocked_status::NOT_BLOCKED;
659        let buf_len: isize = buf.len().try_into().map_err(|_| Error::INVALID_INPUT)?;
660        let buf_ptr = buf.as_ptr() as *const ::libc::c_void;
661        unsafe { s2n_send(self.connection.as_ptr(), buf_ptr, buf_len, &mut blocked).into_poll() }
662    }
663
664    #[cfg(not(feature = "unstable-renegotiate"))]
665    pub(crate) fn poll_recv_raw(
666        &mut self,
667        buf_ptr: *mut ::libc::c_void,
668        buf_len: isize,
669    ) -> Poll<Result<usize, Error>> {
670        let mut blocked = s2n_blocked_status::NOT_BLOCKED;
671        unsafe { s2n_recv(self.connection.as_ptr(), buf_ptr, buf_len, &mut blocked).into_poll() }
672    }
673
674    /// Reads and decrypts data from a connection where
675    /// [negotiate](`Self::poll_negotiate`) has succeeded.
676    ///
677    /// Returns the number of bytes read, and may indicate a partial read.
678    /// 0 bytes returned indicates EOF due to connection closure.
679    ///
680    /// Corresponds to [`s2n_recv`].
681    pub fn poll_recv(&mut self, buf: &mut [u8]) -> Poll<Result<usize, Error>> {
682        let buf_len: isize = buf.len().try_into().map_err(|_| Error::INVALID_INPUT)?;
683        let buf_ptr = buf.as_ptr() as *mut ::libc::c_void;
684        self.poll_recv_raw(buf_ptr, buf_len)
685    }
686
687    /// Reads and decrypts data from a connection where
688    /// [negotiate](`Self::poll_negotiate`) has succeeded
689    /// to a uninitialized buffer.
690    ///
691    /// Returns the number of bytes read, and may indicate a partial read.
692    /// 0 bytes returned indicates EOF due to connection closure.
693    ///
694    /// Safety: this function is always safe to call, and additionally:
695    /// 1. It will never uninitialize any bytes in `buf`.
696    /// 2. If it returns `Ok(n)`, then the first `n` bytes of `buf`
697    ///    will have been initialized by this function.
698    ///
699    /// Corresponds to [`s2n_recv`].
700    pub fn poll_recv_uninitialized(
701        &mut self,
702        buf: &mut [MaybeUninit<u8>],
703    ) -> Poll<Result<usize, Error>> {
704        let buf_len: isize = buf.len().try_into().map_err(|_| Error::INVALID_INPUT)?;
705        let buf_ptr = buf.as_ptr() as *mut ::libc::c_void;
706
707        // Safety:
708        // 1. s2n_recv never writes uninitialized garbage to `buf`.
709        // 2. if s2n_recv returns `+n`, it guarantees that the first
710        // `n` bytes of `buf` have been initialized, which allows this
711        // function to return `Ok(n)`
712        self.poll_recv_raw(buf_ptr, buf_len)
713    }
714
715    /// Attempts to flush any data previously buffered by a call to [send](`Self::poll_send`).
716    ///
717    /// poll_flush can only flush data that s2n-tls has already encrypted and
718    /// buffered for sending. poll_send may need to be called again to fully send
719    /// all data. See the [Usage Guide](https://github.com/aws/s2n-tls/blob/main/docs/usage-guide/topics/ch07-io.md)
720    /// for more details.
721    ///
722    /// Corresponds to [`s2n_flush`].
723    pub fn poll_flush(&mut self) -> Poll<Result<&mut Self, Error>> {
724        let mut blocked = s2n_blocked_status::NOT_BLOCKED;
725        unsafe {
726            s2n_flush(self.connection.as_ptr(), &mut blocked)
727                .into_poll()
728                .map_ok(|_| self)
729        }
730    }
731
732    /// Gets the number of bytes that are currently available in the buffer to be read.
733    ///
734    /// Corresponds to [`s2n_peek`].
735    pub fn peek_len(&self) -> usize {
736        unsafe { s2n_peek(self.connection.as_ptr()) as usize }
737    }
738
739    /// Gets the number of additional ciphertext bytes available to be read.
740    ///
741    /// <div class="warning">
742    ///
743    /// This API is _not_ intuitive, and probably doesn't do what you think
744    /// it does. You should rigorously test your assumptions about its behavior.
745    ///
746    /// </div>
747    ///
748    /// Corresponds to [`s2n_peek_buffered`].
749    pub fn peek_buffered_len(&self) -> usize {
750        unsafe { s2n_peek_buffered(self.connection.as_ptr()) as usize }
751    }
752
753    /// Attempts a graceful shutdown of the TLS connection.
754    ///
755    /// The shutdown is not complete until the necessary shutdown messages
756    /// have been successfully sent and received. If the peer does not respond
757    /// correctly, the graceful shutdown may fail.
758    ///
759    /// Corresponds to [`s2n_shutdown`].
760    pub fn poll_shutdown(&mut self) -> Poll<Result<&mut Self, Error>> {
761        if !self.remaining_blinding_delay()?.is_zero() {
762            return Poll::Pending;
763        }
764        let mut blocked = s2n_blocked_status::NOT_BLOCKED;
765        unsafe {
766            s2n_shutdown(self.connection.as_ptr(), &mut blocked)
767                .into_poll()
768                .map_ok(|_| self)
769        }
770    }
771
772    /// Attempts a graceful shutdown of the write side of a TLS connection.
773    ///
774    /// Unlike Self::poll_shutdown, no response from the peer is necessary.
775    /// If using TLS1.3, the connection can continue to be used for reading afterwards.
776    ///
777    /// Corresponds to [`s2n_shutdown_send`].
778    pub fn poll_shutdown_send(&mut self) -> Poll<Result<&mut Self, Error>> {
779        if !self.remaining_blinding_delay()?.is_zero() {
780            return Poll::Pending;
781        }
782        let mut blocked = s2n_blocked_status::NOT_BLOCKED;
783        unsafe {
784            s2n_shutdown_send(self.connection.as_ptr(), &mut blocked)
785                .into_poll()
786                .map_ok(|_| self)
787        }
788    }
789
790    /// Returns the TLS alert code, if any
791    ///
792    /// Corresponds to [`s2n_connection_get_alert`].
793    pub fn alert(&self) -> Option<u8> {
794        let alert =
795            unsafe { s2n_connection_get_alert(self.connection.as_ptr()).into_result() }.ok()?;
796        Some(alert as u8)
797    }
798
799    /// Sets the server name value for the connection
800    ///
801    /// Corresponds to [`s2n_set_server_name`].
802    pub fn set_server_name(&mut self, server_name: &str) -> Result<&mut Self, Error> {
803        let server_name = std::ffi::CString::new(server_name).map_err(|_| Error::INVALID_INPUT)?;
804        unsafe {
805            s2n_set_server_name(self.connection.as_ptr(), server_name.as_ptr()).into_result()
806        }?;
807        Ok(self)
808    }
809
810    /// Get the server name associated with the connection client hello.
811    ///
812    /// Corresponds to [`s2n_get_server_name`].
813    pub fn server_name(&self) -> Option<&str> {
814        unsafe {
815            let server_name = s2n_get_server_name(self.connection.as_ptr());
816            match server_name.into_result() {
817                Ok(server_name) => CStr::from_ptr(server_name).to_str().ok(),
818                Err(_) => None,
819            }
820        }
821    }
822
823    /// Adds a session ticket from a previous TLS connection to create a resumed session
824    ///
825    /// Corresponds to [`s2n_connection_set_session`].
826    pub fn set_session_ticket(&mut self, session: &[u8]) -> Result<&mut Self, Error> {
827        unsafe {
828            s2n_connection_set_session(self.connection.as_ptr(), session.as_ptr(), session.len())
829                .into_result()
830        }?;
831        Ok(self)
832    }
833
834    /// Retrieves the size of the session ticket.
835    ///
836    /// Corresponds to [`s2n_connection_get_session_length`].
837    pub fn session_ticket_length(&self) -> Result<usize, Error> {
838        let len =
839            unsafe { s2n_connection_get_session_length(self.connection.as_ptr()).into_result()? };
840        Ok(len.try_into().unwrap())
841    }
842
843    /// Serializes the session state from the connection into `output` and returns
844    /// the length of the session ticket.
845    ///
846    /// If the buffer does not have the size for the session_ticket,
847    /// `Error::INVALID_INPUT` is returned.
848    ///
849    /// Note: This function is not recommended for > TLS1.2 because in TLS1.3
850    /// servers can send multiple session tickets and this will return only
851    /// the most recently received ticket.
852    ///
853    /// Corresponds to [`s2n_connection_get_session`].
854    pub fn session_ticket(&self, output: &mut [u8]) -> Result<usize, Error> {
855        if output.len() < self.session_ticket_length()? {
856            return Err(Error::INVALID_INPUT);
857        }
858        let written = unsafe {
859            s2n_connection_get_session(self.connection.as_ptr(), output.as_mut_ptr(), output.len())
860                .into_result()?
861        };
862        Ok(written.try_into().unwrap())
863    }
864
865    /// Sets a Waker on the connection context or clears it if `None` is passed.
866    pub fn set_waker(&mut self, waker: Option<&Waker>) -> Result<&mut Self, Error> {
867        let ctx = self.context_mut();
868
869        if let Some(waker) = waker {
870            if let Some(prev_waker) = ctx.waker.as_mut() {
871                // only replace the Waker if they don't reference the same task
872                if !prev_waker.will_wake(waker) {
873                    prev_waker.clone_from(waker);
874                }
875            } else {
876                ctx.waker = Some(waker.clone());
877            }
878        } else {
879            ctx.waker = None;
880        }
881        Ok(self)
882    }
883
884    /// Returns the Waker set on the connection context.
885    pub fn waker(&self) -> Option<&Waker> {
886        let ctx = self.context();
887        ctx.waker.as_ref()
888    }
889
890    /// Takes the [`Option::take`] the connection_future stored on the
891    /// connection context.
892    ///
893    /// If the Future returns `Poll::Pending` and has not completed, then it
894    /// should be re-set using [`Self::set_connection_future()`]
895    fn take_async_callback(&mut self) -> Option<AsyncCallback> {
896        let ctx = self.context_mut();
897        ctx.async_callback.take()
898    }
899
900    /// Sets a `connection_future` on the connection context.
901    pub(crate) fn set_async_callback(&mut self, callback: AsyncCallback) {
902        let ctx = self.context_mut();
903        debug_assert!(ctx.async_callback.is_none());
904        ctx.async_callback = Some(callback);
905    }
906
907    /// Retrieve a mutable reference to the [`Context`] stored on the connection.
908    fn context_mut(&mut self) -> &mut Context {
909        unsafe {
910            let ctx = s2n_connection_get_ctx(self.connection.as_ptr())
911                .into_result()
912                .unwrap();
913            &mut *(ctx.as_ptr() as *mut Context)
914        }
915    }
916
917    /// Retrieve a reference to the [`Context`] stored on the connection.
918    fn context(&self) -> &Context {
919        unsafe {
920            let ctx = s2n_connection_get_ctx(self.connection.as_ptr())
921                .into_result()
922                .unwrap();
923            &*(ctx.as_ptr() as *mut Context)
924        }
925    }
926
927    /// Drop the context
928    ///
929    /// SAFETY:
930    /// A connection without a context is invalid. After calling this method
931    /// from anywhere other than Drop, you must reinitialize the context.
932    unsafe fn drop_context(&mut self) -> Result<(), Error> {
933        let ctx = s2n_connection_get_ctx(self.connection.as_ptr()).into_result();
934        if let Ok(ctx) = ctx {
935            drop(Box::from_raw(ctx.as_ptr() as *mut Context));
936        }
937        // Setting a NULL context is important: if we don't also remove the context
938        // from the connection, then the invalid memory is still accessible and
939        // may even be double-freed.
940        s2n_connection_set_ctx(self.connection.as_ptr(), core::ptr::null_mut()).into_result()?;
941        Ok(())
942    }
943
944    /// Mark that the server_name extension was used to configure the connection.
945    ///
946    /// Corresponds to [`s2n_connection_server_name_extension_used`].
947    pub fn server_name_extension_used(&mut self) {
948        // TODO: requiring the application to call this method is a pretty sharp edge.
949        // Figure out if its possible to automatically call this from the Rust bindings.
950        unsafe {
951            s2n_connection_server_name_extension_used(self.connection.as_ptr())
952                .into_result()
953                .unwrap();
954        }
955    }
956
957    /// Check if client auth was used for a connection.
958    ///
959    /// This is especially useful when the server has [`ClientAuthType::Optional`] configured.
960    ///
961    /// Corresponds to [`s2n_connection_client_cert_used`].
962    pub fn client_cert_used(&self) -> bool {
963        unsafe { s2n_connection_client_cert_used(self.connection.as_ptr()) == 1 }
964    }
965
966    /// Retrieves the raw bytes of the client cert chain received from the peer, if present.
967    ///
968    /// Corresponds to [`s2n_connection_get_client_cert_chain`].
969    pub fn client_cert_chain_bytes(&self) -> Result<Option<&[u8]>, Error> {
970        if !self.client_cert_used() {
971            return Ok(None);
972        }
973
974        let mut chain = std::ptr::null_mut();
975        let mut len = 0;
976        unsafe {
977            s2n_connection_get_client_cert_chain(self.connection.as_ptr(), &mut chain, &mut len)
978                .into_result()?;
979        }
980
981        if chain.is_null() || len == 0 {
982            return Ok(None);
983        }
984
985        unsafe { Ok(Some(std::slice::from_raw_parts(chain, len as usize))) }
986    }
987
988    // The memory backing the ClientHello is owned by the Connection, so we
989    // tie the ClientHello to the lifetime of the Connection. This is validated
990    // with a doc test that ensures the ClientHello is invalid once the
991    // connection has gone out of scope.
992    //
993    /// Returns a reference to the ClientHello associated with the connection.
994    /// ```compile_fail
995    /// use s2n_tls::client_hello::ClientHello;
996    /// use s2n_tls::connection::Connection;
997    /// use s2n_tls::enums::Mode;
998    ///
999    /// let mut conn = Connection::new(Mode::Server);
1000    /// let mut client_hello: &ClientHello = conn.client_hello().unwrap();
1001    /// drop(conn);
1002    /// client_hello.raw_message();
1003    /// ```
1004    ///
1005    /// The compilation could be failing for a variety of reasons, so make sure
1006    /// that the test case is actually good.
1007    /// ```no_run
1008    /// use s2n_tls::client_hello::ClientHello;
1009    /// use s2n_tls::connection::Connection;
1010    /// use s2n_tls::enums::Mode;
1011    ///
1012    /// let mut conn = Connection::new(Mode::Server);
1013    /// let mut client_hello: &ClientHello = conn.client_hello().unwrap();
1014    /// client_hello.raw_message();
1015    /// drop(conn);
1016    /// ```
1017    ///
1018    /// Corresponds to [`s2n_connection_get_client_hello`].
1019    pub fn client_hello(&self) -> Result<&crate::client_hello::ClientHello, Error> {
1020        let mut handle =
1021            unsafe { s2n_connection_get_client_hello(self.connection.as_ptr()).into_result()? };
1022        Ok(crate::client_hello::ClientHello::from_ptr(unsafe {
1023            handle.as_mut()
1024        }))
1025    }
1026
1027    /// Corresponds to [`s2n_client_hello_cb_done`].
1028    pub(crate) fn mark_client_hello_cb_done(&mut self) -> Result<(), Error> {
1029        unsafe {
1030            s2n_client_hello_cb_done(self.connection.as_ptr()).into_result()?;
1031        }
1032        Ok(())
1033    }
1034
1035    /// Access the protocol version selected for the connection.
1036    ///
1037    /// Corresponds to [`s2n_connection_get_actual_protocol_version`].
1038    pub fn actual_protocol_version(&self) -> Result<Version, Error> {
1039        let version = unsafe {
1040            s2n_connection_get_actual_protocol_version(self.connection.as_ptr()).into_result()?
1041        };
1042        version.try_into()
1043    }
1044
1045    /// Detects if the client hello is using the SSLv2 format.
1046    ///
1047    /// s2n-tls will not negotiate SSLv2, but will accept SSLv2 ClientHellos
1048    /// advertising a higher protocol version like SSLv3 or TLS1.0.
1049    /// [Connection::actual_protocol_version()] can be used to retrieve the
1050    /// protocol version that is actually used on the connection.
1051    ///
1052    /// Corresponds to [`s2n_connection_get_client_hello_version`], but only checks
1053    /// for SSLv2.
1054    pub fn client_hello_is_sslv2(&self) -> Result<bool, Error> {
1055        let version = unsafe {
1056            s2n_connection_get_client_hello_version(self.connection.as_ptr()).into_result()?
1057        };
1058        let version: Version = version.try_into()?;
1059        Ok(version == Version::SSLV2)
1060    }
1061
1062    /// Corresponds to [`s2n_connection_get_handshake_type_name`].
1063    pub fn handshake_type(&self) -> Result<&str, Error> {
1064        let handshake = unsafe {
1065            s2n_connection_get_handshake_type_name(self.connection.as_ptr()).into_result()?
1066        };
1067        unsafe {
1068            // SAFETY: Constructed strings have a null byte appended to them.
1069            // SAFETY: The data has a 'static lifetime, because it resides in a
1070            //         static char array, and is never modified after its initial
1071            //         creation.
1072            const_str!(handshake)
1073        }
1074    }
1075
1076    /// Corresponds to [`s2n_connection_get_cipher`].
1077    pub fn cipher_suite(&self) -> Result<&str, Error> {
1078        let cipher = unsafe { s2n_connection_get_cipher(self.connection.as_ptr()).into_result()? };
1079        unsafe {
1080            // SAFETY: The data is null terminated because it is declared as a C
1081            //         string literal.
1082            // SAFETY: cipher has a static lifetime because it lives on s2n_cipher_suite,
1083            //         a static struct.
1084            const_str!(cipher)
1085        }
1086    }
1087
1088    /// Corresponds to [`s2n_connection_get_kem_name`].
1089    #[deprecated = "PQ TLS 1.2 KEM Names are no longer supported. Use kem_group_name() to retrieve PQ TLS 1.3 Group name."]
1090    pub fn kem_name(&self) -> Option<&str> {
1091        let name_bytes = {
1092            let name = unsafe { s2n_connection_get_kem_name(self.connection.as_ptr()) };
1093            if name.is_null() {
1094                return None;
1095            }
1096            name
1097        };
1098
1099        let name_str = unsafe {
1100            // SAFETY: The data is null terminated because it is declared as a C
1101            //         string literal.
1102            // SAFETY: kem_name has a static lifetime because it lives on a const
1103            //         struct s2n_kem with file scope.
1104            const_str!(name_bytes)
1105        };
1106
1107        match name_str {
1108            Ok("NONE") => None,
1109            Ok(name) => Some(name),
1110            Err(_) => {
1111                // Unreachable: This would indicate a non-utf-8 string literal in
1112                // the s2n-tls C codebase.
1113                None
1114            }
1115        }
1116    }
1117
1118    /// Corresponds to [`s2n_connection_get_kem_group_name`].
1119    pub fn kem_group_name(&self) -> Option<&str> {
1120        let name_bytes = {
1121            let name = unsafe { s2n_connection_get_kem_group_name(self.connection.as_ptr()) };
1122            if name.is_null() {
1123                return None;
1124            }
1125            name
1126        };
1127
1128        let name_str = unsafe {
1129            // SAFETY: The data is null terminated because it is declared as a C
1130            //         string literal.
1131            // SAFETY: kem_name has a static lifetime because it lives on a const
1132            //         struct s2n_kem with file scope.
1133            const_str!(name_bytes)
1134        };
1135
1136        match name_str {
1137            Ok("NONE") => None,
1138            Ok(name) => Some(name),
1139            Err(_) => {
1140                // Unreachable: This would indicate a non-utf-8 string literal in
1141                // the s2n-tls C codebase.
1142                None
1143            }
1144        }
1145    }
1146
1147    /// Corresponds to [`s2n_connection_get_curve`].
1148    #[deprecated = "Use selected_key_exchange_group instead"]
1149    pub fn selected_curve(&self) -> Result<&str, Error> {
1150        let curve = unsafe { s2n_connection_get_curve(self.connection.as_ptr()).into_result()? };
1151        unsafe {
1152            // SAFETY: The data is null terminated because it is declared as a C
1153            //         string literal.
1154            // SAFETY: curve has a static lifetime because it lives on s2n_ecc_named_curve,
1155            //         which is a static const struct.
1156            const_str!(curve)
1157        }
1158    }
1159
1160    /// Corresponds to [`s2n_connection_get_key_exchange_group`].
1161    pub fn selected_key_exchange_group(&self) -> Option<&str> {
1162        let mut group_name = core::ptr::null();
1163        unsafe {
1164            s2n_connection_get_key_exchange_group(self.connection.as_ptr(), &mut group_name)
1165                .into_result()
1166                .ok()
1167        }?;
1168
1169        unsafe {
1170            // SAFETY: The data is null terminated because it is declared as a C
1171            //         string literal.
1172            // SAFETY: group_name has a static lifetime because it lives on either
1173            //         s2n_ecc_named_curve or s2n_kem, both of which are static
1174            //         const structs.
1175            const_str!(group_name).ok()
1176        }
1177    }
1178
1179    /// Corresponds to [`s2n_connection_get_selected_signature_algorithm`].
1180    pub fn selected_signature_algorithm(&self) -> Result<SignatureAlgorithm, Error> {
1181        let mut sig_alg = s2n_tls_signature_algorithm::ANONYMOUS;
1182        unsafe {
1183            s2n_connection_get_selected_signature_algorithm(self.connection.as_ptr(), &mut sig_alg)
1184                .into_result()?;
1185        }
1186        sig_alg.try_into()
1187    }
1188
1189    /// Return the negotiated signature scheme, e.g. "rsa_pss_rsae_sha256".
1190    ///
1191    /// Note that this does not strictly follow IANA naming conventions for ECDSA
1192    /// signatures and legacy SHA224/SHA1 signatures.
1193    ///
1194    /// This will be `None` in the case of session resumption or RSA key exchange.
1195    ///
1196    /// Corresponds to [`s2n_connection_get_signature_scheme`].
1197    pub fn signature_scheme(&self) -> Option<&'static str> {
1198        let mut sig_alg: *const std::ffi::c_char = std::ptr::null();
1199        unsafe {
1200            s2n_connection_get_signature_scheme(self.connection.as_ptr(), &mut sig_alg)
1201                .into_result()
1202                .ok()?;
1203        }
1204        let result = unsafe {
1205            // Safety: signature schemes are C string literals in the s2n-tls codebase,
1206            // so they are null-terminated and static.
1207            cstr_to_str(sig_alg)
1208        };
1209        if result == "none" {
1210            None
1211        } else {
1212            Some(result)
1213        }
1214    }
1215
1216    /// Corresponds to [`s2n_connection_get_selected_digest_algorithm`].
1217    pub fn selected_hash_algorithm(&self) -> Result<HashAlgorithm, Error> {
1218        let mut hash_alg = s2n_tls_hash_algorithm::NONE;
1219        unsafe {
1220            s2n_connection_get_selected_digest_algorithm(self.connection.as_ptr(), &mut hash_alg)
1221                .into_result()?;
1222        }
1223        hash_alg.try_into()
1224    }
1225
1226    /// Corresponds to [`s2n_connection_get_certificate_match`].
1227    pub fn certificate_match(&self) -> Result<CertSNIMatch, Error> {
1228        let mut cert_match = s2n_cert_sni_match::SNI_NO_MATCH;
1229        unsafe {
1230            s2n_connection_get_certificate_match(self.connection.as_ptr(), &mut cert_match)
1231                .into_result()?;
1232        }
1233        cert_match.try_into()
1234    }
1235
1236    /// Corresponds to [`s2n_connection_get_selected_client_cert_signature_algorithm`].
1237    pub fn selected_client_signature_algorithm(&self) -> Result<Option<SignatureAlgorithm>, Error> {
1238        let mut sig_alg = s2n_tls_signature_algorithm::ANONYMOUS;
1239        unsafe {
1240            s2n_connection_get_selected_client_cert_signature_algorithm(
1241                self.connection.as_ptr(),
1242                &mut sig_alg,
1243            )
1244            .into_result()?;
1245        }
1246        Ok(match sig_alg {
1247            s2n_tls_signature_algorithm::ANONYMOUS => None,
1248            sig_alg => Some(sig_alg.try_into()?),
1249        })
1250    }
1251
1252    /// Corresponds to [`s2n_connection_get_selected_client_cert_digest_algorithm`].
1253    pub fn selected_client_hash_algorithm(&self) -> Result<Option<HashAlgorithm>, Error> {
1254        let mut hash_alg = s2n_tls_hash_algorithm::NONE;
1255        unsafe {
1256            s2n_connection_get_selected_client_cert_digest_algorithm(
1257                self.connection.as_ptr(),
1258                &mut hash_alg,
1259            )
1260            .into_result()?;
1261        }
1262        Ok(match hash_alg {
1263            s2n_tls_hash_algorithm::NONE => None,
1264            hash_alg => Some(hash_alg.try_into()?),
1265        })
1266    }
1267
1268    /// Corresponds to [`s2n_get_application_protocol`].
1269    pub fn application_protocol(&self) -> Option<&[u8]> {
1270        let protocol = unsafe { s2n_get_application_protocol(self.connection.as_ptr()) };
1271        if protocol.is_null() {
1272            return None;
1273        }
1274        Some(unsafe { CStr::from_ptr(protocol).to_bytes() })
1275    }
1276
1277    /// Provides access to the TLS-Exporter functionality.
1278    ///
1279    /// See https://datatracker.ietf.org/doc/html/rfc5705 and https://www.rfc-editor.org/rfc/rfc8446.
1280    ///
1281    /// This is currently only available with TLS 1.3 connections which have finished a handshake.
1282    ///
1283    /// Corresponds to [`s2n_connection_tls_exporter`].
1284    pub fn tls_exporter(
1285        &self,
1286        label: &[u8],
1287        context: &[u8],
1288        output: &mut [u8],
1289    ) -> Result<(), Error> {
1290        unsafe {
1291            s2n_connection_tls_exporter(
1292                self.connection.as_ptr(),
1293                label.as_ptr(),
1294                label.len().try_into().map_err(|_| Error::INVALID_INPUT)?,
1295                context.as_ptr(),
1296                context.len().try_into().map_err(|_| Error::INVALID_INPUT)?,
1297                output.as_mut_ptr(),
1298                output.len().try_into().map_err(|_| Error::INVALID_INPUT)?,
1299            )
1300            .into_result()
1301            .map(|_| ())
1302        }
1303    }
1304
1305    /// Returns the validated peer certificate chain.
1306    // 'static lifetime is because this copies the certificate chain from the connection into a new
1307    // chain, so the lifetime is independent of the connection.
1308    ///
1309    /// Corresponds to [`s2n_connection_get_peer_cert_chain`].
1310    pub fn peer_cert_chain(&self) -> Result<CertificateChain<'static>, Error> {
1311        unsafe {
1312            let chain_handle = CertificateChainHandle::allocate()?;
1313            s2n_connection_get_peer_cert_chain(
1314                self.connection.as_ptr(),
1315                chain_handle.cert.as_ptr(),
1316            )
1317            .into_result()
1318            .map(|_| ())?;
1319            Ok(CertificateChain::from_allocated(chain_handle))
1320        }
1321    }
1322
1323    /// Get the certificate used during the TLS handshake
1324    ///
1325    /// - If `self` is a server connection, the certificate selected will depend on the
1326    ///   ServerName sent by the client and supported ciphers.
1327    /// - If `self` is a client connection, the certificate sent in response to a CertificateRequest
1328    ///   message is returned. Currently s2n-tls supports loading only one certificate in client mode. Note that
1329    ///   not all TLS endpoints will request a certificate.
1330    ///
1331    /// Corresponds to [`s2n_connection_get_selected_cert`].
1332    pub fn selected_cert(&self) -> Option<CertificateChain<'_>> {
1333        unsafe {
1334            // The API only returns null, no error is actually set.
1335            // Clippy doesn't realize from_ptr_reference is unsafe.
1336            #[allow(clippy::manual_map)]
1337            if let Some(ptr) =
1338                NonNull::new(s2n_connection_get_selected_cert(self.connection.as_ptr()))
1339            {
1340                Some(CertificateChain::from_ptr_reference(ptr))
1341            } else {
1342                None
1343            }
1344        }
1345    }
1346
1347    /// Corresponds to [`s2n_connection_get_master_secret`].
1348    pub fn master_secret(&self) -> Result<Vec<u8>, Error> {
1349        // TLS1.2 master secrets are always 48 bytes
1350        let mut secret = vec![0; 48];
1351        unsafe {
1352            s2n_connection_get_master_secret(
1353                self.connection.as_ptr(),
1354                secret.as_mut_ptr(),
1355                secret.len(),
1356            )
1357            .into_result()?;
1358        }
1359        Ok(secret)
1360    }
1361
1362    /// Retrieves the size of the serialized connection
1363    ///
1364    /// Corresponds to [`s2n_connection_serialization_length`].
1365    pub fn serialization_length(&self) -> Result<usize, Error> {
1366        unsafe {
1367            let mut length = 0;
1368            s2n_connection_serialization_length(self.connection.as_ptr(), &mut length)
1369                .into_result()?;
1370            Ok(length.try_into().unwrap())
1371        }
1372    }
1373
1374    /// Serializes the TLS connection into the provided buffer
1375    ///
1376    /// Corresponds to [`s2n_connection_serialize`].
1377    pub fn serialize(&self, output: &mut [u8]) -> Result<(), Error> {
1378        unsafe {
1379            s2n_connection_serialize(
1380                self.connection.as_ptr(),
1381                output.as_mut_ptr(),
1382                output.len().try_into().map_err(|_| Error::INVALID_INPUT)?,
1383            )
1384            .into_result()?;
1385            Ok(())
1386        }
1387    }
1388
1389    /// Deserializes the input buffer into a new TLS connection that can send/recv
1390    /// data from the original peer.
1391    ///
1392    /// Corresponds to [`s2n_connection_deserialize`].
1393    pub fn deserialize(&mut self, input: &[u8]) -> Result<(), Error> {
1394        let size = input.len();
1395        /* This is not ideal, we know that s2n_connection_deserialize will not mutate the
1396         * input value, however, the mut is needed to use the stuffer functions. */
1397        let input = input.as_ptr() as *mut u8;
1398        unsafe {
1399            s2n_connection_deserialize(
1400                self.as_ptr(),
1401                input,
1402                size.try_into().map_err(|_| Error::INVALID_INPUT)?,
1403            )
1404            .into_result()?;
1405            Ok(())
1406        }
1407    }
1408
1409    /// Determines whether the connection was resumed from an earlier handshake.
1410    ///
1411    /// Corresponds to [`s2n_connection_is_session_resumed`].
1412    pub fn resumed(&self) -> bool {
1413        unsafe { s2n_connection_is_session_resumed(self.connection.as_ptr()) == 1 }
1414    }
1415
1416    /// Append an external psk to a connection.
1417    ///
1418    /// This may be called repeatedly to support multiple PSKs.
1419    ///
1420    /// Corresponds to [`s2n_connection_append_psk`].
1421    pub fn append_psk(&mut self, psk: &Psk) -> Result<(), Error> {
1422        unsafe {
1423            // SAFETY: retrieving a *mut s2n_psk from &Psk: s2n-tls does not treat
1424            // the pointer as mutable, and only holds the reference to copy the
1425            // PSK onto the connection.
1426            s2n_connection_append_psk(self.as_ptr(), psk.ptr.as_ptr()).into_result()?
1427        };
1428        Ok(())
1429    }
1430
1431    /// Corresponds to [`s2n_connection_get_negotiated_psk_identity_length`].
1432    pub fn negotiated_psk_identity_length(&self) -> Result<usize, Error> {
1433        let mut length = 0;
1434        unsafe {
1435            s2n_connection_get_negotiated_psk_identity_length(self.connection.as_ptr(), &mut length)
1436                .into_result()?
1437        };
1438        Ok(length as usize)
1439    }
1440
1441    /// Retrieve the negotiated psk identity. Use [Connection::negotiated_psk_identity_length]
1442    /// to retrieve the length of the psk identity.
1443    ///
1444    /// Corresponds to [`s2n_connection_get_negotiated_psk_identity`].
1445    pub fn negotiated_psk_identity(&self, destination: &mut [u8]) -> Result<(), Error> {
1446        unsafe {
1447            s2n_connection_get_negotiated_psk_identity(
1448                self.connection.as_ptr(),
1449                destination.as_mut_ptr(),
1450                destination.len().min(u16::MAX as usize) as u16,
1451            )
1452            .into_result()?;
1453        }
1454        Ok(())
1455    }
1456
1457    /// Associates arbitrary application contexts with the Connection to be later retrieved via
1458    /// the [`Self::application_context()`] and [`Self::application_context_mut()`] APIs.
1459    ///
1460    /// While multiple application contexts of different types may be set, previous values of the same type will be overridden.
1461    ///
1462    /// Corresponds to [`s2n_connection_set_ctx`].
1463    pub fn set_application_context<T: Send + Sync + 'static>(&mut self, app_context: T) {
1464        let context_type_id = TypeId::of::<T>();
1465        self.context_mut()
1466            .app_context
1467            .insert(context_type_id, Box::new(app_context));
1468    }
1469
1470    /// Removes an application context set on the Connection.
1471    ///
1472    /// Returns Some containing the removed context if it exists, or None if no context
1473    /// of the specified type was previously set.
1474    pub fn remove_application_context<T: Send + Sync + 'static>(
1475        &mut self,
1476    ) -> Option<Box<dyn Any + Send + Sync>> {
1477        let context_type_id = TypeId::of::<T>();
1478        self.context_mut().app_context.remove(&context_type_id)
1479    }
1480
1481    /// Retrieves a reference to the application context associated with the Connection.
1482    ///
1483    /// Returns None if the provided type T does not match the type of any application context set on the Connection.
1484    ///
1485    /// To set a context on the connection, use [`Self::set_application_context()`]. To retrieve a
1486    /// mutable reference to the context, use [`Self::application_context_mut()`].
1487    ///
1488    /// Corresponds to [`s2n_connection_get_ctx`].
1489    pub fn application_context<T: Send + Sync + 'static>(&self) -> Option<&T> {
1490        let context_type_id = TypeId::of::<T>();
1491        // The Any trait keeps track of the application context's type. downcast_ref() returns
1492        // Some only if the correct type is provided:
1493        // https://doc.rust-lang.org/std/any/trait.Any.html#method.downcast_ref
1494        self.context()
1495            .app_context
1496            .get(&context_type_id)
1497            .and_then(|app_context| app_context.downcast_ref::<T>())
1498    }
1499
1500    /// Retrieves a mutable reference to the application context associated with the Connection.
1501    ///
1502    /// Returns None if the provided type T does not match the type of any application context set on the Connection.
1503    ///
1504    /// To set a context on the connection, use [`Self::set_application_context()`]. To retrieve an
1505    /// immutable reference to the context, use [`Self::application_context()`].
1506    ///
1507    /// Corresponds to [`s2n_connection_get_ctx`].
1508    pub fn application_context_mut<T: Send + Sync + 'static>(&mut self) -> Option<&mut T> {
1509        let context_type_id = TypeId::of::<T>();
1510        self.context_mut()
1511            .app_context
1512            .get_mut(&context_type_id)
1513            .and_then(|app_context| app_context.downcast_mut::<T>())
1514    }
1515
1516    #[cfg(feature = "unstable-cert_authorities")]
1517    pub(crate) fn cert_request_state(&mut self) -> &mut CertRequestState {
1518        &mut self.context_mut().cert_request_state
1519    }
1520
1521    #[cfg(feature = "unstable-renegotiate")]
1522    pub(crate) fn renegotiate_state_mut(&mut self) -> &mut RenegotiateState {
1523        &mut self.context_mut().renegotiate_state
1524    }
1525
1526    #[cfg(feature = "unstable-renegotiate")]
1527    pub(crate) fn renegotiate_state(&self) -> &RenegotiateState {
1528        &self.context().renegotiate_state
1529    }
1530}
1531
1532struct Context {
1533    mode: Mode,
1534    waker: Option<Waker>,
1535    async_callback: Option<AsyncCallback>,
1536    verify_host_callback: Option<Box<dyn VerifyHostNameCallback>>,
1537    connection_initialized: bool,
1538    app_context: HashMap<TypeId, Box<dyn Any + Send + Sync>>,
1539    #[cfg(feature = "unstable-renegotiate")]
1540    pub(crate) renegotiate_state: RenegotiateState,
1541    #[cfg(feature = "unstable-cert_authorities")]
1542    pub(crate) cert_request_state: CertRequestState,
1543}
1544
1545impl Context {
1546    fn new(mode: Mode) -> Self {
1547        Context {
1548            mode,
1549            waker: None,
1550            async_callback: None,
1551            verify_host_callback: None,
1552            connection_initialized: false,
1553            app_context: HashMap::new(),
1554            #[cfg(feature = "unstable-renegotiate")]
1555            renegotiate_state: RenegotiateState::default(),
1556            #[cfg(feature = "unstable-cert_authorities")]
1557            cert_request_state: CertRequestState::default(),
1558        }
1559    }
1560}
1561
1562#[cfg(feature = "quic")]
1563impl Connection {
1564    /// Corresponds to [`s2n_connection_enable_quic`].
1565    pub fn enable_quic(&mut self) -> Result<&mut Self, Error> {
1566        unsafe { s2n_connection_enable_quic(self.connection.as_ptr()).into_result() }?;
1567        Ok(self)
1568    }
1569
1570    /// Corresponds to [`s2n_connection_set_quic_transport_parameters`].
1571    pub fn set_quic_transport_parameters(&mut self, buffer: &[u8]) -> Result<&mut Self, Error> {
1572        unsafe {
1573            s2n_connection_set_quic_transport_parameters(
1574                self.connection.as_ptr(),
1575                buffer.as_ptr(),
1576                buffer.len().try_into().map_err(|_| Error::INVALID_INPUT)?,
1577            )
1578            .into_result()
1579        }?;
1580        Ok(self)
1581    }
1582
1583    /// Corresponds to [`s2n_connection_get_quic_transport_parameters`].
1584    pub fn quic_transport_parameters(&mut self) -> Result<&[u8], Error> {
1585        let mut ptr = core::ptr::null();
1586        let mut len = 0;
1587        unsafe {
1588            s2n_connection_get_quic_transport_parameters(
1589                self.connection.as_ptr(),
1590                &mut ptr,
1591                &mut len,
1592            )
1593            .into_result()
1594        }?;
1595        let buffer = unsafe { core::slice::from_raw_parts(ptr, len as _) };
1596        Ok(buffer)
1597    }
1598
1599    /// # Safety
1600    ///
1601    /// The `context` pointer must live at least as long as the connection
1602    ///
1603    /// Corresponds to [`s2n_connection_set_secret_callback`].
1604    pub unsafe fn set_secret_callback(
1605        &mut self,
1606        callback: s2n_secret_cb,
1607        context: *mut c_void,
1608    ) -> Result<&mut Self, Error> {
1609        s2n_connection_set_secret_callback(self.connection.as_ptr(), callback, context)
1610            .into_result()?;
1611        Ok(self)
1612    }
1613
1614    /// Corresponds to [`s2n_recv_quic_post_handshake_message`].
1615    pub fn quic_process_post_handshake_message(&mut self) -> Result<&mut Self, Error> {
1616        let mut blocked = s2n_blocked_status::NOT_BLOCKED;
1617        unsafe {
1618            s2n_recv_quic_post_handshake_message(self.connection.as_ptr(), &mut blocked)
1619                .into_result()
1620        }?;
1621        Ok(self)
1622    }
1623
1624    /// Allows the quic library to check if session tickets are expected
1625    ///
1626    /// Corresponds to [`s2n_connection_are_session_tickets_enabled`].
1627    pub fn are_session_tickets_enabled(&self) -> bool {
1628        unsafe { s2n_connection_are_session_tickets_enabled(self.connection.as_ptr()) }
1629    }
1630}
1631
1632impl AsRef<Connection> for Connection {
1633    fn as_ref(&self) -> &Connection {
1634        self
1635    }
1636}
1637
1638impl AsMut<Connection> for Connection {
1639    fn as_mut(&mut self) -> &mut Connection {
1640        self
1641    }
1642}
1643
1644impl Drop for Connection {
1645    /// Corresponds to [`s2n_connection_free`].
1646    fn drop(&mut self) {
1647        // ignore failures since there's not much we can do about it
1648        unsafe {
1649            // clean up context
1650            let _ = self.drop_context();
1651
1652            // cleanup config
1653            let _ = self.drop_config();
1654
1655            // cleanup connection
1656            let _ = s2n_connection_free(self.connection.as_ptr()).into_result();
1657        }
1658    }
1659}
1660
1661#[cfg(test)]
1662mod tests {
1663    use futures_test::task::noop_waker;
1664
1665    use super::*;
1666    use crate::{
1667        security::Policy,
1668        testing::{build_config, config_builder, LIFOSessionResumption, SniTestCerts, TestPair},
1669    };
1670    use std::{
1671        net::{IpAddr, Ipv4Addr, SocketAddr},
1672        time::SystemTime,
1673    };
1674
1675    // ensure the connection context is send
1676    #[test]
1677    fn context_send_test() {
1678        fn assert_send<T: 'static + Send>() {}
1679        assert_send::<Context>();
1680    }
1681
1682    // ensure the connection context is sync
1683    #[test]
1684    fn context_sync_test() {
1685        fn assert_sync<T: 'static + Sync>() {}
1686        assert_sync::<Context>();
1687    }
1688
1689    /// Test that an application context can be set and retrieved.
1690    #[test]
1691    fn test_app_context_set_and_retrieve() {
1692        let mut connection = Connection::new_server();
1693
1694        let test_value: u32 = 1142;
1695
1696        // Before a context is set, None is returned.
1697        assert!(connection.application_context::<u32>().is_none());
1698
1699        connection.set_application_context(test_value);
1700
1701        // After a context is set, the application data is returned.
1702        assert_eq!(*connection.application_context::<u32>().unwrap(), 1142);
1703    }
1704
1705    /// Test that an application context can be modified.
1706    #[test]
1707    fn test_app_context_modify() {
1708        let test_value: u64 = 0;
1709
1710        let mut connection = Connection::new_server();
1711        connection.set_application_context(test_value);
1712
1713        let context_value = connection.application_context_mut::<u64>().unwrap();
1714        *context_value += 1;
1715
1716        assert_eq!(*connection.application_context::<u64>().unwrap(), 1);
1717    }
1718
1719    /// Test that an application context can be overridden.
1720    #[test]
1721    fn test_app_context_override() {
1722        let mut connection = Connection::new_server();
1723
1724        let test_value: u16 = 1142;
1725        connection.set_application_context(test_value);
1726
1727        assert_eq!(*connection.application_context::<u16>().unwrap(), 1142);
1728
1729        // Override the context with a new value.
1730        let test_value: u16 = 10;
1731        connection.set_application_context(test_value);
1732
1733        assert_eq!(*connection.application_context::<u16>().unwrap(), 10);
1734
1735        // Override the context with a new type.
1736        let test_value: i16 = -20;
1737        connection.set_application_context(test_value);
1738
1739        assert_eq!(*connection.application_context::<i16>().unwrap(), -20);
1740    }
1741
1742    /// Test that multiple application contexts can be set in a connection
1743    #[test]
1744    fn test_multiple_app_contexts() {
1745        let mut connection = Connection::new_server();
1746
1747        let first_test_value: u16 = 1142;
1748        connection.set_application_context(first_test_value);
1749
1750        assert_eq!(*connection.application_context::<u16>().unwrap(), 1142);
1751
1752        // Insert the second application context to the connection
1753        let second_test_value: SocketAddr =
1754            SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080);
1755        connection.set_application_context(second_test_value);
1756
1757        assert_eq!(
1758            *connection.application_context::<SocketAddr>().unwrap(),
1759            second_test_value
1760        );
1761
1762        // Remove the second application context
1763        assert_eq!(
1764            second_test_value,
1765            *connection
1766                .remove_application_context::<SocketAddr>()
1767                .unwrap()
1768                .downcast::<SocketAddr>()
1769                .unwrap()
1770        );
1771
1772        assert!(connection.application_context::<SocketAddr>().is_none());
1773    }
1774
1775    /// Test that a context of another type can't be retrieved.
1776    #[test]
1777    fn test_app_context_invalid_type() {
1778        let mut connection = Connection::new_server();
1779
1780        let test_value: u32 = 0;
1781        connection.set_application_context(test_value);
1782
1783        // A context type that wasn't set shouldn't be returned.
1784        assert!(connection.application_context::<i16>().is_none());
1785
1786        // Retrieving the correct type succeeds.
1787        assert!(connection.application_context::<u32>().is_some());
1788    }
1789
1790    /// Test that the `certificate_match` Rust wrapper returns expected enum variant
1791    /// for different SNI scenarios (None, NoMatch, ExactMatch)
1792    #[test]
1793    fn test_certificate_match_variants() -> Result<(), Box<dyn std::error::Error>> {
1794        let scenarios = vec![
1795            (None, CertSNIMatch::NoSNI),
1796            (Some("nonmatching_sni"), CertSNIMatch::NoMatch),
1797            (Some("127.0.0.1"), CertSNIMatch::ExactMatch),
1798        ];
1799
1800        for (sni_opt, expected) in scenarios {
1801            let config = build_config(&security::DEFAULT_TLS13)?;
1802            let mut pair = TestPair::from_config(&config);
1803
1804            if let Some(sni) = sni_opt {
1805                pair.client.set_server_name(sni)?;
1806            }
1807
1808            pair.handshake()?;
1809            let cert_match = pair.server.certificate_match()?;
1810
1811            assert_eq!(cert_match, expected,);
1812        }
1813
1814        Ok(())
1815    }
1816
1817    /// Test that the `certificate_match` Rust wrapper returns WildcardMatch enum
1818    #[test]
1819    fn test_certificate_match_returns_wildcard_match() -> Result<(), Box<dyn std::error::Error>> {
1820        let wildcard_cert = SniTestCerts::WildcardInsectRsa.get();
1821
1822        let mut builder = crate::config::Builder::new();
1823        builder.load_pem(wildcard_cert.cert(), wildcard_cert.key())?;
1824        let server_config = builder.build()?;
1825
1826        let mut client_builder = crate::config::Builder::new();
1827        client_builder.trust_pem(wildcard_cert.cert())?;
1828        let client_config = client_builder.build()?;
1829
1830        let mut pair = TestPair::from_configs(&client_config, &server_config);
1831
1832        pair.client.set_server_name("anything.insect.hexapod")?;
1833        pair.handshake()?;
1834
1835        let cert_match = pair.server.certificate_match()?;
1836        assert_eq!(cert_match, CertSNIMatch::WildcardMatch);
1837
1838        Ok(())
1839    }
1840
1841    /// Test that `unstable_as_ptr()` can be used to call an s2n_tls_sys API.
1842    #[cfg(s2n_tls_external_build)]
1843    #[test]
1844    fn test_unstable_as_ptr() -> Result<(), Error> {
1845        let mut connection = Connection::new_client();
1846
1847        let test_server_name = "test-server-name";
1848        connection.set_server_name(test_server_name)?;
1849
1850        let server_name = unsafe {
1851            let server_name = s2n_get_server_name(connection.unstable_as_ptr());
1852            CStr::from_ptr(server_name).to_str().unwrap()
1853        };
1854
1855        assert_eq!(server_name, test_server_name);
1856        Ok(())
1857    }
1858
1859    #[test]
1860    fn signature_scheme_before_handshake() {
1861        let connection = Connection::new_server();
1862        assert_eq!(connection.signature_scheme(), None);
1863    }
1864
1865    #[test]
1866    fn signature_scheme_after_handshake() -> Result<(), Box<dyn std::error::Error>> {
1867        let server_config = {
1868            // arbitrary policy that negotiates a cipher suite with a signature scheme
1869            let policy = Policy::from_version("20240503")?;
1870            let mut builder = config_builder(&policy).unwrap();
1871            builder.add_session_ticket_key(
1872                b"a key name",
1873                b"good enough bytes for test",
1874                SystemTime::UNIX_EPOCH,
1875            )?;
1876            builder.build()?
1877        };
1878
1879        let client_config = {
1880            let session_tickets = LIFOSessionResumption::default();
1881            let mut builder = config_builder(&security::DEFAULT).unwrap();
1882            builder.enable_session_tickets(true)?;
1883            builder.set_session_ticket_callback(session_tickets.clone())?;
1884            builder.set_connection_initializer(session_tickets.clone())?;
1885            builder.build()?
1886        };
1887
1888        // full handshake: signature is reported
1889        {
1890            let mut test_pair = TestPair::from_configs(&client_config, &server_config);
1891            test_pair.client.set_waker(Some(&noop_waker()))?;
1892            test_pair.handshake().unwrap();
1893            // read in session_ticket
1894            assert!(test_pair.client.poll_recv(&mut [0]).is_pending());
1895
1896            for conn in [&test_pair.client, &test_pair.server] {
1897                assert_eq!(conn.signature_scheme(), Some("rsa_pss_rsae_sha256"))
1898            }
1899        }
1900
1901        // session resumption: signature is not reported
1902        {
1903            let mut test_pair = TestPair::from_configs(&client_config, &server_config);
1904            test_pair.client.set_waker(Some(&noop_waker()))?;
1905            test_pair.handshake().unwrap();
1906            assert!(test_pair.client.resumed());
1907            assert_eq!(test_pair.client.signature_scheme(), None);
1908            assert_eq!(test_pair.server.signature_scheme(), None);
1909        }
1910        Ok(())
1911    }
1912}