Files
asterisk/third-party/pjproject/patches/0075-Fixed-2030-Improve-error-handling-in-OpenSSL-socket.patch

248 lines
7.6 KiB
Diff
Raw Normal View History

From 96c06899d95eaf01d05561554b21e8c63baa7129 Mon Sep 17 00:00:00 2001
From: ming <ming@localhost>
Date: Thu, 27 Jul 2017 06:07:54 +0000
Subject: [PATCH 75/76] Fixed #2030: Improve error handling in OpenSSL socket
---
pjlib/src/pj/ssl_sock_ossl.c | 173 ++++++++++++++++++++++++++++++++++++++-----
1 file changed, 156 insertions(+), 17 deletions(-)
diff --git a/pjlib/src/pj/ssl_sock_ossl.c b/pjlib/src/pj/ssl_sock_ossl.c
index c466b3c..b8175e1 100644
--- a/pjlib/src/pj/ssl_sock_ossl.c
+++ b/pjlib/src/pj/ssl_sock_ossl.c
@@ -298,14 +298,104 @@ static pj_status_t flush_delayed_send(pj_ssl_sock_t *ssock);
/* Expected maximum value of reason component in OpenSSL error code */
#define MAX_OSSL_ERR_REASON 1200
-static pj_status_t STATUS_FROM_SSL_ERR(pj_ssl_sock_t *ssock,
- unsigned long err)
+
+static char *SSLErrorString (int err)
{
- pj_status_t status;
+ switch (err) {
+ case SSL_ERROR_NONE:
+ return "SSL_ERROR_NONE";
+ case SSL_ERROR_ZERO_RETURN:
+ return "SSL_ERROR_ZERO_RETURN";
+ case SSL_ERROR_WANT_READ:
+ return "SSL_ERROR_WANT_READ";
+ case SSL_ERROR_WANT_WRITE:
+ return "SSL_ERROR_WANT_WRITE";
+ case SSL_ERROR_WANT_CONNECT:
+ return "SSL_ERROR_WANT_CONNECT";
+ case SSL_ERROR_WANT_ACCEPT:
+ return "SSL_ERROR_WANT_ACCEPT";
+ case SSL_ERROR_WANT_X509_LOOKUP:
+ return "SSL_ERROR_WANT_X509_LOOKUP";
+ case SSL_ERROR_SYSCALL:
+ return "SSL_ERROR_SYSCALL";
+ case SSL_ERROR_SSL:
+ return "SSL_ERROR_SSL";
+ default:
+ return "SSL_ERROR_UNKNOWN";
+ }
+}
- /* General SSL error, dig more from OpenSSL error queue */
- if (err == SSL_ERROR_SSL)
- err = ERR_get_error();
+#define ERROR_LOG(msg, err) \
+ PJ_LOG(2,("SSL", "%s (%s): Level: %d err: <%lu> <%s-%s-%s> len: %d", \
+ msg, action, level, err, \
+ (ERR_lib_error_string(err)? ERR_lib_error_string(err): "???"), \
+ (ERR_func_error_string(err)? ERR_func_error_string(err):"???"),\
+ (ERR_reason_error_string(err)? \
+ ERR_reason_error_string(err): "???"), len));
+
+static void SSLLogErrors(char * action, int ret, int ssl_err, int len)
+{
+ char *ssl_err_str = SSLErrorString(ssl_err);
+
+ if (!action) {
+ action = "UNKNOWN";
+ }
+
+ switch (ssl_err) {
+ case SSL_ERROR_SYSCALL:
+ {
+ unsigned long err2 = ERR_get_error();
+ if (err2) {
+ int level = 0;
+ while (err2) {
+ ERROR_LOG("SSL_ERROR_SYSCALL", err2);
+ level++;
+ err2 = ERR_get_error();
+ }
+ } else if (ret == 0) {
+ /* An EOF was observed that violates the protocol */
+
+ /* The TLS/SSL handshake was not successful but was shut down
+ * controlled and by the specifications of the TLS/SSL protocol.
+ */
+ } else if (ret == -1) {
+ /* BIO error - look for more info in errno... */
+ char errStr[250] = "";
+ strerror_r(errno, errStr, sizeof(errStr));
+ /* for now - continue logging these if they occur.... */
+ PJ_LOG(4,("SSL", "BIO error, SSL_ERROR_SYSCALL (%s): "
+ "errno: <%d> <%s> len: %d",
+ action, errno, errStr, len));
+ } else {
+ /* ret!=0 & ret!=-1 & nothing on error stack - is this valid??? */
+ PJ_LOG(2,("SSL", "SSL_ERROR_SYSCALL (%s) ret: %d len: %d",
+ action, ret, len));
+ }
+ break;
+ }
+ case SSL_ERROR_SSL:
+ {
+ unsigned long err2 = ERR_get_error();
+ int level = 0;
+
+ while (err2) {
+ ERROR_LOG("SSL_ERROR_SSL", err2);
+ level++;
+ err2 = ERR_get_error();
+ }
+ break;
+ }
+ default:
+ PJ_LOG(2,("SSL", "%lu [%s] (%s) ret: %d len: %d",
+ ssl_err, ssl_err_str, action, ret, len));
+ break;
+ }
+}
+
+
+static pj_status_t GET_STATUS_FROM_SSL_ERR(unsigned long err)
+{
+ pj_status_t status;
/* OpenSSL error range is much wider than PJLIB errno space, so
* if it exceeds the space, only the error reason will be kept.
@@ -317,13 +407,49 @@ static pj_status_t STATUS_FROM_SSL_ERR(pj_ssl_sock_t *ssock,
status = ERR_GET_REASON(err);
status += PJ_SSL_ERRNO_START;
- ssock->last_err = err;
return status;
}
+/* err contains ERR_get_error() status */
+static pj_status_t STATUS_FROM_SSL_ERR(char *action, pj_ssl_sock_t *ssock,
+ unsigned long err)
+{
+ int level = 0;
+ int len = 0; //dummy
+
+ ERROR_LOG("STATUS_FROM_SSL_ERR", err);
+ level++;
+
+ /* General SSL error, dig more from OpenSSL error queue */
+ if (err == SSL_ERROR_SSL) {
+ err = ERR_get_error();
+ ERROR_LOG("STATUS_FROM_SSL_ERR", err);
+ }
+
+ ssock->last_err = err;
+ return GET_STATUS_FROM_SSL_ERR(err);
+}
+
+/* err contains SSL_get_error() status */
+static pj_status_t STATUS_FROM_SSL_ERR2(char *action, pj_ssl_sock_t *ssock,
+ int ret, int err, int len)
+{
+ unsigned long ssl_err = err;
+
+ if (err == SSL_ERROR_SSL) {
+ ssl_err = ERR_peek_error();
+ }
+
+ /* Dig for more from OpenSSL error queue */
+ SSLLogErrors(action, ret, err, len);
+
+ ssock->last_err = ssl_err;
+ return GET_STATUS_FROM_SSL_ERR(ssl_err);
+}
+
static pj_status_t GET_SSL_STATUS(pj_ssl_sock_t *ssock)
{
- return STATUS_FROM_SSL_ERR(ssock, ERR_get_error());
+ return STATUS_FROM_SSL_ERR("status", ssock, ERR_get_error());
}
@@ -1514,7 +1640,7 @@ static pj_bool_t on_handshake_complete(pj_ssl_sock_t *ssock,
unsigned long err;
err = ERR_get_error();
if (err != SSL_ERROR_NONE)
- status = STATUS_FROM_SSL_ERR(ssock, err);
+ status = STATUS_FROM_SSL_ERR("connecting", ssock, err);
}
reset_ssl_sock_state(ssock);
}
@@ -1833,11 +1959,11 @@ static pj_status_t do_handshake(pj_ssl_sock_t *ssock)
}
if (err < 0) {
- err = SSL_get_error(ssock->ossl_ssl, err);
- if (err != SSL_ERROR_NONE && err != SSL_ERROR_WANT_READ)
+ int err2 = SSL_get_error(ssock->ossl_ssl, err);
+ if (err2 != SSL_ERROR_NONE && err2 != SSL_ERROR_WANT_READ)
{
/* Handshake fails */
- status = STATUS_FROM_SSL_ERR(ssock, err);
+ status = STATUS_FROM_SSL_ERR2("Handshake", ssock, err, err2, 0);
return status;
}
}
@@ -1913,6 +2039,7 @@ static pj_bool_t asock_on_data_read (pj_activesock_t *asock,
read_data_t *buf = *(OFFSET_OF_READ_DATA_PTR(ssock, data));
void *data_ = (pj_int8_t*)buf->data + buf->len;
int size_ = (int)(ssock->read_size - buf->len);
+ int len = size_;
/* SSL_read() may write some data to BIO write when re-negotiation
* is on progress, so let's protect it with write mutex.
@@ -1965,10 +2092,22 @@ static pj_bool_t asock_on_data_read (pj_activesock_t *asock,
*/
if (err != SSL_ERROR_NONE && err != SSL_ERROR_WANT_READ)
{
- /* Reset SSL socket state, then return PJ_FALSE */
- status = STATUS_FROM_SSL_ERR(ssock, err);
- reset_ssl_sock_state(ssock);
- goto on_error;
+ if (err == SSL_ERROR_SYSCALL && size_ == -1 &&
+ ERR_peek_error() == 0 && errno == 0)
+ {
+ status = STATUS_FROM_SSL_ERR2("Read", ssock, size_,
+ err, len);
+ PJ_LOG(4,("SSL", "SSL_read() = -1, with "
+ "SSL_ERROR_SYSCALL, no SSL error, "
+ "and errno = 0 - skip BIO error"));
+ /* Ignore these errors */
+ } else {
+ /* Reset SSL socket state, then return PJ_FALSE */
+ status = STATUS_FROM_SSL_ERR2("Read", ssock, size_,
+ err, len);
+ reset_ssl_sock_state(ssock);
+ goto on_error;
+ }
}
status = do_handshake(ssock);
@@ -2856,7 +2995,7 @@ static pj_status_t ssl_write(pj_ssl_sock_t *ssock,
status = PJ_EBUSY;
} else {
/* Some problem occured */
- status = STATUS_FROM_SSL_ERR(ssock, err);
+ status = STATUS_FROM_SSL_ERR2("Write", ssock, nwritten, err, size);
}
} else {
/* nwritten < *size, shouldn't happen, unless write BIO cannot hold
--
2.9.4