Emeric Brun | 4659195 | 2012-05-18 15:47:34 +0200 | [diff] [blame] | 1 | /* |
| 2 | * SSL data transfer functions between buffers and SOCK_STREAM sockets |
| 3 | * |
| 4 | * Copyright (C) 2012 EXCELIANCE, Emeric Brun <ebrun@exceliance.fr> |
| 5 | * |
| 6 | * This program is free software; you can redistribute it and/or |
| 7 | * modify it under the terms of the GNU General Public License |
| 8 | * as published by the Free Software Foundation; either version |
| 9 | * 2 of the License, or (at your option) any later version. |
| 10 | * |
| 11 | */ |
| 12 | |
| 13 | #define _GNU_SOURCE |
| 14 | #include <errno.h> |
| 15 | #include <fcntl.h> |
| 16 | #include <stdio.h> |
| 17 | #include <stdlib.h> |
| 18 | |
| 19 | #include <sys/socket.h> |
| 20 | #include <sys/stat.h> |
| 21 | #include <sys/types.h> |
| 22 | |
| 23 | #include <netinet/tcp.h> |
| 24 | |
| 25 | #include <openssl/ssl.h> |
| 26 | |
| 27 | #include <common/buffer.h> |
| 28 | #include <common/compat.h> |
| 29 | #include <common/config.h> |
| 30 | #include <common/debug.h> |
| 31 | #include <common/standard.h> |
| 32 | #include <common/ticks.h> |
| 33 | #include <common/time.h> |
| 34 | |
| 35 | #include <proto/connection.h> |
| 36 | #include <proto/fd.h> |
| 37 | #include <proto/freq_ctr.h> |
| 38 | #include <proto/frontend.h> |
| 39 | #include <proto/log.h> |
| 40 | #include <proto/protocols.h> |
| 41 | #include <proto/ssl_sock.h> |
| 42 | #include <proto/task.h> |
| 43 | |
| 44 | #include <types/global.h> |
| 45 | |
| 46 | |
Emeric Brun | e1f38db | 2012-09-03 20:36:47 +0200 | [diff] [blame] | 47 | |
| 48 | void ssl_sock_infocbk(const SSL *ssl, int where, int ret) |
| 49 | { |
| 50 | struct connection *conn = (struct connection *)SSL_get_app_data(ssl); |
| 51 | (void)ret; /* shut gcc stupid warning */ |
| 52 | |
| 53 | if (where & SSL_CB_HANDSHAKE_START) { |
| 54 | /* Disable renegotiation (CVE-2009-3555) */ |
| 55 | if (conn->flags & CO_FL_CONNECTED) |
| 56 | conn->flags |= CO_FL_ERROR; |
| 57 | } |
| 58 | } |
| 59 | |
Emeric Brun | 4659195 | 2012-05-18 15:47:34 +0200 | [diff] [blame] | 60 | /* |
| 61 | * This function is called if SSL * context is not yet allocated. The function |
| 62 | * is designed to be called before any other data-layer operation and sets the |
| 63 | * handshake flag on the connection. It is safe to call it multiple times. |
| 64 | * It returns 0 on success and -1 in error case. |
| 65 | */ |
| 66 | static int ssl_sock_init(struct connection *conn) |
| 67 | { |
| 68 | /* already initialized */ |
| 69 | if (conn->data_ctx) |
| 70 | return 0; |
| 71 | |
| 72 | /* If it is in client mode initiate SSL session |
| 73 | in connect state otherwise accept state */ |
| 74 | if (target_srv(&conn->target)) { |
| 75 | |
| 76 | /* Alloc a new SSL session ctx */ |
| 77 | conn->data_ctx = SSL_new(target_srv(&conn->target)->ssl_ctx.ctx); |
| 78 | if (!conn->data_ctx) |
| 79 | return -1; |
| 80 | |
| 81 | SSL_set_connect_state(conn->data_ctx); |
| 82 | if (target_srv(&conn->target)->ssl_ctx.reused_sess) |
| 83 | SSL_set_session(conn->data_ctx, target_srv(&conn->target)->ssl_ctx.reused_sess); |
| 84 | |
| 85 | /* set fd on SSL session context */ |
| 86 | SSL_set_fd(conn->data_ctx, conn->t.sock.fd); |
| 87 | |
| 88 | /* leave init state and start handshake */ |
| 89 | conn->flags |= CO_FL_SSL_WAIT_HS; |
| 90 | return 0; |
| 91 | } |
| 92 | else if (target_client(&conn->target)) { |
| 93 | |
| 94 | /* Alloc a new SSL session ctx */ |
| 95 | conn->data_ctx = SSL_new(target_client(&conn->target)->ssl_ctx.ctx); |
| 96 | if (!conn->data_ctx) |
| 97 | return -1; |
| 98 | |
| 99 | SSL_set_accept_state(conn->data_ctx); |
| 100 | |
| 101 | /* set fd on SSL session context */ |
| 102 | SSL_set_fd(conn->data_ctx, conn->t.sock.fd); |
| 103 | |
Emeric Brun | e1f38db | 2012-09-03 20:36:47 +0200 | [diff] [blame] | 104 | /* set connection pointer */ |
| 105 | SSL_set_app_data(conn->data_ctx, conn); |
| 106 | |
Emeric Brun | 4659195 | 2012-05-18 15:47:34 +0200 | [diff] [blame] | 107 | /* leave init state and start handshake */ |
| 108 | conn->flags |= CO_FL_SSL_WAIT_HS; |
| 109 | return 0; |
| 110 | } |
| 111 | /* don't know how to handle such a target */ |
| 112 | return -1; |
| 113 | } |
| 114 | |
| 115 | |
| 116 | /* This is the callback which is used when an SSL handshake is pending. It |
| 117 | * updates the FD status if it wants some polling before being called again. |
| 118 | * It returns 0 if it fails in a fatal way or needs to poll to go further, |
| 119 | * otherwise it returns non-zero and removes itself from the connection's |
| 120 | * flags (the bit is provided in <flag> by the caller). |
| 121 | */ |
| 122 | int ssl_sock_handshake(struct connection *conn, unsigned int flag) |
| 123 | { |
| 124 | int ret; |
| 125 | |
| 126 | if (!conn->data_ctx) |
| 127 | goto out_error; |
| 128 | |
| 129 | ret = SSL_do_handshake(conn->data_ctx); |
| 130 | if (ret != 1) { |
| 131 | /* handshake did not complete, let's find why */ |
| 132 | ret = SSL_get_error(conn->data_ctx, ret); |
| 133 | |
| 134 | if (ret == SSL_ERROR_WANT_WRITE) { |
| 135 | /* SSL handshake needs to write, L4 connection may not be ready */ |
| 136 | __conn_sock_stop_recv(conn); |
| 137 | __conn_sock_poll_send(conn); |
| 138 | return 0; |
| 139 | } |
| 140 | else if (ret == SSL_ERROR_WANT_READ) { |
| 141 | /* SSL handshake needs to read, L4 connection is ready */ |
| 142 | if (conn->flags & CO_FL_WAIT_L4_CONN) |
| 143 | conn->flags &= ~CO_FL_WAIT_L4_CONN; |
| 144 | __conn_sock_stop_send(conn); |
| 145 | __conn_sock_poll_recv(conn); |
| 146 | return 0; |
| 147 | } |
| 148 | else { |
| 149 | /* Fail on all other handshake errors */ |
| 150 | goto out_error; |
| 151 | } |
| 152 | } |
| 153 | |
| 154 | /* Handshake succeeded */ |
| 155 | if (target_srv(&conn->target)) { |
| 156 | if (!SSL_session_reused(conn->data_ctx)) { |
| 157 | /* check if session was reused, if not store current session on server for reuse */ |
| 158 | if (target_srv(&conn->target)->ssl_ctx.reused_sess) |
| 159 | SSL_SESSION_free(target_srv(&conn->target)->ssl_ctx.reused_sess); |
| 160 | |
| 161 | target_srv(&conn->target)->ssl_ctx.reused_sess = SSL_get1_session(conn->data_ctx); |
| 162 | } |
| 163 | } |
| 164 | |
| 165 | /* The connection is now established at both layers, it's time to leave */ |
| 166 | conn->flags &= ~(flag | CO_FL_WAIT_L4_CONN | CO_FL_WAIT_L6_CONN); |
| 167 | return 1; |
| 168 | |
| 169 | out_error: |
| 170 | /* Fail on all other handshake errors */ |
| 171 | conn->flags |= CO_FL_ERROR; |
| 172 | conn->flags &= ~flag; |
| 173 | return 0; |
| 174 | } |
| 175 | |
| 176 | /* Receive up to <count> bytes from connection <conn>'s socket and store them |
| 177 | * into buffer <buf>. The caller must ensure that <count> is always smaller |
| 178 | * than the buffer's size. Only one call to recv() is performed, unless the |
| 179 | * buffer wraps, in which case a second call may be performed. The connection's |
| 180 | * flags are updated with whatever special event is detected (error, read0, |
| 181 | * empty). The caller is responsible for taking care of those events and |
| 182 | * avoiding the call if inappropriate. The function does not call the |
| 183 | * connection's polling update function, so the caller is responsible for this. |
| 184 | */ |
| 185 | static int ssl_sock_to_buf(struct connection *conn, struct buffer *buf, int count) |
| 186 | { |
| 187 | int ret, done = 0; |
| 188 | int try = count; |
| 189 | |
| 190 | if (!conn->data_ctx) |
| 191 | goto out_error; |
| 192 | |
| 193 | if (conn->flags & CO_FL_HANDSHAKE) |
| 194 | /* a handshake was requested */ |
| 195 | return 0; |
| 196 | |
| 197 | /* compute the maximum block size we can read at once. */ |
| 198 | if (buffer_empty(buf)) { |
| 199 | /* let's realign the buffer to optimize I/O */ |
| 200 | buf->p = buf->data; |
| 201 | } |
| 202 | else if (buf->data + buf->o < buf->p && |
| 203 | buf->p + buf->i < buf->data + buf->size) { |
| 204 | /* remaining space wraps at the end, with a moving limit */ |
| 205 | if (try > buf->data + buf->size - (buf->p + buf->i)) |
| 206 | try = buf->data + buf->size - (buf->p + buf->i); |
| 207 | } |
| 208 | |
| 209 | /* read the largest possible block. For this, we perform only one call |
| 210 | * to recv() unless the buffer wraps and we exactly fill the first hunk, |
| 211 | * in which case we accept to do it once again. A new attempt is made on |
| 212 | * EINTR too. |
| 213 | */ |
| 214 | while (try) { |
| 215 | ret = SSL_read(conn->data_ctx, bi_end(buf), try); |
Emeric Brun | e1f38db | 2012-09-03 20:36:47 +0200 | [diff] [blame] | 216 | if (conn->flags & CO_FL_ERROR) { |
| 217 | /* CO_FL_ERROR may be set by ssl_sock_infocbk */ |
| 218 | break; |
| 219 | } |
Emeric Brun | 4659195 | 2012-05-18 15:47:34 +0200 | [diff] [blame] | 220 | if (ret > 0) { |
| 221 | buf->i += ret; |
| 222 | done += ret; |
| 223 | if (ret < try) |
| 224 | break; |
| 225 | count -= ret; |
| 226 | try = count; |
| 227 | } |
| 228 | else if (ret == 0) { |
| 229 | goto read0; |
| 230 | } |
| 231 | else { |
| 232 | ret = SSL_get_error(conn->data_ctx, ret); |
| 233 | if (ret == SSL_ERROR_WANT_WRITE) { |
| 234 | /* handshake is running, and it needs to poll for a write event */ |
| 235 | conn->flags |= CO_FL_SSL_WAIT_HS; |
| 236 | __conn_sock_poll_send(conn); |
| 237 | break; |
| 238 | } |
| 239 | else if (ret == SSL_ERROR_WANT_READ) { |
| 240 | /* we need to poll for retry a read later */ |
| 241 | __conn_data_poll_recv(conn); |
| 242 | break; |
| 243 | } |
| 244 | /* otherwise it's a real error */ |
| 245 | goto out_error; |
| 246 | } |
| 247 | } |
| 248 | return done; |
| 249 | |
| 250 | read0: |
| 251 | conn_sock_read0(conn); |
| 252 | return done; |
| 253 | out_error: |
| 254 | conn->flags |= CO_FL_ERROR; |
| 255 | return done; |
| 256 | } |
| 257 | |
| 258 | |
| 259 | /* Send all pending bytes from buffer <buf> to connection <conn>'s socket. |
| 260 | * <flags> may contain MSG_MORE to make the system hold on without sending |
| 261 | * data too fast, but this flag is ignored at the moment. |
| 262 | * Only one call to send() is performed, unless the buffer wraps, in which case |
| 263 | * a second call may be performed. The connection's flags are updated with |
| 264 | * whatever special event is detected (error, empty). The caller is responsible |
| 265 | * for taking care of those events and avoiding the call if inappropriate. The |
| 266 | * function does not call the connection's polling update function, so the caller |
| 267 | * is responsible for this. |
| 268 | */ |
| 269 | static int ssl_sock_from_buf(struct connection *conn, struct buffer *buf, int flags) |
| 270 | { |
| 271 | int ret, try, done; |
| 272 | |
| 273 | done = 0; |
| 274 | |
| 275 | if (!conn->data_ctx) |
| 276 | goto out_error; |
| 277 | |
| 278 | if (conn->flags & CO_FL_HANDSHAKE) |
| 279 | /* a handshake was requested */ |
| 280 | return 0; |
| 281 | |
| 282 | /* send the largest possible block. For this we perform only one call |
| 283 | * to send() unless the buffer wraps and we exactly fill the first hunk, |
| 284 | * in which case we accept to do it once again. |
| 285 | */ |
| 286 | while (buf->o) { |
| 287 | try = buf->o; |
| 288 | /* outgoing data may wrap at the end */ |
| 289 | if (buf->data + try > buf->p) |
| 290 | try = buf->data + try - buf->p; |
| 291 | |
| 292 | ret = SSL_write(conn->data_ctx, bo_ptr(buf), try); |
Emeric Brun | e1f38db | 2012-09-03 20:36:47 +0200 | [diff] [blame] | 293 | if (conn->flags & CO_FL_ERROR) { |
| 294 | /* CO_FL_ERROR may be set by ssl_sock_infocbk */ |
| 295 | break; |
| 296 | } |
Emeric Brun | 4659195 | 2012-05-18 15:47:34 +0200 | [diff] [blame] | 297 | if (ret > 0) { |
| 298 | buf->o -= ret; |
| 299 | done += ret; |
| 300 | |
| 301 | if (likely(!buffer_len(buf))) |
| 302 | /* optimize data alignment in the buffer */ |
| 303 | buf->p = buf->data; |
| 304 | |
| 305 | /* if the system buffer is full, don't insist */ |
| 306 | if (ret < try) |
| 307 | break; |
| 308 | } |
| 309 | else { |
| 310 | ret = SSL_get_error(conn->data_ctx, ret); |
| 311 | if (ret == SSL_ERROR_WANT_WRITE) { |
| 312 | /* we need to poll to retry a write later */ |
| 313 | __conn_data_poll_send(conn); |
| 314 | break; |
| 315 | } |
| 316 | else if (ret == SSL_ERROR_WANT_READ) { |
| 317 | /* handshake is running, and |
| 318 | it needs to poll for a read event, |
| 319 | write polling must be disabled cause |
| 320 | we are sure we can't write anything more |
| 321 | before handshake re-performed */ |
| 322 | conn->flags |= CO_FL_SSL_WAIT_HS; |
| 323 | __conn_sock_poll_recv(conn); |
| 324 | break; |
| 325 | } |
| 326 | goto out_error; |
| 327 | } |
| 328 | } |
| 329 | return done; |
| 330 | |
| 331 | out_error: |
| 332 | conn->flags |= CO_FL_ERROR; |
| 333 | return done; |
| 334 | } |
| 335 | |
| 336 | |
| 337 | static void ssl_sock_close(struct connection *conn) { |
| 338 | |
| 339 | if (conn->data_ctx) { |
| 340 | SSL_free(conn->data_ctx); |
| 341 | conn->data_ctx = NULL; |
| 342 | } |
| 343 | |
| 344 | } |
| 345 | |
| 346 | /* This function tries to perform a clean shutdown on an SSL connection, and in |
| 347 | * any case, flags the connection as reusable if no handshake was in progress. |
| 348 | */ |
| 349 | static void ssl_sock_shutw(struct connection *conn, int clean) |
| 350 | { |
| 351 | if (conn->flags & CO_FL_HANDSHAKE) |
| 352 | return; |
| 353 | /* no handshake was in progress, try a clean ssl shutdown */ |
| 354 | if (clean) |
| 355 | SSL_shutdown(conn->data_ctx); |
| 356 | |
| 357 | /* force flag on ssl to keep session in cache regardless shutdown result */ |
| 358 | SSL_set_shutdown(conn->data_ctx, SSL_SENT_SHUTDOWN); |
| 359 | } |
| 360 | |
| 361 | |
| 362 | /* data-layer operations for SSL sockets */ |
| 363 | struct data_ops ssl_sock = { |
| 364 | .snd_buf = ssl_sock_from_buf, |
| 365 | .rcv_buf = ssl_sock_to_buf, |
| 366 | .rcv_pipe = NULL, |
| 367 | .snd_pipe = NULL, |
| 368 | .shutr = NULL, |
| 369 | .shutw = ssl_sock_shutw, |
| 370 | .close = ssl_sock_close, |
| 371 | .init = ssl_sock_init, |
| 372 | }; |
| 373 | |
| 374 | __attribute__((constructor)) |
| 375 | static void __ssl_sock_init(void) { |
| 376 | STACK_OF(SSL_COMP)* cm; |
| 377 | |
| 378 | SSL_library_init(); |
| 379 | cm = SSL_COMP_get_compression_methods(); |
| 380 | sk_SSL_COMP_zero(cm); |
| 381 | } |
| 382 | |
| 383 | /* |
| 384 | * Local variables: |
| 385 | * c-indent-level: 8 |
| 386 | * c-basic-offset: 8 |
| 387 | * End: |
| 388 | */ |