1#if defined(HAVE_CONFIG_H)
15#include <openssl/opensslv.h>
16#if !defined(LIBRESSL_VERSION_NUMBER)
17#include <openssl/e_os2.h>
19#include <openssl/evp.h>
20#include <openssl/crypto.h>
21#include <openssl/err.h>
22#include <openssl/pem.h>
23#include <openssl/pkcs7.h>
24#include <openssl/x509v3.h>
25#include <openssl/ssl.h>
30#define RESIPROCATE_SUBSYSTEM Subsystem::TRANSPORT
36 Connection(transport, tuple, fd, compression, server),
43 InfoLog(<<
"Creating TLS connection for domain " << mDomain <<
" " << tuple <<
" on " << fd);
50 DebugLog(<<
"Trying to form TLS connection - acting as server");
53 ErrLog(<<
"Tranport was not created with a server domain so can not act as server");
60 DebugLog(<<
"Trying to form TLS connection - acting as client");
78 int verify_mode = SSL_VERIFY_PEER;
82 verify_mode = SSL_VERIFY_NONE;
83 DebugLog(<<
"Not expecting client certificate");
86 verify_mode = SSL_VERIFY_PEER;
87 DebugLog(<<
"Optional client certificate mode");
90 verify_mode = SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
91 DebugLog(<<
"Mandatory client certificate mode");
96 SSL_set_verify(mSsl, verify_mode, 0);
99 mBio = BIO_new_socket((
int)fd, 0);
106 SSL_set_bio(mSsl, mBio, mBio);
111 mHandShakeWantsRead =
false;
125 int ret = SSL_shutdown(mSsl);
128 int err = SSL_get_error(mSsl, ret);
131 case SSL_ERROR_WANT_READ:
132 case SSL_ERROR_WANT_WRITE:
136 StackLog(<<
"Got TLS shutdown error condition of " << err);
140 handleOpenSSLErrorQueue(ret, err,
"SSL_shutdown");
153 case Initial:
return "Initial";
break;
155 case Broken:
return "Broken";
break;
156 case Up:
return "Up";
break;
163TlsConnection::checkState()
168 if (mTlsState ==
Up || mTlsState ==
Broken)
173 int handshakeRet = 0;
181 InfoLog(<<
"TLS handshake starting (server mode)");
182 SSL_set_accept_state(mSsl);
194 InfoLog(<<
"TLS handshake starting (client mode), SNI=" << targetDomain);
195 if (SSL_set_tlsext_host_name(mSsl, targetDomain.
c_str()) != 1)
197 WarningLog(<<
"Failed to set SNI " << targetDomain <<
", continuing without it");
203 InfoLog(<<
"TLS handshake starting (client mode), no SNI for target <" << targetDomain <<
">");
205 SSL_set_connect_state(mSsl);
210 mHandShakeWantsRead =
false;
211 handshakeRet = SSL_do_handshake(mSsl);
213 if (handshakeRet <= 0)
215 int err = SSL_get_error(mSsl, handshakeRet);
219 case SSL_ERROR_WANT_READ:
220 StackLog(<<
"TLS handshake want read");
221 mHandShakeWantsRead =
true;
224 case SSL_ERROR_WANT_WRITE:
225 StackLog(<<
"TLS handshake want write");
229 case SSL_ERROR_ZERO_RETURN:
230 StackLog(<<
"TLS connection closed cleanly");
233 case SSL_ERROR_WANT_CONNECT:
234 StackLog(<<
"BIO not connected, try later");
237 case SSL_ERROR_WANT_ACCEPT:
238 StackLog(<<
"TLS connection want accept");
241 case SSL_ERROR_WANT_X509_LOOKUP:
242 DebugLog(<<
"Try later / SSL_ERROR_WANT_X509_LOOKUP");
247 int failureSubCode = 0;
250 bool addToAdditionalFailureStrings =
true;
251 ds <<
"TLS handshake failed: ";
252 if (err == SSL_ERROR_SYSCALL)
259#if EAGAIN != EWOULDBLOCK
273 ds <<
", client may have disconnected to prompt for user certificate, because it can't supply a certificate (verification mode == " << (t->
getClientVerificationMode() ==
SecurityTypes::Mandatory ?
"Mandatory" :
"Optional") <<
" for this transport) or because it does not support using client certificates";
277 else if (err == SSL_ERROR_SSL)
279 ds <<
"SSL cipher or certificate failure(SSL_ERROR_SSL), note: ";
280 int verifyErrorCode = SSL_get_verify_result(mSsl);
281 switch (verifyErrorCode)
287#if OPENSSL_VERSION_NUMBER < 0x30000000L
288 X509* peerCert = SSL_get_peer_certificate(mSsl);
290 X509* peerCert = SSL_get1_peer_certificate(mSsl);
294 ds <<
"peer supplied a certificate, it has either not been checked or it was checked successfully";
299 ds <<
"peer did not supply a certificate";
305 ds <<
"peer certificate validation failure: " << X509_verify_cert_error_string(verifyErrorCode);
308 addToAdditionalFailureStrings =
false;
317 ds <<
"; mandatory client certificate verification required";
321 failureSubCode = verifyErrorCode;
325 ds <<
"unhandled SSL_get_error result: " << err;
326 failureSubCode = err;
330 const char* sni = SSL_get_servername(mSsl, TLSEXT_NAMETYPE_host_name);
331 ds <<
"; SNI received: " << (sni ? sni :
"<none>");
335 handleOpenSSLErrorQueue(handshakeRet, err,
"SSL_do_handshake", addToAdditionalFailureStrings);
346 const char* sni = SSL_get_servername(mSsl, TLSEXT_NAMETYPE_host_name);
347 mSni = sni ?
Data(sni) :
Data::Empty;
348 InfoLog(<<
"TLS connected (server mode), SNI received: " << (sni ? sni :
"<none>"));
352 InfoLog(<<
"TLS connected (client mode)");
362 bool matches =
false;
363 for (std::list<BaseSecurity::PeerName>::iterator it = mPeerNames.begin(); it != mPeerNames.end(); it++)
378 ds <<
"Certificate name mismatch: trying to connect to <"
380 <<
"> remote cert domain(s) are <"
381 << getPeerNamesData() <<
">";
389 InfoLog(<<
"TLS handshake done for peer " << getPeerNamesData());
400TlsConnection::handleOpenSSLErrorQueue(
int ret,
unsigned long err,
const char* op,
bool addToAdditionalFailureStrings)
402 bool hadReason =
false;
403 ErrLog(<< op <<
" error=" << err <<
", ret=" << ret);
409#if OPENSSL_VERSION_NUMBER < 0x30000000L
410 unsigned long code = ERR_get_error_line(&file, &line);
412 unsigned long code = ERR_get_error_all(&file, &line, NULL, NULL, NULL);
420 ERR_error_string_n(code, buf,
sizeof(buf));
424 ds <<
" " << buf <<
" (file=" << file <<
", line=" << line <<
")";
427 if (addToAdditionalFailureStrings)
443 switch (checkState())
457 DebugLog(<<
"Got TLS read bad bio ");
470 int bytesRead = SSL_read(mSsl, buf, count);
475 int bytesPending = SSL_pending(mSsl);
476 if (bytesPending > 0)
482 bytesPending = SSL_read(mSsl, buffer, bytesPending);
485 if (bytesPending > 0)
487 bytesRead += bytesPending;
497 int err = SSL_get_error(mSsl, bytesPending);
498 if (err != SSL_ERROR_WANT_READ &&
499 err != SSL_ERROR_WANT_WRITE &&
500 err != SSL_ERROR_NONE)
504 bytesRead = bytesPending;
513 else if (bytesPending < 0)
515 int err = SSL_get_error(mSsl, bytesPending);
516 handleOpenSSLErrorQueue(bytesPending, err,
"SSL_pending");
523 int err = SSL_get_error(mSsl, bytesRead);
526 case SSL_ERROR_WANT_READ:
527 case SSL_ERROR_WANT_WRITE:
530 StackLog(<<
"Got TLS read got condition of " << err);
534 case SSL_ERROR_ZERO_RETURN:
536 DebugLog(<<
"Got SSL_ERROR_ZERO_RETURN (TLS shutdown by peer)");
540 case SSL_ERROR_SYSCALL:
542 if (ERR_peek_error() == 0)
547 if (bytesRead == 0 || e == 0)
549 InfoLog(<<
"TLS connection closed by the peer without a close_notify");
557 handleOpenSSLErrorQueue(bytesRead, err,
"SSL_read");
563#if defined(SSL_R_UNEXPECTED_EOF_WHILE_READING)
565 if (err == SSL_ERROR_SSL &&
566 ERR_GET_REASON(ERR_peek_error()) == SSL_R_UNEXPECTED_EOF_WHILE_READING)
568 InfoLog(<<
"TLS connection closed by the peer without a close_notify");
573 handleOpenSSLErrorQueue(bytesRead, err,
"SSL_read");
580 StackLog(<<
"SSL bytesRead=" << bytesRead);
596 DebugLog(<<
"transportWrite in Handshaking state, remove from write: " << (mHandShakeWantsRead ?
"true" :
"false"));
597 return mHandShakeWantsRead;
601 DebugLog(<<
"transportWrite in Initial state (Handshake complete), calling write");
606 DebugLog(<<
"transportWrite in " <<
fromState(mTlsState) <<
" state, calling write");
619 switch (checkState())
627 DebugLog(<<
"Tried to Tls write, but connection state is not Up");
634 DebugLog(<<
"Got TLS write bad bio");
645 ret = SSL_write(mSsl, (
const char*)buf, count);
648 int err = SSL_get_error(mSsl, ret);
651 case SSL_ERROR_WANT_READ:
652 case SSL_ERROR_WANT_WRITE:
655 StackLog(<<
"Got TLS write got condition of " << err);
659 case SSL_ERROR_ZERO_RETURN:
661 DebugLog(<<
"Got SSL_ERROR_ZERO_RETURN (TLS shutdown by peer)");
667 handleOpenSSLErrorQueue(ret, err,
"SSL_write");
675 StackLog(<<
"Did TLS write " << ret <<
" " << count <<
" " <<
"[[" << monkey <<
"]]");
690 if (checkState() !=
Up)
695 int p = SSL_pending(mSsl);
712 int mode = SSL_get_shutdown(mSsl);
715 int err = SSL_get_error(mSsl, mode);
716 handleOpenSSLErrorQueue(mode, err,
"SSL_get_shutdown");
736 return mHandShakeWantsRead ? false :
true;
753 for (std::list<BaseSecurity::PeerName>::const_iterator it = mPeerNames.begin(); it != mPeerNames.end(); it++)
755 peerNames.push_back(it->mName);
760TlsConnection::getPeerNamesData()
const
762 Data peerNamesString;
763 for (std::list<BaseSecurity::PeerName>::const_iterator it = mPeerNames.begin(); it != mPeerNames.end(); it++)
765 if (it == mPeerNames.begin())
767 peerNamesString += it->mName;
771 peerNamesString +=
", " + it->mName;
774 return peerNamesString;
778TlsConnection::computePeerName()
792 const SSL_CIPHER* ciph;
793 ciph = SSL_get_current_cipher(mSsl);
794 InfoLog(<<
"TLS session set up with "
795 << SSL_get_version(mSsl) <<
" "
796 << SSL_CIPHER_get_version(ciph) <<
" "
797 << SSL_CIPHER_get_name(ciph) <<
" ");
800#if OPENSSL_VERSION_NUMBER < 0x30000000L
801 X509* cert = SSL_get_peer_certificate(mSsl);
803 X509* cert = SSL_get1_peer_certificate(mSsl);
807 DebugLog(<<
"No peer certificate in TLS connection");
812 if (X509_V_OK != SSL_get_verify_result(mSsl))
814 DebugLog(<<
"Peer certificate in TLS connection is not valid");
815 X509_free(cert); cert = NULL;
824 if (mPeerNames.empty())
826 ErrLog(<<
"Invalid certificate: no subjectAltName/CommonName found");
827 X509_free(cert); cert = NULL;
834 unsigned char* buf = NULL;
835 int len = i2d_X509(cert, &buf);
838 Data derCert(buf, len);
839 for (std::list<BaseSecurity::PeerName>::iterator it = mPeerNames.begin(); it != mPeerNames.end(); it++)
847 OPENSSL_free(buf); buf = NULL;
850 X509_free(cert); cert = NULL;
struct ssl_ctx_st SSL_CTX
#define WarningLog(args_)
#define resip_assert(x)
This file needs to work for both C and C++ code.
Handles cross-platform sockets compatibility.
static int getResipConnectionExDataIdx()
static void getCertNames(X509 *cert, std::list< PeerName > &peerNames, bool useEmailAsSIP=false)
static int matchHostName(const Data &certificateName, const Data &domainName)
Applies the certificate and domain name matching rules.
void addDomainCertDER(const Data &domainName, const Data &certDER)
bool hasDomainCert(const Data &domainName, bool logErrors=true) const
virtual Transport * transport() const
void setFailureReason(TransportFailure::FailureReason failReason, int subCode, const Data &failureString)
char * getWriteBufferForExtraBytes(int bytesRead, int extraBytes)
std::list< SendData * > mOutstandingSends
void addAdditionalFailureString(const Data &additionalFailureString)
Connection implements, via sockets, ConnectionBase for managed connections.
void ensureWritable()
ensure that we are on the writeable list if required
int read()
move data from the connection to the buffer; move this to front of least recently used list.
An iostream that operates on an existing Data.
An alternative to std::string, encapsulates an arbitrary buffer of bytes.
const char * c_str() const
Returns a null-terminated string representing.
@ Borrow
The Data instance is borrowing the memory from the passed in buffer.
bool empty() const noexcept
Checks whether the Data is empty.
static bool isIpAddress(const Data &ipAddress)
SecurityTypes::TlsClientVerificationMode getClientVerificationMode()
static const char * fromState(TlsState)
int write(const char *buf, const int count)
pure virtual, but need concrete Connection for book-ends of lists
virtual bool isGood()
has valid connection
virtual bool hasDataToRead()
always true – always add to fdset as read ready
virtual bool transportWrite()
virtual bool isWritable()
void getPeerNames(std::list< Data > &peerNames) const
General exception class for Transport.
The base class for Transport classes.
static Data errorToString(int e)
Represents a network address.
const Data & getTargetDomain() const
Get the domain name this address tuple intends to represent.
SSLType
Note: Before adding to the SSLType enum, please see the comments about mTlsCtx in resip/stack/ssl/Sec...
dcm! – add UnusedChecking(_enum) below;