xref: /PHP-5.5/ext/openssl/xp_ssl.c (revision 601d60a9)
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