From cb4263f91e6d772e097c9c4a366921b68d804585 Mon Sep 17 00:00:00 2001 From: Geoffroy Couprie Date: Sat, 21 Nov 2015 17:46:39 +0100 Subject: [PATCH 1/6] test SNI support --- openssl-sys/src/lib.rs | 6 +++ openssl/src/ssl/mod.rs | 96 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 102 insertions(+) diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index 239f8d9e..be33ea4c 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -135,6 +135,8 @@ pub const PKCS5_SALT_LEN: c_int = 8; pub const SSL_CTRL_OPTIONS: c_int = 32; pub const SSL_CTRL_CLEAR_OPTIONS: c_int = 77; +pub const SSL_CTRL_SET_TLSEXT_SERVERNAME_CB: c_int = 53; +pub const SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG: c_int = 54; pub const SSL_CTRL_SET_TLSEXT_HOSTNAME: c_int = 55; pub const SSL_CTRL_EXTRA_CHAIN_CERT: c_int = 14; @@ -538,6 +540,8 @@ extern "C" { pub fn SSL_state_string(ssl: *mut SSL) -> *const c_char; pub fn SSL_state_string_long(ssl: *mut SSL) -> *const c_char; + pub fn SSL_get_servername(ssl: *const SSL, name_type: c_long) -> *const c_char; + pub fn SSL_COMP_get_name(comp: *const COMP_METHOD) -> *const c_char; pub fn SSL_CTX_new(method: *const SSL_METHOD) -> *mut SSL_CTX; @@ -567,6 +571,8 @@ extern "C" { pub fn SSL_CTX_set_cipher_list(ssl: *mut SSL_CTX, s: *const c_char) -> c_int; pub fn SSL_CTX_ctrl(ssl: *mut SSL_CTX, cmd: c_int, larg: c_long, parg: *mut c_void) -> c_long; + pub fn SSL_CTX_callback_ctrl(ssl: *mut SSL_CTX, cmd: c_int, callback: Option) -> c_long; + #[cfg(feature = "npn")] pub fn SSL_CTX_set_next_protos_advertised_cb(ssl: *mut SSL_CTX, cb: extern "C" fn(ssl: *mut SSL, diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index cca369a2..f73c263a 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -32,6 +32,7 @@ pub mod error; mod tests; static mut VERIFY_IDX: c_int = -1; +static mut SNI_IDX: c_int = -1; /// Manually initialize SSL. /// It is optional to call this function and safe to do so more than once. @@ -46,6 +47,11 @@ pub fn init() { None, None); assert!(verify_idx >= 0); VERIFY_IDX = verify_idx; + + let sni_idx = ffi::SSL_CTX_get_ex_new_index(0, ptr::null(), None, + None, None); + assert!(sni_idx >= 0); + SNI_IDX = sni_idx; }); } } @@ -297,6 +303,51 @@ extern fn raw_verify_with_data(preverify_ok: c_int, } } +extern fn raw_sni(ssl: *mut ffi::SSL, ad: &mut c_int, arg: *mut c_void) + -> c_int { + println!("openssl called raw_sni. ad=={:?}", *ad); + unsafe { + let ssl_ctx = ffi::SSL_get_SSL_CTX(ssl); + let callback = ffi::SSL_CTX_get_ex_data(ssl_ctx, SNI_IDX); + let callback: Option = mem::transmute(callback); + let mut ssl = Ssl { ssl: ssl }; + println!("openssl got callback"); + + let res = match callback { + None => ffi::SSL_TLSEXT_ERR_ALERT_FATAL, + Some(callback) => callback(&mut ssl, ad) + }; + println!("openssl got callback result: {}", res); + res + } +} + +extern fn raw_sni_with_data(ssl: *mut ffi::SSL, ad: &mut c_int, arg: *mut c_void) -> c_int + where T: Any + 'static { + unsafe { + let ssl_ctx = ffi::SSL_get_SSL_CTX(ssl); + + let callback = ffi::SSL_CTX_get_ex_data(ssl_ctx, SNI_IDX); + let callback: Option> = mem::transmute(callback); + let mut ssl = Ssl { ssl: ssl }; + + let data: Box = mem::transmute(arg); + + let res = match callback { + None => ffi::SSL_TLSEXT_ERR_ALERT_FATAL, + Some(callback) => callback(&mut ssl, ad, &*data) + }; + + // Since data might be required on the next verification + // it is time to forget about it and avoid dropping + // data will be freed once OpenSSL considers it is time + // to free all context data + mem::forget(data); + res + } +} + + #[cfg(any(feature = "npn", feature = "alpn"))] unsafe fn select_proto_using(ssl: *mut ffi::SSL, out: *mut *mut c_uchar, outlen: *mut c_uchar, @@ -404,6 +455,11 @@ pub type VerifyCallbackData = fn(preverify_ok: bool, x509_ctx: &X509StoreContext, data: &T) -> bool; +/// The signature of functions that can be used to choose the context depending on the server name +pub type ServerNameCallback = fn(ssl: &mut Ssl, ad: &mut i32) -> i32; + +pub type ServerNameCallbackData = fn(ssl: &mut Ssl, ad: &mut i32, data: &T) -> i32; + // FIXME: macro may be instead of inlining? #[inline] fn wrap_ssl_result(res: c_int) -> Result<(),SslError> { @@ -485,6 +541,31 @@ impl SslContext { } } + /// Configures the certificate verification method for new connections. + pub fn set_servername_callback(&mut self, callback: Option) { + unsafe { + ffi::SSL_CTX_set_ex_data(self.ctx, SNI_IDX, + mem::transmute(callback)); + //let f: extern fn(c_int, *mut ffi::X509_STORE_CTX) -> c_int = raw_sni; + let f: extern fn() = mem::transmute(raw_sni); + ffi::SSL_CTX_callback_ctrl(self.ctx, ffi::SSL_CTRL_SET_TLSEXT_SERVERNAME_CB, Some(f)); + } + } + + pub fn set_servername_callback_with_data(&mut self, callback: ServerNameCallbackData, + data: T) + where T: Any + 'static { + let data = Box::new(data); + unsafe { + ffi::SSL_CTX_set_ex_data(self.ctx, SNI_IDX, + mem::transmute(Some(callback))); + + ffi::SSL_CTX_ctrl(self.ctx, ffi::SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG, 0, mem::transmute(data)); + let f: extern fn() = mem::transmute(raw_sni_with_data::); + ffi::SSL_CTX_callback_ctrl(self.ctx, ffi::SSL_CTRL_SET_TLSEXT_SERVERNAME_CB, Some(f)); + } + } + /// Sets verification depth pub fn set_verify_depth(&mut self, depth: u32) { unsafe { @@ -673,6 +754,7 @@ impl SslContext { ffi::SSL_CTX_set_alpn_select_cb(self.ctx, raw_alpn_select_cb, ptr::null_mut()); } } + } #[allow(dead_code)] @@ -886,6 +968,20 @@ impl Ssl { SslMethod::from_raw(method) } } + + /// Returns the server name for the current connection + pub fn get_servername(&self) -> Option { + let name = unsafe { ffi::SSL_get_servername(self.ssl, ffi::TLSEXT_NAMETYPE_host_name) }; + if name == ptr::null() { + return None; + } + + println!("openssl will return servername"); + unsafe { + String::from_utf8(CStr::from_ptr(name).to_bytes().to_vec()).ok() + } + } + } macro_rules! make_LibSslError { From dba3a0ced24147414abaa9f8394b9f249b08f599 Mon Sep 17 00:00:00 2001 From: Geoffroy Couprie Date: Sun, 22 Nov 2015 20:01:41 +0100 Subject: [PATCH 2/6] implement get/set ssl context --- openssl-sys/src/lib.rs | 1 + openssl/src/ssl/mod.rs | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index be33ea4c..e2eaab38 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -534,6 +534,7 @@ extern "C" { pub fn SSL_write(ssl: *mut SSL, buf: *const c_void, num: c_int) -> c_int; pub fn SSL_get_ex_data_X509_STORE_CTX_idx() -> c_int; pub fn SSL_get_SSL_CTX(ssl: *mut SSL) -> *mut SSL_CTX; + pub fn SSL_set_SSL_CTX(ssl: *mut SSL, ctx: *mut SSL_CTX) -> *mut SSL_CTX; pub fn SSL_get_current_compression(ssl: *mut SSL) -> *const COMP_METHOD; pub fn SSL_get_peer_certificate(ssl: *mut SSL) -> *mut X509; pub fn SSL_get_ssl_method(ssl: *mut SSL) -> *const SSL_METHOD; diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index f73c263a..736e6b4c 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -982,6 +982,14 @@ impl Ssl { } } + pub fn set_ssl_context(&self, ctx: &SslContext) -> SslContext { + SslContext { ctx: unsafe { ffi::SSL_set_SSL_CTX(self.ssl, ctx.ctx) } } + } + + pub fn get_ssl_context(&self) -> SslContext { + let ssl_ctx = unsafe { ffi::SSL_get_SSL_CTX(self.ssl) }; + SslContext { ctx: ssl_ctx } + } } macro_rules! make_LibSslError { From 667e3f44b99450fbf9b1d80a8949183ce295fbf8 Mon Sep 17 00:00:00 2001 From: Geoffroy Couprie Date: Sun, 22 Nov 2015 20:01:56 +0100 Subject: [PATCH 3/6] Avoid freeing the SSL object when Ssl is dropped --- openssl/src/ssl/mod.rs | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index 736e6b4c..e49b28b2 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -305,19 +305,19 @@ extern fn raw_verify_with_data(preverify_ok: c_int, extern fn raw_sni(ssl: *mut ffi::SSL, ad: &mut c_int, arg: *mut c_void) -> c_int { - println!("openssl called raw_sni. ad=={:?}", *ad); unsafe { let ssl_ctx = ffi::SSL_get_SSL_CTX(ssl); let callback = ffi::SSL_CTX_get_ex_data(ssl_ctx, SNI_IDX); let callback: Option = mem::transmute(callback); - let mut ssl = Ssl { ssl: ssl }; - println!("openssl got callback"); + let mut s = Ssl { ssl: ssl }; let res = match callback { None => ffi::SSL_TLSEXT_ERR_ALERT_FATAL, - Some(callback) => callback(&mut ssl, ad) + Some(callback) => callback(&mut s, ad) }; - println!("openssl got callback result: {}", res); + + // Allows dropping the Ssl instance without calling SSL_FREE on the SSL object + s.ssl = ptr::null_mut() as *mut ffi::SSL; res } } @@ -329,15 +329,18 @@ extern fn raw_sni_with_data(ssl: *mut ffi::SSL, ad: &mut c_int, arg: *mut c_v let callback = ffi::SSL_CTX_get_ex_data(ssl_ctx, SNI_IDX); let callback: Option> = mem::transmute(callback); - let mut ssl = Ssl { ssl: ssl }; + let mut s = Ssl { ssl: ssl }; let data: Box = mem::transmute(arg); let res = match callback { None => ffi::SSL_TLSEXT_ERR_ALERT_FATAL, - Some(callback) => callback(&mut ssl, ad, &*data) + Some(callback) => callback(&mut s, ad, &*data) }; + // Allows dropping the Ssl instance without calling SSL_FREE on the SSL object + s.ssl = ptr::null_mut() as *mut ffi::SSL; + // Since data might be required on the next verification // it is time to forget about it and avoid dropping // data will be freed once OpenSSL considers it is time @@ -541,7 +544,10 @@ impl SslContext { } } - /// Configures the certificate verification method for new connections. + /// Configures the server name indication (SNI) callback for new connections + /// + /// obtain the server name with `get_servername` then set the corresponding context + /// with `set_ssl_context` pub fn set_servername_callback(&mut self, callback: Option) { unsafe { ffi::SSL_CTX_set_ex_data(self.ctx, SNI_IDX, @@ -552,6 +558,8 @@ impl SslContext { } } + /// Configures the server name indication (SNI) callback for new connections + /// carrying supplied data pub fn set_servername_callback_with_data(&mut self, callback: ServerNameCallbackData, data: T) where T: Any + 'static { @@ -969,23 +977,24 @@ impl Ssl { } } - /// Returns the server name for the current connection + /// Returns the server's name for the current connection pub fn get_servername(&self) -> Option { let name = unsafe { ffi::SSL_get_servername(self.ssl, ffi::TLSEXT_NAMETYPE_host_name) }; if name == ptr::null() { return None; } - println!("openssl will return servername"); unsafe { String::from_utf8(CStr::from_ptr(name).to_bytes().to_vec()).ok() } } + /// change the context corresponding to the current connection pub fn set_ssl_context(&self, ctx: &SslContext) -> SslContext { SslContext { ctx: unsafe { ffi::SSL_set_SSL_CTX(self.ssl, ctx.ctx) } } } + /// obtain the context corresponding to the current connection pub fn get_ssl_context(&self) -> SslContext { let ssl_ctx = unsafe { ffi::SSL_get_SSL_CTX(self.ssl) }; SslContext { ctx: ssl_ctx } From e48694432008c752d17dbe08a26a2f7fbeb18155 Mon Sep 17 00:00:00 2001 From: Geoffroy Couprie Date: Wed, 25 Nov 2015 07:51:22 +0100 Subject: [PATCH 4/6] fix memory management --- openssl/src/ssl/mod.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index e49b28b2..8de09396 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -317,7 +317,7 @@ extern fn raw_sni(ssl: *mut ffi::SSL, ad: &mut c_int, arg: *mut c_void) }; // Allows dropping the Ssl instance without calling SSL_FREE on the SSL object - s.ssl = ptr::null_mut() as *mut ffi::SSL; + mem::forget(s); res } } @@ -331,7 +331,7 @@ extern fn raw_sni_with_data(ssl: *mut ffi::SSL, ad: &mut c_int, arg: *mut c_v let callback: Option> = mem::transmute(callback); let mut s = Ssl { ssl: ssl }; - let data: Box = mem::transmute(arg); + let data: &T = mem::transmute(arg); let res = match callback { None => ffi::SSL_TLSEXT_ERR_ALERT_FATAL, @@ -339,13 +339,12 @@ extern fn raw_sni_with_data(ssl: *mut ffi::SSL, ad: &mut c_int, arg: *mut c_v }; // Allows dropping the Ssl instance without calling SSL_FREE on the SSL object - s.ssl = ptr::null_mut() as *mut ffi::SSL; + mem::forget(s); // Since data might be required on the next verification // it is time to forget about it and avoid dropping // data will be freed once OpenSSL considers it is time // to free all context data - mem::forget(data); res } } @@ -552,7 +551,6 @@ impl SslContext { unsafe { ffi::SSL_CTX_set_ex_data(self.ctx, SNI_IDX, mem::transmute(callback)); - //let f: extern fn(c_int, *mut ffi::X509_STORE_CTX) -> c_int = raw_sni; let f: extern fn() = mem::transmute(raw_sni); ffi::SSL_CTX_callback_ctrl(self.ctx, ffi::SSL_CTRL_SET_TLSEXT_SERVERNAME_CB, Some(f)); } From 7835ea1c906450c524b8575a668860ee9e0b2d85 Mon Sep 17 00:00:00 2001 From: Geoffroy Couprie Date: Wed, 25 Nov 2015 08:10:36 +0100 Subject: [PATCH 5/6] Make shims for SSL_CTX_ctrl and SSL_CTX_callback_ctrl macro wrappers --- openssl-sys-extras/src/lib.rs | 6 +++++- openssl-sys-extras/src/openssl_shim.c | 8 ++++++++ openssl-sys/src/lib.rs | 3 --- openssl/src/ssl/mod.rs | 6 +++--- 4 files changed, 16 insertions(+), 7 deletions(-) diff --git a/openssl-sys-extras/src/lib.rs b/openssl-sys-extras/src/lib.rs index a768f436..f17c7fd5 100644 --- a/openssl-sys-extras/src/lib.rs +++ b/openssl-sys-extras/src/lib.rs @@ -4,7 +4,7 @@ extern crate openssl_sys; extern crate libc; -use libc::{c_int, c_uint, c_long, c_char}; +use libc::{c_int, c_uint, c_long, c_char, c_void}; use openssl_sys::{HMAC_CTX, EVP_MD, ENGINE, SSL_CTX, BIO, X509, stack_st_X509_EXTENSION, SSL, DH}; macro_rules! import_options { @@ -65,4 +65,8 @@ extern { pub fn SSL_CTX_set_tmp_dh(s: *mut SSL, dh: *const DH) -> c_long; #[link_name = "X509_get_extensions_shim"] pub fn X509_get_extensions(x: *mut X509) -> *mut stack_st_X509_EXTENSION; + #[link_name = "SSL_CTX_set_tlsext_servername_callback_shim"] + pub fn SSL_CTX_set_tlsext_servername_callback(ssl: *mut SSL_CTX, callback: Option); + #[link_name = "SSL_CTX_set_tlsext_servername_arg_shim"] + pub fn SSL_CTX_set_tlsext_servername_arg(ssl: *mut SSL_CTX, arg: *const c_void); } diff --git a/openssl-sys-extras/src/openssl_shim.c b/openssl-sys-extras/src/openssl_shim.c index 84adb47b..302e539a 100644 --- a/openssl-sys-extras/src/openssl_shim.c +++ b/openssl-sys-extras/src/openssl_shim.c @@ -115,6 +115,14 @@ long SSL_CTX_set_tmp_dh_shim(SSL_CTX *ctx, DH *dh) { return SSL_CTX_set_tmp_dh(ctx, dh); } +long SSL_CTX_set_tlsext_servername_callback_shim(SSL_CTX *ctx, int (*callback)(SSL_CTX *, int *, void*)) { + return SSL_CTX_set_tlsext_servername_callback(ctx, callback); +} + +long SSL_CTX_set_tlsext_servername_arg_shim(SSL_CTX *ctx, void* arg) { + return SSL_CTX_set_tlsext_servername_arg(ctx, arg); +} + #if OPENSSL_VERSION_NUMBER >= 0x10002000L int SSL_CTX_set_ecdh_auto_shim(SSL_CTX *ctx, int onoff) { return SSL_CTX_set_ecdh_auto(ctx, onoff); diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index e2eaab38..b9b4e3e9 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -571,9 +571,6 @@ extern "C" { pub fn SSL_CTX_set_cipher_list(ssl: *mut SSL_CTX, s: *const c_char) -> c_int; - pub fn SSL_CTX_ctrl(ssl: *mut SSL_CTX, cmd: c_int, larg: c_long, parg: *mut c_void) -> c_long; - pub fn SSL_CTX_callback_ctrl(ssl: *mut SSL_CTX, cmd: c_int, callback: Option) -> c_long; - #[cfg(feature = "npn")] pub fn SSL_CTX_set_next_protos_advertised_cb(ssl: *mut SSL_CTX, cb: extern "C" fn(ssl: *mut SSL, diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index 8de09396..b25e7d28 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -552,7 +552,7 @@ impl SslContext { ffi::SSL_CTX_set_ex_data(self.ctx, SNI_IDX, mem::transmute(callback)); let f: extern fn() = mem::transmute(raw_sni); - ffi::SSL_CTX_callback_ctrl(self.ctx, ffi::SSL_CTRL_SET_TLSEXT_SERVERNAME_CB, Some(f)); + ffi_extras::SSL_CTX_set_tlsext_servername_callback(self.ctx, Some(f)); } } @@ -566,9 +566,9 @@ impl SslContext { ffi::SSL_CTX_set_ex_data(self.ctx, SNI_IDX, mem::transmute(Some(callback))); - ffi::SSL_CTX_ctrl(self.ctx, ffi::SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG, 0, mem::transmute(data)); + ffi_extras::SSL_CTX_set_tlsext_servername_arg(self.ctx, mem::transmute(data)); let f: extern fn() = mem::transmute(raw_sni_with_data::); - ffi::SSL_CTX_callback_ctrl(self.ctx, ffi::SSL_CTRL_SET_TLSEXT_SERVERNAME_CB, Some(f)); + ffi_extras::SSL_CTX_set_tlsext_servername_callback(self.ctx, Some(f)); } } From 6850c810d32a11330c9b1dd4889b447fa8434c36 Mon Sep 17 00:00:00 2001 From: Geoffroy Couprie Date: Thu, 3 Dec 2015 12:26:55 +0100 Subject: [PATCH 6/6] Increment SSL_CTX's reference count in Ssl::get_ssl_context() Without this, whenever the returned SslContext is released, the refcount of the underlying SSL_CTX will decrease and it will be freed too soon --- openssl-sys-extras/src/lib.rs | 2 ++ openssl-sys-extras/src/openssl_shim.c | 5 +++++ openssl/src/ssl/mod.rs | 1 + 3 files changed, 8 insertions(+) diff --git a/openssl-sys-extras/src/lib.rs b/openssl-sys-extras/src/lib.rs index f17c7fd5..69a1fee9 100644 --- a/openssl-sys-extras/src/lib.rs +++ b/openssl-sys-extras/src/lib.rs @@ -69,4 +69,6 @@ extern { pub fn SSL_CTX_set_tlsext_servername_callback(ssl: *mut SSL_CTX, callback: Option); #[link_name = "SSL_CTX_set_tlsext_servername_arg_shim"] pub fn SSL_CTX_set_tlsext_servername_arg(ssl: *mut SSL_CTX, arg: *const c_void); + #[link_name = "SSL_CTX_increment_refcount_shim"] + pub fn SSL_CTX_increment_refcount(ssl: *mut SSL_CTX) -> c_long; } diff --git a/openssl-sys-extras/src/openssl_shim.c b/openssl-sys-extras/src/openssl_shim.c index 302e539a..51630daf 100644 --- a/openssl-sys-extras/src/openssl_shim.c +++ b/openssl-sys-extras/src/openssl_shim.c @@ -123,6 +123,11 @@ long SSL_CTX_set_tlsext_servername_arg_shim(SSL_CTX *ctx, void* arg) { return SSL_CTX_set_tlsext_servername_arg(ctx, arg); } +long SSL_CTX_increment_refcount_shim(SSL_CTX *ctx) { + int i = CRYPTO_add(&ctx->references,1,CRYPTO_LOCK_SSL_CTX); + return i; +} + #if OPENSSL_VERSION_NUMBER >= 0x10002000L int SSL_CTX_set_ecdh_auto_shim(SSL_CTX *ctx, int onoff) { return SSL_CTX_set_ecdh_auto(ctx, onoff); diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index b25e7d28..a2096f41 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -995,6 +995,7 @@ impl Ssl { /// obtain the context corresponding to the current connection pub fn get_ssl_context(&self) -> SslContext { let ssl_ctx = unsafe { ffi::SSL_get_SSL_CTX(self.ssl) }; + let count = unsafe { ffi_extras::SSL_CTX_increment_refcount(ssl_ctx) }; SslContext { ctx: ssl_ctx } } }