bundled_pjproject: Improve SSL/TLS error handling
[asterisk/asterisk.git] / third-party / pjproject / patches / 0075-Fixed-2030-Improve-error-handling-in-OpenSSL-socket.patch
1 From 96c06899d95eaf01d05561554b21e8c63baa7129 Mon Sep 17 00:00:00 2001
2 From: ming <ming@localhost>
3 Date: Thu, 27 Jul 2017 06:07:54 +0000
4 Subject: [PATCH 75/76] Fixed #2030: Improve error handling in OpenSSL socket
5
6 ---
7  pjlib/src/pj/ssl_sock_ossl.c | 173 ++++++++++++++++++++++++++++++++++++++-----
8  1 file changed, 156 insertions(+), 17 deletions(-)
9
10 diff --git a/pjlib/src/pj/ssl_sock_ossl.c b/pjlib/src/pj/ssl_sock_ossl.c
11 index c466b3c..b8175e1 100644
12 --- a/pjlib/src/pj/ssl_sock_ossl.c
13 +++ b/pjlib/src/pj/ssl_sock_ossl.c
14 @@ -298,14 +298,104 @@ static pj_status_t flush_delayed_send(pj_ssl_sock_t *ssock);
15  /* Expected maximum value of reason component in OpenSSL error code */
16  #define MAX_OSSL_ERR_REASON            1200
17  
18 -static pj_status_t STATUS_FROM_SSL_ERR(pj_ssl_sock_t *ssock,
19 -                                      unsigned long err)
20 +
21 +static char *SSLErrorString (int err)
22  {
23 -    pj_status_t status;
24 +    switch (err) {
25 +    case SSL_ERROR_NONE:
26 +       return "SSL_ERROR_NONE";
27 +    case SSL_ERROR_ZERO_RETURN:
28 +       return "SSL_ERROR_ZERO_RETURN";
29 +    case SSL_ERROR_WANT_READ:
30 +       return "SSL_ERROR_WANT_READ";
31 +    case SSL_ERROR_WANT_WRITE:
32 +       return "SSL_ERROR_WANT_WRITE";
33 +    case SSL_ERROR_WANT_CONNECT:
34 +       return "SSL_ERROR_WANT_CONNECT";
35 +    case SSL_ERROR_WANT_ACCEPT:
36 +       return "SSL_ERROR_WANT_ACCEPT";
37 +    case SSL_ERROR_WANT_X509_LOOKUP:
38 +       return "SSL_ERROR_WANT_X509_LOOKUP";
39 +    case SSL_ERROR_SYSCALL:
40 +       return "SSL_ERROR_SYSCALL";
41 +    case SSL_ERROR_SSL:
42 +       return "SSL_ERROR_SSL";
43 +    default:
44 +       return "SSL_ERROR_UNKNOWN";
45 +    }
46 +}
47  
48 -    /* General SSL error, dig more from OpenSSL error queue */
49 -    if (err == SSL_ERROR_SSL)
50 -       err = ERR_get_error();
51 +#define ERROR_LOG(msg, err) \
52 +    PJ_LOG(2,("SSL", "%s (%s): Level: %d err: <%lu> <%s-%s-%s> len: %d", \
53 +             msg, action, level, err, \
54 +             (ERR_lib_error_string(err)? ERR_lib_error_string(err): "???"), \
55 +             (ERR_func_error_string(err)? ERR_func_error_string(err):"???"),\
56 +             (ERR_reason_error_string(err)? \
57 +              ERR_reason_error_string(err): "???"), len));
58 +
59 +static void SSLLogErrors(char * action, int ret, int ssl_err, int len)
60 +{
61 +    char *ssl_err_str = SSLErrorString(ssl_err);
62 +
63 +    if (!action) {
64 +       action = "UNKNOWN";
65 +    }
66 +
67 +    switch (ssl_err) {
68 +    case SSL_ERROR_SYSCALL:
69 +    {
70 +       unsigned long err2 = ERR_get_error();
71 +       if (err2) {
72 +           int level = 0;
73 +           while (err2) {
74 +               ERROR_LOG("SSL_ERROR_SYSCALL", err2);
75 +               level++;
76 +               err2 = ERR_get_error();
77 +           }
78 +       } else if (ret == 0) {
79 +           /* An EOF was observed that violates the protocol */
80 +
81 +           /* The TLS/SSL handshake was not successful but was shut down
82 +            * controlled and by the specifications of the TLS/SSL protocol.
83 +            */
84 +       } else if (ret == -1) {
85 +           /* BIO error - look for more info in errno... */
86 +           char errStr[250] = "";
87 +           strerror_r(errno, errStr, sizeof(errStr));
88 +           /* for now - continue logging these if they occur.... */
89 +           PJ_LOG(4,("SSL", "BIO error, SSL_ERROR_SYSCALL (%s): "
90 +                            "errno: <%d> <%s> len: %d",
91 +                            action, errno, errStr, len));
92 +       } else {
93 +           /* ret!=0 & ret!=-1 & nothing on error stack - is this valid??? */
94 +           PJ_LOG(2,("SSL", "SSL_ERROR_SYSCALL (%s) ret: %d len: %d",
95 +                     action, ret, len));
96 +       }
97 +       break;
98 +    }
99 +    case SSL_ERROR_SSL:
100 +    {
101 +       unsigned long err2 = ERR_get_error();
102 +       int level = 0;
103 +
104 +       while (err2) {
105 +           ERROR_LOG("SSL_ERROR_SSL", err2);
106 +           level++;
107 +           err2 = ERR_get_error();
108 +       }
109 +       break;
110 +    }
111 +    default:
112 +       PJ_LOG(2,("SSL", "%lu [%s] (%s) ret: %d len: %d",
113 +                 ssl_err, ssl_err_str, action, ret, len));
114 +       break;
115 +    }
116 +}
117 +
118 +
119 +static pj_status_t GET_STATUS_FROM_SSL_ERR(unsigned long err)
120 +{
121 +    pj_status_t status;
122  
123      /* OpenSSL error range is much wider than PJLIB errno space, so
124       * if it exceeds the space, only the error reason will be kept.
125 @@ -317,13 +407,49 @@ static pj_status_t STATUS_FROM_SSL_ERR(pj_ssl_sock_t *ssock,
126         status = ERR_GET_REASON(err);
127  
128      status += PJ_SSL_ERRNO_START;
129 -    ssock->last_err = err;
130      return status;
131  }
132  
133 +/* err contains ERR_get_error() status */
134 +static pj_status_t STATUS_FROM_SSL_ERR(char *action, pj_ssl_sock_t *ssock,
135 +                                      unsigned long err)
136 +{
137 +    int level = 0;
138 +    int len = 0; //dummy
139 +
140 +    ERROR_LOG("STATUS_FROM_SSL_ERR", err);
141 +    level++;
142 +
143 +    /* General SSL error, dig more from OpenSSL error queue */
144 +    if (err == SSL_ERROR_SSL) {
145 +       err = ERR_get_error();
146 +       ERROR_LOG("STATUS_FROM_SSL_ERR", err);
147 +    }
148 +
149 +    ssock->last_err = err;
150 +    return GET_STATUS_FROM_SSL_ERR(err);
151 +}
152 +
153 +/* err contains SSL_get_error() status */
154 +static pj_status_t STATUS_FROM_SSL_ERR2(char *action, pj_ssl_sock_t *ssock,
155 +                                       int ret, int err, int len)
156 +{
157 +    unsigned long ssl_err = err;
158 +
159 +    if (err == SSL_ERROR_SSL) {
160 +       ssl_err = ERR_peek_error();
161 +    }
162 +
163 +    /* Dig for more from OpenSSL error queue */
164 +    SSLLogErrors(action, ret, err, len);
165 +
166 +    ssock->last_err = ssl_err;
167 +    return GET_STATUS_FROM_SSL_ERR(ssl_err);
168 +}
169 +
170  static pj_status_t GET_SSL_STATUS(pj_ssl_sock_t *ssock)
171  {
172 -    return STATUS_FROM_SSL_ERR(ssock, ERR_get_error());
173 +    return STATUS_FROM_SSL_ERR("status", ssock, ERR_get_error());
174  }
175  
176  
177 @@ -1514,7 +1640,7 @@ static pj_bool_t on_handshake_complete(pj_ssl_sock_t *ssock,
178                 unsigned long err;
179                 err = ERR_get_error();
180                 if (err != SSL_ERROR_NONE)
181 -                   status = STATUS_FROM_SSL_ERR(ssock, err);
182 +                   status = STATUS_FROM_SSL_ERR("connecting", ssock, err);
183             }
184             reset_ssl_sock_state(ssock);
185         }
186 @@ -1833,11 +1959,11 @@ static pj_status_t do_handshake(pj_ssl_sock_t *ssock)
187      }
188  
189      if (err < 0) {
190 -       err = SSL_get_error(ssock->ossl_ssl, err);
191 -       if (err != SSL_ERROR_NONE && err != SSL_ERROR_WANT_READ) 
192 +       int err2 = SSL_get_error(ssock->ossl_ssl, err);
193 +       if (err2 != SSL_ERROR_NONE && err2 != SSL_ERROR_WANT_READ)
194         {
195             /* Handshake fails */
196 -           status = STATUS_FROM_SSL_ERR(ssock, err);
197 +           status = STATUS_FROM_SSL_ERR2("Handshake", ssock, err, err2, 0);
198             return status;
199         }
200      }
201 @@ -1913,6 +2039,7 @@ static pj_bool_t asock_on_data_read (pj_activesock_t *asock,
202             read_data_t *buf = *(OFFSET_OF_READ_DATA_PTR(ssock, data));
203             void *data_ = (pj_int8_t*)buf->data + buf->len;
204             int size_ = (int)(ssock->read_size - buf->len);
205 +           int len = size_;
206  
207             /* SSL_read() may write some data to BIO write when re-negotiation
208              * is on progress, so let's protect it with write mutex.
209 @@ -1965,10 +2092,22 @@ static pj_bool_t asock_on_data_read (pj_activesock_t *asock,
210                  */
211                 if (err != SSL_ERROR_NONE && err != SSL_ERROR_WANT_READ)
212                 {
213 -                   /* Reset SSL socket state, then return PJ_FALSE */
214 -                   status = STATUS_FROM_SSL_ERR(ssock, err);
215 -                   reset_ssl_sock_state(ssock);
216 -                   goto on_error;
217 +                   if (err == SSL_ERROR_SYSCALL && size_ == -1 &&
218 +                       ERR_peek_error() == 0 && errno == 0)
219 +                   {
220 +                       status = STATUS_FROM_SSL_ERR2("Read", ssock, size_,
221 +                                                     err, len);
222 +                       PJ_LOG(4,("SSL", "SSL_read() = -1, with "
223 +                                        "SSL_ERROR_SYSCALL, no SSL error, "
224 +                                        "and errno = 0 - skip BIO error"));
225 +                       /* Ignore these errors */
226 +                   } else {
227 +                       /* Reset SSL socket state, then return PJ_FALSE */
228 +                       status = STATUS_FROM_SSL_ERR2("Read", ssock, size_,
229 +                                                     err, len);
230 +                       reset_ssl_sock_state(ssock);
231 +                       goto on_error;
232 +                   }
233                 }
234  
235                 status = do_handshake(ssock);
236 @@ -2856,7 +2995,7 @@ static pj_status_t ssl_write(pj_ssl_sock_t *ssock,
237                 status = PJ_EBUSY;
238         } else {
239             /* Some problem occured */
240 -           status = STATUS_FROM_SSL_ERR(ssock, err);
241 +           status = STATUS_FROM_SSL_ERR2("Write", ssock, nwritten, err, size);
242         }
243      } else {
244         /* nwritten < *size, shouldn't happen, unless write BIO cannot hold 
245 -- 
246 2.9.4
247