Skip to content

Commit

Permalink
connection: expose handshake kind
Browse files Browse the repository at this point in the history
This commit adds a `rustls_connection_handshake_kind()` fn for getting
the handshake kind of a `rustls_connection`. The kind of connection is
returned as a `rustls_handshake_kind` enum, which can be translated to
a `rustls_str` using `rustls_handshake_kind_str()`. The
`rustls_handshake_kind` enum has variants for full, full with hello
retry request, and resumed handshake types matching the upstream
`rustls::HandshakeKind` enum.
  • Loading branch information
cpu committed Oct 4, 2024
1 parent d24ac34 commit 51ac465
Show file tree
Hide file tree
Showing 6 changed files with 134 additions and 4 deletions.
13 changes: 13 additions & 0 deletions src/connection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ use crate::{
try_slice, try_slice_mut, userdata_push,
};

use crate::enums::rustls_handshake_kind;
use rustls_result::NullParameter;

pub(crate) struct Connection {
Expand Down Expand Up @@ -287,6 +288,18 @@ impl rustls_connection {
}
}

#[no_mangle]
pub extern "C" fn rustls_connection_handshake_kind(
conn: *const rustls_connection,
) -> rustls_handshake_kind {
ffi_panic_boundary! {
try_ref_from_ptr!(conn)
.handshake_kind()
.map(Into::into)
.unwrap_or(rustls_handshake_kind::Unknown)
}
}

/// Sets a limit on the internal buffers used to buffer unsent plaintext (prior
/// to completing the TLS handshake) and unsent TLS records. By default, there
/// is no limit. The limit can be set at any time, even if the current buffer
Expand Down
62 changes: 61 additions & 1 deletion src/enums.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use rustls::{ProtocolVersion, SupportedProtocolVersion};
use crate::ffi_panic_boundary;
use crate::rslice::rustls_str;
use rustls::{HandshakeKind, ProtocolVersion, SupportedProtocolVersion};

#[derive(Debug, Default)]
#[repr(C)]
Expand Down Expand Up @@ -52,6 +54,64 @@ pub static RUSTLS_DEFAULT_VERSIONS: [u16; 2] = [
#[no_mangle]
pub static RUSTLS_DEFAULT_VERSIONS_LEN: usize = RUSTLS_DEFAULT_VERSIONS.len();

#[derive(Debug, Default)]
#[repr(C)]
/// Describes which sort of handshake happened.
pub enum rustls_handshake_kind {
/// The type of handshake could not be determined.
///
/// This variant should not be used.
#[default]
Unknown = 0x0,

/// A full TLS handshake.
///
/// This is the typical TLS connection initiation process when resumption is
/// not yet unavailable, and the initial client hello was accepted by the server.
Full = 0x1,

/// A full TLS handshake, with an extra round-trip for a hello retry request.
///
/// The server can respond with a hello retry request (HRR) if the initial client
/// hello is unacceptable for several reasons, the most likely if no supported key
/// shares were offered by the client.
FullWithHelloRetryRequest = 0x2,

/// A resumed TLS handshake.
///
/// Resumed handshakes involve fewer round trips and less cryptography than
/// full ones, but can only happen when the peers have previously done a full
/// handshake together, and then remember data about it.
Resumed = 0x3,
}

/// Convert a `rustls_handshake_kind` to a string with a friendly description of the kind
/// of handshake.
///
/// The returned `rustls_str` has a static lifetime equal to that of the program and does
/// not need to be manually freed.
#[no_mangle]
pub extern "C" fn rustls_handshake_kind_str(kind: rustls_handshake_kind) -> rustls_str<'static> {
ffi_panic_boundary! {
rustls_str::from_str_unchecked(match kind {
rustls_handshake_kind::Unknown => "unknown",
rustls_handshake_kind::Full => "full",
rustls_handshake_kind::FullWithHelloRetryRequest => "full with hello retry request",
rustls_handshake_kind::Resumed => "resumed",
})
}
}

impl From<HandshakeKind> for rustls_handshake_kind {
fn from(kind: HandshakeKind) -> Self {
match kind {
HandshakeKind::Full => Self::Full,
HandshakeKind::FullWithHelloRetryRequest => Self::FullWithHelloRetryRequest,
HandshakeKind::Resumed => Self::Resumed,
}
}
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
4 changes: 3 additions & 1 deletion src/panic.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use libc::EINVAL;

use crate::enums::rustls_tls_version;
use crate::enums::{rustls_handshake_kind, rustls_tls_version};
use crate::error::{rustls_io_result, rustls_result};
use crate::rslice::{rustls_slice_bytes, rustls_str};

Expand Down Expand Up @@ -38,6 +38,8 @@ impl Defaultable for () {}

impl Defaultable for rustls_tls_version {}

impl Defaultable for rustls_handshake_kind {}

impl<T> Defaultable for Option<T> {}

impl Defaultable for rustls_slice_bytes<'_> {}
Expand Down
46 changes: 46 additions & 0 deletions src/rustls.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,41 @@
#include <stdint.h>
#include <stdlib.h>

/**
* Describes which sort of handshake happened.
*/
typedef enum rustls_handshake_kind {
/**
* The type of handshake could not be determined.
*
* This variant should not be used.
*/
RUSTLS_HANDSHAKE_KIND_UNKNOWN = 0,
/**
* A full TLS handshake.
*
* This is the typical TLS connection initiation process when resumption is
* not yet unavailable, and the initial client hello was accepted by the server.
*/
RUSTLS_HANDSHAKE_KIND_FULL = 1,
/**
* A full TLS handshake, with an extra round-trip for a hello retry request.
*
* The server can respond with a hello retry request (HRR) if the initial client
* hello is unacceptable for several reasons, the most likely if no supported key
* shares were offered by the client.
*/
RUSTLS_HANDSHAKE_KIND_FULL_WITH_HELLO_RETRY_REQUEST = 2,
/**
* A resumed TLS handshake.
*
* Resumed handshakes involve fewer round trips and less cryptography than
* full ones, but can only happen when the peers have previously done a full
* handshake together, and then remember data about it.
*/
RUSTLS_HANDSHAKE_KIND_RESUMED = 3,
} rustls_handshake_kind;

enum rustls_result {
RUSTLS_RESULT_OK = 7000,
RUSTLS_RESULT_IO = 7001,
Expand Down Expand Up @@ -1850,6 +1885,8 @@ bool rustls_connection_wants_write(const struct rustls_connection *conn);
*/
bool rustls_connection_is_handshaking(const struct rustls_connection *conn);

enum rustls_handshake_kind rustls_connection_handshake_kind(const struct rustls_connection *conn);

/**
* Sets a limit on the internal buffers used to buffer unsent plaintext (prior
* to completing the TLS handshake) and unsent TLS records. By default, there
Expand Down Expand Up @@ -2243,6 +2280,15 @@ rustls_result rustls_default_crypto_provider_random(uint8_t *buff, size_t len);
*/
void rustls_signing_key_free(struct rustls_signing_key *signing_key);

/**
* Convert a `rustls_handshake_kind` to a string with a friendly description of the kind
* of handshake.
*
* The returned `rustls_str` has a static lifetime equal to that of the program and does
* not need to be manually freed.
*/
struct rustls_str rustls_handshake_kind_str(enum rustls_handshake_kind kind);

/**
* After a rustls function returns an error, you may call
* this to get a pointer to a buffer containing a detailed error
Expand Down
7 changes: 6 additions & 1 deletion tests/client.c
Original file line number Diff line number Diff line change
Expand Up @@ -170,8 +170,9 @@ send_request_and_read_response(struct conndata *conn,
unsigned long content_length = 0;
size_t headers_len = 0;
struct rustls_str version;
rustls_handshake_kind hs_kind;
int ciphersuite_id, kex_id;
struct rustls_str ciphersuite_name, kex_name;
struct rustls_str ciphersuite_name, kex_name, hs_kind_name;

version = rustls_version();
memset(buf, '\0', sizeof(buf));
Expand Down Expand Up @@ -298,6 +299,10 @@ send_request_and_read_response(struct conndata *conn,
LOG_SIMPLE("send_request_and_read_response: loop fell through");

drain_plaintext:
hs_kind = rustls_connection_handshake_kind(rconn);
hs_kind_name = rustls_handshake_kind_str(hs_kind);
LOG("handshake kind: %.*s", (int)hs_kind_name.len, hs_kind_name.data);

kex_id = rustls_connection_get_negotiated_key_exchange_group(rconn);
kex_name = rustls_connection_get_negotiated_key_exchange_group_name(rconn);
LOG("negotiated key exchange: %.*s (%#x)",
Expand Down
6 changes: 5 additions & 1 deletion tests/server.c
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,9 @@ handle_conn(struct conndata *conn)
int sockfd = conn->fd;
struct timeval tv;
enum exchange_state state = READING_REQUEST;
rustls_handshake_kind hs_kind;
int ciphersuite_id, kex_id;
struct rustls_str ciphersuite_name, kex_name;
struct rustls_str ciphersuite_name, kex_name, hs_kind_name;

LOG("acccepted conn on fd %d", conn->fd);

Expand Down Expand Up @@ -191,6 +192,9 @@ handle_conn(struct conndata *conn)
if(state == READING_REQUEST && body_beginning(&conn->data) != NULL) {
state = SENT_RESPONSE;
LOG_SIMPLE("writing response");
hs_kind = rustls_connection_handshake_kind(rconn);
hs_kind_name = rustls_handshake_kind_str(hs_kind);
LOG("handshake kind: %.*s", (int)hs_kind_name.len, hs_kind_name.data);
ciphersuite_id = rustls_connection_get_negotiated_ciphersuite(rconn);
ciphersuite_name =
rustls_connection_get_negotiated_ciphersuite_name(rconn);
Expand Down

0 comments on commit 51ac465

Please sign in to comment.