rustls_ffi/connection.rs
1use std::io::{ErrorKind, Read, Write};
2use std::{ffi::c_void, ptr::null};
3use std::{ptr::null_mut, slice};
4
5use libc::{EINVAL, EIO, size_t};
6use rustls::CipherSuite::TLS_NULL_WITH_NULL_NULL;
7use rustls::pki_types::CertificateDer;
8use rustls::{ClientConnection, ServerConnection};
9
10use crate::certificate::rustls_certificate;
11use crate::enums::rustls_handshake_kind;
12use crate::error::{map_error, rustls_io_result, rustls_result};
13use crate::ffi::{
14 Castable, OwnershipBox, free_box, try_callback, try_mut_from_ptr, try_ref_from_ptr, try_slice,
15 try_slice_mut,
16};
17use crate::io::{
18 CallbackReader, CallbackWriter, VectoredCallbackWriter, rustls_read_callback,
19 rustls_write_callback, rustls_write_vectored_callback,
20};
21use crate::log::{ensure_log_registered, rustls_log_callback};
22use crate::panic::ffi_panic_boundary;
23use crate::rslice::rustls_str;
24use crate::userdata::userdata_push;
25
26pub(crate) struct Connection {
27 conn: rustls::Connection,
28 userdata: *mut c_void,
29 log_callback: rustls_log_callback,
30}
31
32impl Connection {
33 pub(crate) fn from_client(conn: ClientConnection) -> Self {
34 Connection {
35 conn: conn.into(),
36 userdata: null_mut(),
37 log_callback: None,
38 }
39 }
40
41 pub(crate) fn from_server(conn: ServerConnection) -> Self {
42 Connection {
43 conn: conn.into(),
44 userdata: null_mut(),
45 log_callback: None,
46 }
47 }
48
49 #[allow(dead_code)]
50 pub(crate) fn as_client(&self) -> Option<&ClientConnection> {
51 match &self.conn {
52 rustls::Connection::Client(c) => Some(c),
53 _ => None,
54 }
55 }
56
57 pub(crate) fn as_server(&self) -> Option<&ServerConnection> {
58 match &self.conn {
59 rustls::Connection::Server(s) => Some(s),
60 _ => None,
61 }
62 }
63
64 #[allow(dead_code)]
65 pub(crate) fn as_client_mut(&mut self) -> Option<&mut ClientConnection> {
66 match &mut self.conn {
67 rustls::Connection::Client(c) => Some(c),
68 _ => None,
69 }
70 }
71
72 #[allow(dead_code)]
73 pub(crate) fn as_server_mut(&mut self) -> Option<&mut ServerConnection> {
74 match &mut self.conn {
75 rustls::Connection::Server(s) => Some(s),
76 _ => None,
77 }
78 }
79}
80
81impl std::ops::Deref for Connection {
82 type Target = rustls::Connection;
83
84 fn deref(&self) -> &Self::Target {
85 &self.conn
86 }
87}
88
89impl std::ops::DerefMut for Connection {
90 fn deref_mut(&mut self) -> &mut Self::Target {
91 &mut self.conn
92 }
93}
94
95/// A C representation of a Rustls `Connection`.
96pub struct rustls_connection {
97 _private: [u8; 0],
98}
99
100impl Castable for rustls_connection {
101 type Ownership = OwnershipBox;
102 type RustType = Connection;
103}
104
105impl rustls_connection {
106 /// Set the userdata pointer associated with this connection. This will be passed
107 /// to any callbacks invoked by the connection, if you've set up callbacks in the config.
108 /// The pointed-to data must outlive the connection.
109 #[no_mangle]
110 pub extern "C" fn rustls_connection_set_userdata(
111 conn: *mut rustls_connection,
112 userdata: *mut c_void,
113 ) {
114 try_mut_from_ptr!(conn).userdata = userdata;
115 }
116
117 /// Set the logging callback for this connection. The log callback will be invoked
118 /// with the userdata parameter previously set by rustls_connection_set_userdata, or
119 /// NULL if no userdata was set.
120 #[no_mangle]
121 pub extern "C" fn rustls_connection_set_log_callback(
122 conn: *mut rustls_connection,
123 cb: rustls_log_callback,
124 ) {
125 let conn = try_mut_from_ptr!(conn);
126 ensure_log_registered();
127 conn.log_callback = cb;
128 }
129
130 /// Read some TLS bytes from the network into internal buffers. The actual network
131 /// I/O is performed by `callback`, which you provide. Rustls will invoke your
132 /// callback with a suitable buffer to store the read bytes into. You don't have
133 /// to fill it up, just fill with as many bytes as you get in one syscall.
134 /// The `userdata` parameter is passed through directly to `callback`. Note that
135 /// this is distinct from the `userdata` parameter set with
136 /// `rustls_connection_set_userdata`.
137 /// Returns 0 for success, or an errno value on error. Passes through return values
138 /// from callback. See rustls_read_callback for more details.
139 /// <https://docs.rs/rustls/latest/rustls/enum.Connection.html#method.read_tls>
140 #[no_mangle]
141 pub extern "C" fn rustls_connection_read_tls(
142 conn: *mut rustls_connection,
143 callback: rustls_read_callback,
144 userdata: *mut c_void,
145 out_n: *mut size_t,
146 ) -> rustls_io_result {
147 ffi_panic_boundary! {
148 let conn = try_mut_from_ptr!(conn);
149 if out_n.is_null() {
150 return rustls_io_result(EINVAL);
151 }
152 let callback = try_callback!(callback);
153
154 let mut reader = CallbackReader { callback, userdata };
155 let n_read = match conn.read_tls(&mut reader) {
156 Ok(n) => n,
157 Err(e) => return rustls_io_result(e.raw_os_error().unwrap_or(EIO)),
158 };
159 unsafe {
160 *out_n = n_read;
161 }
162
163 rustls_io_result(0)
164 }
165 }
166
167 /// Write some TLS bytes to the network. The actual network I/O is performed by
168 /// `callback`, which you provide. Rustls will invoke your callback with a
169 /// suitable buffer containing TLS bytes to send. You don't have to write them
170 /// all, just as many as you can in one syscall.
171 /// The `userdata` parameter is passed through directly to `callback`. Note that
172 /// this is distinct from the `userdata` parameter set with
173 /// `rustls_connection_set_userdata`.
174 /// Returns 0 for success, or an errno value on error. Passes through return values
175 /// from callback. See rustls_write_callback for more details.
176 /// <https://docs.rs/rustls/latest/rustls/enum.Connection.html#method.write_tls>
177 #[no_mangle]
178 pub extern "C" fn rustls_connection_write_tls(
179 conn: *mut rustls_connection,
180 callback: rustls_write_callback,
181 userdata: *mut c_void,
182 out_n: *mut size_t,
183 ) -> rustls_io_result {
184 ffi_panic_boundary! {
185 let conn = try_mut_from_ptr!(conn);
186 if out_n.is_null() {
187 return rustls_io_result(EINVAL);
188 }
189 let callback = try_callback!(callback);
190
191 let mut writer = CallbackWriter { callback, userdata };
192 let n_written = match conn.write_tls(&mut writer) {
193 Ok(n) => n,
194 Err(e) => return rustls_io_result(e.raw_os_error().unwrap_or(EIO)),
195 };
196 unsafe {
197 *out_n = n_written;
198 }
199
200 rustls_io_result(0)
201 }
202 }
203
204 /// Write all available TLS bytes to the network. The actual network I/O is performed by
205 /// `callback`, which you provide. Rustls will invoke your callback with an array
206 /// of rustls_slice_bytes, each containing a buffer with TLS bytes to send.
207 /// You don't have to write them all, just as many as you are willing.
208 /// The `userdata` parameter is passed through directly to `callback`. Note that
209 /// this is distinct from the `userdata` parameter set with
210 /// `rustls_connection_set_userdata`.
211 /// Returns 0 for success, or an errno value on error. Passes through return values
212 /// from callback. See rustls_write_callback for more details.
213 /// <https://docs.rs/rustls/latest/rustls/struct.Writer.html#method.write_vectored>
214 #[no_mangle]
215 pub extern "C" fn rustls_connection_write_tls_vectored(
216 conn: *mut rustls_connection,
217 callback: rustls_write_vectored_callback,
218 userdata: *mut c_void,
219 out_n: *mut size_t,
220 ) -> rustls_io_result {
221 ffi_panic_boundary! {
222 let conn = try_mut_from_ptr!(conn);
223 if out_n.is_null() {
224 return rustls_io_result(EINVAL);
225 }
226 let callback = try_callback!(callback);
227
228 let mut writer = VectoredCallbackWriter { callback, userdata };
229 let n_written = match conn.write_tls(&mut writer) {
230 Ok(n) => n,
231 Err(e) => return rustls_io_result(e.raw_os_error().unwrap_or(EIO)),
232 };
233 unsafe {
234 *out_n = n_written;
235 }
236
237 rustls_io_result(0)
238 }
239 }
240
241 /// Decrypt any available ciphertext from the internal buffer and put it
242 /// into the internal plaintext buffer, potentially making bytes available
243 /// for rustls_connection_read().
244 /// <https://docs.rs/rustls/latest/rustls/enum.Connection.html#method.process_new_packets>
245 #[no_mangle]
246 pub extern "C" fn rustls_connection_process_new_packets(
247 conn: *mut rustls_connection,
248 ) -> rustls_result {
249 ffi_panic_boundary! {
250 let conn = try_mut_from_ptr!(conn);
251 let guard = match userdata_push(conn.userdata, conn.log_callback) {
252 Ok(g) => g,
253 Err(_) => return rustls_result::Panic,
254 };
255 let result = match conn.process_new_packets() {
256 Ok(_) => rustls_result::Ok,
257 Err(e) => map_error(e),
258 };
259 match guard.try_drop() {
260 Ok(()) => result,
261 Err(_) => rustls_result::Panic,
262 }
263 }
264 }
265
266 /// <https://docs.rs/rustls/latest/rustls/struct.CommonState.html#method.wants_read>
267 #[no_mangle]
268 pub extern "C" fn rustls_connection_wants_read(conn: *const rustls_connection) -> bool {
269 ffi_panic_boundary! {
270 try_ref_from_ptr!(conn).wants_read()
271 }
272 }
273
274 /// <https://docs.rs/rustls/latest/rustls/struct.CommonState.html#method.wants_write>
275 #[no_mangle]
276 pub extern "C" fn rustls_connection_wants_write(conn: *const rustls_connection) -> bool {
277 ffi_panic_boundary! {
278 try_ref_from_ptr!(conn).wants_write()
279 }
280 }
281
282 /// Returns true if the connection is currently performing the TLS handshake.
283 ///
284 /// Note: This may return `false` while there are still handshake packets waiting
285 /// to be extracted and transmitted with `rustls_connection_write_tls()`.
286 ///
287 /// See the rustls documentation for more information.
288 ///
289 /// <https://docs.rs/rustls/latest/rustls/struct.CommonState.html#method.is_handshaking>
290 #[no_mangle]
291 pub extern "C" fn rustls_connection_is_handshaking(conn: *const rustls_connection) -> bool {
292 ffi_panic_boundary! {
293 try_ref_from_ptr!(conn).is_handshaking()
294 }
295 }
296
297 /// Returns a `rustls_handshake_kind` describing the `rustls_connection`.
298 #[no_mangle]
299 pub extern "C" fn rustls_connection_handshake_kind(
300 conn: *const rustls_connection,
301 ) -> rustls_handshake_kind {
302 ffi_panic_boundary! {
303 try_ref_from_ptr!(conn)
304 .handshake_kind()
305 .map(Into::into)
306 .unwrap_or(rustls_handshake_kind::Unknown)
307 }
308 }
309
310 /// Sets a limit on the internal buffers used to buffer unsent plaintext (prior
311 /// to completing the TLS handshake) and unsent TLS records. By default, there
312 /// is no limit. The limit can be set at any time, even if the current buffer
313 /// use is higher.
314 /// <https://docs.rs/rustls/latest/rustls/enum.Connection.html#method.set_buffer_limit>
315 #[no_mangle]
316 pub extern "C" fn rustls_connection_set_buffer_limit(conn: *mut rustls_connection, n: usize) {
317 ffi_panic_boundary! {
318 try_mut_from_ptr!(conn).set_buffer_limit(Some(n));
319 }
320 }
321
322 /// Queues a close_notify fatal alert to be sent in the next write_tls call.
323 /// <https://docs.rs/rustls/latest/rustls/enum.Connection.html#method.send_close_notify>
324 #[no_mangle]
325 pub extern "C" fn rustls_connection_send_close_notify(conn: *mut rustls_connection) {
326 ffi_panic_boundary! {
327 try_mut_from_ptr!(conn).send_close_notify();
328 }
329 }
330
331 /// Queues a TLS1.3 key_update message to refresh a connection’s keys.
332 ///
333 /// Rustls internally manages key updates as required and so this function should
334 /// seldom be used. See the Rustls documentation for important caveats and suggestions
335 /// on occasions that merit its use.
336 ///
337 /// <https://docs.rs/rustls/latest/rustls/struct.ConnectionCommon.html#method.refresh_traffic_keys>
338 #[no_mangle]
339 pub extern "C" fn rustls_connection_refresh_traffic_keys(
340 conn: *mut rustls_connection,
341 ) -> rustls_result {
342 ffi_panic_boundary! {
343 match try_mut_from_ptr!(conn).refresh_traffic_keys() {
344 Ok(_) => rustls_result::Ok,
345 Err(e) => map_error(e),
346 }
347 }
348 }
349
350 /// Return the i-th certificate provided by the peer.
351 /// Index 0 is the end entity certificate. Higher indexes are certificates
352 /// in the chain. Requesting an index higher than what is available returns
353 /// NULL.
354 /// The returned pointer is valid until the next mutating function call
355 /// affecting the connection. A mutating function call is one where the
356 /// first argument has type `struct rustls_connection *` (as opposed to
357 /// `const struct rustls_connection *`).
358 /// <https://docs.rs/rustls/latest/rustls/enum.Connection.html#method.peer_certificates>
359 #[no_mangle]
360 pub extern "C" fn rustls_connection_get_peer_certificate<'a>(
361 conn: *const rustls_connection,
362 i: size_t,
363 ) -> *const rustls_certificate<'a> {
364 ffi_panic_boundary! {
365 match try_ref_from_ptr!(conn)
366 .peer_certificates()
367 .and_then(|c| c.get(i))
368 {
369 Some(cert) => cert as *const CertificateDer as *const _,
370 None => null(),
371 }
372 }
373 }
374
375 /// Get the ALPN protocol that was negotiated, if any. Stores a pointer to a
376 /// borrowed buffer of bytes, and that buffer's len, in the output parameters.
377 /// The borrow lives as long as the connection.
378 /// If the connection is still handshaking, or no ALPN protocol was negotiated,
379 /// stores NULL and 0 in the output parameters.
380 /// The provided pointer is valid until the next mutating function call
381 /// affecting the connection. A mutating function call is one where the
382 /// first argument has type `struct rustls_connection *` (as opposed to
383 /// `const struct rustls_connection *`).
384 /// <https://www.iana.org/assignments/tls-parameters/>
385 /// <https://docs.rs/rustls/latest/rustls/enum.Connection.html#method.alpn_protocol>
386 #[no_mangle]
387 pub extern "C" fn rustls_connection_get_alpn_protocol(
388 conn: *const rustls_connection,
389 protocol_out: *mut *const u8,
390 protocol_out_len: *mut usize,
391 ) {
392 ffi_panic_boundary! {
393 let conn = try_ref_from_ptr!(conn);
394 if protocol_out.is_null() || protocol_out_len.is_null() {
395 return;
396 }
397 match conn.alpn_protocol() {
398 Some(p) => unsafe {
399 *protocol_out = p.as_ptr();
400 *protocol_out_len = p.len();
401 },
402 None => unsafe {
403 *protocol_out = null();
404 *protocol_out_len = 0;
405 },
406 }
407 }
408 }
409
410 /// Return the TLS protocol version that has been negotiated. Before this
411 /// has been decided during the handshake, this will return 0. Otherwise,
412 /// the u16 version number as defined in the relevant RFC is returned.
413 /// <https://docs.rs/rustls/latest/rustls/enum.Connection.html#method.protocol_version>
414 /// <https://docs.rs/rustls/latest/rustls/internal/msgs/enums/enum.ProtocolVersion.html>
415 #[no_mangle]
416 pub extern "C" fn rustls_connection_get_protocol_version(
417 conn: *const rustls_connection,
418 ) -> u16 {
419 ffi_panic_boundary! {
420 try_ref_from_ptr!(conn)
421 .protocol_version()
422 .map(u16::from)
423 .unwrap_or_default()
424 }
425 }
426
427 /// Retrieves the [IANA registered cipher suite identifier][IANA] agreed with the peer.
428 ///
429 /// This returns `TLS_NULL_WITH_NULL_NULL` (0x0000) until the ciphersuite is agreed.
430 ///
431 /// [IANA]: <https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-4>
432 #[no_mangle]
433 pub extern "C" fn rustls_connection_get_negotiated_ciphersuite(
434 conn: *const rustls_connection,
435 ) -> u16 {
436 ffi_panic_boundary! {
437 try_ref_from_ptr!(conn)
438 .negotiated_cipher_suite()
439 .map(|cs| u16::from(cs.suite()))
440 .unwrap_or(u16::from(TLS_NULL_WITH_NULL_NULL))
441 }
442 }
443
444 /// Retrieves the cipher suite name agreed with the peer.
445 ///
446 /// This returns "" until the ciphersuite is agreed.
447 ///
448 /// The lifetime of the `rustls_str` is the lifetime of the program, it does not
449 /// need to be freed.
450 ///
451 /// <https://docs.rs/rustls/latest/rustls/enum.Connection.html#method.negotiated_cipher_suite>
452 #[no_mangle]
453 pub extern "C" fn rustls_connection_get_negotiated_ciphersuite_name(
454 conn: *const rustls_connection,
455 ) -> rustls_str<'static> {
456 ffi_panic_boundary! {
457 try_ref_from_ptr!(conn)
458 .negotiated_cipher_suite()
459 .and_then(|cs| rustls_str::try_from(cs.suite().as_str().unwrap_or_default()).ok())
460 .unwrap_or(rustls_str::from_str_unchecked(""))
461 }
462 }
463
464 /// Retrieves the [IANA registered supported group identifier][IANA] agreed with the peer.
465 ///
466 /// This returns Reserved (0x0000) until the key exchange group is agreed.
467 ///
468 /// [IANA]: <https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-8>
469 #[no_mangle]
470 pub extern "C" fn rustls_connection_get_negotiated_key_exchange_group(
471 conn: *const rustls_connection,
472 ) -> u16 {
473 ffi_panic_boundary! {
474 try_ref_from_ptr!(conn)
475 .negotiated_key_exchange_group()
476 .map(|kxg| u16::from(kxg.name()))
477 .unwrap_or_default()
478 }
479 }
480
481 /// Retrieves the key exchange group name agreed with the peer.
482 ///
483 /// This returns "" until the key exchange group is agreed.
484 ///
485 /// The lifetime of the `rustls_str` is the lifetime of the program, it does not
486 /// need to be freed.
487 #[no_mangle]
488 pub extern "C" fn rustls_connection_get_negotiated_key_exchange_group_name(
489 conn: *const rustls_connection,
490 ) -> rustls_str<'static> {
491 ffi_panic_boundary! {
492 try_ref_from_ptr!(conn)
493 .negotiated_key_exchange_group()
494 .and_then(|kxg| rustls_str::try_from(kxg.name().as_str().unwrap_or_default()).ok())
495 .unwrap_or(rustls_str::from_str_unchecked(""))
496 }
497 }
498
499 /// Retrieves the number of TLS 1.3 tickets that have been received by a client connection.
500 ///
501 /// This returns 0 if the `conn` is `NULL`, or a server connection.
502 #[no_mangle]
503 pub extern "C" fn rustls_connection_get_tls13_tickets_received(
504 conn: *const rustls_connection,
505 ) -> u32 {
506 ffi_panic_boundary! {
507 try_ref_from_ptr!(conn)
508 .as_client()
509 .map(|cc| cc.tls13_tickets_received())
510 .unwrap_or_default()
511 }
512 }
513
514 /// Write up to `count` plaintext bytes from `buf` into the `rustls_connection`.
515 /// This will increase the number of output bytes available to
516 /// `rustls_connection_write_tls`.
517 /// On success, store the number of bytes actually written in *out_n
518 /// (this may be less than `count`).
519 /// <https://docs.rs/rustls/latest/rustls/struct.Writer.html#method.write>
520 #[no_mangle]
521 pub extern "C" fn rustls_connection_write(
522 conn: *mut rustls_connection,
523 buf: *const u8,
524 count: size_t,
525 out_n: *mut size_t,
526 ) -> rustls_result {
527 ffi_panic_boundary! {
528 let conn = try_mut_from_ptr!(conn);
529 let write_buf = try_slice!(buf, count);
530 if out_n.is_null() {
531 return rustls_result::NullParameter;
532 }
533 let n_written = match conn.writer().write(write_buf) {
534 Ok(n) => n,
535 Err(_) => return rustls_result::Io,
536 };
537 unsafe {
538 *out_n = n_written;
539 }
540 rustls_result::Ok
541 }
542 }
543
544 /// Read up to `count` plaintext bytes from the `rustls_connection` into `buf`.
545 /// On success, store the number of bytes read in *out_n (this may be less
546 /// than `count`). A success with *out_n set to 0 means "all bytes currently
547 /// available have been read, but more bytes may become available after
548 /// subsequent calls to rustls_connection_read_tls and
549 /// rustls_connection_process_new_packets."
550 ///
551 /// Subtle note: Even though this function only writes to `buf` and does not
552 /// read from it, the memory in `buf` must be initialized before the call (for
553 /// Rust-internal reasons). Initializing a buffer once and then using it
554 /// multiple times without zeroizing before each call is fine.
555 /// <https://docs.rs/rustls/latest/rustls/struct.Reader.html#method.read>
556 #[no_mangle]
557 pub extern "C" fn rustls_connection_read(
558 conn: *mut rustls_connection,
559 buf: *mut u8,
560 count: size_t,
561 out_n: *mut size_t,
562 ) -> rustls_result {
563 ffi_panic_boundary! {
564 let conn = try_mut_from_ptr!(conn);
565 if buf.is_null() {
566 return rustls_result::NullParameter;
567 }
568 if out_n.is_null() {
569 return rustls_result::NullParameter;
570 }
571
572 // Safety: the memory pointed at by buf must be initialized
573 // (required by documentation of this function).
574 let read_buf = try_slice_mut!(buf, count);
575
576 let n_read = match conn.reader().read(read_buf) {
577 Ok(n) => n,
578 Err(e) if e.kind() == ErrorKind::UnexpectedEof => {
579 return rustls_result::UnexpectedEof;
580 }
581 Err(e) if e.kind() == ErrorKind::WouldBlock => {
582 return rustls_result::PlaintextEmpty;
583 }
584 Err(_) => return rustls_result::Io,
585 };
586 unsafe {
587 *out_n = n_read;
588 }
589 rustls_result::Ok
590 }
591 }
592
593 /// Read up to `count` plaintext bytes from the `rustls_connection` into `buf`.
594 /// On success, store the number of bytes read in *out_n (this may be less
595 /// than `count`). A success with *out_n set to 0 means "all bytes currently
596 /// available have been read, but more bytes may become available after
597 /// subsequent calls to rustls_connection_read_tls and
598 /// rustls_connection_process_new_packets."
599 ///
600 /// This experimental API is only available when using a nightly Rust compiler
601 /// and enabling the `read_buf` Cargo feature. It will be deprecated and later
602 /// removed in future versions.
603 ///
604 /// Unlike with `rustls_connection_read`, this function may be called with `buf`
605 /// pointing to an uninitialized memory buffer.
606 #[cfg(feature = "read_buf")]
607 #[no_mangle]
608 pub extern "C" fn rustls_connection_read_2(
609 conn: *mut rustls_connection,
610 buf: *mut std::mem::MaybeUninit<u8>,
611 count: size_t,
612 out_n: *mut size_t,
613 ) -> rustls_result {
614 ffi_panic_boundary! {
615 let conn = try_mut_from_ptr!(conn);
616 if buf.is_null() || out_n.is_null() {
617 return rustls_result::NullParameter;
618 }
619 let mut read_buf: std::io::BorrowedBuf<'_> = try_slice_mut!(buf, count).into();
620
621 let n_read = match conn.reader().read_buf(read_buf.unfilled()) {
622 Ok(()) => read_buf.filled().len(),
623 Err(e) if e.kind() == ErrorKind::UnexpectedEof => {
624 return rustls_result::UnexpectedEof;
625 }
626 Err(e) if e.kind() == ErrorKind::WouldBlock => {
627 return rustls_result::PlaintextEmpty;
628 }
629 Err(_) => return rustls_result::Io,
630 };
631 unsafe {
632 *out_n = n_read;
633 }
634 rustls_result::Ok
635 }
636 }
637
638 /// Returns true if the `rustls_connection` was made with a `rustls_client_config`
639 /// or `rustls_server_config` that is FIPS compatible.
640 ///
641 /// This is different from `rustls_crypto_provider_fips` which is concerned
642 /// only with cryptography, whereas this also covers TLS-level configuration that NIST
643 /// recommends, as well as ECH HPKE suites if applicable.
644 #[no_mangle]
645 pub extern "C" fn rustls_connection_fips(conn: *const rustls_connection) -> bool {
646 ffi_panic_boundary! {
647 let conn = try_ref_from_ptr!(conn);
648 match &conn.conn {
649 rustls::Connection::Client(c) => c.fips(),
650 rustls::Connection::Server(c) => c.fips(),
651 }
652 }
653 }
654
655 /// Free a rustls_connection. Calling with NULL is fine.
656 /// Must not be called twice with the same value.
657 #[no_mangle]
658 pub extern "C" fn rustls_connection_free(conn: *mut rustls_connection) {
659 ffi_panic_boundary! {
660 free_box(conn);
661 }
662 }
663}