Skip to content

Commit

Permalink
Implement SSL_get_servername and SSL_get_servername_type
Browse files Browse the repository at this point in the history
  • Loading branch information
ctz committed Apr 3, 2024
1 parent 3f710c4 commit 0662104
Show file tree
Hide file tree
Showing 6 changed files with 88 additions and 5 deletions.
4 changes: 2 additions & 2 deletions rustls-libssl/MATRIX.md
Original file line number Diff line number Diff line change
Expand Up @@ -362,8 +362,8 @@
| `SSL_get_security_level` | | | |
| `SSL_get_selected_srtp_profile` [^srtp] | | | |
| `SSL_get_server_random` | | | |
| `SSL_get_servername` | | :white_check_mark: | |
| `SSL_get_servername_type` | | | |
| `SSL_get_servername` | | :white_check_mark: | :white_check_mark: |
| `SSL_get_servername_type` | | | :white_check_mark: |
| `SSL_get_session` | | :white_check_mark: | :exclamation: [^stub] |
| `SSL_get_shared_ciphers` | | | |
| `SSL_get_shared_sigalgs` | | | |
Expand Down
2 changes: 2 additions & 0 deletions rustls-libssl/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,8 @@ const ENTRYPOINTS: &[&str] = &[
"SSL_get_peer_cert_chain",
"SSL_get_privatekey",
"SSL_get_rbio",
"SSL_get_servername",
"SSL_get_servername_type",
"SSL_get_session",
"SSL_get_shutdown",
"SSL_get_state",
Expand Down
39 changes: 37 additions & 2 deletions rustls-libssl/src/entry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ use std::sync::Mutex;
use std::{fs, io, path::PathBuf};

use openssl_sys::{
stack_st_X509, OPENSSL_malloc, EVP_PKEY, OPENSSL_NPN_NEGOTIATED, OPENSSL_NPN_NO_OVERLAP, X509,
X509_STORE, X509_STORE_CTX, X509_V_ERR_UNSPECIFIED,
stack_st_X509, OPENSSL_malloc, TLSEXT_NAMETYPE_host_name, EVP_PKEY, OPENSSL_NPN_NEGOTIATED,
OPENSSL_NPN_NO_OVERLAP, X509, X509_STORE, X509_STORE_CTX, X509_V_ERR_UNSPECIFIED,
};
use rustls::pki_types::{CertificateDer, PrivateKeyDer, PrivatePkcs8KeyDer};

Expand Down Expand Up @@ -1117,6 +1117,41 @@ entry! {
}
}

entry! {
pub fn _SSL_get_servername(ssl: *const SSL, ty: c_int) -> *const c_char {
let ssl = try_clone_arc!(ssl);

if ty != TLSEXT_NAMETYPE_host_name {
return ptr::null();
}

let ret = if let Ok(mut inner) = ssl.lock() {
inner.server_name_pointer()
} else {
ptr::null()
};
ret
}
}

entry! {
pub fn _SSL_get_servername_type(ssl: *const SSL) -> c_int {
let ssl = try_clone_arc!(ssl);

let any_server_name = if let Ok(mut inner) = ssl.lock() {
!inner.server_name_pointer().is_null()
} else {
false
};

if any_server_name {
TLSEXT_NAMETYPE_host_name
} else {
-1
}
}
}

impl Castable for SSL {
type Ownership = OwnershipArc;
type RustType = Mutex<SSL>;
Expand Down
37 changes: 36 additions & 1 deletion rustls-libssl/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use core::ffi::{c_int, c_uint, c_void, CStr};
use core::ffi::{c_char, c_int, c_uint, c_void, CStr};
use core::{mem, ptr};
use std::ffi::CString;
use std::io::{ErrorKind, Read, Write};
use std::sync::{Arc, Mutex};

Expand Down Expand Up @@ -360,6 +361,7 @@ struct Ssl {
alpn_callback: callbacks::AlpnCallbackConfig,
cert_callback: callbacks::CertCallbackConfig,
sni_server_name: Option<ServerName<'static>>,
server_name: Option<CString>,
bio: Option<bio::Bio>,
conn: ConnState,
peer_cert: Option<x509::OwnedX509>,
Expand Down Expand Up @@ -390,6 +392,7 @@ impl Ssl {
alpn_callback: inner.alpn_callback.clone(),
cert_callback: inner.cert_callback.clone(),
sni_server_name: None,
server_name: None,
bio: None,
conn: ConnState::Nothing,
peer_cert: None,
Expand Down Expand Up @@ -472,6 +475,33 @@ impl Ssl {
}
}

fn server_name_pointer(&mut self) -> *const c_char {
// This does double duty (see `SSL_get_servername`):
//
// for clients, it is just `sni_server_name`
// (filled in here, lazily)
//
// for servers, it is the client's offered SNI name
// (filled in below in `prepare_accepted_callbacks`)
//
// the remaining annoyance is that the returned pointer has to NUL-terminated.

match self.mode {
ConnMode::Server => self.server_name.as_ref().map(|cstr| cstr.as_ptr()),
ConnMode::Client | ConnMode::Unknown => match &self.server_name {
Some(existing) => Some(existing.as_ptr()),
None => {
self.server_name = self
.sni_server_name
.as_ref()
.and_then(|name| CString::new(name.to_str().as_bytes()).ok());
self.server_name.as_ref().map(|cstr| cstr.as_ptr())
}
},
}
.unwrap_or_else(ptr::null)
}

fn set_bio(&mut self, bio: bio::Bio) {
self.bio = Some(bio);
}
Expand Down Expand Up @@ -573,6 +603,11 @@ impl Ssl {
_ => unreachable!(),
};

self.server_name = accepted
.client_hello()
.server_name()
.and_then(|sni| CString::new(sni.as_bytes()).ok());

if let Some(alpn_iter) = accepted.client_hello().alpn() {
let offer = encode_alpn(alpn_iter);
callbacks.add(Box::new(callbacks::AlpnPendingCallback {
Expand Down
8 changes: 8 additions & 0 deletions rustls-libssl/tests/client.c
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,14 @@ int main(int argc, char **argv) {
printf("SSL_new: SSL_get_certificate %s SSL_CTX_get0_certificate\n",
SSL_get_certificate(ssl) == client_cert ? "same as" : "differs to");
state(ssl);
printf("SSL_get_servername: %s (%d)\n",
SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name),
SSL_get_servername_type(ssl));
TRACE(SSL_set_tlsext_host_name(ssl, "localhost"));
dump_openssl_error_stack();
printf("SSL_get_servername: %s (%d)\n",
SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name),
SSL_get_servername_type(ssl));
TRACE(SSL_set1_host(ssl, host));
dump_openssl_error_stack();
TRACE(SSL_set_fd(ssl, sock));
Expand Down
3 changes: 3 additions & 0 deletions rustls-libssl/tests/server.c
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,9 @@ int main(int argc, char **argv) {
printf("version: %s\n", SSL_get_version(ssl));
printf("verify-result: %ld\n", SSL_get_verify_result(ssl));
printf("cipher: %s\n", SSL_CIPHER_standard_name(SSL_get_current_cipher(ssl)));
printf("SSL_get_servername: %s (%d)\n",
SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name),
SSL_get_servername_type(ssl));

// check the peer certificate and chain
X509 *cert = SSL_get1_peer_certificate(ssl);
Expand Down

0 comments on commit 0662104

Please sign in to comment.