Skip to main content

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