Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Disable TLS renegotiation #9885

Merged
merged 1 commit into from
Dec 12, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions lib/base/tlsutility.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
#include <boost/asio/ssl/context.hpp>
#include <openssl/opensslv.h>
#include <openssl/crypto.h>
#include <openssl/ssl.h>
#include <openssl/ssl3.h>
#include <fstream>

namespace icinga
Expand Down Expand Up @@ -91,6 +93,16 @@ static void InitSslContext(const Shared<boost::asio::ssl::context>::Ptr& context

flags |= SSL_OP_CIPHER_SERVER_PREFERENCE;

#if OPENSSL_VERSION_NUMBER < 0x10100000L
SSL_CTX_set_info_callback(sslContext, [](const SSL* ssl, int where, int) {
if (where & SSL_CB_HANDSHAKE_DONE) {
ssl->s3->flags |= SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS;
}
});
Comment on lines +97 to +101
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Test

CentOS 7.

# yum info icinga2
Geladene Plugins: fastestmirror
In Paketquelle '7ce9457a4' fehlt der Name in der Konfiguration, id wird benutzt
Loading mirror speeds from cached hostfile
 * base: de.mirrors.clouvider.net
 * epel: mirror.imt-systems.com
 * extras: ftp.rz.uni-frankfurt.de
 * updates: de.mirrors.clouvider.net
Installierte Pakete
Name       : icinga2
Architektur : x86_64
Version    : 2.14.0+32.g7ce9457a4
...
$ openssl s_client -connect 127.0.0.1:5665
CONNECTED(00000003)
...
---
R
RENEGOTIATING
140428114962320:error:1409E0E5:SSL routines:ssl3_write_bytes:ssl handshake failure:s3_pkt.c:659:
$

error:1409E0E5 needs some time to appear.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Entering R triggers:

[pid 26756] <... epoll_wait resumed>[{EPOLLIN, {u32=2818574528, u64=140280745429184}}], 128, -1) = 1
[pid 26756] futex(0x31ef204, FUTEX_WAKE_OP_PRIVATE, 1, 1, 0x31ef200, FUTEX_OP_SET<<28|0<<12|FUTEX_OP_CMP_GT<<24|0x1) = 1
[pid 26755] <... futex resumed>)        = 0
[pid 26756] recvmsg(18,  <unfinished ...>
[pid 26755] futex(0x31ef1c8, FUTEX_WAKE_PRIVATE, 1 <unfinished ...>
[pid 26756] <... recvmsg resumed>{msg_name=NULL, msg_namelen=0, msg_iov=[{iov_base="\26\3\3\0\344\0\0\0\0\0\0\0\1\v\215\312\201M\232\242\32\246\345\244\217\306\245\31\375qa\270\2356\2244\37\254\10i\243\360v\n\314\324Z\300j\334\327\355\203B(`\221\27\0\r\310\235\212A\252\223'\322\216\242\226\312\373\363\336b$=\211%u\252m\343\301%\32\0\270\363'\32\304\345I\202\370\352-eP\204\253~\":JN>\275e\236\177b-\266\355\334G6\202\234oYg1t\7,\211\302!bb\326\266\224\302\342O\333\272\37\360\212.\215\23\"H\214/)\335.d\364\235i[!\310\3415\333\36\1M\247\24\301_\t\265\325\207\373k\220\366\305\250\ns\262H\31[?\272\220\222\260\205\323;\34t\246\36\255;;\346A\30N>\324=\313\23\7\270\273l\225x\354*r\245\300\313\214\375V\200=\243@\357\34", iov_len=17408}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 233
[pid 26755] <... futex resumed>)        = 0
[pid 26756] recvmsg(18,  <unfinished ...>
[pid 26755] epoll_wait(15,  <unfinished ...>
[pid 26756] <... recvmsg resumed>{msg_namelen=0}, 0) = -1 EAGAIN (Die Ressource ist zur Zeit nicht verfügbar)

And after a lot of business as usual via futex and clock_gettime it gets closed:

[pid 26755] <... epoll_wait resumed>[{EPOLLIN, {u32=52161028, u64=52161028}}], 128, -1) = 1
[pid 26755] timerfd_settime(16, 0, {it_interval={tv_sec=0, tv_nsec=0}, it_value={tv_sec=300, tv_nsec=0}}, {it_interval={tv_sec=0, tv_nsec=0}, it_value={tv_sec=0, tv_nsec=0}}) = 0
[pid 26755] futex(0x31ef204, FUTEX_WAKE_OP_PRIVATE, 1, 1, 0x31ef200, FUTEX_OP_SET<<28|0<<12|FUTEX_OP_CMP_GT<<24|0x1 <unfinished ...>
[pid 26757] <... futex resumed>)        = 0
[pid 26755] <... futex resumed>)        = 1
[pid 26757] futex(0x31ef1c8, FUTEX_WAKE_PRIVATE, 1 <unfinished ...>
[pid 26755] getpeername(18,  <unfinished ...>
[pid 26757] <... futex resumed>)        = 0
[pid 26755] <... getpeername resumed>{sa_family=AF_INET6, sin6_port=htons(63720), inet_pton(AF_INET6, "::ffff:192.168.204.19", &sin6_addr), sin6_flowinfo=htonl(0), sin6_scope_id=0}, [28]) = 0
[pid 26757] epoll_wait(15,  <unfinished ...>
[pid 26755] futex(0x31ef204, FUTEX_WAKE_OP_PRIVATE, 1, 1, 0x31ef200, FUTEX_OP_SET<<28|0<<12|FUTEX_OP_CMP_GT<<24|0x1) = 1
[pid 26754] <... futex resumed>)        = 0
[pid 26755] epoll_ctl(15, EPOLL_CTL_DEL, 18, 0x7f95a8053350 <unfinished ...>
[pid 26754] futex(0x31ef1c8, FUTEX_WAKE_PRIVATE, 1 <unfinished ...>
[pid 26755] <... epoll_ctl resumed>)    = 0
[pid 26754] <... futex resumed>)        = 0
[pid 26755] close(18 <unfinished ...>
[pid 26754] futex(0x31ef204, FUTEX_WAIT_PRIVATE, 68, NULL <unfinished ...>
[pid 26755] <... close resumed>)        = 0

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While awaiting R result:

Thread 11 (Thread 0x7f95d7794700 (LWP 26739)):
#0  pthread_cond_wait@@GLIBC_2.3.2 ()
    at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S:185
#1  0x00000000009fff92 in wait<boost::asio::detail::conditionally_enabled_mutex::scoped_lock> (lock=..., this=0x2b58070)
    at /usr/include/boost169/boost/asio/detail/conditionally_enabled_mutex.hpp:98
#2  wait (lock=..., this=0x2b58068)
    at /usr/include/boost169/boost/asio/detail/conditionally_enabled_event.hpp:89
#3  boost::asio::detail::scheduler::do_run_one (this=this@entry=0x2b58000,
    lock=..., this_thread=..., ec=...)
    at /usr/include/boost169/boost/asio/detail/impl/scheduler.ipp:409
#4  0x0000000000a092f1 in boost::asio::detail::scheduler::run (this=0x2b58000,
    ec=...) at /usr/include/boost169/boost/asio/detail/impl/scheduler.ipp:154
#5  0x0000000000a09555 in operator() (this=<optimized out>)
    at /usr/include/boost169/boost/asio/impl/thread_pool.ipp:33
#6  boost::asio::detail::posix_thread::func<boost::asio::thread_pool::thread_function>::run (this=<optimized out>)
    at /usr/include/boost169/boost/asio/detail/posix_thread.hpp:86
#7  0x00000000009f8d50 in boost::asio::detail::boost_asio_detail_posix_thread_function (arg=0x2b5a2e0)
    at /usr/include/boost169/boost/asio/detail/impl/posix_thread.ipp:74
#8  0x00007f95d6504ea5 in start_thread (arg=0x7f95d7794700)
    at pthread_create.c:307
#9  0x00007f95d413db0d in clone ()
    at ../sysdeps/unix/sysv/linux/x86_64/clone.S:111

Thread 10 (Thread 0x7f95d7753700 (LWP 26740)):
#0  pthread_cond_wait@@GLIBC_2.3.2 ()
    at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S:185
#1  0x00000000009fff92 in wait<boost::asio::detail::conditionally_enabled_mutex::scoped_lock> (lock=..., this=0x2b58070)
    at /usr/include/boost169/boost/asio/detail/conditionally_enabled_mutex.hpp:98
#2  wait (lock=..., this=0x2b58068)
    at /usr/include/boost169/boost/asio/detail/conditionally_enabled_event.hpp:89
#3  boost::asio::detail::scheduler::do_run_one (this=this@entry=0x2b58000,
    lock=..., this_thread=..., ec=...)
    at /usr/include/boost169/boost/asio/detail/impl/scheduler.ipp:409
#4  0x0000000000a092f1 in boost::asio::detail::scheduler::run (this=0x2b58000,
    ec=...) at /usr/include/boost169/boost/asio/detail/impl/scheduler.ipp:154
#5  0x0000000000a09555 in operator() (this=<optimized out>)
    at /usr/include/boost169/boost/asio/impl/thread_pool.ipp:33
#6  boost::asio::detail::posix_thread::func<boost::asio::thread_pool::thread_function>::run (this=<optimized out>)
    at /usr/include/boost169/boost/asio/detail/posix_thread.hpp:86
#7  0x00000000009f8d50 in boost::asio::detail::boost_asio_detail_posix_thread_function (arg=0x2b58120)
    at /usr/include/boost169/boost/asio/detail/impl/posix_thread.ipp:74
#8  0x00007f95d6504ea5 in start_thread (arg=0x7f95d7753700)
    at pthread_create.c:307
#9  0x00007f95d413db0d in clone ()
    at ../sysdeps/unix/sysv/linux/x86_64/clone.S:111

Thread 9 (Thread 0x7f95d7712700 (LWP 26741)):
#0  pthread_cond_wait@@GLIBC_2.3.2 ()
    at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S:185
#1  0x00000000009fff92 in wait<boost::asio::detail::conditionally_enabled_mutex::scoped_lock> (lock=..., this=0x2b58070)
    at /usr/include/boost169/boost/asio/detail/conditionally_enabled_mutex.hpp:98
#2  wait (lock=..., this=0x2b58068)
    at /usr/include/boost169/boost/asio/detail/conditionally_enabled_event.hpp:89
#3  boost::asio::detail::scheduler::do_run_one (this=this@entry=0x2b58000,
    lock=..., this_thread=..., ec=...)
    at /usr/include/boost169/boost/asio/detail/impl/scheduler.ipp:409
#4  0x0000000000a092f1 in boost::asio::detail::scheduler::run (this=0x2b58000,
    ec=...) at /usr/include/boost169/boost/asio/detail/impl/scheduler.ipp:154
#5  0x0000000000a09555 in operator() (this=<optimized out>)
    at /usr/include/boost169/boost/asio/impl/thread_pool.ipp:33
#6  boost::asio::detail::posix_thread::func<boost::asio::thread_pool::thread_function>::run (this=<optimized out>)
    at /usr/include/boost169/boost/asio/detail/posix_thread.hpp:86
#7  0x00000000009f8d50 in boost::asio::detail::boost_asio_detail_posix_thread_function (arg=0x2b58160)
    at /usr/include/boost169/boost/asio/detail/impl/posix_thread.ipp:74
#8  0x00007f95d6504ea5 in start_thread (arg=0x7f95d7712700)
    at pthread_create.c:307
#9  0x00007f95d413db0d in clone ()
    at ../sysdeps/unix/sysv/linux/x86_64/clone.S:111

Thread 8 (Thread 0x7f95d76d1700 (LWP 26742)):
#0  pthread_cond_wait@@GLIBC_2.3.2 ()
    at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S:185
#1  0x00000000009fff92 in wait<boost::asio::detail::conditionally_enabled_mutex::scoped_lock> (lock=..., this=0x2b58070)
    at /usr/include/boost169/boost/asio/detail/conditionally_enabled_mutex.hpp:98
#2  wait (lock=..., this=0x2b58068)
    at /usr/include/boost169/boost/asio/detail/conditionally_enabled_event.hpp:89
#3  boost::asio::detail::scheduler::do_run_one (this=this@entry=0x2b58000,
    lock=..., this_thread=..., ec=...)
    at /usr/include/boost169/boost/asio/detail/impl/scheduler.ipp:409
#4  0x0000000000a092f1 in boost::asio::detail::scheduler::run (this=0x2b58000,
    ec=...) at /usr/include/boost169/boost/asio/detail/impl/scheduler.ipp:154
#5  0x0000000000a09555 in operator() (this=<optimized out>)
    at /usr/include/boost169/boost/asio/impl/thread_pool.ipp:33
#6  boost::asio::detail::posix_thread::func<boost::asio::thread_pool::thread_function>::run (this=<optimized out>)
    at /usr/include/boost169/boost/asio/detail/posix_thread.hpp:86
#7  0x00000000009f8d50 in boost::asio::detail::boost_asio_detail_posix_thread_function (arg=0x2b59d40)
    at /usr/include/boost169/boost/asio/detail/impl/posix_thread.ipp:74
#8  0x00007f95d6504ea5 in start_thread (arg=0x7f95d76d1700)
    at pthread_create.c:307
#9  0x00007f95d413db0d in clone ()
    at ../sysdeps/unix/sysv/linux/x86_64/clone.S:111

Thread 7 (Thread 0x7f95d7690700 (LWP 26744)):
#0  pthread_cond_timedwait@@GLIBC_2.3.2 ()
    at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S:238
#1  0x00000000009ce10d in __gthread_cond_timedwait (
    __abs_timeout=0x7f95d768fb80, __mutex=<optimized out>,
    __cond=0x12b8a60 <l_TimerCV>)
    at /opt/rh/devtoolset-11/root/usr/include/c++/11/x86_64-redhat-linux/bits/gthr-default.h:872
#2  wait_until (__abs_time=..., __m=..., this=0x12b8a60 <l_TimerCV>)
    at /opt/rh/devtoolset-11/root/usr/include/c++/11/bits/std_mutex.h:162
#3  __wait_until_impl<std::chrono::duration<double> > (__lock=..., __lock=...,
    __atime=<synthetic pointer>, this=0x12b8a60 <l_TimerCV>)
    at /opt/rh/devtoolset-11/root/usr/include/c++/11/condition_variable:222
#4  wait_until<std::chrono::duration<double> > (__atime=<synthetic pointer>,
    __lock=..., this=0x12b8a60 <l_TimerCV>)
    at /opt/rh/devtoolset-11/root/usr/include/c++/11/condition_variable:118
#5  icinga::Timer::TimerThreadProc() ()
    at /usr/src/debug/icinga2-2.14.0+32.g7ce9457a4/lib/base/timer.cpp:329
#6  0x0000000000feaeb4 in execute_native_thread_routine ()
#7  0x00007f95d6504ea5 in start_thread (arg=0x7f95d7690700)
    at pthread_create.c:307
#8  0x00007f95d413db0d in clone ()
    at ../sysdeps/unix/sysv/linux/x86_64/clone.S:111

Thread 6 (Thread 0x7f95d764f700 (LWP 26753)):
#0  pthread_cond_wait@@GLIBC_2.3.2 ()
    at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S:185
#1  0x00007f95d49d6aec in __gthread_cond_wait (__mutex=<optimized out>,
    __cond=__cond@entry=0x7f95c0006be0)
    at /usr/src/debug/gcc-4.8.5-20150702/obj-x86_64-redhat-linux/x86_64-redhat-linux/libstdc++-v3/include/x86_64-redhat-linux/bits/gthr-default.h:864
#2  std::condition_variable::wait (this=this@entry=0x7f95c0006be0, __lock=...)
    at ../../../../../libstdc++-v3/src/c++11/condition_variable.cc:52
#3  0x00000000009a57e6 in icinga::WorkQueue::WorkerThreadProc() ()
    at /usr/src/debug/icinga2-2.14.0+32.g7ce9457a4/lib/base/workqueue.cpp:264
#4  0x00007f95d6728954 in boost::(anonymous namespace)::thread_proxy (
    param=<optimized out>) at libs/thread/src/pthread/thread.cpp:177
#5  0x00007f95d6504ea5 in start_thread (arg=0x7f95d764f700)
    at pthread_create.c:307
#6  0x00007f95d413db0d in clone ()
    at ../sysdeps/unix/sysv/linux/x86_64/clone.S:111

Thread 5 (Thread 0x7f95d760e700 (LWP 26754)):
#0  pthread_cond_wait@@GLIBC_2.3.2 ()
    at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S:185
#1  0x00000000009fff92 in wait<boost::asio::detail::conditionally_enabled_mutex::scoped_lock> (lock=..., this=0x31ef200)
    at /usr/include/boost169/boost/asio/detail/conditionally_enabled_mutex.hpp:98
#2  wait (lock=..., this=0x31ef1f8)
    at /usr/include/boost169/boost/asio/detail/conditionally_enabled_event.hpp:89
#3  boost::asio::detail::scheduler::do_run_one (this=this@entry=0x31ef190,
    lock=..., this_thread=..., ec=...)
    at /usr/include/boost169/boost/asio/detail/impl/scheduler.ipp:409
#4  0x0000000000a092f1 in boost::asio::detail::scheduler::run (this=0x31ef190,
    ec=...) at /usr/include/boost169/boost/asio/detail/impl/scheduler.ipp:154
#5  0x00000000009c8d97 in run (this=0x31a7450)
    at /usr/include/boost169/boost/asio/impl/io_context.ipp:62
#6  icinga::IoEngine::RunEventLoop() ()
    at /usr/src/debug/icinga2-2.14.0+32.g7ce9457a4/lib/base/io-engine.cpp:115
#7  0x0000000000feaeb4 in execute_native_thread_routine ()
#8  0x00007f95d6504ea5 in start_thread (arg=0x7f95d760e700)
    at pthread_create.c:307
#9  0x00007f95d413db0d in clone ()
    at ../sysdeps/unix/sysv/linux/x86_64/clone.S:111

Thread 4 (Thread 0x7f95cf144700 (LWP 26755)):
#0  pthread_cond_wait@@GLIBC_2.3.2 ()
    at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S:185
#1  0x00000000009fff92 in wait<boost::asio::detail::conditionally_enabled_mutex::scoped_lock> (lock=..., this=0x31ef200)
    at /usr/include/boost169/boost/asio/detail/conditionally_enabled_mutex.hpp:98
#2  wait (lock=..., this=0x31ef1f8)
    at /usr/include/boost169/boost/asio/detail/conditionally_enabled_event.hpp:89
#3  boost::asio::detail::scheduler::do_run_one (this=this@entry=0x31ef190,
    lock=..., this_thread=..., ec=...)
    at /usr/include/boost169/boost/asio/detail/impl/scheduler.ipp:409
#4  0x0000000000a092f1 in boost::asio::detail::scheduler::run (this=0x31ef190,
    ec=...) at /usr/include/boost169/boost/asio/detail/impl/scheduler.ipp:154
#5  0x00000000009c8d97 in run (this=0x31a7450)
    at /usr/include/boost169/boost/asio/impl/io_context.ipp:62
#6  icinga::IoEngine::RunEventLoop() ()
    at /usr/src/debug/icinga2-2.14.0+32.g7ce9457a4/lib/base/io-engine.cpp:115
#7  0x0000000000feaeb4 in execute_native_thread_routine ()
#8  0x00007f95d6504ea5 in start_thread (arg=0x7f95cf144700)
    at pthread_create.c:307
#9  0x00007f95d413db0d in clone ()
    at ../sysdeps/unix/sysv/linux/x86_64/clone.S:111

Thread 3 (Thread 0x7f95cf103700 (LWP 26756)):
#0  0x00007f95d413e0e3 in epoll_wait ()
    lock=..., this_thread=..., ec=...)
    at /usr/include/boost169/boost/asio/detail/impl/scheduler.ipp:409
#4  0x0000000000a092f1 in boost::asio::detail::scheduler::run (this=0x31ef190,
    ec=...) at /usr/include/boost169/boost/asio/detail/impl/scheduler.ipp:154
#5  0x00000000009c8d97 in run (this=0x31a7450)
    at /usr/include/boost169/boost/asio/impl/io_context.ipp:62
#6  icinga::IoEngine::RunEventLoop() ()
    at /usr/src/debug/icinga2-2.14.0+32.g7ce9457a4/lib/base/io-engine.cpp:115
#7  0x0000000000feaeb4 in execute_native_thread_routine ()
#8  0x00007f95d6504ea5 in start_thread (arg=0x7f95cf144700)
    at pthread_create.c:307
#9  0x00007f95d413db0d in clone ()
    at ../sysdeps/unix/sysv/linux/x86_64/clone.S:111

Thread 3 (Thread 0x7f95cf103700 (LWP 26756)):
#0  0x00007f95d413e0e3 in epoll_wait ()
---Type <return> to continue, or q <return> to quit---
    at ../sysdeps/unix/syscall-template.S:81
#1  0x00000000009ff256 in boost::asio::detail::epoll_reactor::run (
    this=0x31be990, usec=<optimized out>, ops=...)
    at /usr/include/boost169/boost/asio/detail/impl/epoll_reactor.ipp:471
#2  0x00000000009ffe9a in boost::asio::detail::scheduler::do_run_one (
    this=this@entry=0x31ef190, lock=..., this_thread=..., ec=...)
    at /usr/include/boost169/boost/asio/detail/impl/scheduler.ipp:385
#3  0x0000000000a092f1 in boost::asio::detail::scheduler::run (this=0x31ef190,
    ec=...) at /usr/include/boost169/boost/asio/detail/impl/scheduler.ipp:154
#4  0x00000000009c8d97 in run (this=0x31a7450)
    at /usr/include/boost169/boost/asio/impl/io_context.ipp:62
#5  icinga::IoEngine::RunEventLoop() ()
    at /usr/src/debug/icinga2-2.14.0+32.g7ce9457a4/lib/base/io-engine.cpp:115
#6  0x0000000000feaeb4 in execute_native_thread_routine ()
#7  0x00007f95d6504ea5 in start_thread (arg=0x7f95cf103700)
    at pthread_create.c:307
#8  0x00007f95d413db0d in clone ()
    at ../sysdeps/unix/sysv/linux/x86_64/clone.S:111

Thread 2 (Thread 0x7f95cf0c2700 (LWP 26757)):
#0  pthread_cond_wait@@GLIBC_2.3.2 ()
    at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S:185
#1  0x00000000009fff92 in wait<boost::asio::detail::conditionally_enabled_mutex::scoped_lock> (lock=..., this=0x31ef200)
    at /usr/include/boost169/boost/asio/detail/conditionally_enabled_mutex.hpp:98
#2  wait (lock=..., this=0x31ef1f8)
    at /usr/include/boost169/boost/asio/detail/conditionally_enabled_event.hpp:89
#3  boost::asio::detail::scheduler::do_run_one (this=this@entry=0x31ef190,
    lock=..., this_thread=..., ec=...)
    at /usr/include/boost169/boost/asio/detail/impl/scheduler.ipp:409
#4  0x0000000000a092f1 in boost::asio::detail::scheduler::run (this=0x31ef190,
    ec=...) at /usr/include/boost169/boost/asio/detail/impl/scheduler.ipp:154
#5  0x00000000009c8d97 in run (this=0x31a7450)
    at /usr/include/boost169/boost/asio/impl/io_context.ipp:62
#6  icinga::IoEngine::RunEventLoop() ()
    at /usr/src/debug/icinga2-2.14.0+32.g7ce9457a4/lib/base/io-engine.cpp:115
#7  0x0000000000feaeb4 in execute_native_thread_routine ()
#8  0x00007f95d6504ea5 in start_thread (arg=0x7f95cf0c2700)
    at pthread_create.c:307
#9  0x00007f95d413db0d in clone ()
    at ../sysdeps/unix/sysv/linux/x86_64/clone.S:111

Thread 1 (Thread 0x7f95d7797900 (LWP 26738)):
#0  0x00007f95d41049fd in nanosleep () at ../sysdeps/unix/syscall-template.S:81
#1  0x00007f95d4104894 in __sleep (seconds=0)
    at ../sysdeps/unix/sysv/linux/sleep.c:137
#2  0x00000000009d3a96 in Sleep (timeout=2.5)
    at /usr/src/debug/icinga2-2.14.0+32.g7ce9457a4/lib/base/utility.cpp:370
#3  icinga::Application::RunEventLoop() ()
    at /usr/src/debug/icinga2-2.14.0+32.g7ce9457a4/lib/base/application.cpp:329
#4  0x0000000000cde8d8 in icinga::IcingaApplication::Main() ()
    at /usr/src/debug/icinga2-2.14.0+32.g7ce9457a4/lib/icinga/icingaapplication.cpp:112
#5  0x0000000000974f4a in icinga::Application::Run (this=0x7f95c0005aa0)
    at /usr/src/debug/icinga2-2.14.0+32.g7ce9457a4/lib/base/application.cpp:1014
#6  0x0000000000bf0242 in RunWorker (stderrFile=...,
    closeConsoleLog=<optimized out>,
    configs=std::vector of length 1, capacity 1 = {...})
    at /usr/include/boost169/boost/smart_ptr/intrusive_ptr.hpp:197
#7  StartUnixWorker(std::vector<std::string, std::allocator<std::string> > const&, bool, icinga::String const&) ()
    at /usr/src/debug/icinga2-2.14.0+32.g7ce9457a4/lib/cli/daemoncommand.cpp:545
#8  0x0000000000bf0f32 in icinga::DaemonCommand::Run(boost::program_options::variables_map const&, std::vector<std::string, std::allocator<std::string> > const&) const ()
    at /opt/rh/devtoolset-11/root/usr/include/c++/11/ext/new_allocator.h:89
#9  0x0000000000950918 in Main() ()
    at /usr/include/boost169/boost/smart_ptr/intrusive_ptr.hpp:197
#10 0x000000000093e719 in main ()
    at /usr/src/debug/icinga2-2.14.0+32.g7ce9457a4/icinga-app/icinga.cpp:946
#11 0x00007f95d4061555 in __libc_start_main (main=0x93e610 <main>, argc=6,
    argv=0x7ffdc96f2048, init=<optimized out>, fini=<optimized out>,
    rtld_fini=<optimized out>, stack_end=0x7ffdc96f2038)
    at ../csu/libc-start.c:266
#12 0x000000000094e9bb in _start ()
    at /opt/rh/devtoolset-11/root/usr/include/c++/11/bits/alloc_traits.h:851

👍 The renegotiation attempt happens completely in the background.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Even for i in {1..30}; do while true; do openssl s_client -connect 10.27.0.91:5665 -no_tls1_3 <<<R; done & done doesn't impress Icinga 2 CPU usage nor the gdb picture shown above and curl -kv https://10.27.0.91:5665/v1/ go through immediately.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

$ openssl s_client -connect 127.0.0.1:5665
CONNECTED(00000003)
...
---
R
RENEGOTIATING
140428114962320:error:1409E0E5:SSL routines:ssl3_write_bytes:ssl handshake failure:s3_pkt.c:659:
$

error:1409E0E5 needs some time to appear.

Is "some time to appear" 15 seconds by any chance? That's probably just ApiListener.connect_timeout kicking in and forcefully terminating the connection:

$ time strace -fyyt openssl s_client -connect localhost:5665 <<<R
[...]
15:32:42 write(3<TCPv6:[[::1]:55474->[::1]:5665]>, "\26\3\3\1C\17uL\326E\307\350_a\35X\271o\317\321\347\327\370\214\246\31\277\203\232hGf"..., 328) = 328
15:32:42 read(3<TCPv6:[[::1]:55474->[::1]:5665]>, "", 5) = 0
15:32:57 write(2</dev/pts/1<char 136:1>>, "140071599794064:error:1409E0E5:S"..., 97140071599794064:error:1409E0E5:SSL routines:ssl3_write_bytes:ssl handshake failure:s3_pkt.c:659:
) = 97
15:32:57 shutdown(3<TCPv6:[[::1]:55474->[::1]:5665]>, SHUT_RD) = 0
15:32:57 close(3<TCPv6:[[::1]:55474->[::1]:5665]>) = 0
15:32:57 exit_group(1)                  = ?
15:32:57 +++ exited with 1 +++

real	0m15.052s
user	0m0.024s
sys	0m0.040s
[2023-11-22 15:32:42 +0000] information/ApiListener: New client connection from [::1]:55474 (no client certificate)
[2023-11-22 15:32:57 +0000] warning/ApiListener: Timeout while processing incoming connection from [::1]:55474
[2023-11-22 15:32:57 +0000] information/ApiListener: No data received on new API connection from [::1]:55474. Ensure that the remote endpoints are properly configured in a cluster setup.

👍 The renegotiation attempt happens completely in the background.

Looks more like a TLS connection remaining in a weird state instead of being terminated with an error like it should.

So, let's go down the debugging rabbit hole and write a minimal reproducer to see if there's might be a problem somewhere else in the Icinga 2 code and allow for quicker testing:

asio-tls.cpp
#include <iostream>
#include <memory>

#include <boost/asio/buffered_stream.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/asio/io_context.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/read.hpp>
#include <boost/asio/spawn.hpp>
#include <boost/asio/ssl/context.hpp>
#include <boost/asio/ssl/stream.hpp>
#include <boost/asio/write.hpp>
#include <boost/system/error_code.hpp>

#include <openssl/ssl.h>

static boost::asio::io_context io_context;

int main() {
	std::cerr << "Hello (Boost: " << BOOST_LIB_VERSION << "; OpenSSL: " << OPENSSL_VERSION_TEXT << ")" << std::endl;

	boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::tcp::v6(), 4242);
	boost::asio::ip::tcp::acceptor acceptor(io_context, endpoint);
	acceptor.listen();

	boost::asio::ssl::context tls_context(boost::asio::ssl::context::tls);
	tls_context.set_options(
		boost::asio::ssl::context::default_workarounds |
		boost::asio::ssl::context::no_compression |
		boost::asio::ssl::context::no_sslv2 |
		boost::asio::ssl::context::no_sslv3 |
		boost::asio::ssl::context::no_tlsv1 |
		boost::asio::ssl::context::no_tlsv1_1
	);
	tls_context.use_certificate_chain_file("server.crt");
	tls_context.use_private_key_file("server.key", boost::asio::ssl::context::pem);

#if OPENSSL_VERSION_NUMBER >= 0x10100000L
	SSL_CTX_set_options(tls_context.native_handle(), SSL_OP_NO_RENEGOTIATION);
#endif


	SSL_CTX_set_info_callback(tls_context.native_handle(), [](const SSL* ssl, int where, int) {
		if (where & SSL_CB_HANDSHAKE_START) {
			std::cerr << "SSL_CB_HANDSHAKE_START " << SSL_in_before(ssl) << std::endl; 	
		}
		if (where & SSL_CB_HANDSHAKE_DONE) {
			std::cerr << "SSL_CB_HANDSHAKE_DONE " << SSL_in_before(ssl) << std::endl; 	
		}

#if OPENSSL_VERSION_NUMBER < 0x10100000L
		if (where & SSL_CB_HANDSHAKE_DONE) {
			std::cerr << "Apply workaround" << std::endl;
			ssl->s3->flags |= SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS;
		}
#endif
	});

	boost::asio::spawn(io_context, [&tls_context, &acceptor](boost::asio::yield_context yc) {
		while (true) {
			boost::asio::ip::tcp::socket socket(io_context);
			acceptor.async_accept(socket.lowest_layer(), yc);

			auto tls_conn = std::make_shared<boost::asio::ssl::stream<boost::asio::ip::tcp::socket>>(io_context, tls_context);
			tls_conn->lowest_layer() = std::move(socket);

			boost::asio::spawn(io_context, [tls_conn](boost::asio::yield_context yc) {
				try {
					std::cerr << "Connection accepted" << std::endl;
					boost::system::error_code ec;
					tls_conn->async_handshake(tls_conn->server, yc[ec]);
					std::cerr << "TLS handshake completed: " << ec.message() << std::endl;

					//while (true) {
					//	boost::asio::async_write(*tls_conn, boost::asio::const_buffer("B", 1), yc);
					//}

					while (true) {
						char c;
						boost::asio::async_read(*tls_conn, boost::asio::mutable_buffer(&c, 1), yc);
						std::cerr << "read: '" << c << "'" << std::endl; 
					}
				} catch (const std::exception &e) {
					std::cerr << "Exception in connection: " << e.what() << std::endl;
				}
			});
		}
	});

	std::cerr << "Running..." << std::endl;
	io_context.run();
}

And it showed just the same behavior: trigger a renegotiation and the connection hangs.

Then I found an interesting commit in Boost.Asio, but applying it did not make a difference.

Next, trying Boost 1.83 on CentOS 7 (still with the antiquated OpenSSL 1.0.2 it provides): still the same result, connection hangs.

Next attempt: try OpenSSL 1.1.1, and now it works and you immediately get the "no renegotiation" error, even with Boost 1.69, so doesn't look like that Boost version is doing something completely wrong here as the commit I referenced previously might suggest.

Hints for compiling with different versions of Boost and OpenSSL

OpenSSL 1.0.2, Boost 1.69

g++ -g -std=c++11 -Wall -Wextra -I/usr/include/boost169 -L/usr/lib64/boost169 -DBOOST_COROUTINES_NO_DEPRECATION_WARNING -pthread asio-tls.cpp -lssl -lcrypto -lboost_coroutine -lboost_context -oasio-tls-o102-b169

OpenSSL 1.0.2, Boost 1.83 (run with LD_LIBRARY_PATH=/opt/boost183/lib)

g++ -g -std=c++11 -Wall -Wextra -I/opt/boost183/include -L/opt/boost183/lib -DBOOST_COROUTINES_NO_DEPRECATION_WARNING -pthread asio-tls.cpp -lssl -lcrypto -lboost_coroutine -lboost_context -oasio-tls-o102-b183

OpenSSL 1.1.1, Boost 1.69

g++ -g -std=c++11 -Wall -Wextra -I/usr/include/boost169 -L/usr/lib64/boost169 -I/usr/include/openssl11 -DBOOST_COROUTINES_NO_DEPRECATION_WARNING -pthread asio-tls.cpp -l:libssl.so.1.1 -l:libcrypto.so.1.1 -lboost_coroutine -lboost_context -oasio-tls-o111-b169

OpenSSL 1.1.1, Boost 1.83 (run with LD_LIBRARY_PATH=/opt/boost183/lib)

g++ -g -std=c++11 -Wall -Wextra -I/opt/boost183/include -L/opt/boost183/lib -I/usr/include/openssl11 -DBOOST_COROUTINES_NO_DEPRECATION_WARNING -pthread asio-tls.cpp -l:libssl.so.1.1 -l:libcrypto.so.1.1 -lboost_coroutine -lboost_context -oasio-tls-o111-b183

openssl11-{devel,libs} can be installed from EPEL, Boost 1.83 can be installed from source (./bootstrap.sh --prefix=/opt/boost183; ./b2 install).

But still, nginx manages to immediately give you an "no renegotiation" error with OpenSSL 1.0.2, also note how something is read from the socket instead of it just closing:

$ time strace -fyyt openssl s_client -connect localhost:443 <<<R
[...]
16:09:20 write(3<TCPv6:[[::1]:44270->[::1]:443]>, "\26\3\3\1C}\236\n\300\4\230\257\0\21I(=1\274Zs\311\272C\201\302\366\205\313\372\211o"..., 328) = 328
16:09:20 read(3<TCPv6:[[::1]:44270->[::1]:443]>, "\25\3\3\0\32", 5) = 5
16:09:20 read(3<TCPv6:[[::1]:44270->[::1]:443]>, "\312\271.\302\327\231kj\324\336On\3164o\33 \344\310\255\260?\270\316\312\320", 26) = 26
16:09:20 write(3<TCPv6:[[::1]:44270->[::1]:443]>, "\25\3\3\0\32}\236\n\300\4\230\257\1\240\372\252\220\210\314R\230\202t\225A\211\324h\243\376H", 31) = 31
16:09:20 write(2</dev/pts/1<char 136:1>>, "140369448245136:error:14094153:S"..., 92140369448245136:error:14094153:SSL routines:ssl3_read_bytes:no renegotiation:s3_pkt.c:1481:
) = 92
16:09:20 shutdown(3<TCPv6:[[::1]:44270->[::1]:443]>, SHUT_RD) = 0
16:09:20 close(3<TCPv6:[[::1]:44270->[::1]:443]>) = 0
16:09:20 exit_group(1)                  = ?
16:09:20 +++ exited with 1 +++

real	0m0.080s
user	0m0.031s
sys	0m0.036s

So that's where I got so far, something is odd here, I just don't know what exactly.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I totally agree with Yonas. Your approach "gives the cleanest result" for what exactly?

Clean as in the connection is cleaned up immediately. Can you explain the state the connection remains in within Asio otherwise? What would happen if the client would send more data?

I mean, name just one legit Icinga API client who renegotiates in prod (which theoretically gives it the right to complain that we didn't immediately close the connection).

It's not about legit clients, if we'd only consider those, we wouldn't need this PR at all.

In contrast, a DoS client is now not wasting our CPU as we hanged it. A security feature IMAO.

How is this a security feature? All I can tell is that a connection in an unclear (to me) and somewhat dysfunctional state remains.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the connection is cleaned up immediately. Can you explain the state the connection remains in within Asio otherwise?

Actually ASIO only r/w-s data from/to the other side as we instruct it to do, passing it through OpenSSL (to duplicate as less of its logic as possible).* The latter is indeed interesting:

What would happen if the client would send more data?

First of all, as a bad guy "exploiting" this "weakness" I'd still have to follow the protocol. I.e. to initiate a handshake, which is what OpenSSL does on renegotiation**, and to wait for the response before (maybe) sending anything else. After all I'd expect the server to kick me for protocol violation. But, to actually answer your question, our imaginary bad guy will notice my little client-hangup trick and not wait for a handshake response. Instead he'll immediately send data as if the renegotiation handshake never happened. (At least this is how I understand your question.)

Before the additional data, let's see what happens on the server on renegotiation itself. SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS is used in three different locations (ex. headers and DTLS):

  1. https://github.com/openssl/openssl/blob/OpenSSL_1_0_2k/ssl/s3_lib.c#L4496
  2. https://github.com/openssl/openssl/blob/OpenSSL_1_0_2k/ssl/s3_pkt.c#L1380
  3. https://github.com/openssl/openssl/blob/OpenSSL_1_0_2k/ssl/s3_pkt.c#L1560

(2) is on the client side. (1), ssl3_renegotiate(), is only called by:

And (3) is the only interesting one as it's ssl3_read_bytes(), the thing which ASIO calls* to receive the renegotiation request at all. Due to the flag being set, this if isn't run (but the rest of the condition implies SSL_ST_OK): https://github.com/openssl/openssl/blob/OpenSSL_1_0_2k/ssl/s3_pkt.c#L1559-L1572

On the next line ssl3_accept() is called: https://github.com/openssl/openssl/blob/OpenSSL_1_0_2k/ssl/s3_pkt.c#L1573

Nothing really interesting happens during its init: https://github.com/openssl/openssl/blob/OpenSSL_1_0_2k/ssl/s3_srvr.c#L214-L227

Ex. the increment here: https://github.com/openssl/openssl/blob/OpenSSL_1_0_2k/ssl/s3_srvr.c#L230

But it's undone on return: https://github.com/openssl/openssl/blob/OpenSSL_1_0_2k/ssl/s3_srvr.c#L884

Oh. Due to currently SSL_ST_OK, the SSL object is cleared:

But SSL_ST_OK stays, so the SSL is cleaned even more before returning 1: https://github.com/openssl/openssl/blob/OpenSSL_1_0_2k/ssl/s3_srvr.c#L828-L837

If I did the math correctly, we're in a kinda funny state now. But not in a somewhat dangerous one, this seems to be just the immediate post-handshake state, as set also by: https://github.com/openssl/openssl/blob/OpenSSL_1_0_2k/ssl/s3_srvr.c#L724-L749

Finally reading more data is scheduled (which explains that the connection isn't active and the ASIO event loop is waiting for something to happen, see gdb above):

For a moment (the "Oh." above) I really wasn't sure, but now I think it is fine. I mean, a fresh state as just after the regular handshake and the server waits for some data. Exactly the additional data you worry about.👍 I'd say business as usual. Really as if the renegotiation was never requested. Could be worse. In addition I can crash-test the whole thing if you wish. But I don't think this is necessary. I mean, depending on the state OpenSSL either reads more data or throws an SSL error, e.g. protocol violation. What can happen?

It's not about legit clients, if we'd only consider those, we wouldn't need this PR at all.

In contrast, a DoS client is now not wasting our CPU as we hanged it. A security feature IMAO.

How is this a security feature? All I can tell is that a connection in an unclear (to me) and somewhat dysfunctional state remains.

On a DoS client the connection is indeed broken as it expects a handshake response, but gets nothing at all. Now instead of wasting our CPU, our bad guy's OpenSSL hangs.👍

Notes

I can explain those in human readable language if you wish, but not at this unorthodox time of the day.😅

*

**

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In addition I can crash-test the whole thing

Icinga says [2023-12-08 13:56:48 +0100] information/ApiListener: No data received on new API connection from [::ffff:127.0.0.1]:64397. Ensure that the remote endpoints are properly configured in a cluster setup.👍 on additional data after a renegotiation request via the following program:

#include <assert.h>
#include <openssl/bio.h>
#include <openssl/ssl.h>
#include <signal.h>
#include <stdio.h>
#include <unistd.h>

int main(void) {
	SSL_library_init();

	SSL_CTX *ctx = SSL_CTX_new(TLSv1_2_client_method());
	assert(ctx);

	BIO *bio = BIO_new_ssl_connect(ctx);
	assert(bio);

	BIO_set_conn_hostname(bio, "localhost");
	BIO_set_conn_port(bio, "5665");
	assert(BIO_do_connect(bio) == 1u);

	SSL *ssl;
	BIO_get_ssl(bio, &ssl);

	SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
	assert(SSL_do_handshake(ssl) == 1u);

	pid_t renegotiator = fork();
	assert(renegotiator >= 0);

	if (renegotiator) {
		assert(!sleep(2)); // await else branch to hang
		assert(!kill(renegotiator, SIGKILL)); // get the connection just for us
		assert(!sleep(2)); // await else branch to vanish

		for (;;) {
			printf("BIO_puts() = %d\n", BIO_puts(bio, "violate the protocol"));
		}
	} else {
		assert(SSL_renegotiate(ssl));
		assert(BIO_puts(bio, "won't arrive as Icinga blocks renegotiation scheduled above") == 42u);
		assert(!"we're still alive");
	}

	return 0;
}

TL;DR

IMAO we have the following options (sorted by my preference, ascending):

  1. "The nginx way", Disable TLS renegotiation #9885 (comment): be nice to "attackers" by immediately closing their connection, at the cost of hacky code for just a few distros* (which are near EOL)
  2. "The Klimov way", 7ce9457: basically the opposite, keep the code clean and understandable, at the cost of malfunctioning clients(!) of "attackers"
  3. "The Postgres way", f95c4d3: honestly admit that using neither official nor documented APIs is not the best idea, at the cost of keeping just a few distros* (which are near EOL) "vulnerable"

(If I understood you correctly, legitimate API users aren't affected as they don't renegotiate.)

We could also make this decision even easier by using OpenSSL 1.1+ wherever it's available (everywhere) and doesn't conflict with v1.0 (used by libmysqlclient and libpq) at runtime (almost everywhere).

*

  • RHEL 7
    • CentOS 7
    • Amazon 2
  • SLES 12.5

Shall we count derivatives (indented) separately here? 🤔

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BIO_puts(bio, "violate the protocol"));

What exactly does this do? Does it write plain text directly to the TCP connection as I think it does? If so, what happens if you try to send something inside the TLS connection (which should be SSL_write())?

information/ApiListener: No data received on new API connection from [::ffff:127.0.0.1]:64397. Ensure that the remote endpoints are properly configured in a cluster setup.

But looks like it's actually able to unblock the coroutine here:

boost::system::error_code ec;
if (client->async_fill(yc[ec]) == 0u) {
if (identity.IsEmpty()) {
Log(LogInformation, "ApiListener")
<< "No data received on new API connection " << conninfo << ". "
<< "Ensure that the remote endpoints are properly configured in a cluster setup.";
} else {
Log(LogWarning, "ApiListener")
<< "No data received on new API connection " << conninfo << " for identity '" << identity << "'. "
<< "Ensure that the remote endpoints are properly configured in a cluster setup.";
}
return;
}

Would be interesting to know what error_code/ec is here (should be something like protocol error) and if this would actually successfully continue if you sent a HTTP request inside the TLS connection for example.

I mean, a fresh state as just after the regular handshake and the server waits for some data. Exactly the additional data you worry about.👍 I'd say business as usual. Really as if the renegotiation was never requested.

So is that the answer to what's happening here? We're inside a read, OpenSSL receives a renegotiation request, ignores it, and because we're in a read, just tells Boost.Asio that it wants to read more data (as we're in a read after all)?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BIO_puts(bio, "violate the protocol"));

What exactly does this do? Does it write plain text directly to the TCP connection as I think it does? If so, what happens if you try to send something inside the TLS connection (which should be SSL_write())?

Wireshark said it is TLS application data. Admittedly I've written this throwaway program not entirely by myself to save time. So yes, that may be partially crap, but as long as that crap does its thing... 👍

But looks like it's actually able to unblock the coroutine here:

Of course. I mean, the coroutine is awaiting something to read and my C program puts something on the wire. Business as usual. 🤷‍♂️

Would be interesting to know what error_code/ec is here (should be something like protocol error)

This is actually a good idea by itself!

But, to answer the question: [2023-12-11 17:14:27 +0100] information/ApiListener: No data received on new API connection from [::ffff:127.0.0.1]:50906. Ensure that the remote endpoints are properly configured in a cluster setup. Error: unexpected record

and if this would actually successfully continue if you sent a HTTP request inside the TLS connection for example.

I doubt, given the error above.

So is that the answer to what's happening here? We're inside a read, OpenSSL receives a renegotiation request, ignores it, and because we're in a read, just tells Boost.Asio that it wants to read more data (as we're in a read after all)?

Exactly!

#else /* OPENSSL_VERSION_NUMBER < 0x10100000L */
flags |= SSL_OP_NO_RENEGOTIATION;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Test

Debian 11.

# docker run --rm -it --entrypoint '' icinga/icinga2:test icinga2 --version
icinga2 - The Icinga 2 network monitoring daemon (version: v2.14.0-32-g7ce9457a4)
...
$ openssl s_client -connect 127.0.0.1:5665 -no_tls1_3
CONNECTED(00000003)
...
---
R
RENEGOTIATING
80EBB39BA07F0000:error:0A000153:SSL routines:ssl3_read_bytes:no renegotiation:../ssl/record/rec_layer_s3.c:1602:
$

error:0A000153 fires immediately.

#endif /* OPENSSL_VERSION_NUMBER < 0x10100000L */

SSL_CTX_set_options(sslContext, flags);

SSL_CTX_set_mode(sslContext, SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
Expand Down
Loading