1 /*
2 +----------------------------------------------------------------------+
3 | PHP Version 5 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 1997-2015 The PHP Group |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
15 | Author: Wez Furlong <wez@thebrainroom.com> |
16 +----------------------------------------------------------------------+
17 */
18
19 /* $Id$ */
20
21 #include "php.h"
22 #include "ext/standard/file.h"
23 #include "ext/standard/url.h"
24 #include "streams/php_streams_int.h"
25 #include "ext/standard/php_smart_str.h"
26 #include "php_network.h"
27 #include "php_openssl.h"
28 #include <openssl/ssl.h>
29 #include <openssl/x509.h>
30 #include <openssl/err.h>
31
32 #ifdef PHP_WIN32
33 #include "win32/time.h"
34 #endif
35
36 #ifdef NETWARE
37 #include <sys/select.h>
38 #endif
39
40 int php_openssl_apply_verification_policy(SSL *ssl, X509 *peer, php_stream *stream TSRMLS_DC);
41 SSL *php_SSL_new_from_context(SSL_CTX *ctx, php_stream *stream TSRMLS_DC);
42 int php_openssl_get_x509_list_id(void);
43 static struct timeval subtract_timeval( struct timeval a, struct timeval b );
44 static int compare_timeval( struct timeval a, struct timeval b );
45 static size_t php_openssl_sockop_io(int read, php_stream *stream, char *buf, size_t count TSRMLS_DC);
46
47 /* This implementation is very closely tied to the that of the native
48 * sockets implemented in the core.
49 * Don't try this technique in other extensions!
50 * */
51
52 typedef struct _php_openssl_netstream_data_t {
53 php_netstream_data_t s;
54 SSL *ssl_handle;
55 SSL_CTX *ctx;
56 struct timeval connect_timeout;
57 int enable_on_connect;
58 int is_client;
59 int ssl_active;
60 php_stream_xport_crypt_method_t method;
61 char *sni;
62 unsigned state_set:1;
63 unsigned _spare:31;
64 } php_openssl_netstream_data_t;
65
66 php_stream_ops php_openssl_socket_ops;
67
68 /* it doesn't matter that we do some hash traversal here, since it is done only
69 * in an error condition arising from a network connection problem */
is_http_stream_talking_to_iis(php_stream * stream TSRMLS_DC)70 static int is_http_stream_talking_to_iis(php_stream *stream TSRMLS_DC)
71 {
72 if (stream->wrapperdata && stream->wrapper && strcasecmp(stream->wrapper->wops->label, "HTTP") == 0) {
73 /* the wrapperdata is an array zval containing the headers */
74 zval **tmp;
75
76 #define SERVER_MICROSOFT_IIS "Server: Microsoft-IIS"
77 #define SERVER_GOOGLE "Server: GFE/"
78
79 zend_hash_internal_pointer_reset(Z_ARRVAL_P(stream->wrapperdata));
80 while (SUCCESS == zend_hash_get_current_data(Z_ARRVAL_P(stream->wrapperdata), (void**)&tmp)) {
81
82 if (strncasecmp(Z_STRVAL_PP(tmp), SERVER_MICROSOFT_IIS, sizeof(SERVER_MICROSOFT_IIS)-1) == 0) {
83 return 1;
84 } else if (strncasecmp(Z_STRVAL_PP(tmp), SERVER_GOOGLE, sizeof(SERVER_GOOGLE)-1) == 0) {
85 return 1;
86 }
87
88 zend_hash_move_forward(Z_ARRVAL_P(stream->wrapperdata));
89 }
90 }
91 return 0;
92 }
93
handle_ssl_error(php_stream * stream,int nr_bytes,zend_bool is_init TSRMLS_DC)94 static int handle_ssl_error(php_stream *stream, int nr_bytes, zend_bool is_init TSRMLS_DC)
95 {
96 php_openssl_netstream_data_t *sslsock = (php_openssl_netstream_data_t*)stream->abstract;
97 int err = SSL_get_error(sslsock->ssl_handle, nr_bytes);
98 char esbuf[512];
99 smart_str ebuf = {0};
100 unsigned long ecode;
101 int retry = 1;
102
103 switch(err) {
104 case SSL_ERROR_ZERO_RETURN:
105 /* SSL terminated (but socket may still be active) */
106 retry = 0;
107 break;
108 case SSL_ERROR_WANT_READ:
109 case SSL_ERROR_WANT_WRITE:
110 /* re-negotiation, or perhaps the SSL layer needs more
111 * packets: retry in next iteration */
112 errno = EAGAIN;
113 retry = is_init ? 1 : sslsock->s.is_blocked;
114 break;
115 case SSL_ERROR_SYSCALL:
116 if (ERR_peek_error() == 0) {
117 if (nr_bytes == 0) {
118 if (!is_http_stream_talking_to_iis(stream TSRMLS_CC) && ERR_get_error() != 0) {
119 php_error_docref(NULL TSRMLS_CC, E_WARNING,
120 "SSL: fatal protocol error");
121 }
122 SSL_set_shutdown(sslsock->ssl_handle, SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN);
123 stream->eof = 1;
124 retry = 0;
125 } else {
126 char *estr = php_socket_strerror(php_socket_errno(), NULL, 0);
127
128 php_error_docref(NULL TSRMLS_CC, E_WARNING,
129 "SSL: %s", estr);
130
131 efree(estr);
132 retry = 0;
133 }
134 break;
135 }
136
137
138 /* fall through */
139 default:
140 /* some other error */
141 ecode = ERR_get_error();
142
143 switch (ERR_GET_REASON(ecode)) {
144 case SSL_R_NO_SHARED_CIPHER:
145 php_error_docref(NULL TSRMLS_CC, E_WARNING, "SSL_R_NO_SHARED_CIPHER: no suitable shared cipher could be used. This could be because the server is missing an SSL certificate (local_cert context option)");
146 retry = 0;
147 break;
148
149 default:
150 do {
151 /* NULL is automatically added */
152 ERR_error_string_n(ecode, esbuf, sizeof(esbuf));
153 if (ebuf.c) {
154 smart_str_appendc(&ebuf, '\n');
155 }
156 smart_str_appends(&ebuf, esbuf);
157 } while ((ecode = ERR_get_error()) != 0);
158
159 smart_str_0(&ebuf);
160
161 php_error_docref(NULL TSRMLS_CC, E_WARNING,
162 "SSL operation failed with code %d. %s%s",
163 err,
164 ebuf.c ? "OpenSSL Error messages:\n" : "",
165 ebuf.c ? ebuf.c : "");
166 if (ebuf.c) {
167 smart_str_free(&ebuf);
168 }
169 }
170
171 retry = 0;
172 errno = 0;
173 }
174 return retry;
175 }
176
php_openssl_sockop_read(php_stream * stream,char * buf,size_t count TSRMLS_DC)177 static size_t php_openssl_sockop_read(php_stream *stream, char *buf, size_t count TSRMLS_DC)
178 {
179 return php_openssl_sockop_io(1, stream, buf, count TSRMLS_CC);
180 }
181
php_openssl_sockop_write(php_stream * stream,const char * buf,size_t count TSRMLS_DC)182 static size_t php_openssl_sockop_write(php_stream *stream, const char *buf, size_t count TSRMLS_DC)
183 {
184 return php_openssl_sockop_io(0, stream, (char*)buf, count TSRMLS_CC);
185 }
186
187 /**
188 * Factored out common functionality (blocking, timeout, loop management) for read and write.
189 * Perform IO (read or write) to an SSL socket. If we have a timeout, we switch to non-blocking mode
190 * for the duration of the operation, using select to do our waits. If we time out, or we have an error
191 * report that back to PHP
192 *
193 */
php_openssl_sockop_io(int read,php_stream * stream,char * buf,size_t count TSRMLS_DC)194 static size_t php_openssl_sockop_io(int read, php_stream *stream, char *buf, size_t count TSRMLS_DC)
195 {
196 php_openssl_netstream_data_t *sslsock = (php_openssl_netstream_data_t*)stream->abstract;
197 int nr_bytes = 0;
198
199 /* Only do this if SSL is active. */
200 if (sslsock->ssl_active) {
201 int retry = 1;
202 struct timeval start_time;
203 struct timeval *timeout = NULL;
204 int began_blocked = sslsock->s.is_blocked;
205 int has_timeout = 0;
206
207 /* never use a timeout with non-blocking sockets */
208 if (began_blocked && &sslsock->s.timeout) {
209 timeout = &sslsock->s.timeout;
210 }
211
212 if (timeout && php_set_sock_blocking(sslsock->s.socket, 0 TSRMLS_CC) == SUCCESS) {
213 sslsock->s.is_blocked = 0;
214 }
215
216 if (!sslsock->s.is_blocked && timeout && (timeout->tv_sec || timeout->tv_usec)) {
217 has_timeout = 1;
218 /* gettimeofday is not monotonic; using it here is not strictly correct */
219 gettimeofday(&start_time, NULL);
220 }
221
222 /* Main IO loop. */
223 do {
224 struct timeval cur_time, elapsed_time, left_time;
225
226 /* If we have a timeout to check, figure out how much time has elapsed since we started. */
227 if (has_timeout) {
228 gettimeofday(&cur_time, NULL);
229
230 /* Determine how much time we've taken so far. */
231 elapsed_time = subtract_timeval(cur_time, start_time);
232
233 /* and return an error if we've taken too long. */
234 if (compare_timeval(elapsed_time, *timeout) > 0 ) {
235 /* If the socket was originally blocking, set it back. */
236 if (began_blocked) {
237 php_set_sock_blocking(sslsock->s.socket, 1 TSRMLS_CC);
238 sslsock->s.is_blocked = 1;
239 }
240 sslsock->s.timeout_event = 1;
241 return -1;
242 }
243 }
244
245 /* Now, do the IO operation. Don't block if we can't complete... */
246 if (read) {
247 nr_bytes = SSL_read(sslsock->ssl_handle, buf, count);
248 } else {
249 nr_bytes = SSL_write(sslsock->ssl_handle, buf, count);
250 }
251
252 /* Now, how much time until we time out? */
253 if (has_timeout) {
254 left_time = subtract_timeval( *timeout, elapsed_time );
255 }
256
257 /* If we didn't do anything on the last loop (or an error) check to see if we should retry or exit. */
258 if (nr_bytes <= 0) {
259
260 /* Get the error code from SSL, and check to see if it's an error or not. */
261 int err = SSL_get_error(sslsock->ssl_handle, nr_bytes );
262 retry = handle_ssl_error(stream, nr_bytes, 0 TSRMLS_CC);
263
264 /* If we get this (the above doesn't check) then we'll retry as well. */
265 if (errno == EAGAIN && err == SSL_ERROR_WANT_READ && read) {
266 retry = 1;
267 }
268 if (errno == EAGAIN && err == SSL_ERROR_WANT_WRITE && read == 0) {
269 retry = 1;
270 }
271
272 /* Also, on reads, we may get this condition on an EOF. We should check properly. */
273 if (read) {
274 stream->eof = (retry == 0 && errno != EAGAIN && !SSL_pending(sslsock->ssl_handle));
275 }
276
277 /* Don't loop indefinitely in non-blocking mode if no data is available */
278 if (began_blocked == 0) {
279 break;
280 }
281
282 /* Now, if we have to wait some time, and we're supposed to be blocking, wait for the socket to become
283 * available. Now, php_pollfd_for uses select to wait up to our time_left value only...
284 */
285 if (retry) {
286 if (read) {
287 php_pollfd_for(sslsock->s.socket, (err == SSL_ERROR_WANT_WRITE) ?
288 (POLLOUT|POLLPRI) : (POLLIN|POLLPRI), has_timeout ? &left_time : NULL);
289 } else {
290 php_pollfd_for(sslsock->s.socket, (err == SSL_ERROR_WANT_READ) ?
291 (POLLIN|POLLPRI) : (POLLOUT|POLLPRI), has_timeout ? &left_time : NULL);
292 }
293 }
294 } else {
295 /* Else, if we got bytes back, check for possible errors. */
296 int err = SSL_get_error(sslsock->ssl_handle, nr_bytes);
297
298 /* If we didn't get any error, then let's return it to PHP. */
299 if (err == SSL_ERROR_NONE) {
300 break;
301 }
302
303 /* Otherwise, we need to wait again (up to time_left or we get an error) */
304 if (began_blocked) {
305 if (read) {
306 php_pollfd_for(sslsock->s.socket, (err == SSL_ERROR_WANT_WRITE) ?
307 (POLLOUT|POLLPRI) : (POLLIN|POLLPRI), has_timeout ? &left_time : NULL);
308 } else {
309 php_pollfd_for(sslsock->s.socket, (err == SSL_ERROR_WANT_READ) ?
310 (POLLIN|POLLPRI) : (POLLOUT|POLLPRI), has_timeout ? &left_time : NULL);
311 }
312 }
313 }
314 /* Finally, we keep going until we got data, and an SSL_ERROR_NONE, unless we had an error. */
315 } while (retry);
316
317 /* Tell PHP if we read / wrote bytes. */
318 if (nr_bytes > 0) {
319 php_stream_notify_progress_increment(stream->context, nr_bytes, 0);
320 }
321
322 /* And if we were originally supposed to be blocking, let's reset the socket to that. */
323 if (began_blocked && php_set_sock_blocking(sslsock->s.socket, 1 TSRMLS_CC) == SUCCESS) {
324 sslsock->s.is_blocked = 1;
325 }
326 } else {
327 /* This block is if we had no timeout... We will just sit and wait forever on the IO operation. */
328 if (read) {
329 nr_bytes = php_stream_socket_ops.read(stream, buf, count TSRMLS_CC);
330 } else {
331 nr_bytes = php_stream_socket_ops.write(stream, buf, count TSRMLS_CC);
332 }
333 }
334
335 /* PHP doesn't expect a negative return. */
336 if (nr_bytes < 0) {
337 nr_bytes = 0;
338 }
339
340 return nr_bytes;
341 }
342
subtract_timeval(struct timeval a,struct timeval b)343 struct timeval subtract_timeval( struct timeval a, struct timeval b )
344 {
345 struct timeval difference;
346
347 difference.tv_sec = a.tv_sec - b.tv_sec;
348 difference.tv_usec = a.tv_usec - b.tv_usec;
349
350 if (a.tv_usec < b.tv_usec) {
351 b.tv_sec -= 1L;
352 b.tv_usec += 1000000L;
353 }
354
355 return difference;
356 }
357
compare_timeval(struct timeval a,struct timeval b)358 int compare_timeval( struct timeval a, struct timeval b )
359 {
360 if (a.tv_sec > b.tv_sec || (a.tv_sec == b.tv_sec && a.tv_usec > b.tv_usec) ) {
361 return 1;
362 } else if( a.tv_sec == b.tv_sec && a.tv_usec == b.tv_usec ) {
363 return 0;
364 } else {
365 return -1;
366 }
367 }
368
php_openssl_sockop_close(php_stream * stream,int close_handle TSRMLS_DC)369 static int php_openssl_sockop_close(php_stream *stream, int close_handle TSRMLS_DC)
370 {
371 php_openssl_netstream_data_t *sslsock = (php_openssl_netstream_data_t*)stream->abstract;
372 #ifdef PHP_WIN32
373 int n;
374 #endif
375 if (close_handle) {
376 if (sslsock->ssl_active) {
377 SSL_shutdown(sslsock->ssl_handle);
378 sslsock->ssl_active = 0;
379 }
380 if (sslsock->ssl_handle) {
381 SSL_free(sslsock->ssl_handle);
382 sslsock->ssl_handle = NULL;
383 }
384 if (sslsock->ctx) {
385 SSL_CTX_free(sslsock->ctx);
386 sslsock->ctx = NULL;
387 }
388 #ifdef PHP_WIN32
389 if (sslsock->s.socket == -1)
390 sslsock->s.socket = SOCK_ERR;
391 #endif
392 if (sslsock->s.socket != SOCK_ERR) {
393 #ifdef PHP_WIN32
394 /* prevent more data from coming in */
395 shutdown(sslsock->s.socket, SHUT_RD);
396
397 /* try to make sure that the OS sends all data before we close the connection.
398 * Essentially, we are waiting for the socket to become writeable, which means
399 * that all pending data has been sent.
400 * We use a small timeout which should encourage the OS to send the data,
401 * but at the same time avoid hanging indefinitely.
402 * */
403 do {
404 n = php_pollfd_for_ms(sslsock->s.socket, POLLOUT, 500);
405 } while (n == -1 && php_socket_errno() == EINTR);
406 #endif
407 closesocket(sslsock->s.socket);
408 sslsock->s.socket = SOCK_ERR;
409 }
410 }
411
412 if (sslsock->sni) {
413 pefree(sslsock->sni, php_stream_is_persistent(stream));
414 }
415 pefree(sslsock, php_stream_is_persistent(stream));
416
417 return 0;
418 }
419
php_openssl_sockop_flush(php_stream * stream TSRMLS_DC)420 static int php_openssl_sockop_flush(php_stream *stream TSRMLS_DC)
421 {
422 return php_stream_socket_ops.flush(stream TSRMLS_CC);
423 }
424
php_openssl_sockop_stat(php_stream * stream,php_stream_statbuf * ssb TSRMLS_DC)425 static int php_openssl_sockop_stat(php_stream *stream, php_stream_statbuf *ssb TSRMLS_DC)
426 {
427 return php_stream_socket_ops.stat(stream, ssb TSRMLS_CC);
428 }
429
430
php_openssl_setup_crypto(php_stream * stream,php_openssl_netstream_data_t * sslsock,php_stream_xport_crypto_param * cparam TSRMLS_DC)431 static inline int php_openssl_setup_crypto(php_stream *stream,
432 php_openssl_netstream_data_t *sslsock,
433 php_stream_xport_crypto_param *cparam
434 TSRMLS_DC)
435 {
436 SSL_METHOD *method;
437 long ssl_ctx_options = SSL_OP_ALL;
438
439 if (sslsock->ssl_handle) {
440 if (sslsock->s.is_blocked) {
441 php_error_docref(NULL TSRMLS_CC, E_WARNING, "SSL/TLS already set-up for this stream");
442 return -1;
443 } else {
444 return 0;
445 }
446 }
447
448 /* need to do slightly different things, based on client/server method,
449 * so lets remember which method was selected */
450
451 switch (cparam->inputs.method) {
452 case STREAM_CRYPTO_METHOD_SSLv23_CLIENT:
453 sslsock->is_client = 1;
454 method = SSLv23_client_method();
455 break;
456 case STREAM_CRYPTO_METHOD_SSLv2_CLIENT:
457 #ifdef OPENSSL_NO_SSL2
458 php_error_docref(NULL TSRMLS_CC, E_WARNING, "SSLv2 support is not compiled into the OpenSSL library PHP is linked against");
459 return -1;
460 #else
461 sslsock->is_client = 1;
462 method = SSLv2_client_method();
463 break;
464 #endif
465 case STREAM_CRYPTO_METHOD_SSLv3_CLIENT:
466 #ifdef OPENSSL_NO_SSL3
467 php_error_docref(NULL TSRMLS_CC, E_WARNING, "SSLv3 support is not compiled into the OpenSSL library PHP is linked against");
468 return -1;
469 #else
470 sslsock->is_client = 1;
471 method = SSLv3_client_method();
472 break;
473 #endif
474 case STREAM_CRYPTO_METHOD_TLS_CLIENT:
475 sslsock->is_client = 1;
476 method = TLSv1_client_method();
477 break;
478 case STREAM_CRYPTO_METHOD_SSLv23_SERVER:
479 sslsock->is_client = 0;
480 method = SSLv23_server_method();
481 break;
482 case STREAM_CRYPTO_METHOD_SSLv3_SERVER:
483 #ifdef OPENSSL_NO_SSL3
484 php_error_docref(NULL TSRMLS_CC, E_WARNING, "SSLv3 support is not compiled into the OpenSSL library PHP is linked against");
485 return -1;
486 #else
487 sslsock->is_client = 0;
488 method = SSLv3_server_method();
489 break;
490 #endif
491 case STREAM_CRYPTO_METHOD_SSLv2_SERVER:
492 #ifdef OPENSSL_NO_SSL2
493 php_error_docref(NULL TSRMLS_CC, E_WARNING, "SSLv2 support is not compiled into the OpenSSL library PHP is linked against");
494 return -1;
495 #else
496 sslsock->is_client = 0;
497 method = SSLv2_server_method();
498 break;
499 #endif
500 case STREAM_CRYPTO_METHOD_TLS_SERVER:
501 sslsock->is_client = 0;
502 method = TLSv1_server_method();
503 break;
504 default:
505 return -1;
506
507 }
508
509 sslsock->ctx = SSL_CTX_new(method);
510 if (sslsock->ctx == NULL) {
511 php_error_docref(NULL TSRMLS_CC, E_WARNING, "failed to create an SSL context");
512 return -1;
513 }
514
515 #if OPENSSL_VERSION_NUMBER >= 0x0090605fL
516 ssl_ctx_options &= ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS;
517 #endif
518 SSL_CTX_set_options(sslsock->ctx, ssl_ctx_options);
519
520 #if OPENSSL_VERSION_NUMBER >= 0x0090806fL
521 {
522 zval **val;
523
524 if (stream->context && SUCCESS == php_stream_context_get_option(
525 stream->context, "ssl", "no_ticket", &val) &&
526 zval_is_true(*val)) {
527 SSL_CTX_set_options(sslsock->ctx, SSL_OP_NO_TICKET);
528 }
529 }
530 #endif
531
532 #if OPENSSL_VERSION_NUMBER >= 0x10000000L
533 {
534 zval **val;
535
536 if (stream->context && SUCCESS == php_stream_context_get_option(
537 stream->context, "ssl", "disable_compression", &val) &&
538 zval_is_true(*val)) {
539 SSL_CTX_set_options(sslsock->ctx, SSL_OP_NO_COMPRESSION);
540 }
541 }
542 #endif
543
544 sslsock->ssl_handle = php_SSL_new_from_context(sslsock->ctx, stream TSRMLS_CC);
545 if (sslsock->ssl_handle == NULL) {
546 php_error_docref(NULL TSRMLS_CC, E_WARNING, "failed to create an SSL handle");
547 SSL_CTX_free(sslsock->ctx);
548 sslsock->ctx = NULL;
549 return -1;
550 }
551
552 if (!SSL_set_fd(sslsock->ssl_handle, sslsock->s.socket)) {
553 handle_ssl_error(stream, 0, 1 TSRMLS_CC);
554 }
555
556 if (cparam->inputs.session) {
557 if (cparam->inputs.session->ops != &php_openssl_socket_ops) {
558 php_error_docref(NULL TSRMLS_CC, E_WARNING, "supplied session stream must be an SSL enabled stream");
559 } else if (((php_openssl_netstream_data_t*)cparam->inputs.session->abstract)->ssl_handle == NULL) {
560 php_error_docref(NULL TSRMLS_CC, E_WARNING, "supplied SSL session stream is not initialized");
561 } else {
562 SSL_copy_session_id(sslsock->ssl_handle, ((php_openssl_netstream_data_t*)cparam->inputs.session->abstract)->ssl_handle);
563 }
564 }
565 return 0;
566 }
567
php_openssl_enable_crypto(php_stream * stream,php_openssl_netstream_data_t * sslsock,php_stream_xport_crypto_param * cparam TSRMLS_DC)568 static inline int php_openssl_enable_crypto(php_stream *stream,
569 php_openssl_netstream_data_t *sslsock,
570 php_stream_xport_crypto_param *cparam
571 TSRMLS_DC)
572 {
573 int n, retry = 1;
574
575 if (cparam->inputs.activate && !sslsock->ssl_active) {
576 struct timeval start_time,
577 *timeout;
578 int blocked = sslsock->s.is_blocked,
579 has_timeout = 0;
580
581 #if OPENSSL_VERSION_NUMBER >= 0x0090806fL && !defined(OPENSSL_NO_TLSEXT)
582 if (sslsock->is_client && sslsock->sni) {
583 SSL_set_tlsext_host_name(sslsock->ssl_handle, sslsock->sni);
584 }
585 #endif
586
587 if (!sslsock->state_set) {
588 if (sslsock->is_client) {
589 SSL_set_connect_state(sslsock->ssl_handle);
590 } else {
591 SSL_set_accept_state(sslsock->ssl_handle);
592 }
593 sslsock->state_set = 1;
594 }
595
596 if (SUCCESS == php_set_sock_blocking(sslsock->s.socket, 0 TSRMLS_CC)) {
597 sslsock->s.is_blocked = 0;
598 }
599
600 timeout = sslsock->is_client ? &sslsock->connect_timeout : &sslsock->s.timeout;
601 has_timeout = !sslsock->s.is_blocked && (timeout->tv_sec || timeout->tv_usec);
602 /* gettimeofday is not monotonic; using it here is not strictly correct */
603 if (has_timeout) {
604 gettimeofday(&start_time, NULL);
605 }
606
607 do {
608 struct timeval cur_time,
609 elapsed_time = {0};
610
611 if (sslsock->is_client) {
612 n = SSL_connect(sslsock->ssl_handle);
613 } else {
614 n = SSL_accept(sslsock->ssl_handle);
615 }
616
617 if (has_timeout) {
618 gettimeofday(&cur_time, NULL);
619 elapsed_time = subtract_timeval( cur_time, start_time );
620
621 if (compare_timeval( elapsed_time, *timeout) > 0) {
622 php_error_docref(NULL TSRMLS_CC, E_WARNING, "SSL: crypto enabling timeout");
623 return -1;
624 }
625 }
626
627 if (n <= 0) {
628 /* in case of SSL_ERROR_WANT_READ/WRITE, do not retry in non-blocking mode */
629 retry = handle_ssl_error(stream, n, blocked TSRMLS_CC);
630 if (retry) {
631 /* wait until something interesting happens in the socket. It may be a
632 * timeout. Also consider the unlikely of possibility of a write block */
633 int err = SSL_get_error(sslsock->ssl_handle, n);
634 struct timeval left_time;
635
636 if (has_timeout) {
637 left_time = subtract_timeval( *timeout, elapsed_time );
638 }
639 php_pollfd_for(sslsock->s.socket, (err == SSL_ERROR_WANT_READ) ?
640 (POLLIN|POLLPRI) : POLLOUT, has_timeout ? &left_time : NULL);
641 }
642 } else {
643 retry = 0;
644 }
645 } while (retry);
646
647 if (sslsock->s.is_blocked != blocked && SUCCESS == php_set_sock_blocking(sslsock->s.socket, blocked TSRMLS_CC)) {
648 sslsock->s.is_blocked = blocked;
649 }
650
651 if (n == 1) {
652 X509 *peer_cert;
653
654 peer_cert = SSL_get_peer_certificate(sslsock->ssl_handle);
655
656 if (FAILURE == php_openssl_apply_verification_policy(sslsock->ssl_handle, peer_cert, stream TSRMLS_CC)) {
657 SSL_shutdown(sslsock->ssl_handle);
658 n = -1;
659 } else {
660 sslsock->ssl_active = 1;
661
662 /* allow the script to capture the peer cert
663 * and/or the certificate chain */
664 if (stream->context) {
665 zval **val, *zcert;
666
667 if (SUCCESS == php_stream_context_get_option(
668 stream->context, "ssl",
669 "capture_peer_cert", &val) &&
670 zval_is_true(*val)) {
671 MAKE_STD_ZVAL(zcert);
672 ZVAL_RESOURCE(zcert, zend_list_insert(peer_cert,
673 php_openssl_get_x509_list_id() TSRMLS_CC));
674 php_stream_context_set_option(stream->context,
675 "ssl", "peer_certificate",
676 zcert);
677 peer_cert = NULL;
678 FREE_ZVAL(zcert);
679 }
680
681 if (SUCCESS == php_stream_context_get_option(
682 stream->context, "ssl",
683 "capture_peer_cert_chain", &val) &&
684 zval_is_true(*val)) {
685 zval *arr;
686 STACK_OF(X509) *chain;
687
688 MAKE_STD_ZVAL(arr);
689 chain = SSL_get_peer_cert_chain(
690 sslsock->ssl_handle);
691
692 if (chain && sk_X509_num(chain) > 0) {
693 int i;
694 array_init(arr);
695
696 for (i = 0; i < sk_X509_num(chain); i++) {
697 X509 *mycert = X509_dup(
698 sk_X509_value(chain, i));
699 MAKE_STD_ZVAL(zcert);
700 ZVAL_RESOURCE(zcert,
701 zend_list_insert(mycert,
702 php_openssl_get_x509_list_id() TSRMLS_CC));
703 add_next_index_zval(arr, zcert);
704 }
705
706 } else {
707 ZVAL_NULL(arr);
708 }
709
710 php_stream_context_set_option(stream->context,
711 "ssl", "peer_certificate_chain",
712 arr);
713 zval_dtor(arr);
714 efree(arr);
715 }
716 }
717 }
718
719 if (peer_cert) {
720 X509_free(peer_cert);
721 }
722 } else {
723 n = errno == EAGAIN ? 0 : -1;
724 }
725
726 return n;
727
728 } else if (!cparam->inputs.activate && sslsock->ssl_active) {
729 /* deactivate - common for server/client */
730 SSL_shutdown(sslsock->ssl_handle);
731 sslsock->ssl_active = 0;
732 }
733 return -1;
734 }
735
php_openssl_tcp_sockop_accept(php_stream * stream,php_openssl_netstream_data_t * sock,php_stream_xport_param * xparam STREAMS_DC TSRMLS_DC)736 static inline int php_openssl_tcp_sockop_accept(php_stream *stream, php_openssl_netstream_data_t *sock,
737 php_stream_xport_param *xparam STREAMS_DC TSRMLS_DC)
738 {
739 int clisock;
740
741 xparam->outputs.client = NULL;
742
743 clisock = php_network_accept_incoming(sock->s.socket,
744 xparam->want_textaddr ? &xparam->outputs.textaddr : NULL,
745 xparam->want_textaddr ? &xparam->outputs.textaddrlen : NULL,
746 xparam->want_addr ? &xparam->outputs.addr : NULL,
747 xparam->want_addr ? &xparam->outputs.addrlen : NULL,
748 xparam->inputs.timeout,
749 xparam->want_errortext ? &xparam->outputs.error_text : NULL,
750 &xparam->outputs.error_code
751 TSRMLS_CC);
752
753 if (clisock >= 0) {
754 php_openssl_netstream_data_t *clisockdata;
755
756 clisockdata = emalloc(sizeof(*clisockdata));
757
758 if (clisockdata == NULL) {
759 closesocket(clisock);
760 /* technically a fatal error */
761 } else {
762 /* copy underlying tcp fields */
763 memset(clisockdata, 0, sizeof(*clisockdata));
764 memcpy(clisockdata, sock, sizeof(clisockdata->s));
765
766 clisockdata->s.socket = clisock;
767
768 xparam->outputs.client = php_stream_alloc_rel(stream->ops, clisockdata, NULL, "r+");
769 if (xparam->outputs.client) {
770 xparam->outputs.client->context = stream->context;
771 if (stream->context) {
772 zend_list_addref(stream->context->rsrc_id);
773 }
774 }
775 }
776
777 if (xparam->outputs.client && sock->enable_on_connect) {
778 /* apply crypto */
779 switch (sock->method) {
780 case STREAM_CRYPTO_METHOD_SSLv23_CLIENT:
781 sock->method = STREAM_CRYPTO_METHOD_SSLv23_SERVER;
782 break;
783 case STREAM_CRYPTO_METHOD_SSLv2_CLIENT:
784 sock->method = STREAM_CRYPTO_METHOD_SSLv2_SERVER;
785 break;
786 case STREAM_CRYPTO_METHOD_SSLv3_CLIENT:
787 sock->method = STREAM_CRYPTO_METHOD_SSLv3_SERVER;
788 break;
789 case STREAM_CRYPTO_METHOD_TLS_CLIENT:
790 sock->method = STREAM_CRYPTO_METHOD_TLS_SERVER;
791 break;
792 default:
793 break;
794 }
795
796 clisockdata->method = sock->method;
797
798 if (php_stream_xport_crypto_setup(xparam->outputs.client, clisockdata->method,
799 NULL TSRMLS_CC) < 0 || php_stream_xport_crypto_enable(
800 xparam->outputs.client, 1 TSRMLS_CC) < 0) {
801 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to enable crypto");
802
803 php_stream_close(xparam->outputs.client);
804 xparam->outputs.client = NULL;
805 xparam->outputs.returncode = -1;
806 }
807 }
808 }
809
810 return xparam->outputs.client == NULL ? -1 : 0;
811 }
php_openssl_sockop_set_option(php_stream * stream,int option,int value,void * ptrparam TSRMLS_DC)812 static int php_openssl_sockop_set_option(php_stream *stream, int option, int value, void *ptrparam TSRMLS_DC)
813 {
814 php_openssl_netstream_data_t *sslsock = (php_openssl_netstream_data_t*)stream->abstract;
815 php_stream_xport_crypto_param *cparam = (php_stream_xport_crypto_param *)ptrparam;
816 php_stream_xport_param *xparam = (php_stream_xport_param *)ptrparam;
817
818 switch (option) {
819 case PHP_STREAM_OPTION_CHECK_LIVENESS:
820 {
821 struct timeval tv;
822 char buf;
823 int alive = 1;
824
825 if (value == -1) {
826 if (sslsock->s.timeout.tv_sec == -1) {
827 tv.tv_sec = FG(default_socket_timeout);
828 tv.tv_usec = 0;
829 } else {
830 tv = sslsock->connect_timeout;
831 }
832 } else {
833 tv.tv_sec = value;
834 tv.tv_usec = 0;
835 }
836
837 if (sslsock->s.socket == -1) {
838 alive = 0;
839 } else if (php_pollfd_for(sslsock->s.socket, PHP_POLLREADABLE|POLLPRI, &tv) > 0) {
840 if (sslsock->ssl_active) {
841 int n;
842
843 do {
844 n = SSL_peek(sslsock->ssl_handle, &buf, sizeof(buf));
845 if (n <= 0) {
846 int err = SSL_get_error(sslsock->ssl_handle, n);
847
848 if (err == SSL_ERROR_SYSCALL) {
849 alive = php_socket_errno() == EAGAIN;
850 break;
851 }
852
853 if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) {
854 /* re-negotiate */
855 continue;
856 }
857
858 /* any other problem is a fatal error */
859 alive = 0;
860 }
861 /* either peek succeeded or there was an error; we
862 * have set the alive flag appropriately */
863 break;
864 } while (1);
865 } else if (0 == recv(sslsock->s.socket, &buf, sizeof(buf), MSG_PEEK) && php_socket_errno() != EAGAIN) {
866 alive = 0;
867 }
868 }
869 return alive ? PHP_STREAM_OPTION_RETURN_OK : PHP_STREAM_OPTION_RETURN_ERR;
870 }
871
872 case PHP_STREAM_OPTION_CRYPTO_API:
873
874 switch(cparam->op) {
875
876 case STREAM_XPORT_CRYPTO_OP_SETUP:
877 cparam->outputs.returncode = php_openssl_setup_crypto(stream, sslsock, cparam TSRMLS_CC);
878 return PHP_STREAM_OPTION_RETURN_OK;
879 break;
880 case STREAM_XPORT_CRYPTO_OP_ENABLE:
881 cparam->outputs.returncode = php_openssl_enable_crypto(stream, sslsock, cparam TSRMLS_CC);
882 return PHP_STREAM_OPTION_RETURN_OK;
883 break;
884 default:
885 /* fall through */
886 break;
887 }
888
889 break;
890
891 case PHP_STREAM_OPTION_XPORT_API:
892 switch(xparam->op) {
893
894 case STREAM_XPORT_OP_CONNECT:
895 case STREAM_XPORT_OP_CONNECT_ASYNC:
896 /* TODO: Async connects need to check the enable_on_connect option when
897 * we notice that the connect has actually been established */
898 php_stream_socket_ops.set_option(stream, option, value, ptrparam TSRMLS_CC);
899
900 if ((sslsock->enable_on_connect) &&
901 ((xparam->outputs.returncode == 0) ||
902 (xparam->op == STREAM_XPORT_OP_CONNECT_ASYNC &&
903 xparam->outputs.returncode == 1 && xparam->outputs.error_code == EINPROGRESS)))
904 {
905 if (php_stream_xport_crypto_setup(stream, sslsock->method, NULL TSRMLS_CC) < 0 ||
906 php_stream_xport_crypto_enable(stream, 1 TSRMLS_CC) < 0) {
907 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to enable crypto");
908 xparam->outputs.returncode = -1;
909 }
910 }
911 return PHP_STREAM_OPTION_RETURN_OK;
912
913 case STREAM_XPORT_OP_ACCEPT:
914 /* we need to copy the additional fields that the underlying tcp transport
915 * doesn't know about */
916 xparam->outputs.returncode = php_openssl_tcp_sockop_accept(stream, sslsock, xparam STREAMS_CC TSRMLS_CC);
917
918
919 return PHP_STREAM_OPTION_RETURN_OK;
920
921 default:
922 /* fall through */
923 break;
924 }
925 }
926
927 return php_stream_socket_ops.set_option(stream, option, value, ptrparam TSRMLS_CC);
928 }
929
php_openssl_sockop_cast(php_stream * stream,int castas,void ** ret TSRMLS_DC)930 static int php_openssl_sockop_cast(php_stream *stream, int castas, void **ret TSRMLS_DC)
931 {
932 php_openssl_netstream_data_t *sslsock = (php_openssl_netstream_data_t*)stream->abstract;
933
934 switch(castas) {
935 case PHP_STREAM_AS_STDIO:
936 if (sslsock->ssl_active) {
937 return FAILURE;
938 }
939 if (ret) {
940 *ret = fdopen(sslsock->s.socket, stream->mode);
941 if (*ret) {
942 return SUCCESS;
943 }
944 return FAILURE;
945 }
946 return SUCCESS;
947
948 case PHP_STREAM_AS_FD_FOR_SELECT:
949 if (ret) {
950 /* OpenSSL has an internal buffer which select() cannot see. If we don't
951 * fetch it into the stream's buffer, no activity will be reported on the
952 * stream even though there is data waiting to be read - but we only fetch
953 * the lower of bytes OpenSSL has ready to give us or chunk_size since we
954 * weren't asked for any data at this stage. This is only likely to cause
955 * issues with non-blocking streams, but it's harmless to always do it. */
956 size_t pending;
957 if (stream->writepos == stream->readpos
958 && sslsock->ssl_active
959 && (pending = (size_t)SSL_pending(sslsock->ssl_handle)) > 0) {
960 php_stream_fill_read_buffer(stream, pending < stream->chunk_size
961 ? pending
962 : stream->chunk_size);
963 }
964
965 *(php_socket_t *)ret = sslsock->s.socket;
966 }
967 return SUCCESS;
968
969 case PHP_STREAM_AS_FD:
970 case PHP_STREAM_AS_SOCKETD:
971 if (sslsock->ssl_active) {
972 return FAILURE;
973 }
974 if (ret) {
975 *(php_socket_t *)ret = sslsock->s.socket;
976 }
977 return SUCCESS;
978 default:
979 return FAILURE;
980 }
981 }
982
983 php_stream_ops php_openssl_socket_ops = {
984 php_openssl_sockop_write, php_openssl_sockop_read,
985 php_openssl_sockop_close, php_openssl_sockop_flush,
986 "tcp_socket/ssl",
987 NULL, /* seek */
988 php_openssl_sockop_cast,
989 php_openssl_sockop_stat,
990 php_openssl_sockop_set_option,
991 };
992
get_sni(php_stream_context * ctx,char * resourcename,long resourcenamelen,int is_persistent TSRMLS_DC)993 static char * get_sni(php_stream_context *ctx, char *resourcename, long resourcenamelen, int is_persistent TSRMLS_DC) {
994
995 php_url *url;
996
997 if (ctx) {
998 zval **val = NULL;
999
1000 if (php_stream_context_get_option(ctx, "ssl", "SNI_enabled", &val) == SUCCESS && !zend_is_true(*val)) {
1001 return NULL;
1002 }
1003 if (php_stream_context_get_option(ctx, "ssl", "SNI_server_name", &val) == SUCCESS) {
1004 convert_to_string_ex(val);
1005 return pestrdup(Z_STRVAL_PP(val), is_persistent);
1006 }
1007 }
1008
1009 if (!resourcename) {
1010 return NULL;
1011 }
1012
1013 url = php_url_parse_ex(resourcename, resourcenamelen);
1014 if (!url) {
1015 return NULL;
1016 }
1017
1018 if (url->host) {
1019 const char * host = url->host;
1020 char * sni = NULL;
1021 size_t len = strlen(host);
1022
1023 /* skip trailing dots */
1024 while (len && host[len-1] == '.') {
1025 --len;
1026 }
1027
1028 if (len) {
1029 sni = pestrndup(host, len, is_persistent);
1030 }
1031
1032 php_url_free(url);
1033 return sni;
1034 }
1035
1036 php_url_free(url);
1037 return NULL;
1038 }
1039
php_openssl_ssl_socket_factory(const char * proto,long protolen,char * resourcename,long resourcenamelen,const char * persistent_id,int options,int flags,struct timeval * timeout,php_stream_context * context STREAMS_DC TSRMLS_DC)1040 php_stream *php_openssl_ssl_socket_factory(const char *proto, long protolen,
1041 char *resourcename, long resourcenamelen,
1042 const char *persistent_id, int options, int flags,
1043 struct timeval *timeout,
1044 php_stream_context *context STREAMS_DC TSRMLS_DC)
1045 {
1046 php_stream *stream = NULL;
1047 php_openssl_netstream_data_t *sslsock = NULL;
1048
1049 sslsock = pemalloc(sizeof(php_openssl_netstream_data_t), persistent_id ? 1 : 0);
1050 memset(sslsock, 0, sizeof(*sslsock));
1051
1052 sslsock->s.is_blocked = 1;
1053 /* this timeout is used by standard stream funcs, therefor it should use the default value */
1054 sslsock->s.timeout.tv_sec = FG(default_socket_timeout);
1055 sslsock->s.timeout.tv_usec = 0;
1056
1057 /* use separate timeout for our private funcs */
1058 sslsock->connect_timeout.tv_sec = timeout->tv_sec;
1059 sslsock->connect_timeout.tv_usec = timeout->tv_usec;
1060
1061 /* we don't know the socket until we have determined if we are binding or
1062 * connecting */
1063 sslsock->s.socket = -1;
1064
1065 /* Initialize context as NULL */
1066 sslsock->ctx = NULL;
1067
1068 stream = php_stream_alloc_rel(&php_openssl_socket_ops, sslsock, persistent_id, "r+");
1069
1070 if (stream == NULL) {
1071 pefree(sslsock, persistent_id ? 1 : 0);
1072 return NULL;
1073 }
1074
1075 sslsock->sni = get_sni(context, resourcename, resourcenamelen, !!persistent_id TSRMLS_CC);
1076
1077 if (strncmp(proto, "ssl", protolen) == 0) {
1078 sslsock->enable_on_connect = 1;
1079 sslsock->method = STREAM_CRYPTO_METHOD_SSLv23_CLIENT;
1080 } else if (strncmp(proto, "sslv2", protolen) == 0) {
1081 #ifdef OPENSSL_NO_SSL2
1082 php_error_docref(NULL TSRMLS_CC, E_WARNING, "SSLv2 support is not compiled into the OpenSSL library PHP is linked against");
1083 return NULL;
1084 #else
1085 sslsock->enable_on_connect = 1;
1086 sslsock->method = STREAM_CRYPTO_METHOD_SSLv2_CLIENT;
1087 #endif
1088 } else if (strncmp(proto, "sslv3", protolen) == 0) {
1089 sslsock->enable_on_connect = 1;
1090 sslsock->method = STREAM_CRYPTO_METHOD_SSLv3_CLIENT;
1091 } else if (strncmp(proto, "tls", protolen) == 0) {
1092 sslsock->enable_on_connect = 1;
1093 sslsock->method = STREAM_CRYPTO_METHOD_TLS_CLIENT;
1094 }
1095
1096 return stream;
1097 }
1098
1099
1100
1101 /*
1102 * Local variables:
1103 * tab-width: 4
1104 * c-basic-offset: 4
1105 * End:
1106 * vim600: noet sw=4 ts=4 fdm=marker
1107 * vim<600: noet sw=4 ts=4
1108 */
1109