summaryrefslogtreecommitdiff
path: root/third-party/pjproject/patches/0075-Fixed-2030-Improve-error-handling-in-OpenSSL-socket.patch
blob: 1e7035d93576181e865a54f4210a7eb443921010 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
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