rustls_ffi/
server.rs

1use std::ffi::c_void;
2use std::fmt::{Debug, Formatter};
3use std::slice;
4use std::sync::Arc;
5
6use libc::size_t;
7use rustls::crypto::CryptoProvider;
8use rustls::server::danger::ClientCertVerifier;
9use rustls::server::{
10    ClientHello, ResolvesServerCert, ServerConfig, ServerConnection, StoresServerSessions,
11    WebPkiClientVerifier,
12};
13use rustls::sign::CertifiedKey;
14use rustls::{KeyLog, KeyLogFile, ProtocolVersion, SignatureScheme, SupportedProtocolVersion};
15
16use crate::certificate::rustls_certified_key;
17use crate::connection::{Connection, rustls_connection};
18use crate::crypto_provider::{self, rustls_crypto_provider};
19use crate::error::{map_error, rustls_result};
20use crate::ffi::{
21    Castable, OwnershipRef, arc_castable, box_castable, free_arc, free_box, set_arc_mut_ptr,
22    set_boxed_mut_ptr, to_boxed_mut_ptr, try_box_from_ptr, try_clone_arc, try_mut_from_ptr,
23    try_mut_from_ptr_ptr, try_ref_from_ptr, try_ref_from_ptr_ptr, try_slice,
24};
25use crate::keylog::{CallbackKeyLog, rustls_keylog_log_callback, rustls_keylog_will_log_callback};
26use crate::panic::ffi_panic_boundary;
27use crate::rslice::{rustls_slice_bytes, rustls_slice_slice_bytes, rustls_slice_u16, rustls_str};
28use crate::session::{
29    SessionStoreBroker, rustls_session_store_get_callback, rustls_session_store_put_callback,
30};
31use crate::userdata::userdata_get;
32use crate::verifier::rustls_client_cert_verifier;
33
34box_castable! {
35    /// A server config being constructed.
36    ///
37    /// A builder can be modified by,
38    /// e.g. rustls_server_config_builder_load_native_roots. Once you're
39    /// done configuring settings, call rustls_server_config_builder_build
40    /// to turn it into a *const rustls_server_config.
41    ///
42    /// Alternatively, if an error occurs or, you don't wish to build a config,
43    /// call `rustls_server_config_builder_free` to free the builder directly.
44    ///
45    /// This object is not safe for concurrent mutation.
46    /// <https://docs.rs/rustls/latest/rustls/struct.ConfigBuilder.html>
47    pub struct rustls_server_config_builder(ServerConfigBuilder);
48}
49
50pub(crate) struct ServerConfigBuilder {
51    provider: Option<Arc<CryptoProvider>>,
52    versions: Vec<&'static SupportedProtocolVersion>,
53    verifier: Arc<dyn ClientCertVerifier>,
54    cert_resolver: Option<Arc<dyn ResolvesServerCert>>,
55    session_storage: Option<Arc<dyn StoresServerSessions + Send + Sync>>,
56    alpn_protocols: Vec<Vec<u8>>,
57    ignore_client_order: Option<bool>,
58    key_log: Option<Arc<dyn KeyLog>>,
59}
60
61arc_castable! {
62    /// A server config that is done being constructed and is now read-only.
63    ///
64    /// Under the hood, this object corresponds to an `Arc<ServerConfig>`.
65    /// <https://docs.rs/rustls/latest/rustls/struct.ServerConfig.html>
66    pub struct rustls_server_config(ServerConfig);
67}
68
69impl rustls_server_config_builder {
70    /// Create a rustls_server_config_builder using the process default crypto provider.
71    ///
72    /// Caller owns the memory and must eventually call rustls_server_config_builder_build,
73    /// then free the resulting rustls_server_config.
74    ///
75    /// Alternatively, if an error occurs or, you don't wish to build a config, call
76    /// `rustls_server_config_builder_free` to free the builder directly.
77    ///
78    /// This uses the process default provider's values for the cipher suites and key exchange
79    /// groups, as well as safe defaults for protocol versions.
80    #[no_mangle]
81    pub extern "C" fn rustls_server_config_builder_new() -> *mut rustls_server_config_builder {
82        ffi_panic_boundary! {
83            let builder = ServerConfigBuilder {
84                provider: crypto_provider::get_default_or_install_from_crate_features(),
85                versions: rustls::DEFAULT_VERSIONS.to_vec(),
86                verifier: WebPkiClientVerifier::no_client_auth(),
87                cert_resolver: None,
88                session_storage: None,
89                alpn_protocols: vec![],
90                ignore_client_order: None,
91                key_log: None,
92            };
93            to_boxed_mut_ptr(builder)
94        }
95    }
96
97    /// Create a rustls_server_config_builder using the specified crypto provider.
98    ///
99    /// Caller owns the memory and must eventually call rustls_server_config_builder_build,
100    /// then free the resulting rustls_server_config.
101    ///
102    /// Alternatively, if an error occurs or, you don't wish to build a config, call
103    /// `rustls_server_config_builder_free` to free the builder directly.
104    ///
105    /// `tls_versions` set the TLS protocol versions to use when negotiating a TLS session.
106    ///
107    /// `tls_versions` is the version of the protocol, as defined in rfc8446,
108    /// ch. 4.2.1 and end of ch. 5.1. Some values are defined in
109    /// `rustls_tls_version` for convenience.
110    ///
111    /// `tls_versions` will only be used during the call and the application retains
112    /// ownership. `tls_versions_len` is the number of consecutive `uint16_t` pointed
113    /// to by `tls_versions`.
114    ///
115    /// Ciphersuites are configured separately via the crypto provider. See
116    /// `rustls_crypto_provider_builder_set_cipher_suites` for more information.
117    #[no_mangle]
118    pub extern "C" fn rustls_server_config_builder_new_custom(
119        provider: *const rustls_crypto_provider,
120        tls_versions: *const u16,
121        tls_versions_len: size_t,
122        builder_out: *mut *mut rustls_server_config_builder,
123    ) -> rustls_result {
124        ffi_panic_boundary! {
125            let provider = try_clone_arc!(provider);
126            let tls_versions = try_slice!(tls_versions, tls_versions_len);
127            let mut versions = vec![];
128            for version_number in tls_versions {
129                let proto = ProtocolVersion::from(*version_number);
130                if proto == rustls::version::TLS12.version {
131                    versions.push(&rustls::version::TLS12);
132                } else if proto == rustls::version::TLS13.version {
133                    versions.push(&rustls::version::TLS13);
134                }
135            }
136            let builder_out = try_mut_from_ptr_ptr!(builder_out);
137
138            let builder = ServerConfigBuilder {
139                provider: Some(provider),
140                versions,
141                verifier: WebPkiClientVerifier::no_client_auth(),
142                cert_resolver: None,
143                session_storage: None,
144                alpn_protocols: vec![],
145                ignore_client_order: None,
146                key_log: None,
147            };
148            set_boxed_mut_ptr(builder_out, builder);
149            rustls_result::Ok
150        }
151    }
152
153    /// Create a rustls_server_config_builder for TLS sessions that may verify client
154    /// certificates.
155    ///
156    /// This increases the refcount of `verifier` and doesn't take ownership.
157    #[no_mangle]
158    pub extern "C" fn rustls_server_config_builder_set_client_verifier(
159        builder: *mut rustls_server_config_builder,
160        verifier: *const rustls_client_cert_verifier,
161    ) {
162        ffi_panic_boundary! {
163            let builder = try_mut_from_ptr!(builder);
164            let verifier = try_ref_from_ptr!(verifier);
165            builder.verifier = verifier.clone();
166        }
167    }
168
169    /// Log key material to the file specified by the `SSLKEYLOGFILE` environment variable.
170    ///
171    /// The key material will be logged in the NSS key log format,
172    /// <https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSS/Key_Log_Format> and is
173    /// compatible with tools like Wireshark.
174    ///
175    /// Secrets logged in this manner are **extremely sensitive** and can break the security
176    /// of past, present and future sessions.
177    ///
178    /// For more control over which secrets are logged, or to customize the format, prefer
179    /// `rustls_server_config_builder_set_key_log`.
180    #[no_mangle]
181    pub extern "C" fn rustls_server_config_builder_set_key_log_file(
182        builder: *mut rustls_server_config_builder,
183    ) -> rustls_result {
184        ffi_panic_boundary! {
185            let builder = try_mut_from_ptr!(builder);
186            builder.key_log = Some(Arc::new(KeyLogFile::new()));
187            rustls_result::Ok
188        }
189    }
190
191    /// Provide callbacks to manage logging key material.
192    ///
193    /// The `log_cb` argument is mandatory and must not be `NULL` or a `NullParameter` error is
194    /// returned. The `log_cb` will be invoked with a `client_random` to identify the relevant session,
195    /// a `label` to identify the purpose of the `secret`, and the `secret` itself. See the
196    /// Rustls documentation of the `KeyLog` trait for more information on possible labels:
197    /// <https://docs.rs/rustls/latest/rustls/trait.KeyLog.html#tymethod.log>
198    ///
199    /// The `will_log_cb` may be `NULL`, in which case all key material will be provided to
200    /// the `log_cb`. By providing a custom `will_log_cb` you may return `0` for labels you don't
201    /// wish to log, and non-zero for labels you _do_ wish to log as a performance optimization.
202    ///
203    /// Both callbacks **must** be thread-safe. Arguments provided to the callback live only for as
204    /// long as the callback is executing and are not valid after the callback returns. The
205    /// callbacks must not retain references to the provided data.
206    ///
207    /// Secrets provided to the `log_cb` are **extremely sensitive** and can break the security
208    /// of past, present and future sessions.
209    ///
210    /// See also `rustls_server_config_builder_set_key_log_file` for a simpler way to log
211    /// to a file specified by the `SSLKEYLOGFILE` environment variable.
212    #[no_mangle]
213    pub extern "C" fn rustls_server_config_builder_set_key_log(
214        builder: *mut rustls_server_config_builder,
215        log_cb: rustls_keylog_log_callback,
216        will_log_cb: rustls_keylog_will_log_callback,
217    ) -> rustls_result {
218        ffi_panic_boundary! {
219            let builder = try_mut_from_ptr!(builder);
220            let log_cb = match log_cb {
221                Some(cb) => cb,
222                None => return rustls_result::NullParameter,
223            };
224
225            builder.key_log = Some(Arc::new(CallbackKeyLog {
226                log_cb,
227                will_log_cb,
228            }));
229
230            rustls_result::Ok
231        }
232    }
233
234    /// "Free" a server_config_builder without building it into a rustls_server_config.
235    ///
236    /// Normally builders are built into rustls_server_configs via `rustls_server_config_builder_build`
237    /// and may not be free'd or otherwise used afterwards.
238    ///
239    /// Use free only when the building of a config has to be aborted before a config
240    /// was created.
241    #[no_mangle]
242    pub extern "C" fn rustls_server_config_builder_free(config: *mut rustls_server_config_builder) {
243        ffi_panic_boundary! {
244            free_box(config);
245        }
246    }
247
248    /// With `ignore` != 0, the server will ignore the client ordering of cipher
249    /// suites, aka preference, during handshake and respect its own ordering
250    /// as configured.
251    /// <https://docs.rs/rustls/latest/rustls/struct.ServerConfig.html#structfield.ignore_client_order>
252    #[no_mangle]
253    pub extern "C" fn rustls_server_config_builder_set_ignore_client_order(
254        builder: *mut rustls_server_config_builder,
255        ignore: bool,
256    ) -> rustls_result {
257        ffi_panic_boundary! {
258            let config = try_mut_from_ptr!(builder);
259            config.ignore_client_order = Some(ignore);
260            rustls_result::Ok
261        }
262    }
263
264    /// Set the ALPN protocol list to the given protocols.
265    ///
266    /// `protocols` must point to a buffer of `rustls_slice_bytes` (built by the caller)
267    /// with `len` elements. Each element of the buffer must point to a slice of bytes that
268    /// contains a single ALPN protocol from
269    /// <https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids>.
270    ///
271    /// This function makes a copy of the data in `protocols` and does not retain
272    /// any pointers, so the caller can free the pointed-to memory after calling.
273    ///
274    /// <https://docs.rs/rustls/latest/rustls/server/struct.ServerConfig.html#structfield.alpn_protocols>
275    #[no_mangle]
276    pub extern "C" fn rustls_server_config_builder_set_alpn_protocols(
277        builder: *mut rustls_server_config_builder,
278        protocols: *const rustls_slice_bytes,
279        len: size_t,
280    ) -> rustls_result {
281        ffi_panic_boundary! {
282            let config = try_mut_from_ptr!(builder);
283            let protocols = try_slice!(protocols, len);
284
285            let mut vv = Vec::new();
286            for p in protocols {
287                let v = try_slice!(p.data, p.len);
288                vv.push(v.to_vec());
289            }
290            config.alpn_protocols = vv;
291            rustls_result::Ok
292        }
293    }
294
295    /// Provide the configuration a list of certificates where the connection
296    /// will select the first one that is compatible with the client's signature
297    /// verification capabilities.
298    ///
299    /// Servers that want to support both ECDSA and RSA certificates will want
300    /// the ECSDA to go first in the list.
301    ///
302    /// The built configuration will keep a reference to all certified keys
303    /// provided. The client may `rustls_certified_key_free()` afterwards
304    /// without the configuration losing them. The same certified key may also
305    /// be used in multiple configs.
306    ///
307    /// EXPERIMENTAL: installing a client_hello callback will replace any
308    /// configured certified keys and vice versa.
309    #[no_mangle]
310    pub extern "C" fn rustls_server_config_builder_set_certified_keys(
311        builder: *mut rustls_server_config_builder,
312        certified_keys: *const *const rustls_certified_key,
313        certified_keys_len: size_t,
314    ) -> rustls_result {
315        ffi_panic_boundary! {
316            let builder = try_mut_from_ptr!(builder);
317            let keys_ptrs = try_slice!(certified_keys, certified_keys_len);
318            let mut keys = Vec::new();
319            for &key_ptr in keys_ptrs {
320                let certified_key = try_clone_arc!(key_ptr);
321                keys.push(certified_key);
322            }
323            builder.cert_resolver = Some(Arc::new(ResolvesServerCertFromChoices::new(&keys)));
324            rustls_result::Ok
325        }
326    }
327
328    /// Turn a *rustls_server_config_builder (mutable) into a const *rustls_server_config
329    /// (read-only). The constructed `rustls_server_config` will be written to the `config_out`
330    /// pointer when this function returns `rustls_result::Ok`.
331    ///
332    /// This function may return an error if no process default crypto provider has been set
333    /// and the builder was constructed using `rustls_server_config_builder_new`, or if no
334    /// certificate resolver was set.
335    #[no_mangle]
336    pub extern "C" fn rustls_server_config_builder_build(
337        builder: *mut rustls_server_config_builder,
338        config_out: *mut *const rustls_server_config,
339    ) -> rustls_result {
340        ffi_panic_boundary! {
341            let builder = try_box_from_ptr!(builder);
342            let config_out = try_ref_from_ptr_ptr!(config_out);
343
344            let provider = match builder.provider {
345                Some(provider) => provider,
346                None => return rustls_result::NoDefaultCryptoProvider,
347            };
348
349            let base = match ServerConfig::builder_with_provider(provider)
350                .with_protocol_versions(&builder.versions)
351            {
352                Ok(base) => base,
353                Err(err) => return map_error(err),
354            }
355            .with_client_cert_verifier(builder.verifier);
356
357            let mut config = if let Some(r) = builder.cert_resolver {
358                base.with_cert_resolver(r)
359            } else {
360                return rustls_result::NoCertResolver;
361            };
362            if let Some(ss) = builder.session_storage {
363                config.session_storage = ss;
364            }
365            config.alpn_protocols = builder.alpn_protocols;
366            if let Some(ignore_client_order) = builder.ignore_client_order {
367                config.ignore_client_order = ignore_client_order;
368            }
369
370            if let Some(key_log) = builder.key_log {
371                config.key_log = key_log;
372            }
373
374            set_arc_mut_ptr(config_out, config);
375            rustls_result::Ok
376        }
377    }
378}
379
380impl rustls_server_config {
381    /// Returns true if a `rustls_connection` created from the `rustls_server_config` will
382    /// operate in FIPS mode.
383    ///
384    /// This is different from `rustls_crypto_provider_fips` which is concerned
385    /// only with cryptography, whereas this also covers TLS-level configuration that NIST
386    /// recommends, as well as ECH HPKE suites if applicable.
387    #[no_mangle]
388    pub extern "C" fn rustls_server_config_fips(config: *const rustls_server_config) -> bool {
389        ffi_panic_boundary! {
390            try_ref_from_ptr!(config).fips()
391        }
392    }
393
394    /// "Free" a rustls_server_config previously returned from
395    /// rustls_server_config_builder_build.
396    ///
397    /// Since rustls_server_config is actually an
398    /// atomically reference-counted pointer, extant server connections may still
399    /// hold an internal reference to the Rust object. However, C code must
400    /// consider this pointer unusable after "free"ing it.
401    /// Calling with NULL is fine. Must not be called twice with the same value.
402    #[no_mangle]
403    pub extern "C" fn rustls_server_config_free(config: *const rustls_server_config) {
404        ffi_panic_boundary! {
405            free_arc(config);
406        }
407    }
408
409    /// Create a new rustls_connection containing a server connection, and return it.
410    ///
411    /// It is returned in the output parameter `conn_out`.
412    ///
413    /// If this returns an error code, the memory pointed to by `conn_out` remains unchanged.
414    ///
415    /// If this returns a non-error, the memory pointed to by `conn_out` is modified to point
416    /// at a valid rustls_connection
417    ///
418    /// The caller now owns the rustls_connection and must call `rustls_connection_free` when
419    /// done with it.
420    #[no_mangle]
421    pub extern "C" fn rustls_server_connection_new(
422        config: *const rustls_server_config,
423        conn_out: *mut *mut rustls_connection,
424    ) -> rustls_result {
425        ffi_panic_boundary! {
426            if conn_out.is_null() {
427                return rustls_result::NullParameter;
428            }
429            let config = try_clone_arc!(config);
430            let conn_out = try_mut_from_ptr_ptr!(conn_out);
431
432            let server_connection = match ServerConnection::new(config) {
433                Ok(sc) => sc,
434                Err(e) => return map_error(e),
435            };
436            // We've succeeded. Put the server on the heap, and transfer ownership
437            // to the caller. After this point, we must return rustls_result::Ok so the
438            // caller knows it is responsible for this memory.
439            let c = Connection::from_server(server_connection);
440            set_boxed_mut_ptr(conn_out, c);
441            rustls_result::Ok
442        }
443    }
444}
445
446/// Returns a `rustls_str` reference to the server name sent by the client in a server name
447/// indication (SNI) extension.
448///
449/// The returned `rustls_str` is valid until the next mutating function call affecting the
450/// connection. A mutating function call is one where the first argument has type
451/// `struct rustls_connection *` (as opposed to `const struct rustls_connection *`). The caller
452/// does not need to free the `rustls_str`.
453///
454/// Returns a zero-length `rustls_str` if:
455///
456/// - the connection is not a server connection.
457/// - the connection is a server connection but the SNI extension in the client hello has not
458///   been processed during the handshake yet. Check `rustls_connection_is_handshaking`.
459/// - the SNI value contains null bytes.
460#[no_mangle]
461pub extern "C" fn rustls_server_connection_get_server_name(
462    conn: *const rustls_connection,
463) -> rustls_str<'static> {
464    ffi_panic_boundary! {
465        let Some(server_connection) = try_ref_from_ptr!(conn).as_server() else {
466            return rustls_str::default();
467        };
468        let Some(sni_hostname) = server_connection.server_name() else {
469            return rustls_str::default();
470        };
471        let res = rustls_str::try_from(sni_hostname).unwrap_or_default();
472        unsafe { res.into_static() }
473    }
474}
475
476/// Choose the server certificate to be used for a connection based on certificate
477/// type. Will pick the first CertfiedKey available that is suitable for
478/// the SignatureSchemes supported by the client.
479#[derive(Debug)]
480struct ResolvesServerCertFromChoices {
481    choices: Vec<Arc<CertifiedKey>>,
482}
483
484impl ResolvesServerCertFromChoices {
485    pub fn new(choices: &[Arc<CertifiedKey>]) -> Self {
486        ResolvesServerCertFromChoices {
487            choices: Vec::from(choices),
488        }
489    }
490}
491
492impl ResolvesServerCert for ResolvesServerCertFromChoices {
493    fn resolve(&self, client_hello: ClientHello) -> Option<Arc<CertifiedKey>> {
494        for key in self.choices.iter() {
495            if key
496                .key
497                .choose_scheme(client_hello.signature_schemes())
498                .is_some()
499            {
500                return Some(key.clone());
501            }
502        }
503        None
504    }
505}
506
507/// The TLS Client Hello information provided to a ClientHelloCallback function.
508///
509/// `server_name` is the value of the ServerNameIndication extension provided
510/// by the client. If the client did not send an SNI, the length of this
511/// `rustls_string` will be 0.
512///
513/// `signature_schemes` carries the values supplied by the client or, if the
514/// client did not send this TLS extension, the default schemes in the rustls library. See:
515/// <https://docs.rs/rustls/latest/rustls/internal/msgs/enums/enum.SignatureScheme.html>.
516///
517/// `alpn` carries the list of ALPN protocol names that the client proposed to
518/// the server. Again, the length of this list will be 0 if none were supplied.
519///
520/// All this data, when passed to a callback function, is only accessible during
521/// the call and may not be modified. Users of this API must copy any values that
522/// they want to access when the callback returned.
523///
524/// EXPERIMENTAL: this feature of rustls-ffi is likely to change in the future, as
525/// the rustls library is re-evaluating their current approach to client hello handling.
526#[repr(C)]
527pub struct rustls_client_hello<'a> {
528    server_name: rustls_str<'a>,
529    signature_schemes: rustls_slice_u16<'a>,
530    alpn: *const rustls_slice_slice_bytes<'a>,
531}
532
533impl<'a> Castable for rustls_client_hello<'a> {
534    type Ownership = OwnershipRef;
535    type RustType = rustls_client_hello<'a>;
536}
537
538/// Any context information the callback will receive when invoked.
539pub type rustls_client_hello_userdata = *mut c_void;
540
541/// Prototype of a callback that can be installed by the application at the
542/// `rustls_server_config`.
543///
544/// This callback will be invoked by a `rustls_connection` once the TLS client
545/// hello message has been received.
546///
547/// `userdata` will be set based on rustls_connection_set_userdata.
548///
549/// `hello` gives the value of the available client announcements, as interpreted
550/// by rustls. See the definition of `rustls_client_hello` for details.
551///
552/// NOTE:
553/// - the passed in `hello` and all its values are only available during the
554///   callback invocations.
555/// - the passed callback function must be safe to call multiple times concurrently
556///   with the same userdata, unless there is only a single config and connection
557///   where it is installed.
558///
559/// EXPERIMENTAL: this feature of rustls-ffi is likely to change in the future, as
560/// the rustls library is re-evaluating their current approach to client hello handling.
561pub type rustls_client_hello_callback = Option<
562    unsafe extern "C" fn(
563        userdata: rustls_client_hello_userdata,
564        hello: *const rustls_client_hello,
565    ) -> *const rustls_certified_key,
566>;
567
568// This is the same as a rustls_verify_server_cert_callback after unwrapping
569// the Option (which is equivalent to checking for null).
570type ClientHelloCallback = unsafe extern "C" fn(
571    userdata: rustls_client_hello_userdata,
572    hello: *const rustls_client_hello,
573) -> *const rustls_certified_key;
574
575struct ClientHelloResolver {
576    /// Implementation of rustls::ResolvesServerCert that passes values
577    /// from the supplied ClientHello to the callback function.
578    pub callback: ClientHelloCallback,
579}
580
581impl ClientHelloResolver {
582    pub fn new(callback: ClientHelloCallback) -> ClientHelloResolver {
583        ClientHelloResolver { callback }
584    }
585}
586
587impl ResolvesServerCert for ClientHelloResolver {
588    fn resolve(&self, client_hello: ClientHello) -> Option<Arc<CertifiedKey>> {
589        let server_name = client_hello.server_name().unwrap_or_default();
590        let server_name = match server_name.try_into() {
591            Ok(r) => r,
592            Err(_) => return None,
593        };
594        let mapped_sigs: Vec<u16> = client_hello
595            .signature_schemes()
596            .iter()
597            .map(|s| u16::from(*s))
598            .collect();
599        // Unwrap the Option. None becomes an empty slice.
600        let alpn = match client_hello.alpn() {
601            Some(iter) => iter.collect(),
602            None => vec![],
603        };
604
605        let alpn = rustls_slice_slice_bytes { inner: &alpn };
606        let signature_schemes = (&*mapped_sigs).into();
607        let hello = rustls_client_hello {
608            server_name,
609            signature_schemes,
610            alpn: &alpn,
611        };
612
613        let cb = self.callback;
614        let userdata = match userdata_get() {
615            Ok(u) => u,
616            Err(_) => return None,
617        };
618        let key_ptr = unsafe { cb(userdata, &hello) };
619        let certified_key = try_ref_from_ptr!(key_ptr);
620        Some(Arc::new(certified_key.clone()))
621    }
622}
623
624/// This struct can be considered thread safe, as long
625/// as the registered callbacks are thread safe. This is
626/// documented as a requirement in the API.
627unsafe impl Sync for ClientHelloResolver {}
628
629unsafe impl Send for ClientHelloResolver {}
630
631impl Debug for ClientHelloResolver {
632    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
633        f.debug_struct("ClientHelloResolver").finish()
634    }
635}
636
637impl rustls_server_config_builder {
638    /// Register a callback to be invoked when a connection created from this config
639    /// sees a TLS ClientHello message. If `userdata` has been set with
640    /// rustls_connection_set_userdata, it will be passed to the callback.
641    /// Otherwise the userdata param passed to the callback will be NULL.
642    ///
643    /// Any existing `ResolvesServerCert` implementation currently installed in the
644    /// `rustls_server_config` will be replaced. This also means registering twice
645    /// will overwrite the first registration. It is not permitted to pass a NULL
646    /// value for `callback`.
647    ///
648    /// EXPERIMENTAL: this feature of rustls-ffi is likely to change in the future, as
649    /// the rustls library is re-evaluating their current approach to client hello handling.
650    /// Installing a client_hello callback will replace any configured certified keys
651    /// and vice versa. Same holds true for the set_certified_keys variant.
652    #[no_mangle]
653    pub extern "C" fn rustls_server_config_builder_set_hello_callback(
654        builder: *mut rustls_server_config_builder,
655        callback: rustls_client_hello_callback,
656    ) -> rustls_result {
657        ffi_panic_boundary! {
658            let callback = match callback {
659                Some(cb) => cb,
660                None => return rustls_result::NullParameter,
661            };
662            let builder = try_mut_from_ptr!(builder);
663            builder.cert_resolver = Some(Arc::new(ClientHelloResolver::new(callback)));
664            rustls_result::Ok
665        }
666    }
667}
668
669// Turn a slice of u16's into a vec of SignatureScheme as needed by rustls.
670fn sigschemes(input: &[u16]) -> Vec<SignatureScheme> {
671    input.iter().copied().map(Into::into).collect()
672}
673
674/// Select a `rustls_certified_key` from the list that matches the cryptographic
675/// parameters of a TLS client hello.
676///
677/// Note that this does not do any SNI matching. The input certificates should
678/// already have been filtered to ones matching the SNI from the client hello.
679///
680/// This is intended for servers that are configured with several keys for the
681/// same domain name(s), for example ECDSA and RSA types. The presented keys are
682/// inspected in the order given and keys first in the list are given preference,
683/// all else being equal. However rustls is free to choose whichever it considers
684/// to be the best key with its knowledge about security issues and possible future
685/// extensions of the protocol.
686///
687/// Return RUSTLS_RESULT_OK if a key was selected and RUSTLS_RESULT_NOT_FOUND
688/// if none was suitable.
689#[no_mangle]
690pub extern "C" fn rustls_client_hello_select_certified_key(
691    hello: *const rustls_client_hello,
692    certified_keys: *const *const rustls_certified_key,
693    certified_keys_len: size_t,
694    out_key: *mut *const rustls_certified_key,
695) -> rustls_result {
696    ffi_panic_boundary! {
697        let hello = try_ref_from_ptr!(hello);
698        let schemes = sigschemes(try_slice!(
699            hello.signature_schemes.data,
700            hello.signature_schemes.len
701        ));
702        if out_key.is_null() {
703            return rustls_result::NullParameter;
704        }
705        let keys_ptrs = try_slice!(certified_keys, certified_keys_len);
706        for &key_ptr in keys_ptrs {
707            let key_ref = try_ref_from_ptr!(key_ptr);
708            if key_ref.key.choose_scheme(&schemes).is_some() {
709                unsafe {
710                    *out_key = key_ptr;
711                }
712                return rustls_result::Ok;
713            }
714        }
715        rustls_result::NotFound
716    }
717}
718
719impl rustls_server_config_builder {
720    /// Register callbacks for persistence of TLS session IDs and secrets. Both
721    /// keys and values are highly sensitive data, containing enough information
722    /// to break the security of the connections involved.
723    ///
724    /// If `builder`, `get_cb`, or `put_cb` are NULL, this function will return
725    /// immediately without doing anything.
726    ///
727    /// If `userdata` has been set with rustls_connection_set_userdata, it
728    /// will be passed to the callbacks. Otherwise the userdata param passed to
729    /// the callbacks will be NULL.
730    #[no_mangle]
731    pub extern "C" fn rustls_server_config_builder_set_persistence(
732        builder: *mut rustls_server_config_builder,
733        get_cb: rustls_session_store_get_callback,
734        put_cb: rustls_session_store_put_callback,
735    ) {
736        ffi_panic_boundary! {
737            let Some(get_cb) = get_cb else {
738                return;
739            };
740            let Some(put_cb) = put_cb else {
741                return;
742            };
743
744            try_mut_from_ptr!(builder).session_storage =
745                Some(Arc::new(SessionStoreBroker::new(get_cb, put_cb)));
746        }
747    }
748}
749
750#[cfg(all(test, any(feature = "ring", feature = "aws-lc-rs")))]
751mod tests {
752    use std::ptr::{null, null_mut};
753
754    use super::*;
755
756    #[test]
757    #[cfg_attr(miri, ignore)]
758    fn test_config_builder() {
759        let builder = rustls_server_config_builder::rustls_server_config_builder_new();
760        let h1 = "http/1.1".as_bytes();
761        let h2 = "h2".as_bytes();
762        let alpn = [h1.into(), h2.into()];
763        rustls_server_config_builder::rustls_server_config_builder_set_alpn_protocols(
764            builder,
765            alpn.as_ptr(),
766            alpn.len(),
767        );
768
769        let cert_pem = include_str!("../testdata/localhost/cert.pem").as_bytes();
770        let key_pem = include_str!("../testdata/localhost/key.pem").as_bytes();
771        let mut certified_key = null();
772        let result = rustls_certified_key::rustls_certified_key_build(
773            cert_pem.as_ptr(),
774            cert_pem.len(),
775            key_pem.as_ptr(),
776            key_pem.len(),
777            &mut certified_key,
778        );
779        if !matches!(result, rustls_result::Ok) {
780            panic!(
781                "expected RUSTLS_RESULT_OK from rustls_certified_key_build, got {:?}",
782                result
783            );
784        }
785        rustls_server_config_builder::rustls_server_config_builder_set_certified_keys(
786            builder,
787            &certified_key,
788            1,
789        );
790
791        let mut config = null();
792        let result =
793            rustls_server_config_builder::rustls_server_config_builder_build(builder, &mut config);
794        assert_eq!(result, rustls_result::Ok);
795        assert!(!config.is_null());
796        {
797            let config2 = try_ref_from_ptr!(config);
798            assert_eq!(config2.alpn_protocols, vec![h1, h2]);
799        }
800        rustls_server_config::rustls_server_config_free(config);
801    }
802
803    // Build a server connection and test the getters and initial values.
804    #[test]
805    fn test_server_config_builder_new_empty() {
806        let builder = rustls_server_config_builder::rustls_server_config_builder_new();
807        // Building a config with no certificate and key configured results in an error.
808        let mut config = null();
809        let result =
810            rustls_server_config_builder::rustls_server_config_builder_build(builder, &mut config);
811        assert_eq!(result, rustls_result::NoCertResolver);
812        assert!(config.is_null());
813    }
814
815    #[test]
816    #[cfg_attr(miri, ignore)]
817    fn test_server_connection_new() {
818        let builder = rustls_server_config_builder::rustls_server_config_builder_new();
819        let cert_pem = include_str!("../testdata/localhost/cert.pem").as_bytes();
820        let key_pem = include_str!("../testdata/localhost/key.pem").as_bytes();
821        let mut certified_key = null();
822        let result = rustls_certified_key::rustls_certified_key_build(
823            cert_pem.as_ptr(),
824            cert_pem.len(),
825            key_pem.as_ptr(),
826            key_pem.len(),
827            &mut certified_key,
828        );
829        if !matches!(result, rustls_result::Ok) {
830            panic!(
831                "expected RUSTLS_RESULT_OK from rustls_certified_key_build, got {:?}",
832                result
833            );
834        }
835        rustls_server_config_builder::rustls_server_config_builder_set_certified_keys(
836            builder,
837            &certified_key,
838            1,
839        );
840
841        let mut config = null();
842        let result =
843            rustls_server_config_builder::rustls_server_config_builder_build(builder, &mut config);
844        assert_eq!(result, rustls_result::Ok);
845        assert!(!config.is_null());
846
847        let mut conn = null_mut();
848        let result = rustls_server_config::rustls_server_connection_new(config, &mut conn);
849        if !matches!(result, rustls_result::Ok) {
850            panic!("expected RUSTLS_RESULT_OK, got {:?}", result);
851        }
852        assert!(rustls_connection::rustls_connection_wants_read(conn));
853        assert!(!rustls_connection::rustls_connection_wants_write(conn));
854        assert!(rustls_connection::rustls_connection_is_handshaking(conn));
855
856        let some_byte = 42u8;
857        let mut alpn_protocol: *const u8 = &some_byte;
858        let mut alpn_protocol_len = 1;
859        rustls_connection::rustls_connection_get_alpn_protocol(
860            conn,
861            &mut alpn_protocol,
862            &mut alpn_protocol_len,
863        );
864        assert_eq!(alpn_protocol, null());
865        assert_eq!(alpn_protocol_len, 0);
866
867        assert_eq!(
868            rustls_connection::rustls_connection_get_negotiated_ciphersuite(conn),
869            0
870        );
871        let cs_name = rustls_connection::rustls_connection_get_negotiated_ciphersuite_name(conn);
872        assert_eq!(unsafe { cs_name.to_str() }, "");
873        assert_eq!(
874            rustls_connection::rustls_connection_get_peer_certificate(conn, 0),
875            null()
876        );
877
878        assert_eq!(
879            rustls_connection::rustls_connection_get_protocol_version(conn),
880            0
881        );
882        rustls_connection::rustls_connection_free(conn);
883    }
884}