1use crate::socket;
4use crate::str::String;
5use crate::options::Options;
6use crate::defs::MAX_HOSTNAME_LEN;
7use crate::error::{error, ErrorCode};
8
9use core::ptr::{self, NonNull};
10use core::ffi::CStr;
11
12use nng_c_sys as sys;
13use sys::{nng_tls_mode, nng_tls_auth_mode, nng_tls_version};
14use sys::nng_tls_config;
15
16pub fn get_engine_name() -> &'static str {
18 let name = unsafe {
20 CStr::from_ptr(
21 nng_c_sys::nng_tls_engine_name()
22 )
23 };
24
25 name.to_str().unwrap_or("unknown")
26}
27
28#[derive(Debug, Clone)]
29pub struct CA<'a> {
31 pub cert: String<'a>,
33 pub crl: Option<String<'a>>,
35}
36
37#[derive(Debug, Clone)]
38pub struct OwnCert<'a> {
40 pub cert: String<'a>,
42 pub key: String<'a>,
44 pub pass: Option<String<'a>>,
46}
47
48#[derive(Copy, Clone, Debug)]
50#[repr(i32)]
51pub enum Auth {
52 None = nng_tls_auth_mode::NNG_TLS_AUTH_MODE_NONE,
54 Optional = nng_tls_auth_mode::NNG_TLS_AUTH_MODE_OPTIONAL,
56 Required = nng_tls_auth_mode::NNG_TLS_AUTH_MODE_REQUIRED,
58}
59
60#[derive(Copy, Clone, Debug)]
62#[repr(i32)]
63pub enum Version {
64 Tls1_0 = nng_tls_version::NNG_TLS_1_0,
66 Tls1_1 = nng_tls_version::NNG_TLS_1_1,
68 Tls1_2 = nng_tls_version::NNG_TLS_1_2,
70 Tls1_3 = nng_tls_version::NNG_TLS_1_3,
72}
73
74pub struct Config(NonNull<nng_tls_config>);
80
81impl Config {
82 fn new(mode: nng_tls_mode::Type) -> Option<Self> {
83 let mut ptr = ptr::null_mut();
84 unsafe {
85 sys::nng_tls_config_alloc(&mut ptr, mode);
86 }
87
88 NonNull::new(ptr).map(Self)
89 }
90
91 #[inline(always)]
92 pub fn client() -> Option<Self> {
96 Self::new(nng_tls_mode::NNG_TLS_MODE_CLIENT)
97 }
98
99 #[inline(always)]
100 pub fn server() -> Option<Self> {
104 Self::new(nng_tls_mode::NNG_TLS_MODE_SERVER)
105 }
106
107 pub fn auth_mode(&self, mode: Auth) -> Result<(), ErrorCode> {
113 let result = unsafe {
114 sys::nng_tls_config_auth_mode(self.0.as_ptr(), mode as _)
115 };
116
117 match result {
118 0 => Ok(()),
119 code => Err(error(code)),
120 }
121 }
122
123 pub fn versions(&self, min: Version, max: Version) -> Result<(), ErrorCode> {
125 let result = unsafe {
126 sys::nng_tls_config_version(self.0.as_ptr(), min as _, max as _)
127 };
128
129 match result {
130 0 => Ok(()),
131 code => Err(error(code)),
132 }
133 }
134
135 pub fn server_name(&self, name: &str) -> Result<(), ErrorCode> {
137 if name.len() > MAX_HOSTNAME_LEN {
138 return Err(error(sys::nng_errno_enum::NNG_EADDRINVAL));
139 }
140
141 let mut buffer = [0u8; MAX_HOSTNAME_LEN + 1];
142 let result = unsafe {
143 ptr::copy_nonoverlapping(name.as_ptr(), buffer.as_mut_ptr(), name.len());
144 sys::nng_tls_config_server_name(self.0.as_ptr(), buffer.as_ptr() as _)
145 };
146
147 match result {
148 0 => Ok(()),
149 code => Err(error(code)),
150 }
151 }
152
153 pub fn ca_cert(&self, cert: &CA<'_>) -> Result<(), ErrorCode> {
155 let crl = match cert.crl.as_ref() {
156 Some(crl) => crl.as_ptr(),
157 None => ptr::null()
158 };
159 let cert = cert.cert.as_ptr();
160 let result = unsafe {
161 sys::nng_tls_config_ca_chain(self.0.as_ptr(), cert as _, crl as _)
162 };
163
164 match result {
165 0 => Ok(()),
166 code => Err(error(code)),
167 }
168 }
169
170 pub fn own_cert(&self, cert: &OwnCert<'_>) -> Result<(), ErrorCode> {
172 let pass = match cert.pass.as_ref() {
173 Some(pass) => pass.as_ptr(),
174 None => ptr::null()
175 };
176 let key = cert.key.as_ptr();
177 let cert = cert.cert.as_ptr();
178 let result = unsafe {
179 sys::nng_tls_config_own_cert(self.0.as_ptr(), cert as _, key as _, pass as _)
180 };
181
182 match result {
183 0 => Ok(()),
184 code => Err(error(code)),
185 }
186 }
187}
188
189impl Clone for Config {
190 #[inline]
191 fn clone(&self) -> Self {
192 unsafe {
193 sys::nng_tls_config_hold(self.0.as_ptr())
194 }
195 Self(self.0)
196 }
197}
198
199impl Drop for Config {
200 #[inline(always)]
201 fn drop(&mut self) {
202 unsafe {
203 sys::nng_tls_config_free(self.0.as_ptr())
204 }
205 }
206}
207
208impl Options<socket::Listener> for Config {
209 #[inline]
210 fn apply(&self, target: &socket::Listener) -> Result<(), ErrorCode> {
211 let result = unsafe {
212 sys::nng_listener_set_ptr(target.0, sys::NNG_OPT_TLS_CONFIG.as_ptr() as _, self.0.as_ptr() as _)
213 };
214
215 match result {
216 0 => Ok(()),
217 code => Err(error(code)),
218 }
219 }
220}
221
222impl Options<socket::Dialer> for Config {
223 #[inline]
224 fn apply(&self, target: &socket::Dialer) -> Result<(), ErrorCode> {
225 let result = unsafe {
226 sys::nng_dialer_set_ptr(target.0, sys::NNG_OPT_TLS_CONFIG.as_ptr() as _, self.0.as_ptr() as _)
227 };
228
229 match result {
230 0 => Ok(()),
231 code => Err(error(code)),
232 }
233 }
234}