SNode.C
Loading...
Searching...
No Matches
core::socket::stream::tls Namespace Reference

Classes

class  SocketAcceptor
 
class  SocketConnection
 
class  SocketConnector
 
class  SocketReader
 
class  SocketWriter
 
struct  SslConfig
 
class  TLSHandshake
 
class  TLSShutdown
 

Functions

static int password_callback (char *buf, int size, int a, void *u)
 
static int verify_callback (int preverify_ok, X509_STORE_CTX *ctx)
 
SSL_CTX * ssl_ctx_new (const SslConfig &sslConfig)
 
std::map< std::string, SSL_CTX * > ssl_get_sans (SSL_CTX *sslCtx)
 
void ssl_set_sni (SSL *ssl, const std::string &sni)
 
SSL_CTX * ssl_set_ssl_ctx (SSL *ssl, SSL_CTX *sslCtx)
 
void ssl_ctx_free (SSL_CTX *ctx)
 
std::string ssl_get_servername_from_client_hello (SSL *ssl)
 
void ssl_log (const std::string &message, int sslErr)
 
void ssl_log_error (const std::string &message)
 
void ssl_log_warning (const std::string &message)
 
void ssl_log_info (const std::string &message)
 
bool match (const char *first, const char *second)
 

Function Documentation

◆ match()

bool core::socket::stream::tls::match ( const char * first,
const char * second )

Definition at line 400 of file ssl_utils.cpp.

400 {
401 // If we reach at the end of both strings, we are done
402 if (*first == '\0' && *second == '\0') {
403 return true;
404 }
405
406 // Make sure to eliminate consecutive '*'
407 if (*first == '*') {
408 while (*(first + 1) == '*') {
409 first++;
410 }
411 }
412
413 // Make sure that the characters after '*' are present
414 // in second string. This function assumes that the
415 // first string will not contain two consecutive '*'
416 if (*first == '*' && *(first + 1) != '\0' && *second == '\0') {
417 return false;
418 }
419
420 // If the first string contains '?', or current
421 // characters of both strings match
422 if (*first == '?' || *first == *second) {
423 return match(first + 1, second + 1);
424 }
425
426 // If there is *, then there are two possibilities
427 // a) We consider current character of second string
428 // b) We ignore current character of second string.
429 if (*first == '*') {
430 return match(first + 1, second) || match(first, second + 1);
431 }
432
433 return false;
434 }
bool match(const char *first, const char *second)

References match().

Referenced by match().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ password_callback()

static int core::socket::stream::tls::password_callback ( char * buf,
int size,
int a,
void * u )
static

Definition at line 65 of file ssl_utils.cpp.

65 {
66 strncpy(buf, static_cast<char*>(u), static_cast<std::size_t>(size));
67 buf[size - 1] = '\0';
68
69 memset(u, 0, ::strlen(static_cast<char*>(u))); // garble Password
70 free(u);
71
72 return static_cast<int>(std::strlen(buf));
73 }

Referenced by ssl_ctx_new().

Here is the caller graph for this function:

◆ ssl_ctx_free()

void core::socket::stream::tls::ssl_ctx_free ( SSL_CTX * ctx)

Definition at line 295 of file ssl_utils.cpp.

295 {
296 if (ctx != nullptr) {
297 SSL_CTX_free(ctx);
298 }
299 }

◆ ssl_ctx_new()

SSL_CTX * core::socket::stream::tls::ssl_ctx_new ( const SslConfig & sslConfig)

Definition at line 113 of file ssl_utils.cpp.

113 {
114 static int sslSessionCtxId = 1;
115
116 SSL_CTX* ctx = SSL_CTX_new(sslConfig.server ? TLS_server_method() : TLS_client_method());
117
118 if (ctx != nullptr) {
119 SSL_CTX_set_read_ahead(ctx, 1);
120
121 SSL_CTX_set_mode(ctx, SSL_MODE_ENABLE_PARTIAL_WRITE);
122 SSL_CTX_set_mode(ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
123
124 bool sslErr = false;
125
126 if (sslConfig.server) {
127 SSL_CTX_set_session_id_context(ctx, reinterpret_cast<const unsigned char*>(&sslSessionCtxId), sizeof(sslSessionCtxId));
128 sslSessionCtxId++;
129 }
130 if (!sslConfig.caCert.empty() || !sslConfig.caCertDir.empty()) {
131 if (SSL_CTX_load_verify_locations(ctx,
132 !sslConfig.caCert.empty() ? sslConfig.caCert.c_str() : nullptr,
133 !sslConfig.caCertDir.empty() ? sslConfig.caCertDir.c_str() : nullptr) == 0) {
134 ssl_log_error(sslConfig.instanceName + " SSL/TLS: CA certificate error loading file '" + sslConfig.caCert + "', dir '" +
135 sslConfig.caCertDir + "'");
136 sslErr = true;
137 } else {
138 if (!sslConfig.caCert.empty()) {
139 LOG(TRACE) << sslConfig.instanceName << " SSL/TLS: CA certificate loaded";
140 LOG(TRACE) << " " << sslConfig.caCert;
141 } else {
142 LOG(TRACE) << sslConfig.instanceName << " SSL/TLS: CA certificate not loaded from a file";
143 }
144 if (!sslConfig.caCertDir.empty()) {
145 LOG(TRACE) << sslConfig.instanceName << " SSL/TLS: CA certificates load from";
146 LOG(TRACE) << " " << sslConfig.caCertDir;
147 } else {
148 LOG(TRACE) << sslConfig.instanceName << " SSL/TLS: CA certificates not loaded from a directory";
149 }
150 }
151 } else {
152 LOG(TRACE) << sslConfig.instanceName << " SSL/TLS: CA certificate not loaded from a file";
153 LOG(TRACE) << sslConfig.instanceName << " SSL/TLS: CA certificates not loaded from a directory";
154 }
155 if (!sslErr && sslConfig.caCertUseDefaultDir) {
156 if (SSL_CTX_set_default_verify_paths(ctx) == 0) {
157 ssl_log_error(sslConfig.instanceName + " SSL/TLS: CA certificates error load from default openssl CA directory");
158 sslErr = true;
159 } else {
160 LOG(TRACE) << sslConfig.instanceName << " SSL/TLS: CA certificates enabled load from default openssl CA directory";
161 }
162 } else {
163 LOG(TRACE) << sslConfig.instanceName << " SSL/TLS: CA certificates not loaded from default openssl CA directory";
164 }
165 if (!sslErr) {
166 SSL_CTX_set_verify_depth(ctx, 5);
167 SSL_CTX_set_verify(ctx,
168 (sslConfig.caCertAcceptUnknown ? SSL_VERIFY_NONE
169 : (!sslConfig.caCert.empty() || !sslConfig.caCertDir.empty() || sslConfig.caCertUseDefaultDir)
170 ? SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE | SSL_VERIFY_FAIL_IF_NO_PEER_CERT
171 : 0),
173 if ((SSL_CTX_get_verify_mode(ctx) & SSL_VERIFY_PEER) != 0) {
174 LOG(TRACE) << sslConfig.instanceName << " SSL/TLS: CA requested verify";
175 }
176 if (!sslConfig.cert.empty()) {
177 if (SSL_CTX_use_certificate_chain_file(ctx, sslConfig.cert.c_str()) == 0) {
178 ssl_log_error(sslConfig.instanceName + " SSL/TLS: Cert chain error loading from file '" + sslConfig.cert + "'");
179 sslErr = true;
180 } else if (!sslConfig.certKey.empty()) {
181 if (!sslConfig.password.empty()) {
182 SSL_CTX_set_default_passwd_cb(ctx, password_callback);
183 SSL_CTX_set_default_passwd_cb_userdata(ctx, ::strdup(sslConfig.password.c_str()));
184 }
185 if (SSL_CTX_use_PrivateKey_file(ctx, sslConfig.certKey.c_str(), SSL_FILETYPE_PEM) == 0) {
186 ssl_log_error(sslConfig.instanceName + " SSL/TLS: Cert chain key error loading file '" + sslConfig.certKey +
187 "'");
188 sslErr = true;
189 } else if (SSL_CTX_check_private_key(ctx) != 1) {
190 ssl_log_error(sslConfig.instanceName + " SSL/TLS: Cert chain key error");
191
192 LOG(TRACE) << " " << sslConfig.certKey;
193 sslErr = true;
194 } else {
195 LOG(TRACE) << sslConfig.instanceName << " SSL/TLS: Cert chain key loaded";
196 LOG(TRACE) << " " << sslConfig.certKey;
197
198 LOG(TRACE) << sslConfig.instanceName << " SSL/TLS: Cert chain loaded";
199 LOG(TRACE) << " " << sslConfig.cert;
200 }
201 }
202 }
203 }
204 if (!sslErr) {
205 if (sslConfig.sslOptions != 0) {
206 SSL_CTX_set_options(ctx, sslConfig.sslOptions);
207 }
208 if (!sslConfig.cipherList.empty()) {
209 SSL_CTX_set_cipher_list(ctx, sslConfig.cipherList.c_str());
210 }
211 } else {
212 SSL_CTX_free(ctx);
213 ctx = nullptr;
214 }
215 }
216
217 return ctx;
218 }
static int verify_callback(int preverify_ok, X509_STORE_CTX *ctx)
Definition ssl_utils.cpp:75
void ssl_log_error(const std::string &message)

References password_callback().

Here is the call graph for this function:

◆ ssl_get_sans()

std::map< std::string, SSL_CTX * > core::socket::stream::tls::ssl_get_sans ( SSL_CTX * sslCtx)

Definition at line 220 of file ssl_utils.cpp.

220 {
221 std::map<std::string, SSL_CTX*> sans;
222
223 if (sslCtx != nullptr) {
224 X509* x509 = SSL_CTX_get0_certificate(sslCtx);
225 if (x509 != nullptr) {
226 GENERAL_NAMES* subjectAltNames =
227 static_cast<GENERAL_NAMES*>(X509_get_ext_d2i(x509, NID_subject_alt_name, nullptr, nullptr));
228#ifdef __GNUC__
229#pragma GCC diagnostic push
230#ifdef __has_warning
231#if __has_warning("-Wused-but-marked-unused")
232#pragma GCC diagnostic ignored "-Wused-but-marked-unused"
233#endif
234#endif
235#endif
236 const int32_t altNameCount = sk_GENERAL_NAME_num(subjectAltNames);
237#ifdef __GNUC__
238#pragma GCC diagnostic pop
239#endif
240 for (int32_t i = 0; i < altNameCount; ++i) {
241#ifdef __GNUC__
242#pragma GCC diagnostic push
243#ifdef __has_warning
244#if __has_warning("-Wused-but-marked-unused")
245#pragma GCC diagnostic ignored "-Wused-but-marked-unused"
246#endif
247#endif
248#endif
249 GENERAL_NAME* generalName = sk_GENERAL_NAME_value(subjectAltNames, i);
250#ifdef __GNUC__
251#pragma GCC diagnostic pop
252#endif
253 if (generalName->type == GEN_DNS || generalName->type == GEN_URI || generalName->type == GEN_EMAIL) {
254 const std::string subjectAltName =
255 std::string(reinterpret_cast<const char*>(ASN1_STRING_get0_data(generalName->d.dNSName)),
256 static_cast<std::size_t>(ASN1_STRING_length(generalName->d.dNSName)));
257 sans.insert({subjectAltName, sslCtx});
258 }
259 }
260#ifdef __GNUC__
261#pragma GCC diagnostic push
262#ifdef __has_warning
263#if __has_warning("-Wused-but-marked-unused")
264#pragma GCC diagnostic ignored "-Wused-but-marked-unused"
265#endif
266#endif
267#endif
268 sk_GENERAL_NAME_pop_free(subjectAltNames, GENERAL_NAME_free);
269#ifdef __GNUC__
270#pragma GCC diagnostic pop
271#endif
272 }
273 }
274
275 return sans;
276 }

◆ ssl_get_servername_from_client_hello()

std::string core::socket::stream::tls::ssl_get_servername_from_client_hello ( SSL * ssl)

Definition at line 302 of file ssl_utils.cpp.

302 {
303 const unsigned char* ext = nullptr;
304 size_t ext_len = 0;
305 size_t p = 0;
306 size_t server_name_list_len = 0;
307 size_t server_name_len = 0;
308
309 if (SSL_client_hello_get0_ext(ssl, TLSEXT_TYPE_server_name, &ext, &ext_len) == 0) {
310 return "";
311 }
312
313 /* length (2 bytes) + type (1) + length (2) + server name (1+) */
314 if (ext_len < 6) {
315 return "";
316 }
317
318 /* Fetch Server Name list length */
319 server_name_list_len = static_cast<size_t>((ext[p] << 8) + ext[p + 1]);
320 p += 2;
321 if (p + server_name_list_len != ext_len) {
322 return "";
323 }
324
325 /* Fetch Server Name Type */
326 if (ext[p] != TLSEXT_NAMETYPE_host_name) {
327 return "";
328 }
329 p++;
330
331 /* Fetch Server Name Length */
332 server_name_len = static_cast<size_t>((ext[p] << 8) + ext[p + 1]);
333 p += 2;
334 if (p + server_name_len != ext_len) {
335 return "";
336 }
337
338 /* ext_len >= 6 && p == 5 */
339
340 /* Finally fetch Server Name */
341
342 return std::string(reinterpret_cast<const char*>(ext + p), ext_len - p);
343 }

◆ ssl_log()

void core::socket::stream::tls::ssl_log ( const std::string & message,
int sslErr )

Definition at line 345 of file ssl_utils.cpp.

345 {
346 const utils::PreserveErrno preserveErrno;
347
348 switch (sslErr) {
349 case SSL_ERROR_NONE:
350 [[fallthrough]];
351 case SSL_ERROR_ZERO_RETURN:
352 ssl_log_info(message);
353 break;
354 case SSL_ERROR_SYSCALL:
355 if (errno != 0) {
356 ssl_log_error(message);
357 } else {
358 ssl_log_info(message);
359 }
360 break;
361 case SSL_ERROR_SSL:
362 ssl_log_error(message);
363 break;
364 default:
365 ssl_log_warning(message);
366 break;
367 }
368 }
void ssl_log_info(const std::string &message)

◆ ssl_log_error()

void core::socket::stream::tls::ssl_log_error ( const std::string & message)

Definition at line 370 of file ssl_utils.cpp.

370 {
371 LOG(ERROR) << message;
372 LOG(ERROR) << " " << ERR_error_string(ERR_get_error(), nullptr);
373
374 unsigned long errorCode = 0;
375 while ((errorCode = ERR_get_error()) != 0) {
376 LOG(ERROR) << " " << ERR_error_string(errorCode, nullptr);
377 }
378 }

◆ ssl_log_info()

void core::socket::stream::tls::ssl_log_info ( const std::string & message)

Definition at line 390 of file ssl_utils.cpp.

390 {
391 LOG(INFO) << message;
392 LOG(INFO) << " " << ERR_error_string(ERR_get_error(), nullptr);
393
394 unsigned long errorCode = 0;
395 while ((errorCode = ERR_get_error()) != 0) {
396 LOG(INFO) << " " << ERR_error_string(errorCode, nullptr);
397 }
398 }

◆ ssl_log_warning()

void core::socket::stream::tls::ssl_log_warning ( const std::string & message)

Definition at line 380 of file ssl_utils.cpp.

380 {
381 LOG(WARNING) << message;
382 LOG(WARNING) << " " << ERR_error_string(ERR_get_error(), nullptr);
383
384 unsigned long errorCode = 0;
385 while ((errorCode = ERR_get_error()) != 0) {
386 LOG(WARNING) << " " << ERR_error_string(errorCode, nullptr);
387 }
388 }

◆ ssl_set_sni()

void core::socket::stream::tls::ssl_set_sni ( SSL * ssl,
const std::string & sni )

Definition at line 278 of file ssl_utils.cpp.

278 {
279 if (!sni.empty()) {
280 SSL_set_tlsext_host_name(ssl, sni.data());
281 }
282 }

◆ ssl_set_ssl_ctx()

SSL_CTX * core::socket::stream::tls::ssl_set_ssl_ctx ( SSL * ssl,
SSL_CTX * sslCtx )

Definition at line 284 of file ssl_utils.cpp.

284 {
285 SSL_CTX* newSslCtx = SSL_set_SSL_CTX(ssl, sslCtx);
286 SSL_clear_options(ssl, 0xFFFFFFFFL);
287 SSL_set_options(ssl, SSL_CTX_get_options(sslCtx));
288 SSL_set_verify(ssl, SSL_CTX_get_verify_mode(sslCtx), SSL_CTX_get_verify_callback(sslCtx));
289 SSL_set_verify_depth(ssl, SSL_CTX_get_verify_depth(sslCtx));
290 SSL_set_mode(ssl, SSL_CTX_get_mode(sslCtx));
291
292 return newSslCtx;
293 }

◆ verify_callback()

static int core::socket::stream::tls::verify_callback ( int preverify_ok,
X509_STORE_CTX * ctx )
static

Definition at line 75 of file ssl_utils.cpp.

75 {
76 SSL* ssl = static_cast<SSL*>(X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx()));
77
78 std::string connectionName = *static_cast<std::string*>(SSL_get_ex_data(ssl, 0));
79
80 X509* curr_cert = X509_STORE_CTX_get_current_cert(ctx);
81 const int depth = X509_STORE_CTX_get_error_depth(ctx);
82
83 char subjectName[256];
84 X509_NAME_oneline(X509_get_subject_name(curr_cert), subjectName, 256);
85
86 char issuerName[256];
87 X509_NAME_oneline(X509_get_issuer_name(curr_cert), issuerName, 256);
88
89 if (preverify_ok != 0) {
90 LOG(DEBUG) << connectionName << ": SSL/TLS verify success at depth=" << depth;
91 LOG(DEBUG) << " Issuer: " << issuerName;
92 LOG(DEBUG) << " Subject: " << subjectName;
93 } else {
94 const int err = X509_STORE_CTX_get_error(ctx);
95
96 /*
97 * At this point, err contains the last verification error. We can use
98 * it for something special
99 */
100
101 LOG(DEBUG) << connectionName << ": SSL/TLS verify error at depth=" << depth << ": " << X509_verify_cert_error_string(err);
102 LOG(DEBUG) << " Issuer: " << issuerName;
103 LOG(DEBUG) << " Subject: " << subjectName;
104 }
105
106 return preverify_ok;
107 }