|
|
|
@ -77,6 +77,8 @@ struct IRCBasePriv |
|
|
|
|
std::optional<tcp::socket> sock; |
|
|
|
|
std::optional< asio::ssl::stream<asio::ip::tcp::socket> > sslsock; |
|
|
|
|
|
|
|
|
|
std::vector<IRCError> sslExceptions; // List of SSL verification errors that were ignored.
|
|
|
|
|
|
|
|
|
|
bool isConnected{ false }; // When the socket itself is successfully connected.
|
|
|
|
|
bool isOnline{ false }; // When the client itself is successfully registered.
|
|
|
|
|
IRCError lastError{ IRCError::NoError }; |
|
|
|
@ -249,7 +251,10 @@ struct IRCBasePriv |
|
|
|
|
sock->set_option(asio::socket_base::keep_alive(true)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
super.onConnected(); |
|
|
|
|
if (sslExceptions.empty()) |
|
|
|
|
super.onConnected(); |
|
|
|
|
else |
|
|
|
|
super.onConnectedWithSSLExceptions(sslExceptions); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void write(const std::string& command, const std::vector<std::string>& args, const std::string& msg) |
|
|
|
@ -362,7 +367,7 @@ struct IRCBasePriv |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
IRCError verify_X509(X509* cert) const |
|
|
|
|
IRCError verify_X509(X509* cert) |
|
|
|
|
{ |
|
|
|
|
char sn_char[256]; |
|
|
|
|
X509_NAME_oneline(X509_get_subject_name(cert), sn_char, 256); |
|
|
|
@ -378,21 +383,35 @@ struct IRCBasePriv |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (X509_check_issued(cert, cert) == X509_V_OK && !sslExcept.selfSigned) |
|
|
|
|
return IRCError::SSL_SelfSigned; |
|
|
|
|
if (X509_check_issued(cert, cert) == X509_V_OK) { |
|
|
|
|
if (sslExcept.selfSigned) |
|
|
|
|
sslExceptions.emplace_back(IRCError::SSL_SelfSigned); |
|
|
|
|
else |
|
|
|
|
return IRCError::SSL_SelfSigned; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (!sslExcept.expired) { |
|
|
|
|
const auto notbefore = X509_getm_notBefore(cert); |
|
|
|
|
if (X509_cmp_current_time(notbefore) > -1) |
|
|
|
|
return IRCError::SSL_NotYetValid; |
|
|
|
|
const auto notbefore = X509_getm_notBefore(cert); |
|
|
|
|
if (X509_cmp_current_time(notbefore) > -1) { |
|
|
|
|
if (sslExcept.expired) |
|
|
|
|
sslExceptions.emplace_back(IRCError::SSL_NotYetValid); |
|
|
|
|
else |
|
|
|
|
return IRCError::SSL_NotYetValid; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const auto notafter = X509_getm_notAfter(cert); |
|
|
|
|
if (X509_cmp_current_time(notafter) < 1) |
|
|
|
|
return IRCError::SSL_Expired; |
|
|
|
|
} |
|
|
|
|
const auto notafter = X509_getm_notAfter(cert); |
|
|
|
|
if (X509_cmp_current_time(notafter) < 1) { |
|
|
|
|
if (sslExcept.expired) |
|
|
|
|
sslExceptions.emplace_back(IRCError::SSL_Expired); |
|
|
|
|
else |
|
|
|
|
return IRCError::SSL_Expired; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (CN.empty() && !sslExcept.CNMismactch) |
|
|
|
|
return IRCError::SSL_CN_Missing; |
|
|
|
|
if (CN.empty()) { |
|
|
|
|
if (sslExcept.CNMismactch) |
|
|
|
|
sslExceptions.emplace_back(IRCError::SSL_CN_Mismatch); |
|
|
|
|
else |
|
|
|
|
return IRCError::SSL_CN_Missing; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* CN wildcard matching. |
|
|
|
@ -430,13 +449,21 @@ struct IRCBasePriv |
|
|
|
|
return IRCError::SSL_CN_WildcardIllegal; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (!singleWildcardMatch(hostname, CN) && !sslExcept.CNMismactch) |
|
|
|
|
return IRCError::SSL_CN_Mismatch; |
|
|
|
|
if (!singleWildcardMatch(hostname, CN)) { |
|
|
|
|
if (sslExcept.CNMismactch) |
|
|
|
|
sslExceptions.emplace_back(IRCError::SSL_CN_Mismatch); |
|
|
|
|
else |
|
|
|
|
return IRCError::SSL_CN_Mismatch; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* CN exact hostname match */ |
|
|
|
|
else if (CN != hostname && !sslExcept.CNMismactch) |
|
|
|
|
return IRCError::SSL_CN_Mismatch; |
|
|
|
|
else if (CN != hostname) { |
|
|
|
|
if (sslExcept.CNMismactch) |
|
|
|
|
sslExceptions.emplace_back(IRCError::SSL_CN_Mismatch); |
|
|
|
|
else |
|
|
|
|
return IRCError::SSL_CN_Mismatch; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return IRCError::NoError; |
|
|
|
|
} |
|
|
|
@ -675,6 +702,7 @@ IRCError IRCBase::tryConnect() |
|
|
|
|
return IRCError::RealnameNotSet; |
|
|
|
|
|
|
|
|
|
try { |
|
|
|
|
mp->sslExceptions.clear(); |
|
|
|
|
mp->ioctx.restart(); |
|
|
|
|
mp->endpoints = mp->resolver.resolve(mp->hostname, mp->port); |
|
|
|
|
if (mp->endpoints.empty()) |
|
|
|
|