more test cases
[ghsmtp.git] / TLS-OpenSSL.cpp
blobc8b72ad6b58a439a71508b15939beb86d5ba5559
1 #include "TLS-OpenSSL.hpp"
3 #include <iomanip>
4 #include <string>
6 #include <openssl/err.h>
7 #include <openssl/rand.h>
9 #include <openssl/x509.h>
10 #include <openssl/x509v3.h>
12 #include <glog/logging.h>
14 #define FMT_STRING_ALIAS 1
15 #include <fmt/format.h>
17 #include "DNS.hpp"
18 #include "POSIX.hpp"
19 #include "osutil.hpp"
21 // <https://tools.ietf.org/html/rfc7919>
22 // <https://wiki.mozilla.org/Security/Server_Side_TLS#DHE_handshake_and_dhparam>
23 constexpr char ffdhe4096[] = R"(
24 -----BEGIN DH PARAMETERS-----
25 MIICCAKCAgEA//////////+t+FRYortKmq/cViAnPTzx2LnFg84tNpWp4TZBFGQz
26 +8yTnc4kmz75fS/jY2MMddj2gbICrsRhetPfHtXV/WVhJDP1H18GbtCFY2VVPe0a
27 87VXE15/V8k1mE8McODmi3fipona8+/och3xWKE2rec1MKzKT0g6eXq8CrGCsyT7
28 YdEIqUuyyOP7uWrat2DX9GgdT0Kj3jlN9K5W7edjcrsZCwenyO4KbXCeAvzhzffi
29 7MA0BM0oNC9hkXL+nOmFg/+OTxIy7vKBg8P+OxtMb61zO7X8vC7CIAXFjvGDfRaD
30 ssbzSibBsu/6iGtCOGEfz9zeNVs7ZRkDW7w09N75nAI4YbRvydbmyQd62R0mkff3
31 7lmMsPrBhtkcrv4TCYUTknC0EwyTvEN5RPT9RFLi103TZPLiHnH1S/9croKrnJ32
32 nuhtK8UiNjoNq8Uhl5sN6todv5pC1cRITgq80Gv6U93vPBsg7j/VnXwl5B0rZp4e
33 8W5vUsMWTfT7eTDp5OWIV7asfV9C1p9tGHdjzx1VA0AEh/VbpX4xzHpxNciG77Qx
34 iu1qHgEtnmgyqQdgCpGBMMRtx3j5ca0AOAkpmaMzy4t6Gh25PXFAADwqTs6p+Y0K
35 zAqCkc3OyX3Pjsm1Wn+IpGtNtahR9EGC4caKAH5eZV9q//////////8CAQI=
36 -----END DH PARAMETERS-----
37 )";
39 // convert binary input into a std::string of hex digits
41 auto bin2hexstring(uint8_t const* data, size_t length)
43 std::string ret;
44 ret.reserve(2 * length);
46 for (size_t n = 0u; n < length; ++n) {
47 auto const ch = data[n];
49 auto const lo = ch & 0xF;
50 auto const hi = (ch >> 4) & 0xF;
52 auto constexpr hex_digits = "0123456789abcdef";
54 ret += hex_digits[hi];
55 ret += hex_digits[lo];
58 return ret;
61 TLS::TLS(std::function<void(void)> read_hook)
62 : read_hook_(read_hook)
66 TLS::~TLS()
68 for (auto& ctx : cert_ctx_) {
69 if (ctx.ctx) {
70 SSL_CTX_free(ctx.ctx);
73 if (ssl_) {
74 SSL_free(ssl_);
78 struct session_context {
81 static int session_context_index = -1;
83 static int verify_callback(int preverify_ok, X509_STORE_CTX* ctx)
85 auto const cert = X509_STORE_CTX_get_current_cert(ctx);
86 if (cert == nullptr)
87 return 1;
89 auto err = X509_STORE_CTX_get_error(ctx);
91 // auto const ssl = reinterpret_cast<SSL*>(
92 // X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx()));
94 CHECK_GE(session_context_index, 0);
96 // auto unused = reinterpret_cast<session_context*>(SSL_get_ex_data(ssl,
97 // session_context_index));
99 auto const depth = X509_STORE_CTX_get_error_depth(ctx);
101 char buf[256];
102 X509_NAME_oneline(X509_get_subject_name(cert), buf, sizeof(buf));
104 if (depth > Config::cert_verify_depth) {
105 preverify_ok = 0;
106 err = X509_V_ERR_CERT_CHAIN_TOO_LONG;
107 X509_STORE_CTX_set_error(ctx, err);
109 if (!preverify_ok) {
110 LOG(INFO) << "verify error:num=" << err << ':'
111 << X509_verify_cert_error_string(err) << ": depth=" << depth
112 << ':' << buf;
114 else {
115 LOG(INFO) << "preverify_ok; depth=" << depth << " subject_name=«" << buf
116 << "»";
119 if (!preverify_ok && (err == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT)) {
120 if (cert) {
121 X509_NAME_oneline(X509_get_issuer_name(cert), buf, sizeof(buf));
122 LOG(INFO) << "issuer=" << buf;
124 else {
125 LOG(INFO) << "issuer=<unknown>";
129 return 1; // always continue
132 static int ssl_servername_callback(SSL* s, int* ad, void* arg)
134 auto cert_ctx_ptr
135 = CHECK_NOTNULL(static_cast<std::vector<TLS::per_cert_ctx>*>(arg));
136 auto const& cert_ctx = *cert_ctx_ptr;
138 auto const servername = SSL_get_servername(s, TLSEXT_NAMETYPE_host_name);
140 if (servername && *servername) {
141 LOG(INFO) << "servername requested " << servername;
142 for (auto const& ctx : cert_ctx) {
143 if (auto const& c = std::find(begin(ctx.cn), end(ctx.cn), servername);
144 c != end(ctx.cn)) {
145 if (size(cert_ctx) > 1)
146 SSL_set_SSL_CTX(s, ctx.ctx);
147 return SSL_TLSEXT_ERR_OK;
150 LOG(INFO) << "no cert found for server " << servername;
151 return SSL_TLSEXT_ERR_ALERT_WARNING;
154 // LOG(INFO) << "no specific server name requested";
155 return SSL_TLSEXT_ERR_OK;
158 bool TLS::starttls_client(fs::path config_path,
159 int fd_in,
160 int fd_out,
161 char const* client_name,
162 char const* server_name,
163 DNS::RR_collection const& tlsa_rrs,
164 bool enforce_dane,
165 std::chrono::milliseconds timeout)
167 SSL_load_error_strings();
168 SSL_library_init();
170 CHECK(RAND_status()); // Be sure the PRNG has been seeded with enough data.
172 auto const method = CHECK_NOTNULL(SSLv23_client_method());
174 if (client_name) {
175 auto const certs = osutil::list_directory(config_path, Config::cert_fn_re);
177 CHECK_GE(certs.size(), 1) << "no client cert(s) found";
179 for (auto const& cert : certs) {
181 auto ctx = CHECK_NOTNULL(SSL_CTX_new(method));
182 std::vector<Domain> cn;
184 SSL_CTX_set_ecdh_auto(ctx, 1);
186 // SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
188 CHECK_GT(SSL_CTX_dane_enable(ctx), 0)
189 << "unable to enable DANE on SSL context";
191 // you'd think if it's the default, you'd not have to call this
192 CHECK_EQ(SSL_CTX_set_default_verify_paths(ctx), 1);
194 CHECK_GT(SSL_CTX_use_certificate_chain_file(ctx, cert.string().c_str()),
196 << "Can't load certificate chain file " << cert;
198 auto const key = fs::path(cert).replace_extension(Config::key_ext);
200 if (fs::exists(key)) {
202 CHECK_GT(SSL_CTX_use_PrivateKey_file(ctx, key.string().c_str(),
203 SSL_FILETYPE_PEM),
205 << "Can't load private key file " << key;
207 CHECK(SSL_CTX_check_private_key(ctx))
208 << "SSL_CTX_check_private_key failed for " << key;
211 SSL_CTX_set_verify_depth(ctx, Config::cert_verify_depth + 1);
212 SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE,
213 verify_callback);
215 //.......................................................
217 auto const x509 = CHECK_NOTNULL(SSL_CTX_get0_certificate(ctx));
219 X509_NAME* subj = X509_get_subject_name(x509);
221 int lastpos = -1;
222 for (;;) {
223 lastpos = X509_NAME_get_index_by_NID(subj, NID_commonName, lastpos);
224 if (lastpos == -1)
225 break;
226 auto e = X509_NAME_get_entry(subj, lastpos);
227 ASN1_STRING* d = X509_NAME_ENTRY_get_data(e);
228 auto str = ASN1_STRING_get0_data(d);
229 // LOG(INFO) << "client cert found for " << str;
230 cn.emplace_back(reinterpret_cast<const char*>(str));
233 auto subject_alt_names = static_cast<GENERAL_NAMES*>(
234 X509_get_ext_d2i(x509, NID_subject_alt_name, nullptr, nullptr));
236 for (int i = 0; i < sk_GENERAL_NAME_num(subject_alt_names); ++i) {
238 GENERAL_NAME* gen = sk_GENERAL_NAME_value(subject_alt_names, i);
240 if (gen->type == GEN_URI || gen->type == GEN_EMAIL) {
241 ASN1_IA5STRING* asn1_str = gen->d.uniformResourceIdentifier;
243 std::string const str(
244 reinterpret_cast<char const*>(ASN1_STRING_get0_data(asn1_str)),
245 ASN1_STRING_length(asn1_str));
247 LOG(INFO) << "email or uri alt name " << str;
249 else if (gen->type == GEN_DNS) {
250 ASN1_IA5STRING* asn1_str = gen->d.uniformResourceIdentifier;
252 std::string str(
253 reinterpret_cast<char const*>(ASN1_STRING_get0_data(asn1_str)),
254 ASN1_STRING_length(asn1_str));
256 if (find(begin(cn), end(cn), str) == end(cn)) {
257 // LOG(INFO) << "additional name found " << str;
258 cn.emplace_back(str);
260 else {
261 // LOG(INFO) << "duplicate name " << str << " ignored";
264 else if (gen->type == GEN_IPADD) {
265 unsigned char* p = gen->d.ip->data;
266 if (gen->d.ip->length == 4) {
267 auto const ip = fmt::format(FMT_STRING("{:d}.{:d}.{:d}.{:d}"), p[0],
268 p[1], p[2], p[3]);
269 LOG(INFO) << "alt name IP4 address " << ip;
271 else if (gen->d.ip->length == 16) {
272 LOG(ERROR) << "IPv6 not implemented";
274 else {
275 LOG(ERROR) << "unknown IP type";
278 else {
279 LOG(ERROR) << "unknown alt name type";
283 GENERAL_NAMES_free(subject_alt_names);
285 //.......................................................
287 if (std::find(begin(cn), end(cn), client_name) != end(cn)) {
288 // LOG(INFO) << "**** using cert for " << client_name;
289 cert_ctx_.emplace_back(ctx, cn);
294 if (cert_ctx_.empty()) {
295 LOG(INFO) << "no cert found for client " << client_name;
297 auto ctx = CHECK_NOTNULL(SSL_CTX_new(method));
298 CHECK_GT(SSL_CTX_dane_enable(ctx), 0)
299 << "unable to enable DANE on SSL context";
301 // you'd think if it's the default, you'd not have to call this
302 CHECK_EQ(SSL_CTX_set_default_verify_paths(ctx), 1);
304 SSL_CTX_set_verify_depth(ctx, Config::cert_verify_depth + 1);
305 SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE,
306 verify_callback);
308 LOG(INFO) << "**** using no client cert";
310 std::vector<Domain> cn;
311 cert_ctx_.emplace_back(ctx, cn);
314 ssl_ = CHECK_NOTNULL(SSL_new(cert_ctx_.back().ctx));
316 SSL_set_rfd(ssl_, fd_in);
317 SSL_set_wfd(ssl_, fd_out);
319 // LOG(INFO) << "tlsa_rrs.size() == " << tlsa_rrs.size();
321 if (tlsa_rrs.size()) {
322 CHECK_GE(SSL_dane_enable(ssl_, server_name), 0)
323 << "SSL_dane_enable() failed";
324 LOG(INFO) << "SSL_dane_enable(ssl_, " << server_name << ")";
326 else {
327 CHECK_EQ(SSL_set1_host(ssl_, server_name), 1);
329 // SSL_set_tlsext_host_name(ssl_, server_name);
330 // same as:
331 CHECK_EQ(SSL_ctrl(ssl_, SSL_CTRL_SET_TLSEXT_HOSTNAME,
332 TLSEXT_NAMETYPE_host_name,
333 const_cast<char*>(server_name)),
335 // LOG(INFO) << "SSL_set1_host and SSL_set_tlsext_host_name " <<
336 // server_name;
339 // No partial label wildcards
340 SSL_set_hostflags(ssl_, X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS);
342 auto usable_TLSA_records = 0;
344 for (auto const& tlsa_rr : tlsa_rrs) {
345 if (std::holds_alternative<DNS::RR_TLSA>(tlsa_rr)) {
346 auto const rp = std::get<DNS::RR_TLSA>(tlsa_rr);
347 auto data = rp.assoc_data();
348 auto rc = SSL_dane_tlsa_add(ssl_, rp.cert_usage(), rp.selector(),
349 rp.matching_type(), data.data(), data.size());
351 if (rc < 0) {
352 auto const cp = bin2hexstring(data.data(), data.size());
353 LOG(ERROR) << "SSL_dane_tlsa_add() failed.";
354 LOG(ERROR) << "failed record: " << rp.cert_usage() << " "
355 << rp.selector() << " " << rp.matching_type() << " " << cp;
357 else if (rc == 0) {
358 auto const cp = bin2hexstring(data.data(), data.size());
359 LOG(ERROR) << "unusable TLSA record: " << rp.cert_usage() << " "
360 << rp.selector() << " " << rp.matching_type() << " " << cp;
362 else {
363 // auto const cp = bin2hexstring(data.data(), data.size());
364 // LOG(INFO) << "added TLSA record: " << rp.cert_usage() << " "
365 // << rp.selector() << " " << rp.matching_type() << " " << cp;
366 ++usable_TLSA_records;
371 // CHECK_EQ(SSL_set_tlsext_host_name(ssl_, server_name), 1);
372 // same as:
373 // CHECK_EQ(SSL_ctrl(ssl_, SSL_CTRL_SET_TLSEXT_HOSTNAME,
374 // TLSEXT_NAMETYPE_host_name,
375 // const_cast<char*>(server_name)),
376 // 1);
377 // LOG(INFO) << "SSL_set_tlsext_host_name == " << server_name;
379 if (session_context_index < 0) {
380 session_context_index =
381 SSL_get_ex_new_index(0, nullptr, nullptr, nullptr, nullptr);
383 session_context context;
384 SSL_set_ex_data(ssl_, session_context_index, &context);
386 auto const start = std::chrono::system_clock::now();
388 ERR_clear_error();
390 int rc;
391 while ((rc = SSL_connect(ssl_)) < 0) {
393 auto const now = std::chrono::system_clock::now();
395 CHECK(now < (start + timeout)) << "starttls timed out";
397 auto time_left = std::chrono::duration_cast<std::chrono::milliseconds>(
398 (start + timeout) - now);
400 int n_get_err;
401 switch (n_get_err = SSL_get_error(ssl_, rc)) {
402 case SSL_ERROR_WANT_READ:
403 CHECK(POSIX::input_ready(fd_in, time_left))
404 << "starttls timed out on input_ready";
405 ERR_clear_error();
406 continue; // try SSL_accept again
408 case SSL_ERROR_WANT_WRITE:
409 CHECK(POSIX::output_ready(fd_out, time_left))
410 << "starttls timed out on output_ready";
411 ERR_clear_error();
412 continue; // try SSL_accept again
414 case SSL_ERROR_SYSCALL:
415 LOG(WARNING) << "errno == " << errno << ": " << strerror(errno);
416 [[fallthrough]];
418 default: ssl_error(n_get_err);
422 if (SSL_get_verify_result(ssl_) == X509_V_OK) {
423 LOG(INFO) << "server certificate verified";
424 verified_ = true;
426 char const* const peername = SSL_get0_peername(ssl_);
427 if (peername != nullptr) {
428 // Name checks were in scope and matched the peername
429 verified_peername_ = peername;
430 LOG(INFO) << "verified peername: " << peername;
432 else {
433 LOG(INFO) << "no verified peername";
436 EVP_PKEY* mspki = nullptr;
437 int depth = SSL_get0_dane_authority(ssl_, nullptr, &mspki);
438 if (depth >= 0) {
440 uint8_t usage, selector, mtype;
441 const unsigned char* certdata;
442 size_t certdata_len;
444 SSL_get0_dane_tlsa(ssl_, &usage, &selector, &mtype, &certdata,
445 &certdata_len);
447 LOG(INFO) << "DANE TLSA " << unsigned(usage) << " " << unsigned(selector)
448 << " " << unsigned(mtype) << " [" << bin2hexstring(certdata, 6)
449 << "...] "
450 << ((mspki != nullptr) ? "TA public key verified certificate"
451 : depth ? "matched TA certificate"
452 : "matched EE certificate")
453 << " at depth " << depth;
455 else if (usable_TLSA_records && enforce_dane) {
456 LOG(WARNING) << "enforcing DANE; failing starttls";
457 return false;
460 else {
461 LOG(WARNING) << "server certificate failed to verify";
464 return true;
467 bool TLS::starttls_server(fs::path config_path,
468 int fd_in,
469 int fd_out,
470 std::chrono::milliseconds timeout)
472 SSL_load_error_strings();
473 SSL_library_init();
475 CHECK(RAND_status()); // Be sure the PRNG has been seeded with enough data.
477 auto const method = CHECK_NOTNULL(SSLv23_server_method());
479 auto const bio =
480 CHECK_NOTNULL(BIO_new_mem_buf(const_cast<char*>(ffdhe4096), -1));
481 auto const dh =
482 CHECK_NOTNULL(PEM_read_bio_DHparams(bio, nullptr, nullptr, nullptr));
484 auto const certs = osutil::list_directory(config_path, Config::cert_fn_re);
486 CHECK_GE(certs.size(), 1) << "no server cert(s) found";
488 for (auto const& cert : certs) {
490 auto ctx = CHECK_NOTNULL(SSL_CTX_new(method));
491 std::vector<Domain> names;
493 SSL_CTX_set_options(ctx, SSL_OP_CIPHER_SERVER_PREFERENCE);
494 SSL_CTX_clear_options(ctx, SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION);
496 SSL_CTX_set_ecdh_auto(ctx, 1);
498 CHECK_GT(SSL_CTX_dane_enable(ctx), 0)
499 << "unable to enable DANE on SSL context";
501 // you'd think if it's the default, you'd not have to call this
502 CHECK_EQ(SSL_CTX_set_default_verify_paths(ctx), 1);
504 CHECK_GT(SSL_CTX_use_certificate_chain_file(ctx, cert.string().c_str()), 0)
505 << "Can't load certificate chain file " << cert;
507 auto const key = fs::path(cert).replace_extension(Config::key_ext);
509 if (fs::exists(key)) {
511 CHECK_GT(SSL_CTX_use_PrivateKey_file(ctx, key.string().c_str(),
512 SSL_FILETYPE_PEM),
514 << "Can't load private key file " << key;
516 CHECK(SSL_CTX_check_private_key(ctx))
517 << "SSL_CTX_check_private_key failed for " << key;
520 #pragma GCC diagnostic push
521 #pragma GCC diagnostic ignored "-Wold-style-cast"
523 SSL_CTX_set_tmp_dh(ctx, dh);
525 #pragma GCC diagnostic pop
527 SSL_CTX_set_verify_depth(ctx, Config::cert_verify_depth + 1);
529 SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE,
530 verify_callback);
532 // SSL_CTX_set_tlsext_servername_callback(ctx, ssl_servername_callback);
533 // same as:
534 SSL_CTX_callback_ctrl(
535 ctx, SSL_CTRL_SET_TLSEXT_SERVERNAME_CB,
536 reinterpret_cast<void (*)()>(ssl_servername_callback));
538 // SSL_CTX_set_tlsext_servername_arg(ctx, &cert_ctx_);
539 // same as:
540 SSL_CTX_ctrl(ctx, SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG, 0,
541 reinterpret_cast<void*>(&cert_ctx_));
543 // SSL_CTX_dane_set_flags(ctx, DANE_FLAG_NO_DANE_EE_NAMECHECKS);
545 //.......................................................
547 auto const x509 = CHECK_NOTNULL(SSL_CTX_get0_certificate(ctx));
549 X509_NAME* subj = X509_get_subject_name(x509);
551 int lastpos = -1;
552 for (;;) {
553 lastpos = X509_NAME_get_index_by_NID(subj, NID_commonName, lastpos);
554 if (lastpos == -1)
555 break;
556 auto e = X509_NAME_get_entry(subj, lastpos);
557 ASN1_STRING* d = X509_NAME_ENTRY_get_data(e);
558 auto str = ASN1_STRING_get0_data(d);
559 // LOG(INFO) << "server cert found for " << str;
560 names.emplace_back(reinterpret_cast<const char*>(str));
563 // auto ext_stack = X509_get0_extensions(x509);
564 // for (int i = 0; i < sk_X509_EXTENSION_num(ext_stack); i++) {
565 // X509_EXTENSION* ext
566 // = CHECK_NOTNULL(sk_X509_EXTENSION_value(ext_stack, i));
567 // ASN1_OBJECT* asn1_obj =
568 // CHECK_NOTNULL(X509_EXTENSION_get_object(ext)); unsigned nid =
569 // OBJ_obj2nid(asn1_obj); if (nid == NID_undef) {
570 // // no lookup found for the provided OID so nid came back as
571 // undefined. char extname[256]; OBJ_obj2txt(extname, sizeof(extname),
572 // asn1_obj, 1); LOG(INFO) << "undef extension name is " << extname;
573 // } else {
574 // // the OID translated to a NID which implies that the OID has a
575 // known
576 // // sn/ln
577 // const char* c_ext_name = CHECK_NOTNULL(OBJ_nid2ln(nid));
578 // LOG(INFO) << "extension " << c_ext_name;
579 // }
580 // }
582 auto subject_alt_names = static_cast<GENERAL_NAMES*>(
583 X509_get_ext_d2i(x509, NID_subject_alt_name, nullptr, nullptr));
585 for (int i = 0; i < sk_GENERAL_NAME_num(subject_alt_names); ++i) {
587 GENERAL_NAME* gen = sk_GENERAL_NAME_value(subject_alt_names, i);
589 if (gen->type == GEN_URI || gen->type == GEN_EMAIL) {
590 ASN1_IA5STRING* asn1_str = gen->d.uniformResourceIdentifier;
592 std::string str(
593 reinterpret_cast<char const*>(ASN1_STRING_get0_data(asn1_str)),
594 ASN1_STRING_length(asn1_str));
596 LOG(INFO) << "email or uri alt name " << str;
598 else if (gen->type == GEN_DNS) {
599 ASN1_IA5STRING* asn1_str = gen->d.uniformResourceIdentifier;
601 std::string str(
602 reinterpret_cast<char const*>(ASN1_STRING_get0_data(asn1_str)),
603 ASN1_STRING_length(asn1_str));
605 if (find(begin(names), end(names), str) == end(names)) {
606 // LOG(INFO) << "additional name found " << str;
607 names.emplace_back(str);
609 else {
610 // LOG(INFO) << "duplicate name " << str << " ignored";
613 else if (gen->type == GEN_IPADD) {
614 unsigned char* p = gen->d.ip->data;
615 if (gen->d.ip->length == 4) {
616 auto const ip = fmt::format(FMT_STRING("{:d}.{:d}.{:d}.{:d}"), p[0],
617 p[1], p[2], p[3]);
618 LOG(INFO) << "alt name IP4 address " << ip;
619 names.emplace_back(ip);
621 else if (gen->d.ip->length == 16) {
622 // FIXME!
623 LOG(ERROR) << "IPv6 not implemented";
625 else {
626 LOG(ERROR) << "unknown IP type";
629 else {
630 LOG(ERROR) << "unknown alt name type";
634 GENERAL_NAMES_free(subject_alt_names);
636 //.......................................................
638 cert_ctx_.emplace_back(ctx, names);
641 DH_free(dh);
642 BIO_free(bio);
644 ssl_ = CHECK_NOTNULL(SSL_new(cert_ctx_.back().ctx));
646 SSL_set_rfd(ssl_, fd_in);
647 SSL_set_wfd(ssl_, fd_out);
649 if (session_context_index < 0) {
650 session_context_index =
651 SSL_get_ex_new_index(0, nullptr, nullptr, nullptr, nullptr);
653 session_context context;
654 SSL_set_ex_data(ssl_, session_context_index, &context);
656 auto const start = std::chrono::system_clock::now();
658 ERR_clear_error();
660 int rc;
661 while ((rc = SSL_accept(ssl_)) < 0) {
663 auto const now = std::chrono::system_clock::now();
665 CHECK(now < (start + timeout)) << "starttls timed out";
667 auto const time_left =
668 std::chrono::duration_cast<std::chrono::milliseconds>(
669 (start + timeout) - now);
671 int n_get_err;
672 switch (n_get_err = SSL_get_error(ssl_, rc)) {
673 case SSL_ERROR_WANT_READ:
674 CHECK(POSIX::input_ready(fd_in, time_left))
675 << "starttls timed out on input_ready";
676 ERR_clear_error();
677 continue; // try SSL_accept again
679 case SSL_ERROR_WANT_WRITE:
680 CHECK(POSIX::output_ready(fd_out, time_left))
681 << "starttls timed out on output_ready";
682 ERR_clear_error();
683 continue; // try SSL_accept again
685 case SSL_ERROR_SYSCALL:
686 LOG(WARNING) << "errno == " << errno << ": " << strerror(errno);
687 [[fallthrough]];
689 default: ssl_error(n_get_err);
693 if (auto const peer_cert = SSL_get_peer_certificate(ssl_); peer_cert) {
694 if (SSL_get_verify_result(ssl_) == X509_V_OK) {
695 LOG(INFO) << "client certificate verified";
696 verified_ = true;
698 char const* const peername = SSL_get0_peername(ssl_);
699 if (peername != nullptr) {
700 // name checks were in scope and matched the peername
701 verified_peername_ = peername;
702 LOG(INFO) << "verified peername: " << peername;
704 else {
705 LOG(INFO) << "no verified peername";
708 EVP_PKEY* mspki = nullptr;
709 int depth = SSL_get0_dane_authority(ssl_, nullptr, &mspki);
710 if (depth >= 0) {
712 uint8_t usage, selector, mtype;
713 const unsigned char* certdata;
714 size_t certdata_len;
716 SSL_get0_dane_tlsa(ssl_, &usage, &selector, &mtype, &certdata,
717 &certdata_len);
719 LOG(INFO) << "DANE TLSA " << usage << " " << selector << " " << mtype
720 << " [" << bin2hexstring(certdata, 6) << "...] "
721 << ((mspki != nullptr) ? "TA public key verified certificate"
722 : depth ? "matched TA certificate"
723 : "matched EE certificate")
724 << " at depth " << depth;
727 else {
728 LOG(WARNING) << "client certificate failed to verify";
731 else {
732 // LOG(INFO) << "no client certificate offerd to us";
735 return true;
738 std::string TLS::info() const
740 // same as SSL_CIPHER_get_version() below
741 // info << SSL_get_version(ssl_);
743 auto const c = SSL_get_current_cipher(ssl_);
744 if (c) {
745 int alg_bits;
746 int bits = SSL_CIPHER_get_bits(c, &alg_bits);
747 return fmt::format("version={} cipher={} bits={}/{}{}",
748 SSL_CIPHER_get_version(c), SSL_CIPHER_get_name(c), bits,
749 alg_bits, (verified_ ? " verified" : ""));
752 return "";
755 std::streamsize TLS::io_tls_(char const* fn,
756 std::function<int(SSL*, void*, int)> io_fnc,
757 char* s,
758 std::streamsize n,
759 std::chrono::milliseconds timeout,
760 bool& t_o)
762 auto const start = std::chrono::system_clock::now();
763 auto const end_time = start + timeout;
765 ERR_clear_error();
767 int n_ret;
768 while ((n_ret = io_fnc(ssl_, static_cast<void*>(s), static_cast<int>(n)))
769 < 0) {
770 auto const now = std::chrono::system_clock::now();
771 if (now > end_time) {
772 LOG(WARNING) << fn << " timed out";
773 t_o = true;
774 return static_cast<std::streamsize>(-1);
777 auto const time_left
778 = std::chrono::duration_cast<std::chrono::milliseconds>(end_time - now);
780 int n_get_err;
781 switch (n_get_err = SSL_get_error(ssl_, n_ret)) {
782 case SSL_ERROR_WANT_READ: {
783 int fd = SSL_get_rfd(ssl_);
784 CHECK_NE(-1, fd);
785 read_hook_();
786 if (POSIX::input_ready(fd, time_left)) {
787 ERR_clear_error();
788 continue; // try io_fnc again
790 LOG(WARNING) << fn << " timed out";
791 t_o = true;
792 return static_cast<std::streamsize>(-1);
795 case SSL_ERROR_WANT_WRITE: {
796 int fd = SSL_get_wfd(ssl_);
797 CHECK_NE(-1, fd);
798 if (POSIX::output_ready(fd, time_left)) {
799 ERR_clear_error();
800 continue; // try io_fnc again
802 LOG(WARNING) << fn << " timed out";
803 t_o = true;
804 return static_cast<std::streamsize>(-1);
807 case SSL_ERROR_SYSCALL:
808 LOG(WARNING) << "errno == " << errno << ": " << strerror(errno);
809 [[fallthrough]];
811 default: ssl_error(n_get_err);
815 // The strange (and never before seen) case of 0 return.
816 if (0 == n_ret) {
817 int n_get_err;
818 switch (n_get_err = SSL_get_error(ssl_, n_ret)) {
819 case SSL_ERROR_NONE: LOG(INFO) << fn << " returned SSL_ERROR_NONE"; break;
821 case SSL_ERROR_ZERO_RETURN:
822 // This is a close, not at all sure this is the right thing to do.
823 LOG(INFO) << fn << " returned SSL_ERROR_ZERO_RETURN";
824 break;
826 default: LOG(INFO) << fn << " returned zero"; ssl_error(n_get_err);
830 return static_cast<std::streamsize>(n_ret);
833 void TLS::ssl_error(int n_get_err)
835 LOG(WARNING) << "n_get_err == " << n_get_err;
836 switch (n_get_err) {
837 case SSL_ERROR_NONE: LOG(WARNING) << "SSL_ERROR_NONE"; break;
838 case SSL_ERROR_ZERO_RETURN: LOG(WARNING) << "SSL_ERROR_ZERO_RETURN"; break;
839 case SSL_ERROR_WANT_READ: LOG(WARNING) << "SSL_ERROR_WANT_READ"; break;
840 case SSL_ERROR_WANT_WRITE: LOG(WARNING) << "SSL_ERROR_WANT_WRITE"; break;
841 case SSL_ERROR_WANT_CONNECT: LOG(WARNING) << "SSL_ERROR_WANT_CONNECT"; break;
842 case SSL_ERROR_WANT_ACCEPT: LOG(WARNING) << "SSL_ERROR_WANT_ACCEPT"; break;
843 case SSL_ERROR_WANT_X509_LOOKUP:
844 LOG(WARNING) << "SSL_ERROR_WANT_X509_LOOKUP";
845 break;
846 case SSL_ERROR_SSL: LOG(WARNING) << "SSL_ERROR_SSL"; break;
848 unsigned long er;
849 while (0 != (er = ERR_get_error()))
850 LOG(WARNING) << ERR_error_string(er, nullptr);
851 LOG(FATAL) << "fatal OpenSSL error";