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 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);
97
98
99
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;
114 static int sslSessionCtxId = 1;
116 SSL_CTX* ctx = SSL_CTX_new(sslConfig
.server ? TLS_server_method() : TLS_client_method());
118 if (ctx !=
nullptr) {
119 SSL_CTX_set_read_ahead(ctx, 1);
121 SSL_CTX_set_mode(ctx, SSL_MODE_ENABLE_PARTIAL_WRITE);
122 SSL_CTX_set_mode(ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
127 SSL_CTX_set_session_id_context(ctx,
reinterpret_cast<
const unsigned char*>(&sslSessionCtxId),
sizeof(sslSessionCtxId));
131 if (SSL_CTX_load_verify_locations(ctx,
138 if (!sslConfig
.caCert.empty()) {
139 LOG(TRACE) << sslConfig
.instanceName <<
" SSL/TLS: CA certificate loaded";
140 LOG(TRACE) <<
" " << sslConfig
.caCert;
142 LOG(TRACE) << sslConfig
.instanceName <<
" SSL/TLS: CA certificate not loaded from a file";
145 LOG(TRACE) << sslConfig
.instanceName <<
" SSL/TLS: CA certificates load from";
148 LOG(TRACE) << sslConfig
.instanceName <<
" SSL/TLS: CA certificates not loaded from a directory";
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";
156 if (SSL_CTX_set_default_verify_paths(ctx) == 0) {
160 LOG(TRACE) << sslConfig
.instanceName <<
" SSL/TLS: CA certificates enabled load from default openssl CA directory";
163 LOG(TRACE) << sslConfig
.instanceName <<
" SSL/TLS: CA certificates not loaded from default openssl CA directory";
166 SSL_CTX_set_verify_depth(ctx, 5);
167 SSL_CTX_set_verify(ctx,
170 ? SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE | SSL_VERIFY_FAIL_IF_NO_PEER_CERT
173 if ((SSL_CTX_get_verify_mode(ctx) & SSL_VERIFY_PEER) != 0) {
174 LOG(TRACE) << sslConfig
.instanceName <<
" SSL/TLS: CA requested verify";
176 if (!sslConfig
.cert.empty()) {
177 if (SSL_CTX_use_certificate_chain_file(ctx, sslConfig
.cert.c_str()) == 0) {
180 }
else if (!sslConfig
.certKey.empty()) {
183 SSL_CTX_set_default_passwd_cb_userdata(ctx, ::strdup(sslConfig
.password.c_str()));
185 if (SSL_CTX_use_PrivateKey_file(ctx, sslConfig
.certKey.c_str(), SSL_FILETYPE_PEM) == 0) {
189 }
else if (SSL_CTX_check_private_key(ctx) != 1) {
192 LOG(TRACE) <<
" " << sslConfig
.certKey;
195 LOG(TRACE) << sslConfig
.instanceName <<
" SSL/TLS: Cert chain key loaded";
196 LOG(TRACE) <<
" " << sslConfig
.certKey;
198 LOG(TRACE) << sslConfig
.instanceName <<
" SSL/TLS: Cert chain loaded";
199 LOG(TRACE) <<
" " << sslConfig
.cert;
209 SSL_CTX_set_cipher_list(ctx, sslConfig
.cipherList.c_str());
221 std::map<std::string, SSL_CTX*> sans;
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));
229#pragma GCC diagnostic push
231#if __has_warning
("-Wused-but-marked-unused")
232#pragma GCC diagnostic ignored "-Wused-but-marked-unused"
236 const int32_t altNameCount = sk_GENERAL_NAME_num(subjectAltNames);
238#pragma GCC diagnostic pop
240 for (int32_t i = 0; i < altNameCount; ++i) {
242#pragma GCC diagnostic push
244#if __has_warning
("-Wused-but-marked-unused")
245#pragma GCC diagnostic ignored "-Wused-but-marked-unused"
249 GENERAL_NAME* generalName = sk_GENERAL_NAME_value(subjectAltNames, i);
251#pragma GCC diagnostic pop
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});
261#pragma GCC diagnostic push
263#if __has_warning
("-Wused-but-marked-unused")
264#pragma GCC diagnostic ignored "-Wused-but-marked-unused"
268 sk_GENERAL_NAME_pop_free(subjectAltNames, GENERAL_NAME_free);
270#pragma GCC diagnostic pop
280 SSL_set_tlsext_host_name(ssl, sni.data());
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));
296 if (ctx !=
nullptr) {
303 const unsigned char* ext =
nullptr;
306 size_t server_name_list_len = 0;
307 size_t server_name_len = 0;
309 if (SSL_client_hello_get0_ext(ssl, TLSEXT_TYPE_server_name, &ext, &ext_len) == 0) {
319 server_name_list_len =
static_cast<size_t>((ext[p] << 8) + ext[p + 1]);
321 if (p + server_name_list_len != ext_len) {
326 if (ext[p] != TLSEXT_NAMETYPE_host_name) {
332 server_name_len =
static_cast<size_t>((ext[p] << 8) + ext[p + 1]);
334 if (p + server_name_len != ext_len) {
342 return std::string(
reinterpret_cast<
const char*>(ext + p), ext_len - p);
345 void ssl_log(
const std::string& message,
int sslErr) {
351 case SSL_ERROR_ZERO_RETURN:
354 case SSL_ERROR_SYSCALL:
371 LOG(ERROR) << message;
372 LOG(ERROR) <<
" " << ERR_error_string(ERR_get_error(),
nullptr);
374 unsigned long errorCode = 0;
375 while ((errorCode = ERR_get_error()) != 0) {
376 LOG(ERROR) <<
" " << ERR_error_string(errorCode,
nullptr);
381 LOG(WARNING) << message;
382 LOG(WARNING) <<
" " << ERR_error_string(ERR_get_error(),
nullptr);
384 unsigned long errorCode = 0;
385 while ((errorCode = ERR_get_error()) != 0) {
386 LOG(WARNING) <<
" " << ERR_error_string(errorCode,
nullptr);
391 LOG(INFO) << message;
392 LOG(INFO) <<
" " << ERR_error_string(ERR_get_error(),
nullptr);
394 unsigned long errorCode = 0;
395 while ((errorCode = ERR_get_error()) != 0) {
396 LOG(INFO) <<
" " << ERR_error_string(errorCode,
nullptr);
400 bool match(
const char* first,
const char* second) {
402 if (*first ==
'\0' && *second ==
'\0') {
408 while (*(first + 1) ==
'*') {
416 if (*first ==
'*' && *(first + 1) !=
'\0' && *second ==
'\0') {
422 if (*first ==
'?' || *first == *second) {
423 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)