diff --git a/librustls/src/rustls.h b/librustls/src/rustls.h index 56a2be43..41619f01 100644 --- a/librustls/src/rustls.h +++ b/librustls/src/rustls.h @@ -2365,22 +2365,22 @@ rustls_result rustls_server_connection_new(const struct rustls_server_config *co struct rustls_connection **conn_out); /** - * Copy the server name from the server name indication (SNI) extension to `buf`. + * Returns a `rustls_str` reference to the server name sent by the client in a server name + * indication (SNI) extension. * - * `buf` can hold up to `count` bytes, and the length of that server name in `out_n`. + * The returned `rustls_str` is valid until the next mutating function call affecting the + * connection. A mutating function call is one where the first argument has type + * `struct rustls_connection *` (as opposed to `const struct rustls_connection *`). The caller + * does not need to free the `rustls_str`. * - * The string is stored in UTF-8 with no terminating NUL byte. + * Returns a zero-length `rustls_str` if: * - * Returns RUSTLS_RESULT_INSUFFICIENT_SIZE if the SNI hostname is longer than `count`. - * - * Returns Ok with *out_n == 0 if there is no SNI hostname available on this connection - * because it hasn't been processed yet, or because the client did not send SNI. - * + * - the connection is not a server connection. + * - the connection is a server connection but the SNI extension in the client hello has not + * been processed during the handshake yet. Check `rustls_connection_is_handshaking`. + * - the SNI value contains null bytes. */ -rustls_result rustls_server_connection_get_server_name(const struct rustls_connection *conn, - uint8_t *buf, - size_t count, - size_t *out_n); +struct rustls_str rustls_server_connection_get_server_name(const struct rustls_connection *conn); /** * Register a callback to be invoked when a connection created from this config @@ -2428,13 +2428,16 @@ rustls_result rustls_client_hello_select_certified_key(const struct rustls_clien * keys and values are highly sensitive data, containing enough information * to break the security of the connections involved. * + * If `builder`, `get_cb`, or `put_cb` are NULL, this function will return + * immediately without doing anything. + * * If `userdata` has been set with rustls_connection_set_userdata, it * will be passed to the callbacks. Otherwise the userdata param passed to * the callbacks will be NULL. */ -rustls_result rustls_server_config_builder_set_persistence(struct rustls_server_config_builder *builder, - rustls_session_store_get_callback get_cb, - rustls_session_store_put_callback put_cb); +void rustls_server_config_builder_set_persistence(struct rustls_server_config_builder *builder, + rustls_session_store_get_callback get_cb, + rustls_session_store_put_callback put_cb); /** * Free a `rustls_client_cert_verifier` previously returned from diff --git a/librustls/src/server.rs b/librustls/src/server.rs index a5c595d2..b2d55a68 100644 --- a/librustls/src/server.rs +++ b/librustls/src/server.rs @@ -443,55 +443,33 @@ impl rustls_server_config { } } -/// Copy the server name from the server name indication (SNI) extension to `buf`. +/// Returns a `rustls_str` reference to the server name sent by the client in a server name +/// indication (SNI) extension. /// -/// `buf` can hold up to `count` bytes, and the length of that server name in `out_n`. +/// The returned `rustls_str` is valid until the next mutating function call affecting the +/// connection. A mutating function call is one where the first argument has type +/// `struct rustls_connection *` (as opposed to `const struct rustls_connection *`). The caller +/// does not need to free the `rustls_str`. /// -/// The string is stored in UTF-8 with no terminating NUL byte. +/// Returns a zero-length `rustls_str` if: /// -/// Returns RUSTLS_RESULT_INSUFFICIENT_SIZE if the SNI hostname is longer than `count`. -/// -/// Returns Ok with *out_n == 0 if there is no SNI hostname available on this connection -/// because it hasn't been processed yet, or because the client did not send SNI. -/// +/// - the connection is not a server connection. +/// - the connection is a server connection but the SNI extension in the client hello has not +/// been processed during the handshake yet. Check `rustls_connection_is_handshaking`. +/// - the SNI value contains null bytes. #[no_mangle] pub extern "C" fn rustls_server_connection_get_server_name( conn: *const rustls_connection, - buf: *mut u8, - count: size_t, - out_n: *mut size_t, -) -> rustls_result { +) -> rustls_str<'static> { ffi_panic_boundary! { - let conn = try_ref_from_ptr!(conn); - if buf.is_null() { - return rustls_result::NullParameter; - } - if out_n.is_null() { - return rustls_result::NullParameter; - } - let server_connection = match conn.as_server() { - Some(s) => s, - _ => return rustls_result::InvalidParameter, + let Some(server_connection) = try_ref_from_ptr!(conn).as_server() else { + return rustls_str::default(); }; - let sni_hostname = match server_connection.server_name() { - Some(sni_hostname) => sni_hostname, - None => { - unsafe { - *out_n = 0; - } - return rustls_result::Ok; - } + let Some(sni_hostname) = server_connection.server_name() else { + return rustls_str::default(); }; - let len = sni_hostname.len(); - if len > count { - unsafe { *out_n = 0 } - return rustls_result::InsufficientSize; - } - unsafe { - std::ptr::copy_nonoverlapping(sni_hostname.as_ptr(), buf, len); - *out_n = len; - } - rustls_result::Ok + let res = rustls_str::try_from(sni_hostname).unwrap_or_default(); + unsafe { res.into_static() } } } @@ -743,6 +721,9 @@ impl rustls_server_config_builder { /// keys and values are highly sensitive data, containing enough information /// to break the security of the connections involved. /// + /// If `builder`, `get_cb`, or `put_cb` are NULL, this function will return + /// immediately without doing anything. + /// /// If `userdata` has been set with rustls_connection_set_userdata, it /// will be passed to the callbacks. Otherwise the userdata param passed to /// the callbacks will be NULL. @@ -751,19 +732,17 @@ impl rustls_server_config_builder { builder: *mut rustls_server_config_builder, get_cb: rustls_session_store_get_callback, put_cb: rustls_session_store_put_callback, - ) -> rustls_result { + ) { ffi_panic_boundary! { - let get_cb = match get_cb { - Some(cb) => cb, - None => return rustls_result::NullParameter, + let Some(get_cb) = get_cb else { + return; }; - let put_cb = match put_cb { - Some(cb) => cb, - None => return rustls_result::NullParameter, + let Some(put_cb) = put_cb else { + return; }; - let builder = try_mut_from_ptr!(builder); - builder.session_storage = Some(Arc::new(SessionStoreBroker::new(get_cb, put_cb))); - rustls_result::Ok + + try_mut_from_ptr!(builder).session_storage = + Some(Arc::new(SessionStoreBroker::new(get_cb, put_cb))); } } } diff --git a/librustls/tests/common.c b/librustls/tests/common.c index 7755a7dc..dfa2b238 100644 --- a/librustls/tests/common.c +++ b/librustls/tests/common.c @@ -486,6 +486,14 @@ log_connection_info(const rustls_connection *rconn) else { LOG_SIMPLE("negotiated ALPN protocol: none"); } + + // We can unconditionally call this function whether we have a server + // or client connection, as it will return an empty rustls_str if it was a + // client connection. + const rustls_str sni = rustls_server_connection_get_server_name(rconn); + if(sni.len > 0) { + LOG("client SNI: '%.*s'", (int)sni.len, sni.data); + } } // TLS 1.2 and TLS 1.3, matching Rustls default.