2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
42#ifndef DOXYGEN_SHOULD_SKIP_THIS
44#include "core/socket/stream/tls/ssl_utils.h"
46#include "log/Logger.h"
47#include "utils/PreserveErrno.h"
53#include <openssl/asn1.h>
54#include <openssl/err.h>
55#include <openssl/obj_mac.h>
56#include <openssl/ssl.h>
57#include <openssl/x509.h>
58#include <openssl/x509v3.h>
66 strncpy(buf,
static_cast<
char*>(u),
static_cast<std::size_t>(size));
69 memset(u, 0, ::strlen(
static_cast<
char*>(u)));
72 return static_cast<
int>(std::strlen(buf));
76 SSL* ssl =
static_cast<SSL*>(X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx()));
78 const std::string connectionName = *
static_cast<std::string*>(SSL_get_ex_data(ssl, 0));
80 X509* curr_cert = X509_STORE_CTX_get_current_cert(ctx);
81 const int depth = X509_STORE_CTX_get_error_depth(ctx);
83 char subjectName[256];
84 X509_NAME_oneline(X509_get_subject_name(curr_cert), subjectName, 256);
87 X509_NAME_oneline(X509_get_issuer_name(curr_cert), issuerName, 256);
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;
94 const int err = X509_STORE_CTX_get_error(ctx);
96 LOG(DEBUG) << connectionName <<
": SSL/TLS verify error at depth=" << depth <<
": " << X509_verify_cert_error_string(err);
97 LOG(DEBUG) <<
" Issuer: " << issuerName;
98 LOG(DEBUG) <<
" Subject: " << subjectName;
101
102
103
104
115 static int sslSessionCtxId = 1;
117 SSL_CTX* ctx = SSL_CTX_new(sslConfig
.server ? TLS_server_method() : TLS_client_method());
119 if (ctx !=
nullptr) {
120 SSL_CTX_set_read_ahead(ctx, 1);
122 SSL_CTX_set_mode(ctx, SSL_MODE_ENABLE_PARTIAL_WRITE);
123 SSL_CTX_set_mode(ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
128 SSL_CTX_set_session_id_context(ctx,
reinterpret_cast<
const unsigned char*>(&sslSessionCtxId),
sizeof(sslSessionCtxId));
132 if (SSL_CTX_load_verify_locations(ctx,
139 if (!sslConfig
.caCert.empty()) {
140 LOG(TRACE) << sslConfig
.instanceName <<
" SSL/TLS: CA certificate loaded";
141 LOG(TRACE) <<
" " << sslConfig
.caCert;
143 LOG(TRACE) << sslConfig
.instanceName <<
" SSL/TLS: CA certificate not loaded from a file";
146 LOG(TRACE) << sslConfig
.instanceName <<
" SSL/TLS: CA certificates load from";
149 LOG(TRACE) << sslConfig
.instanceName <<
" SSL/TLS: CA certificates not loaded from a directory";
153 LOG(TRACE) << sslConfig
.instanceName <<
" SSL/TLS: CA certificate not loaded from a file";
154 LOG(TRACE) << sslConfig
.instanceName <<
" SSL/TLS: CA certificates not loaded from a directory";
157 if (SSL_CTX_set_default_verify_paths(ctx) == 0) {
161 LOG(TRACE) << sslConfig
.instanceName <<
" SSL/TLS: CA certificates enabled load from default openssl CA directory";
164 LOG(TRACE) << sslConfig
.instanceName <<
" SSL/TLS: CA certificates not loaded from default openssl CA directory";
167 SSL_CTX_set_verify_depth(ctx, 5);
168 SSL_CTX_set_verify(ctx,
171 ? SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE | SSL_VERIFY_FAIL_IF_NO_PEER_CERT
174 if ((SSL_CTX_get_verify_mode(ctx) & SSL_VERIFY_PEER) != 0) {
175 LOG(TRACE) << sslConfig
.instanceName <<
" SSL/TLS: CA requested verify";
177 if (!sslConfig
.cert.empty()) {
178 if (SSL_CTX_use_certificate_chain_file(ctx, sslConfig
.cert.c_str()) == 0) {
181 }
else if (!sslConfig
.certKey.empty()) {
184 SSL_CTX_set_default_passwd_cb_userdata(ctx, ::strdup(sslConfig
.password.c_str()));
186 if (SSL_CTX_use_PrivateKey_file(ctx, sslConfig
.certKey.c_str(), SSL_FILETYPE_PEM) == 0) {
190 }
else if (SSL_CTX_check_private_key(ctx) != 1) {
193 LOG(TRACE) <<
" " << sslConfig
.certKey;
196 LOG(TRACE) << sslConfig
.instanceName <<
" SSL/TLS: Cert chain key loaded";
197 LOG(TRACE) <<
" " << sslConfig
.certKey;
199 LOG(TRACE) << sslConfig
.instanceName <<
" SSL/TLS: Cert chain loaded";
200 LOG(TRACE) <<
" " << sslConfig
.cert;
210 SSL_CTX_set_cipher_list(ctx, sslConfig
.cipherList.c_str());
222 std::map<std::string, SSL_CTX*> sans;
224 if (sslCtx !=
nullptr) {
225 X509* x509 = SSL_CTX_get0_certificate(sslCtx);
226 if (x509 !=
nullptr) {
227 GENERAL_NAMES* subjectAltNames =
228 static_cast<GENERAL_NAMES*>(X509_get_ext_d2i(x509, NID_subject_alt_name,
nullptr,
nullptr));
230#pragma GCC diagnostic push
232#if __has_warning
("-Wused-but-marked-unused")
233#pragma GCC diagnostic ignored "-Wused-but-marked-unused"
237 const int32_t altNameCount = sk_GENERAL_NAME_num(subjectAltNames);
239#pragma GCC diagnostic pop
241 for (int32_t i = 0; i < altNameCount; ++i) {
243#pragma GCC diagnostic push
245#if __has_warning
("-Wused-but-marked-unused")
246#pragma GCC diagnostic ignored "-Wused-but-marked-unused"
250 GENERAL_NAME* generalName = sk_GENERAL_NAME_value(subjectAltNames, i);
252#pragma GCC diagnostic pop
254 if (generalName->type == GEN_DNS || generalName->type == GEN_URI || generalName->type == GEN_EMAIL) {
255 const std::string subjectAltName =
256 std::string(
reinterpret_cast<
const char*>(ASN1_STRING_get0_data(generalName->d.dNSName)),
257 static_cast<std::size_t>(ASN1_STRING_length(generalName->d.dNSName)));
258 sans.insert({subjectAltName, sslCtx});
262#pragma GCC diagnostic push
264#if __has_warning
("-Wused-but-marked-unused")
265#pragma GCC diagnostic ignored "-Wused-but-marked-unused"
269 sk_GENERAL_NAME_pop_free(subjectAltNames, GENERAL_NAME_free);
271#pragma GCC diagnostic pop
281 SSL_set_tlsext_host_name(ssl, sni.data());
286 SSL_CTX* newSslCtx = SSL_set_SSL_CTX(ssl, sslCtx);
287 SSL_clear_options(ssl, 0xFFFFFFFFL);
288 SSL_set_options(ssl, SSL_CTX_get_options(sslCtx));
289 SSL_set_verify(ssl, SSL_CTX_get_verify_mode(sslCtx), SSL_CTX_get_verify_callback(sslCtx));
290 SSL_set_verify_depth(ssl, SSL_CTX_get_verify_depth(sslCtx));
291 SSL_set_mode(ssl, SSL_CTX_get_mode(sslCtx));
297 if (ctx !=
nullptr) {
304 const unsigned char* ext =
nullptr;
307 size_t server_name_list_len = 0;
308 size_t server_name_len = 0;
310 if (SSL_client_hello_get0_ext(ssl, TLSEXT_TYPE_server_name, &ext, &ext_len) == 0) {
320 server_name_list_len =
static_cast<size_t>((ext[p] << 8) + ext[p + 1]);
322 if (p + server_name_list_len != ext_len) {
327 if (ext[p] != TLSEXT_NAMETYPE_host_name) {
333 server_name_len =
static_cast<size_t>((ext[p] << 8) + ext[p + 1]);
335 if (p + server_name_len != ext_len) {
343 return std::string(
reinterpret_cast<
const char*>(ext + p), ext_len - p);
346 void ssl_log(
const std::string& message,
int sslErr) {
352 case SSL_ERROR_ZERO_RETURN:
355 case SSL_ERROR_SYSCALL:
372 LOG(ERROR) << message;
373 LOG(ERROR) <<
" " << ERR_error_string(ERR_get_error(),
nullptr);
375 unsigned long errorCode = 0;
376 while ((errorCode = ERR_get_error()) != 0) {
377 LOG(ERROR) <<
" " << ERR_error_string(errorCode,
nullptr);
382 LOG(WARNING) << message;
383 LOG(WARNING) <<
" " << ERR_error_string(ERR_get_error(),
nullptr);
385 unsigned long errorCode = 0;
386 while ((errorCode = ERR_get_error()) != 0) {
387 LOG(WARNING) <<
" " << ERR_error_string(errorCode,
nullptr);
392 LOG(INFO) << message;
393 LOG(INFO) <<
" " << ERR_error_string(ERR_get_error(),
nullptr);
395 unsigned long errorCode = 0;
396 while ((errorCode = ERR_get_error()) != 0) {
397 LOG(INFO) <<
" " << ERR_error_string(errorCode,
nullptr);
401 bool match(
const char* first,
const char* second) {
403 if (*first ==
'\0' && *second ==
'\0') {
409 while (*(first + 1) ==
'*') {
417 if (*first ==
'*' && *(first + 1) !=
'\0' && *second ==
'\0') {
423 if (*first ==
'?' || *first == *second) {
424 return match(first + 1
, second + 1
);
void ssl_set_sni(SSL *ssl, const std::string &sni)
bool match(const char *first, const char *second)
static int verify_callback(int preverify_ok, X509_STORE_CTX *ctx)
void ssl_log_warning(const std::string &message)
static int password_callback(char *buf, int size, int a, void *u)
SSL_CTX * ssl_set_ssl_ctx(SSL *ssl, SSL_CTX *sslCtx)
void ssl_log_info(const std::string &message)
std::string ssl_get_servername_from_client_hello(SSL *ssl)
void ssl_log(const std::string &message, int sslErr)
void ssl_ctx_free(SSL_CTX *ctx)
std::map< std::string, SSL_CTX * > ssl_get_sans(SSL_CTX *sslCtx)
SSL_CTX * ssl_ctx_new(const SslConfig &sslConfig)
void ssl_log_error(const std::string &message)