xref: /PHP-7.2/ext/openssl/xp_ssl.c (revision 4f984a2f)
1 /*
2   +----------------------------------------------------------------------+
3   | PHP Version 7                                                        |
4   +----------------------------------------------------------------------+
5   | Copyright (c) 1997-2018 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   | Authors: Wez Furlong <wez@thebrainroom.com>                          |
16   |          Daniel Lowrey <rdlowrey@php.net>                            |
17   |          Chris Wright <daverandom@php.net>                           |
18   +----------------------------------------------------------------------+
19 */
20 
21 /* $Id$ */
22 
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26 
27 #include "php.h"
28 #include "ext/standard/file.h"
29 #include "ext/standard/url.h"
30 #include "streams/php_streams_int.h"
31 #include "zend_smart_str.h"
32 #include "php_openssl.h"
33 #include "php_network.h"
34 #include <openssl/ssl.h>
35 #include <openssl/rsa.h>
36 #include <openssl/x509.h>
37 #include <openssl/x509v3.h>
38 #include <openssl/err.h>
39 
40 #if OPENSSL_VERSION_NUMBER >= 0x10002000L
41 #include <openssl/bn.h>
42 #include <openssl/dh.h>
43 #endif
44 
45 #ifdef PHP_WIN32
46 #include "win32/winutil.h"
47 #include "win32/time.h"
48 #include <Wincrypt.h>
49 /* These are from Wincrypt.h, they conflict with OpenSSL */
50 #undef X509_NAME
51 #undef X509_CERT_PAIR
52 #undef X509_EXTENSIONS
53 #endif
54 
55 #ifndef OPENSSL_NO_SSL3
56 #define HAVE_SSL3 1
57 #endif
58 
59 #define HAVE_TLS11 1
60 #define HAVE_TLS12 1
61 
62 #ifndef OPENSSL_NO_ECDH
63 #define HAVE_ECDH 1
64 #endif
65 
66 #ifndef OPENSSL_NO_TLSEXT
67 #define HAVE_TLS_SNI 1
68 #if OPENSSL_VERSION_NUMBER >= 0x10002000L
69 #define HAVE_TLS_ALPN 1
70 #endif
71 #endif
72 
73 #if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
74 #define HAVE_SEC_LEVEL 1
75 #endif
76 
77 /* Flags for determining allowed stream crypto methods */
78 #define STREAM_CRYPTO_IS_CLIENT            (1<<0)
79 #define STREAM_CRYPTO_METHOD_SSLv2         (1<<1)
80 #define STREAM_CRYPTO_METHOD_SSLv3         (1<<2)
81 #define STREAM_CRYPTO_METHOD_TLSv1_0       (1<<3)
82 #define STREAM_CRYPTO_METHOD_TLSv1_1       (1<<4)
83 #define STREAM_CRYPTO_METHOD_TLSv1_2       (1<<5)
84 
85 /* Simplify ssl context option retrieval */
86 #define GET_VER_OPT(name) \
87 	(PHP_STREAM_CONTEXT(stream) && (val = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "ssl", name)) != NULL)
88 #define GET_VER_OPT_STRING(name, str) \
89 	if (GET_VER_OPT(name)) { convert_to_string_ex(val); str = Z_STRVAL_P(val); }
90 #define GET_VER_OPT_LONG(name, num) \
91 	if (GET_VER_OPT(name)) { convert_to_long_ex(val); num = Z_LVAL_P(val); }
92 
93 /* Used for peer verification in windows */
94 #define PHP_X509_NAME_ENTRY_TO_UTF8(ne, i, out) \
95 	ASN1_STRING_to_UTF8(&out, X509_NAME_ENTRY_get_data(X509_NAME_get_entry(ne, i)))
96 
97 #if PHP_OPENSSL_API_VERSION < 0x10100
98 static RSA *php_openssl_tmp_rsa_cb(SSL *s, int is_export, int keylength);
99 #endif
100 
101 extern php_stream* php_openssl_get_stream_from_ssl_handle(const SSL *ssl);
102 extern zend_string* php_openssl_x509_fingerprint(X509 *peer, const char *method, zend_bool raw);
103 extern int php_openssl_get_ssl_stream_data_index();
104 extern int php_openssl_get_x509_list_id(void);
105 static struct timeval php_openssl_subtract_timeval(struct timeval a, struct timeval b);
106 static int php_openssl_compare_timeval(struct timeval a, struct timeval b);
107 static size_t php_openssl_sockop_io(int read, php_stream *stream, char *buf, size_t count);
108 
109 php_stream_ops php_openssl_socket_ops;
110 
111 /* Certificate contexts used for server-side SNI selection */
112 typedef struct _php_openssl_sni_cert_t {
113 	char *name;
114 	SSL_CTX *ctx;
115 } php_openssl_sni_cert_t;
116 
117 /* Provides leaky bucket handhsake renegotiation rate-limiting  */
118 typedef struct _php_openssl_handshake_bucket_t {
119 	zend_long prev_handshake;
120 	zend_long limit;
121 	zend_long window;
122 	float tokens;
123 	unsigned should_close;
124 } php_openssl_handshake_bucket_t;
125 
126 #ifdef HAVE_TLS_ALPN
127 /* Holds the available server ALPN protocols for negotiation */
128 typedef struct _php_openssl_alpn_ctx_t {
129 	unsigned char *data;
130 	unsigned short len;
131 } php_openssl_alpn_ctx;
132 #endif
133 
134 /* This implementation is very closely tied to the that of the native
135  * sockets implemented in the core.
136  * Don't try this technique in other extensions!
137  * */
138 typedef struct _php_openssl_netstream_data_t {
139 	php_netstream_data_t s;
140 	SSL *ssl_handle;
141 	SSL_CTX *ctx;
142 	struct timeval connect_timeout;
143 	int enable_on_connect;
144 	int is_client;
145 	int ssl_active;
146 	php_stream_xport_crypt_method_t method;
147 	php_openssl_handshake_bucket_t *reneg;
148 	php_openssl_sni_cert_t *sni_certs;
149 	unsigned sni_cert_count;
150 #ifdef HAVE_TLS_ALPN
151 	php_openssl_alpn_ctx alpn_ctx;
152 #endif
153 	char *url_name;
154 	unsigned state_set:1;
155 	unsigned _spare:31;
156 } php_openssl_netstream_data_t;
157 
158 /* it doesn't matter that we do some hash traversal here, since it is done only
159  * in an error condition arising from a network connection problem */
php_openssl_is_http_stream_talking_to_iis(php_stream * stream)160 static int php_openssl_is_http_stream_talking_to_iis(php_stream *stream) /* {{{ */
161 {
162 	if (Z_TYPE(stream->wrapperdata) == IS_ARRAY &&
163 		stream->wrapper &&
164 		strcasecmp(stream->wrapper->wops->label, "HTTP") == 0
165 	) {
166 		/* the wrapperdata is an array zval containing the headers */
167 		zval *tmp;
168 
169 #define SERVER_MICROSOFT_IIS	"Server: Microsoft-IIS"
170 #define SERVER_GOOGLE "Server: GFE/"
171 
172 		ZEND_HASH_FOREACH_VAL(Z_ARRVAL(stream->wrapperdata), tmp) {
173 			if (strncasecmp(Z_STRVAL_P(tmp), SERVER_MICROSOFT_IIS, sizeof(SERVER_MICROSOFT_IIS)-1) == 0) {
174 				return 1;
175 			} else if (strncasecmp(Z_STRVAL_P(tmp), SERVER_GOOGLE, sizeof(SERVER_GOOGLE)-1) == 0) {
176 				return 1;
177 			}
178 		} ZEND_HASH_FOREACH_END();
179 	}
180 	return 0;
181 }
182 /* }}} */
183 
php_openssl_handle_ssl_error(php_stream * stream,int nr_bytes,zend_bool is_init)184 static int php_openssl_handle_ssl_error(php_stream *stream, int nr_bytes, zend_bool is_init) /* {{{ */
185 {
186 	php_openssl_netstream_data_t *sslsock = (php_openssl_netstream_data_t*)stream->abstract;
187 	int err = SSL_get_error(sslsock->ssl_handle, nr_bytes);
188 	char esbuf[512];
189 	smart_str ebuf = {0};
190 	unsigned long ecode;
191 	int retry = 1;
192 
193 	switch(err) {
194 		case SSL_ERROR_ZERO_RETURN:
195 			/* SSL terminated (but socket may still be active) */
196 			retry = 0;
197 			break;
198 		case SSL_ERROR_WANT_READ:
199 		case SSL_ERROR_WANT_WRITE:
200 			/* re-negotiation, or perhaps the SSL layer needs more
201 			 * packets: retry in next iteration */
202 			errno = EAGAIN;
203 			retry = is_init ? 1 : sslsock->s.is_blocked;
204 			break;
205 		case SSL_ERROR_SYSCALL:
206 			if (ERR_peek_error() == 0) {
207 				if (nr_bytes == 0) {
208 					if (!php_openssl_is_http_stream_talking_to_iis(stream) && ERR_get_error() != 0) {
209 						php_error_docref(NULL, E_WARNING, "SSL: fatal protocol error");
210 					}
211 					SSL_set_shutdown(sslsock->ssl_handle, SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN);
212 					stream->eof = 1;
213 					retry = 0;
214 				} else {
215 					char *estr = php_socket_strerror(php_socket_errno(), NULL, 0);
216 
217 					php_error_docref(NULL, E_WARNING,
218 							"SSL: %s", estr);
219 
220 					efree(estr);
221 					retry = 0;
222 				}
223 				break;
224 			}
225 
226 
227 			/* fall through */
228 		default:
229 			/* some other error */
230 			ecode = ERR_get_error();
231 
232 			switch (ERR_GET_REASON(ecode)) {
233 				case SSL_R_NO_SHARED_CIPHER:
234 					php_error_docref(NULL, E_WARNING,
235 							"SSL_R_NO_SHARED_CIPHER: no suitable shared cipher could be used.  "
236 							"This could be because the server is missing an SSL certificate "
237 							"(local_cert context option)");
238 					retry = 0;
239 					break;
240 
241 				default:
242 					do {
243 						/* NULL is automatically added */
244 						ERR_error_string_n(ecode, esbuf, sizeof(esbuf));
245 						if (ebuf.s) {
246 							smart_str_appendc(&ebuf, '\n');
247 						}
248 						smart_str_appends(&ebuf, esbuf);
249 					} while ((ecode = ERR_get_error()) != 0);
250 
251 					smart_str_0(&ebuf);
252 
253 					php_error_docref(NULL, E_WARNING,
254 							"SSL operation failed with code %d. %s%s",
255 							err,
256 							ebuf.s ? "OpenSSL Error messages:\n" : "",
257 							ebuf.s ? ZSTR_VAL(ebuf.s) : "");
258 					if (ebuf.s) {
259 						smart_str_free(&ebuf);
260 					}
261 			}
262 
263 			retry = 0;
264 			errno = 0;
265 	}
266 	return retry;
267 }
268 /* }}} */
269 
verify_callback(int preverify_ok,X509_STORE_CTX * ctx)270 static int verify_callback(int preverify_ok, X509_STORE_CTX *ctx) /* {{{ */
271 {
272 	php_stream *stream;
273 	SSL *ssl;
274 	int err, depth, ret;
275 	zval *val;
276 	zend_ulong allowed_depth = OPENSSL_DEFAULT_STREAM_VERIFY_DEPTH;
277 
278 
279 	ret = preverify_ok;
280 
281 	/* determine the status for the current cert */
282 	err = X509_STORE_CTX_get_error(ctx);
283 	depth = X509_STORE_CTX_get_error_depth(ctx);
284 
285 	/* conjure the stream & context to use */
286 	ssl = X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
287 	stream = (php_stream*)SSL_get_ex_data(ssl, php_openssl_get_ssl_stream_data_index());
288 
289 	/* if allow_self_signed is set, make sure that verification succeeds */
290 	if (err == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT &&
291 		GET_VER_OPT("allow_self_signed") &&
292 		zend_is_true(val)
293 	) {
294 		ret = 1;
295 	}
296 
297 	/* check the depth */
298 	GET_VER_OPT_LONG("verify_depth", allowed_depth);
299 	if ((zend_ulong)depth > allowed_depth) {
300 		ret = 0;
301 		X509_STORE_CTX_set_error(ctx, X509_V_ERR_CERT_CHAIN_TOO_LONG);
302 	}
303 
304 	return ret;
305 }
306 /* }}} */
307 
php_openssl_x509_fingerprint_cmp(X509 * peer,const char * method,const char * expected)308 static int php_openssl_x509_fingerprint_cmp(X509 *peer, const char *method, const char *expected)
309 {
310 	zend_string *fingerprint;
311 	int result = -1;
312 
313 	fingerprint = php_openssl_x509_fingerprint(peer, method, 0);
314 	if (fingerprint) {
315 		result = strcasecmp(expected, ZSTR_VAL(fingerprint));
316 		zend_string_release(fingerprint);
317 	}
318 
319 	return result;
320 }
321 
php_openssl_x509_fingerprint_match(X509 * peer,zval * val)322 static zend_bool php_openssl_x509_fingerprint_match(X509 *peer, zval *val)
323 {
324 	if (Z_TYPE_P(val) == IS_STRING) {
325 		const char *method = NULL;
326 
327 		switch (Z_STRLEN_P(val)) {
328 			case 32:
329 				method = "md5";
330 				break;
331 
332 			case 40:
333 				method = "sha1";
334 				break;
335 		}
336 
337 		return method && php_openssl_x509_fingerprint_cmp(peer, method, Z_STRVAL_P(val)) == 0;
338 	} else if (Z_TYPE_P(val) == IS_ARRAY) {
339 		zval *current;
340 		zend_string *key;
341 
342 		if (!zend_hash_num_elements(Z_ARRVAL_P(val))) {
343 			php_error_docref(NULL, E_WARNING, "Invalid peer_fingerprint array; [algo => fingerprint] form required");
344 			return 0;
345 		}
346 
347 		ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(val), key, current) {
348 			if (key == NULL || Z_TYPE_P(current) != IS_STRING) {
349 				php_error_docref(NULL, E_WARNING, "Invalid peer_fingerprint array; [algo => fingerprint] form required");
350 				return 0;
351 			}
352 			if (php_openssl_x509_fingerprint_cmp(peer, ZSTR_VAL(key), Z_STRVAL_P(current)) != 0) {
353 				return 0;
354 			}
355 		} ZEND_HASH_FOREACH_END();
356 
357 		return 1;
358 	} else {
359 		php_error_docref(NULL, E_WARNING,
360 			"Invalid peer_fingerprint value; fingerprint string or array of the form [algo => fingerprint] required");
361 	}
362 
363 	return 0;
364 }
365 
php_openssl_matches_wildcard_name(const char * subjectname,const char * certname)366 static zend_bool php_openssl_matches_wildcard_name(const char *subjectname, const char *certname) /* {{{ */
367 {
368 	char *wildcard = NULL;
369 	ptrdiff_t prefix_len;
370 	size_t suffix_len, subject_len;
371 
372 	if (strcasecmp(subjectname, certname) == 0) {
373 		return 1;
374 	}
375 
376 	/* wildcard, if present, must only be present in the left-most component */
377 	if (!(wildcard = strchr(certname, '*')) || memchr(certname, '.', wildcard - certname)) {
378 		return 0;
379 	}
380 
381 	/* 1) prefix, if not empty, must match subject */
382 	prefix_len = wildcard - certname;
383 	if (prefix_len && strncasecmp(subjectname, certname, prefix_len) != 0) {
384 		return 0;
385 	}
386 
387 	suffix_len = strlen(wildcard + 1);
388 	subject_len = strlen(subjectname);
389 	if (suffix_len <= subject_len) {
390 		/* 2) suffix must match
391 		 * 3) no . between prefix and suffix
392 		 **/
393 		return strcasecmp(wildcard + 1, subjectname + subject_len - suffix_len) == 0 &&
394 			memchr(subjectname + prefix_len, '.', subject_len - suffix_len - prefix_len) == NULL;
395 	}
396 
397 	return 0;
398 }
399 /* }}} */
400 
php_openssl_matches_san_list(X509 * peer,const char * subject_name)401 static zend_bool php_openssl_matches_san_list(X509 *peer, const char *subject_name) /* {{{ */
402 {
403 	int i, len;
404 	unsigned char *cert_name = NULL;
405 	char ipbuffer[64];
406 
407 	GENERAL_NAMES *alt_names = X509_get_ext_d2i(peer, NID_subject_alt_name, 0, 0);
408 	int alt_name_count = sk_GENERAL_NAME_num(alt_names);
409 
410 	for (i = 0; i < alt_name_count; i++) {
411 		GENERAL_NAME *san = sk_GENERAL_NAME_value(alt_names, i);
412 
413 		if (san->type == GEN_DNS) {
414 			ASN1_STRING_to_UTF8(&cert_name, san->d.dNSName);
415 			if ((size_t)ASN1_STRING_length(san->d.dNSName) != strlen((const char*)cert_name)) {
416 				OPENSSL_free(cert_name);
417 				/* prevent null-byte poisoning*/
418 				continue;
419 			}
420 
421 			/* accommodate valid FQDN entries ending in "." */
422 			len = strlen((const char*)cert_name);
423 			if (len && strcmp((const char *)&cert_name[len-1], ".") == 0) {
424 				cert_name[len-1] = '\0';
425 			}
426 
427 			if (php_openssl_matches_wildcard_name(subject_name, (const char *)cert_name)) {
428 				OPENSSL_free(cert_name);
429 				sk_GENERAL_NAME_pop_free(alt_names, GENERAL_NAME_free);
430 
431 				return 1;
432 			}
433 			OPENSSL_free(cert_name);
434 		} else if (san->type == GEN_IPADD) {
435 			if (san->d.iPAddress->length == 4) {
436 				sprintf(ipbuffer, "%d.%d.%d.%d",
437 					san->d.iPAddress->data[0],
438 					san->d.iPAddress->data[1],
439 					san->d.iPAddress->data[2],
440 					san->d.iPAddress->data[3]
441 				);
442 				if (strcasecmp(subject_name, (const char*)ipbuffer) == 0) {
443 					sk_GENERAL_NAME_pop_free(alt_names, GENERAL_NAME_free);
444 
445 					return 1;
446 				}
447 			}
448 			/* No, we aren't bothering to check IPv6 addresses. Why?
449 			 * Because IP SAN names are officially deprecated and are
450 			 * not allowed by CAs starting in 2015. Deal with it.
451 			 */
452 		}
453 	}
454 
455 	sk_GENERAL_NAME_pop_free(alt_names, GENERAL_NAME_free);
456 
457 	return 0;
458 }
459 /* }}} */
460 
php_openssl_matches_common_name(X509 * peer,const char * subject_name)461 static zend_bool php_openssl_matches_common_name(X509 *peer, const char *subject_name) /* {{{ */
462 {
463 	char buf[1024];
464 	X509_NAME *cert_name;
465 	zend_bool is_match = 0;
466 	int cert_name_len;
467 
468 	cert_name = X509_get_subject_name(peer);
469 	cert_name_len = X509_NAME_get_text_by_NID(cert_name, NID_commonName, buf, sizeof(buf));
470 
471 	if (cert_name_len == -1) {
472 		php_error_docref(NULL, E_WARNING, "Unable to locate peer certificate CN");
473 	} else if ((size_t)cert_name_len != strlen(buf)) {
474 		php_error_docref(NULL, E_WARNING, "Peer certificate CN=`%.*s' is malformed", cert_name_len, buf);
475 	} else if (php_openssl_matches_wildcard_name(subject_name, buf)) {
476 		is_match = 1;
477 	} else {
478 		php_error_docref(NULL, E_WARNING,
479 			"Peer certificate CN=`%.*s' did not match expected CN=`%s'",
480 			cert_name_len, buf, subject_name);
481 	}
482 
483 	return is_match;
484 }
485 /* }}} */
486 
php_openssl_apply_peer_verification_policy(SSL * ssl,X509 * peer,php_stream * stream)487 static int php_openssl_apply_peer_verification_policy(SSL *ssl, X509 *peer, php_stream *stream) /* {{{ */
488 {
489 	zval *val = NULL;
490 	zval *peer_fingerprint;
491 	char *peer_name = NULL;
492 	int err,
493 		must_verify_peer,
494 		must_verify_peer_name,
495 		must_verify_fingerprint;
496 
497 	php_openssl_netstream_data_t *sslsock = (php_openssl_netstream_data_t*)stream->abstract;
498 
499 	must_verify_peer = GET_VER_OPT("verify_peer")
500 		? zend_is_true(val)
501 		: sslsock->is_client;
502 
503 	must_verify_peer_name = GET_VER_OPT("verify_peer_name")
504 		? zend_is_true(val)
505 		: sslsock->is_client;
506 
507 	must_verify_fingerprint = GET_VER_OPT("peer_fingerprint");
508 	peer_fingerprint = val;
509 
510 	if ((must_verify_peer || must_verify_peer_name || must_verify_fingerprint) && peer == NULL) {
511 		php_error_docref(NULL, E_WARNING, "Could not get peer certificate");
512 		return FAILURE;
513 	}
514 
515 	/* Verify the peer against using CA file/path settings */
516 	if (must_verify_peer) {
517 		err = SSL_get_verify_result(ssl);
518 		switch (err) {
519 			case X509_V_OK:
520 				/* fine */
521 				break;
522 			case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
523 				if (GET_VER_OPT("allow_self_signed") && zend_is_true(val)) {
524 					/* allowed */
525 					break;
526 				}
527 				/* not allowed, so fall through */
528 			default:
529 				php_error_docref(NULL, E_WARNING,
530 						"Could not verify peer: code:%d %s",
531 						err,
532 						X509_verify_cert_error_string(err)
533 				);
534 				return FAILURE;
535 		}
536 	}
537 
538 	/* If a peer_fingerprint match is required this trumps peer and peer_name verification */
539 	if (must_verify_fingerprint) {
540 		if (Z_TYPE_P(peer_fingerprint) == IS_STRING || Z_TYPE_P(peer_fingerprint) == IS_ARRAY) {
541 			if (!php_openssl_x509_fingerprint_match(peer, peer_fingerprint)) {
542 				php_error_docref(NULL, E_WARNING,
543 					"peer_fingerprint match failure"
544 				);
545 				return FAILURE;
546 			}
547 		} else {
548 			php_error_docref(NULL, E_WARNING,
549 				"Expected peer fingerprint must be a string or an array"
550 			);
551 			return FAILURE;
552 		}
553 	}
554 
555 	/* verify the host name presented in the peer certificate */
556 	if (must_verify_peer_name) {
557 		GET_VER_OPT_STRING("peer_name", peer_name);
558 
559 		/* If no peer name was specified we use the autodetected url name in client environments */
560 		if (peer_name == NULL && sslsock->is_client) {
561 			peer_name = sslsock->url_name;
562 		}
563 
564 		if (peer_name) {
565 			if (php_openssl_matches_san_list(peer, peer_name)) {
566 				return SUCCESS;
567 			} else if (php_openssl_matches_common_name(peer, peer_name)) {
568 				return SUCCESS;
569 			} else {
570 				return FAILURE;
571 			}
572 		} else {
573 			return FAILURE;
574 		}
575 	}
576 
577 	return SUCCESS;
578 }
579 /* }}} */
580 
php_openssl_passwd_callback(char * buf,int num,int verify,void * data)581 static int php_openssl_passwd_callback(char *buf, int num, int verify, void *data) /* {{{ */
582 {
583 	php_stream *stream = (php_stream *)data;
584 	zval *val = NULL;
585 	char *passphrase = NULL;
586 	/* TODO: could expand this to make a callback into PHP user-space */
587 
588 	GET_VER_OPT_STRING("passphrase", passphrase);
589 
590 	if (passphrase) {
591 		if (Z_STRLEN_P(val) < (size_t)num - 1) {
592 			memcpy(buf, Z_STRVAL_P(val), Z_STRLEN_P(val)+1);
593 			return (int)Z_STRLEN_P(val);
594 		}
595 	}
596 	return 0;
597 }
598 /* }}} */
599 
600 #ifdef PHP_WIN32
601 #define RETURN_CERT_VERIFY_FAILURE(code) X509_STORE_CTX_set_error(x509_store_ctx, code); return 0;
php_openssl_win_cert_verify_callback(X509_STORE_CTX * x509_store_ctx,void * arg)602 static int php_openssl_win_cert_verify_callback(X509_STORE_CTX *x509_store_ctx, void *arg) /* {{{ */
603 {
604 	PCCERT_CONTEXT cert_ctx = NULL;
605 	PCCERT_CHAIN_CONTEXT cert_chain_ctx = NULL;
606 #if OPENSSL_VERSION_NUMBER < 0x10100000L
607 	X509 *cert = x509_store_ctx->cert;
608 #else
609 	X509 *cert = X509_STORE_CTX_get0_cert(x509_store_ctx);
610 #endif
611 
612 	php_stream *stream;
613 	php_openssl_netstream_data_t *sslsock;
614 	zval *val;
615 	zend_bool is_self_signed = 0;
616 
617 
618 	stream = (php_stream*)arg;
619 	sslsock = (php_openssl_netstream_data_t*)stream->abstract;
620 
621 	{ /* First convert the x509 struct back to a DER encoded buffer and let Windows decode it into a form it can work with */
622 		unsigned char *der_buf = NULL;
623 		int der_len;
624 
625 		der_len = i2d_X509(cert, &der_buf);
626 		if (der_len < 0) {
627 			unsigned long err_code, e;
628 			char err_buf[512];
629 
630 			while ((e = ERR_get_error()) != 0) {
631 				err_code = e;
632 			}
633 
634 			php_error_docref(NULL, E_WARNING, "Error encoding X509 certificate: %d: %s", err_code, ERR_error_string(err_code, err_buf));
635 			RETURN_CERT_VERIFY_FAILURE(SSL_R_CERTIFICATE_VERIFY_FAILED);
636 		}
637 
638 		cert_ctx = CertCreateCertificateContext(X509_ASN_ENCODING, der_buf, der_len);
639 		OPENSSL_free(der_buf);
640 
641 		if (cert_ctx == NULL) {
642 			php_error_docref(NULL, E_WARNING, "Error creating certificate context: %s", php_win_err());
643 			RETURN_CERT_VERIFY_FAILURE(SSL_R_CERTIFICATE_VERIFY_FAILED);
644 		}
645 	}
646 
647 	{ /* Next fetch the relevant cert chain from the store */
648 		CERT_ENHKEY_USAGE enhkey_usage = {0};
649 		CERT_USAGE_MATCH cert_usage = {0};
650 		CERT_CHAIN_PARA chain_params = {sizeof(CERT_CHAIN_PARA)};
651 		LPSTR usages[] = {szOID_PKIX_KP_SERVER_AUTH, szOID_SERVER_GATED_CRYPTO, szOID_SGC_NETSCAPE};
652 		DWORD chain_flags = 0;
653 		unsigned long allowed_depth = OPENSSL_DEFAULT_STREAM_VERIFY_DEPTH;
654 		unsigned int i;
655 
656 		enhkey_usage.cUsageIdentifier = 3;
657 		enhkey_usage.rgpszUsageIdentifier = usages;
658 		cert_usage.dwType = USAGE_MATCH_TYPE_OR;
659 		cert_usage.Usage = enhkey_usage;
660 		chain_params.RequestedUsage = cert_usage;
661 		chain_flags = CERT_CHAIN_CACHE_END_CERT | CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT;
662 
663 		if (!CertGetCertificateChain(NULL, cert_ctx, NULL, NULL, &chain_params, chain_flags, NULL, &cert_chain_ctx)) {
664 			php_error_docref(NULL, E_WARNING, "Error getting certificate chain: %s", php_win_err());
665 			CertFreeCertificateContext(cert_ctx);
666 			RETURN_CERT_VERIFY_FAILURE(SSL_R_CERTIFICATE_VERIFY_FAILED);
667 		}
668 
669 		/* check if the cert is self-signed */
670 		if (cert_chain_ctx->cChain > 0 && cert_chain_ctx->rgpChain[0]->cElement > 0
671 			&& (cert_chain_ctx->rgpChain[0]->rgpElement[0]->TrustStatus.dwInfoStatus & CERT_TRUST_IS_SELF_SIGNED) != 0) {
672 			is_self_signed = 1;
673 		}
674 
675 		/* check the depth */
676 		GET_VER_OPT_LONG("verify_depth", allowed_depth);
677 
678 		for (i = 0; i < cert_chain_ctx->cChain; i++) {
679 			if (cert_chain_ctx->rgpChain[i]->cElement > allowed_depth) {
680 				CertFreeCertificateChain(cert_chain_ctx);
681 				CertFreeCertificateContext(cert_ctx);
682 				RETURN_CERT_VERIFY_FAILURE(X509_V_ERR_CERT_CHAIN_TOO_LONG);
683 			}
684 		}
685 	}
686 
687 	{ /* Then verify it against a policy */
688 		SSL_EXTRA_CERT_CHAIN_POLICY_PARA ssl_policy_params = {sizeof(SSL_EXTRA_CERT_CHAIN_POLICY_PARA)};
689 		CERT_CHAIN_POLICY_PARA chain_policy_params = {sizeof(CERT_CHAIN_POLICY_PARA)};
690 		CERT_CHAIN_POLICY_STATUS chain_policy_status = {sizeof(CERT_CHAIN_POLICY_STATUS)};
691 		LPWSTR server_name = NULL;
692 		BOOL verify_result;
693 
694 		{ /* This looks ridiculous and it is - but we validate the name ourselves using the peer_name
695 		     ctx option, so just use the CN from the cert here */
696 
697 			X509_NAME *cert_name;
698 			unsigned char *cert_name_utf8;
699 			int index, cert_name_utf8_len;
700 			DWORD num_wchars;
701 
702 			cert_name = X509_get_subject_name(cert);
703 			index = X509_NAME_get_index_by_NID(cert_name, NID_commonName, -1);
704 			if (index < 0) {
705 				php_error_docref(NULL, E_WARNING, "Unable to locate certificate CN");
706 				CertFreeCertificateChain(cert_chain_ctx);
707 				CertFreeCertificateContext(cert_ctx);
708 				RETURN_CERT_VERIFY_FAILURE(SSL_R_CERTIFICATE_VERIFY_FAILED);
709 			}
710 
711 			cert_name_utf8_len = PHP_X509_NAME_ENTRY_TO_UTF8(cert_name, index, cert_name_utf8);
712 
713 			num_wchars = MultiByteToWideChar(CP_UTF8, 0, (char*)cert_name_utf8, -1, NULL, 0);
714 			if (num_wchars == 0) {
715 				php_error_docref(NULL, E_WARNING, "Unable to convert %s to wide character string", cert_name_utf8);
716 				OPENSSL_free(cert_name_utf8);
717 				CertFreeCertificateChain(cert_chain_ctx);
718 				CertFreeCertificateContext(cert_ctx);
719 				RETURN_CERT_VERIFY_FAILURE(SSL_R_CERTIFICATE_VERIFY_FAILED);
720 			}
721 
722 			server_name = emalloc((num_wchars * sizeof(WCHAR)) + sizeof(WCHAR));
723 
724 			num_wchars = MultiByteToWideChar(CP_UTF8, 0, (char*)cert_name_utf8, -1, server_name, num_wchars);
725 			if (num_wchars == 0) {
726 				php_error_docref(NULL, E_WARNING, "Unable to convert %s to wide character string", cert_name_utf8);
727 				efree(server_name);
728 				OPENSSL_free(cert_name_utf8);
729 				CertFreeCertificateChain(cert_chain_ctx);
730 				CertFreeCertificateContext(cert_ctx);
731 				RETURN_CERT_VERIFY_FAILURE(SSL_R_CERTIFICATE_VERIFY_FAILED);
732 			}
733 
734 			OPENSSL_free(cert_name_utf8);
735 		}
736 
737 		ssl_policy_params.dwAuthType = (sslsock->is_client) ? AUTHTYPE_SERVER : AUTHTYPE_CLIENT;
738 		ssl_policy_params.pwszServerName = server_name;
739 		chain_policy_params.pvExtraPolicyPara = &ssl_policy_params;
740 
741 		verify_result = CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_SSL, cert_chain_ctx, &chain_policy_params, &chain_policy_status);
742 
743 		efree(server_name);
744 		CertFreeCertificateChain(cert_chain_ctx);
745 		CertFreeCertificateContext(cert_ctx);
746 
747 		if (!verify_result) {
748 			php_error_docref(NULL, E_WARNING, "Error verifying certificate chain policy: %s", php_win_err());
749 			RETURN_CERT_VERIFY_FAILURE(SSL_R_CERTIFICATE_VERIFY_FAILED);
750 		}
751 
752 		if (chain_policy_status.dwError != 0) {
753 			/* The chain does not match the policy */
754 			if (is_self_signed && chain_policy_status.dwError == CERT_E_UNTRUSTEDROOT
755 				&& GET_VER_OPT("allow_self_signed") && zend_is_true(val)) {
756 				/* allow self-signed certs */
757 				X509_STORE_CTX_set_error(x509_store_ctx, X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT);
758 			} else {
759 				RETURN_CERT_VERIFY_FAILURE(SSL_R_CERTIFICATE_VERIFY_FAILED);
760 			}
761 		}
762 	}
763 
764 	return 1;
765 }
766 /* }}} */
767 #endif
768 
php_openssl_load_stream_cafile(X509_STORE * cert_store,const char * cafile)769 static long php_openssl_load_stream_cafile(X509_STORE *cert_store, const char *cafile) /* {{{ */
770 {
771 	php_stream *stream;
772 	X509 *cert;
773 	BIO *buffer;
774 	int buffer_active = 0;
775 	char *line = NULL;
776 	size_t line_len;
777 	long certs_added = 0;
778 
779 	stream = php_stream_open_wrapper(cafile, "rb", 0, NULL);
780 
781 	if (stream == NULL) {
782 		php_error(E_WARNING, "failed loading cafile stream: `%s'", cafile);
783 		return 0;
784 	} else if (stream->wrapper->is_url) {
785 		php_stream_close(stream);
786 		php_error(E_WARNING, "remote cafile streams are disabled for security purposes");
787 		return 0;
788 	}
789 
790 	cert_start: {
791 		line = php_stream_get_line(stream, NULL, 0, &line_len);
792 		if (line == NULL) {
793 			goto stream_complete;
794 		} else if (!strcmp(line, "-----BEGIN CERTIFICATE-----\n") ||
795 			!strcmp(line, "-----BEGIN CERTIFICATE-----\r\n")
796 		) {
797 			buffer = BIO_new(BIO_s_mem());
798 			buffer_active = 1;
799 			goto cert_line;
800 		} else {
801 			efree(line);
802 			goto cert_start;
803 		}
804 	}
805 
806 	cert_line: {
807 		BIO_puts(buffer, line);
808 		efree(line);
809 		line = php_stream_get_line(stream, NULL, 0, &line_len);
810 		if (line == NULL) {
811 			goto stream_complete;
812 		} else if (!strcmp(line, "-----END CERTIFICATE-----") ||
813 			!strcmp(line, "-----END CERTIFICATE-----\n") ||
814 			!strcmp(line, "-----END CERTIFICATE-----\r\n")
815 		) {
816 			goto add_cert;
817 		} else {
818 			goto cert_line;
819 		}
820 	}
821 
822 	add_cert: {
823 		BIO_puts(buffer, line);
824 		efree(line);
825 		cert = PEM_read_bio_X509(buffer, NULL, 0, NULL);
826 		BIO_free(buffer);
827 		buffer_active = 0;
828 		if (cert && X509_STORE_add_cert(cert_store, cert)) {
829 			++certs_added;
830 			X509_free(cert);
831 		}
832 		goto cert_start;
833 	}
834 
835 	stream_complete: {
836 		php_stream_close(stream);
837 		if (buffer_active == 1) {
838 			BIO_free(buffer);
839 		}
840 	}
841 
842 	if (certs_added == 0) {
843 		php_error(E_WARNING, "no valid certs found cafile stream: `%s'", cafile);
844 	}
845 
846 	return certs_added;
847 }
848 /* }}} */
849 
php_openssl_enable_peer_verification(SSL_CTX * ctx,php_stream * stream)850 static int php_openssl_enable_peer_verification(SSL_CTX *ctx, php_stream *stream) /* {{{ */
851 {
852 	zval *val = NULL;
853 	char *cafile = NULL;
854 	char *capath = NULL;
855 	php_openssl_netstream_data_t *sslsock = (php_openssl_netstream_data_t*)stream->abstract;
856 
857 	GET_VER_OPT_STRING("cafile", cafile);
858 	GET_VER_OPT_STRING("capath", capath);
859 
860 	if (cafile == NULL) {
861 		cafile = zend_ini_string("openssl.cafile", sizeof("openssl.cafile")-1, 0);
862 		cafile = strlen(cafile) ? cafile : NULL;
863 	} else if (!sslsock->is_client) {
864 		/* Servers need to load and assign CA names from the cafile */
865 		STACK_OF(X509_NAME) *cert_names = SSL_load_client_CA_file(cafile);
866 		if (cert_names != NULL) {
867 			SSL_CTX_set_client_CA_list(ctx, cert_names);
868 		} else {
869 			php_error(E_WARNING, "SSL: failed loading CA names from cafile");
870 			return FAILURE;
871 		}
872 	}
873 
874 	if (capath == NULL) {
875 		capath = zend_ini_string("openssl.capath", sizeof("openssl.capath")-1, 0);
876 		capath = strlen(capath) ? capath : NULL;
877 	}
878 
879 	if (cafile || capath) {
880 		if (!SSL_CTX_load_verify_locations(ctx, cafile, capath)) {
881 			ERR_clear_error();
882 			if (cafile && !php_openssl_load_stream_cafile(SSL_CTX_get_cert_store(ctx), cafile)) {
883 				return FAILURE;
884 			}
885 		}
886 	} else {
887 #ifdef PHP_WIN32
888 		SSL_CTX_set_cert_verify_callback(ctx, php_openssl_win_cert_verify_callback, (void *)stream);
889 		SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
890 #else
891 		if (sslsock->is_client && !SSL_CTX_set_default_verify_paths(ctx)) {
892 			php_error_docref(NULL, E_WARNING,
893 				"Unable to set default verify locations and no CA settings specified");
894 			return FAILURE;
895 		}
896 #endif
897 	}
898 
899 	SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, verify_callback);
900 
901 	return SUCCESS;
902 }
903 /* }}} */
904 
php_openssl_disable_peer_verification(SSL_CTX * ctx,php_stream * stream)905 static void php_openssl_disable_peer_verification(SSL_CTX *ctx, php_stream *stream) /* {{{ */
906 {
907 	SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL);
908 }
909 /* }}} */
910 
php_openssl_set_local_cert(SSL_CTX * ctx,php_stream * stream)911 static int php_openssl_set_local_cert(SSL_CTX *ctx, php_stream *stream) /* {{{ */
912 {
913 	zval *val = NULL;
914 	char *certfile = NULL;
915 
916 	GET_VER_OPT_STRING("local_cert", certfile);
917 
918 	if (certfile) {
919 		char resolved_path_buff[MAXPATHLEN];
920 		const char *private_key = NULL;
921 
922 		if (VCWD_REALPATH(certfile, resolved_path_buff)) {
923 			/* a certificate to use for authentication */
924 			if (SSL_CTX_use_certificate_chain_file(ctx, resolved_path_buff) != 1) {
925 				php_error_docref(NULL, E_WARNING,
926 					"Unable to set local cert chain file `%s'; Check that your cafile/capath "
927 					"settings include details of your certificate and its issuer",
928 					certfile);
929 				return FAILURE;
930 			}
931 			GET_VER_OPT_STRING("local_pk", private_key);
932 
933 			if (private_key) {
934 				char resolved_path_buff_pk[MAXPATHLEN];
935 				if (VCWD_REALPATH(private_key, resolved_path_buff_pk)) {
936 					if (SSL_CTX_use_PrivateKey_file(ctx, resolved_path_buff_pk, SSL_FILETYPE_PEM) != 1) {
937 						php_error_docref(NULL, E_WARNING, "Unable to set private key file `%s'", resolved_path_buff_pk);
938 						return FAILURE;
939 					}
940 				}
941 			} else {
942 				if (SSL_CTX_use_PrivateKey_file(ctx, resolved_path_buff, SSL_FILETYPE_PEM) != 1) {
943 					php_error_docref(NULL, E_WARNING, "Unable to set private key file `%s'", resolved_path_buff);
944 					return FAILURE;
945 				}
946 			}
947 
948 			if (!SSL_CTX_check_private_key(ctx)) {
949 				php_error_docref(NULL, E_WARNING, "Private key does not match certificate!");
950 			}
951 		}
952 	}
953 
954 	return SUCCESS;
955 }
956 /* }}} */
957 
php_openssl_select_crypto_method(zend_long method_value,int is_client)958 static const SSL_METHOD *php_openssl_select_crypto_method(zend_long method_value, int is_client) /* {{{ */
959 {
960 	if (method_value == STREAM_CRYPTO_METHOD_SSLv2) {
961 		php_error_docref(NULL, E_WARNING,
962 				"SSLv2 unavailable in this PHP version");
963 		return NULL;
964 	} else if (method_value == STREAM_CRYPTO_METHOD_SSLv3) {
965 #ifdef HAVE_SSL3
966 		return is_client ? SSLv3_client_method() : SSLv3_server_method();
967 #else
968 		php_error_docref(NULL, E_WARNING,
969 				"SSLv3 unavailable in the OpenSSL library against which PHP is linked");
970 		return NULL;
971 #endif
972 	} else if (method_value == STREAM_CRYPTO_METHOD_TLSv1_0) {
973 		return is_client ? TLSv1_client_method() : TLSv1_server_method();
974 	} else if (method_value == STREAM_CRYPTO_METHOD_TLSv1_1) {
975 #ifdef HAVE_TLS11
976 		return is_client ? TLSv1_1_client_method() : TLSv1_1_server_method();
977 #else
978 		php_error_docref(NULL, E_WARNING,
979 				"TLSv1.1 unavailable in the OpenSSL library against which PHP is linked");
980 		return NULL;
981 #endif
982 	} else if (method_value == STREAM_CRYPTO_METHOD_TLSv1_2) {
983 #ifdef HAVE_TLS12
984 		return is_client ? TLSv1_2_client_method() : TLSv1_2_server_method();
985 #else
986 		php_error_docref(NULL, E_WARNING,
987 				"TLSv1.2 unavailable in the OpenSSL library against which PHP is linked");
988 		return NULL;
989 #endif
990 	} else {
991 		php_error_docref(NULL, E_WARNING,
992 				"Invalid crypto method");
993 		return NULL;
994 	}
995 }
996 /* }}} */
997 
998 #define PHP_SSL_MAX_VERSION_LEN 32
999 
php_openssl_cipher_get_version(const SSL_CIPHER * c,char * buffer,size_t max_len)1000 static char *php_openssl_cipher_get_version(const SSL_CIPHER *c, char *buffer, size_t max_len) /* {{{ */
1001 {
1002 	const char *version = SSL_CIPHER_get_version(c);
1003 
1004 	strncpy(buffer, version, max_len);
1005 	if (max_len <= strlen(version)) {
1006 		buffer[max_len - 1] = 0;
1007 	}
1008 
1009 	return buffer;
1010 }
1011 /* }}} */
1012 
php_openssl_get_crypto_method_ctx_flags(int method_flags)1013 static int php_openssl_get_crypto_method_ctx_flags(int method_flags) /* {{{ */
1014 {
1015 	int ssl_ctx_options = SSL_OP_ALL;
1016 
1017 #ifdef SSL_OP_NO_SSLv2
1018 	ssl_ctx_options |= SSL_OP_NO_SSLv2;
1019 #endif
1020 #ifdef HAVE_SSL3
1021 	if (!(method_flags & STREAM_CRYPTO_METHOD_SSLv3)) {
1022 		ssl_ctx_options |= SSL_OP_NO_SSLv3;
1023 	}
1024 #endif
1025 	if (!(method_flags & STREAM_CRYPTO_METHOD_TLSv1_0)) {
1026 		ssl_ctx_options |= SSL_OP_NO_TLSv1;
1027 	}
1028 #ifdef HAVE_TLS11
1029 	if (!(method_flags & STREAM_CRYPTO_METHOD_TLSv1_1)) {
1030 		ssl_ctx_options |= SSL_OP_NO_TLSv1_1;
1031 	}
1032 #endif
1033 #ifdef HAVE_TLS12
1034 	if (!(method_flags & STREAM_CRYPTO_METHOD_TLSv1_2)) {
1035 		ssl_ctx_options |= SSL_OP_NO_TLSv1_2;
1036 	}
1037 #endif
1038 
1039 	return ssl_ctx_options;
1040 }
1041 /* }}} */
1042 
php_openssl_limit_handshake_reneg(const SSL * ssl)1043 static void php_openssl_limit_handshake_reneg(const SSL *ssl) /* {{{ */
1044 {
1045 	php_stream *stream;
1046 	php_openssl_netstream_data_t *sslsock;
1047 	struct timeval now;
1048 	zend_long elapsed_time;
1049 
1050 	stream = php_openssl_get_stream_from_ssl_handle(ssl);
1051 	sslsock = (php_openssl_netstream_data_t*)stream->abstract;
1052 	gettimeofday(&now, NULL);
1053 
1054 	/* The initial handshake is never rate-limited */
1055 	if (sslsock->reneg->prev_handshake == 0) {
1056 		sslsock->reneg->prev_handshake = now.tv_sec;
1057 		return;
1058 	}
1059 
1060 	elapsed_time = (now.tv_sec - sslsock->reneg->prev_handshake);
1061 	sslsock->reneg->prev_handshake = now.tv_sec;
1062 	sslsock->reneg->tokens -= (elapsed_time * (sslsock->reneg->limit / sslsock->reneg->window));
1063 
1064 	if (sslsock->reneg->tokens < 0) {
1065 		sslsock->reneg->tokens = 0;
1066 	}
1067 	++sslsock->reneg->tokens;
1068 
1069 	/* The token level exceeds our allowed limit */
1070 	if (sslsock->reneg->tokens > sslsock->reneg->limit) {
1071 		zval *val;
1072 
1073 
1074 		sslsock->reneg->should_close = 1;
1075 
1076 		if (PHP_STREAM_CONTEXT(stream) && (val = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream),
1077 				"ssl", "reneg_limit_callback")) != NULL
1078 		) {
1079 			zval param, retval;
1080 
1081 			php_stream_to_zval(stream, &param);
1082 
1083 			/* Closing the stream inside this callback would segfault! */
1084 			stream->flags |= PHP_STREAM_FLAG_NO_FCLOSE;
1085 			if (FAILURE == call_user_function_ex(EG(function_table), NULL, val, &retval, 1, &param, 0, NULL)) {
1086 				php_error(E_WARNING, "SSL: failed invoking reneg limit notification callback");
1087 			}
1088 			stream->flags ^= PHP_STREAM_FLAG_NO_FCLOSE;
1089 
1090 			/* If the reneg_limit_callback returned true don't auto-close */
1091 			if (Z_TYPE(retval) == IS_TRUE) {
1092 				sslsock->reneg->should_close = 0;
1093 			}
1094 
1095 			zval_ptr_dtor(&retval);
1096 		} else {
1097 			php_error_docref(NULL, E_WARNING,
1098 				"SSL: client-initiated handshake rate limit exceeded by peer");
1099 		}
1100 	}
1101 }
1102 /* }}} */
1103 
php_openssl_info_callback(const SSL * ssl,int where,int ret)1104 static void php_openssl_info_callback(const SSL *ssl, int where, int ret) /* {{{ */
1105 {
1106 	/* Rate-limit client-initiated handshake renegotiation to prevent DoS */
1107 	if (where & SSL_CB_HANDSHAKE_START) {
1108 		php_openssl_limit_handshake_reneg(ssl);
1109 	}
1110 }
1111 /* }}} */
1112 
php_openssl_init_server_reneg_limit(php_stream * stream,php_openssl_netstream_data_t * sslsock)1113 static void php_openssl_init_server_reneg_limit(php_stream *stream, php_openssl_netstream_data_t *sslsock) /* {{{ */
1114 {
1115 	zval *val;
1116 	zend_long limit = OPENSSL_DEFAULT_RENEG_LIMIT;
1117 	zend_long window = OPENSSL_DEFAULT_RENEG_WINDOW;
1118 
1119 	if (PHP_STREAM_CONTEXT(stream) &&
1120 		NULL != (val = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "ssl", "reneg_limit"))
1121 	) {
1122 		convert_to_long(val);
1123 		limit = Z_LVAL_P(val);
1124 	}
1125 
1126 	/* No renegotiation rate-limiting */
1127 	if (limit < 0) {
1128 		return;
1129 	}
1130 
1131 	if (PHP_STREAM_CONTEXT(stream) &&
1132 		NULL != (val = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "ssl", "reneg_window"))
1133 	) {
1134 		convert_to_long(val);
1135 		window = Z_LVAL_P(val);
1136 	}
1137 
1138 	sslsock->reneg = (void*)pemalloc(sizeof(php_openssl_handshake_bucket_t),
1139 		php_stream_is_persistent(stream)
1140 	);
1141 
1142 	sslsock->reneg->limit = limit;
1143 	sslsock->reneg->window = window;
1144 	sslsock->reneg->prev_handshake = 0;
1145 	sslsock->reneg->tokens = 0;
1146 	sslsock->reneg->should_close = 0;
1147 
1148 	SSL_set_info_callback(sslsock->ssl_handle, php_openssl_info_callback);
1149 }
1150 /* }}} */
1151 
1152 #if PHP_OPENSSL_API_VERSION < 0x10100
php_openssl_tmp_rsa_cb(SSL * s,int is_export,int keylength)1153 static RSA *php_openssl_tmp_rsa_cb(SSL *s, int is_export, int keylength)
1154 {
1155 	BIGNUM *bn = NULL;
1156 	static RSA *rsa_tmp = NULL;
1157 
1158 	if (!rsa_tmp && ((bn = BN_new()) == NULL)) {
1159 		php_error_docref(NULL, E_WARNING, "allocation error generating RSA key");
1160 	}
1161 	if (!rsa_tmp && bn) {
1162 		if (!BN_set_word(bn, RSA_F4) || ((rsa_tmp = RSA_new()) == NULL) ||
1163 			!RSA_generate_key_ex(rsa_tmp, keylength, bn, NULL)) {
1164 			if (rsa_tmp) {
1165 				RSA_free(rsa_tmp);
1166 			}
1167 			rsa_tmp = NULL;
1168 		}
1169 		BN_free(bn);
1170 	}
1171 
1172 	return (rsa_tmp);
1173 }
1174 #endif
1175 
php_openssl_set_server_dh_param(php_stream * stream,SSL_CTX * ctx)1176 static int php_openssl_set_server_dh_param(php_stream * stream, SSL_CTX *ctx) /* {{{ */
1177 {
1178 	DH *dh;
1179 	BIO* bio;
1180 	zval *zdhpath;
1181 
1182 	zdhpath = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "ssl", "dh_param");
1183 	if (zdhpath == NULL) {
1184 #if 0
1185 	/* Coming in OpenSSL 1.1 ... eventually we'll want to enable this
1186 	 * in the absence of an explicit dh_param.
1187 	 */
1188 	SSL_CTX_set_dh_auto(ctx, 1);
1189 #endif
1190 		return SUCCESS;
1191 	}
1192 
1193 	convert_to_string_ex(zdhpath);
1194 	bio = BIO_new_file(Z_STRVAL_P(zdhpath), PHP_OPENSSL_BIO_MODE_R(PKCS7_BINARY));
1195 
1196 	if (bio == NULL) {
1197 		php_error_docref(NULL, E_WARNING, "invalid dh_param");
1198 		return FAILURE;
1199 	}
1200 
1201 	dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
1202 	BIO_free(bio);
1203 
1204 	if (dh == NULL) {
1205 		php_error_docref(NULL, E_WARNING, "failed reading DH params");
1206 		return FAILURE;
1207 	}
1208 
1209 	if (SSL_CTX_set_tmp_dh(ctx, dh) < 0) {
1210 		php_error_docref(NULL, E_WARNING, "failed assigning DH params");
1211 		DH_free(dh);
1212 		return FAILURE;
1213 	}
1214 
1215 	DH_free(dh);
1216 
1217 	return SUCCESS;
1218 }
1219 /* }}} */
1220 
1221 #if defined(HAVE_ECDH) && PHP_OPENSSL_API_VERSION < 0x10100
php_openssl_set_server_ecdh_curve(php_stream * stream,SSL_CTX * ctx)1222 static int php_openssl_set_server_ecdh_curve(php_stream *stream, SSL_CTX *ctx) /* {{{ */
1223 {
1224 	zval *zvcurve;
1225 	int curve_nid;
1226 	EC_KEY *ecdh;
1227 
1228 	zvcurve = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "ssl", "ecdh_curve");
1229 	if (zvcurve == NULL) {
1230 #if OPENSSL_VERSION_NUMBER >= 0x10002000L
1231 		SSL_CTX_set_ecdh_auto(ctx, 1);
1232 		return SUCCESS;
1233 #else
1234 		curve_nid = NID_X9_62_prime256v1;
1235 #endif
1236 	} else {
1237 		convert_to_string_ex(zvcurve);
1238 		curve_nid = OBJ_sn2nid(Z_STRVAL_P(zvcurve));
1239 		if (curve_nid == NID_undef) {
1240 			php_error_docref(NULL, E_WARNING, "invalid ecdh_curve specified");
1241 			return FAILURE;
1242 		}
1243 	}
1244 
1245 	ecdh = EC_KEY_new_by_curve_name(curve_nid);
1246 	if (ecdh == NULL) {
1247 		php_error_docref(NULL, E_WARNING, "failed generating ECDH curve");
1248 		return FAILURE;
1249 	}
1250 
1251 	SSL_CTX_set_tmp_ecdh(ctx, ecdh);
1252 	EC_KEY_free(ecdh);
1253 
1254 	return SUCCESS;
1255 }
1256 /* }}} */
1257 #endif
1258 
php_openssl_set_server_specific_opts(php_stream * stream,SSL_CTX * ctx)1259 static int php_openssl_set_server_specific_opts(php_stream *stream, SSL_CTX *ctx) /* {{{ */
1260 {
1261 	zval *zv;
1262 	long ssl_ctx_options = SSL_CTX_get_options(ctx);
1263 
1264 #if defined(HAVE_ECDH) && PHP_OPENSSL_API_VERSION < 0x10100
1265 	if (php_openssl_set_server_ecdh_curve(stream, ctx) == FAILURE) {
1266 		return FAILURE;
1267 	}
1268 #endif
1269 
1270 #if PHP_OPENSSL_API_VERSION < 0x10100
1271 	SSL_CTX_set_tmp_rsa_callback(ctx, php_openssl_tmp_rsa_cb);
1272 #endif
1273 	/* We now use php_openssl_tmp_rsa_cb to generate a key of appropriate size whenever necessary */
1274 	if (php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "ssl", "rsa_key_size") != NULL) {
1275 		php_error_docref(NULL, E_WARNING, "rsa_key_size context option has been removed");
1276 	}
1277 
1278 	php_openssl_set_server_dh_param(stream, ctx);
1279 	zv = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "ssl", "single_dh_use");
1280 	if (zv == NULL || zend_is_true(zv)) {
1281 		ssl_ctx_options |= SSL_OP_SINGLE_DH_USE;
1282 	}
1283 
1284 	zv = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "ssl", "honor_cipher_order");
1285 	if (zv == NULL || zend_is_true(zv)) {
1286 		ssl_ctx_options |= SSL_OP_CIPHER_SERVER_PREFERENCE;
1287 	}
1288 
1289 	SSL_CTX_set_options(ctx, ssl_ctx_options);
1290 
1291 	return SUCCESS;
1292 }
1293 /* }}} */
1294 
1295 #ifdef HAVE_TLS_SNI
php_openssl_server_sni_callback(SSL * ssl_handle,int * al,void * arg)1296 static int php_openssl_server_sni_callback(SSL *ssl_handle, int *al, void *arg) /* {{{ */
1297 {
1298 	php_stream *stream;
1299 	php_openssl_netstream_data_t *sslsock;
1300 	unsigned i;
1301 	const char *server_name;
1302 
1303 	server_name = SSL_get_servername(ssl_handle, TLSEXT_NAMETYPE_host_name);
1304 
1305 	if (!server_name) {
1306 		return SSL_TLSEXT_ERR_NOACK;
1307 	}
1308 
1309 	stream = (php_stream*)SSL_get_ex_data(ssl_handle, php_openssl_get_ssl_stream_data_index());
1310 	sslsock = (php_openssl_netstream_data_t*)stream->abstract;
1311 
1312 	if (!(sslsock->sni_cert_count && sslsock->sni_certs)) {
1313 		return SSL_TLSEXT_ERR_NOACK;
1314 	}
1315 
1316 	for (i=0; i < sslsock->sni_cert_count; i++) {
1317 		if (php_openssl_matches_wildcard_name(server_name, sslsock->sni_certs[i].name)) {
1318 			SSL_set_SSL_CTX(ssl_handle, sslsock->sni_certs[i].ctx);
1319 			return SSL_TLSEXT_ERR_OK;
1320 		}
1321 	}
1322 
1323 	return SSL_TLSEXT_ERR_NOACK;
1324 }
1325 /* }}} */
1326 
php_openssl_create_sni_server_ctx(char * cert_path,char * key_path)1327 static SSL_CTX *php_openssl_create_sni_server_ctx(char *cert_path, char *key_path)  /* {{{ */
1328 {
1329 	/* The hello method is not inherited by SSL structs when assigning a new context
1330 	 * inside the SNI callback, so the just use SSLv23 */
1331 	SSL_CTX *ctx = SSL_CTX_new(SSLv23_server_method());
1332 
1333 	if (SSL_CTX_use_certificate_chain_file(ctx, cert_path) != 1) {
1334 		php_error_docref(NULL, E_WARNING,
1335 			"failed setting local cert chain file `%s'; " \
1336 			"check that your cafile/capath settings include " \
1337 			"details of your certificate and its issuer",
1338 			cert_path
1339 		);
1340 		SSL_CTX_free(ctx);
1341 		return NULL;
1342 	} else if (SSL_CTX_use_PrivateKey_file(ctx, key_path, SSL_FILETYPE_PEM) != 1) {
1343 		php_error_docref(NULL, E_WARNING,
1344 			"failed setting private key from file `%s'",
1345 			key_path
1346 		);
1347 		SSL_CTX_free(ctx);
1348 		return NULL;
1349 	}
1350 
1351 	return ctx;
1352 }
1353 /* }}} */
1354 
php_openssl_enable_server_sni(php_stream * stream,php_openssl_netstream_data_t * sslsock)1355 static int php_openssl_enable_server_sni(php_stream *stream, php_openssl_netstream_data_t *sslsock)  /* {{{ */
1356 {
1357 	zval *val;
1358 	zval *current;
1359 	zend_string *key;
1360 	zend_ulong key_index;
1361 	int i = 0;
1362 	char resolved_path_buff[MAXPATHLEN];
1363 	SSL_CTX *ctx;
1364 
1365 	/* If the stream ctx disables SNI we're finished here */
1366 	if (GET_VER_OPT("SNI_enabled") && !zend_is_true(val)) {
1367 		return SUCCESS;
1368 	}
1369 
1370 	/* If no SNI cert array is specified we're finished here */
1371 	if (!GET_VER_OPT("SNI_server_certs")) {
1372 		return SUCCESS;
1373 	}
1374 
1375 	if (Z_TYPE_P(val) != IS_ARRAY) {
1376 		php_error_docref(NULL, E_WARNING,
1377 			"SNI_server_certs requires an array mapping host names to cert paths"
1378 		);
1379 		return FAILURE;
1380 	}
1381 
1382 	sslsock->sni_cert_count = zend_hash_num_elements(Z_ARRVAL_P(val));
1383 	if (sslsock->sni_cert_count == 0) {
1384 		php_error_docref(NULL, E_WARNING,
1385 			"SNI_server_certs host cert array must not be empty"
1386 		);
1387 		return FAILURE;
1388 	}
1389 
1390 	sslsock->sni_certs = (php_openssl_sni_cert_t*)safe_pemalloc(sslsock->sni_cert_count,
1391 		sizeof(php_openssl_sni_cert_t), 0, php_stream_is_persistent(stream)
1392 	);
1393 	memset(sslsock->sni_certs, 0, sslsock->sni_cert_count * sizeof(php_openssl_sni_cert_t));
1394 
1395 	ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(val), key_index, key, current) {
1396 		(void) key_index;
1397 
1398 		if (!key) {
1399 			php_error_docref(NULL, E_WARNING,
1400 				"SNI_server_certs array requires string host name keys"
1401 			);
1402 			return FAILURE;
1403 		}
1404 
1405 		if (Z_TYPE_P(current) == IS_ARRAY) {
1406 			zval *local_pk, *local_cert;
1407 			char resolved_cert_path_buff[MAXPATHLEN], resolved_pk_path_buff[MAXPATHLEN];
1408 
1409 			local_cert = zend_hash_str_find(Z_ARRVAL_P(current), "local_cert", sizeof("local_cert")-1);
1410 			if (local_cert == NULL) {
1411 				php_error_docref(NULL, E_WARNING,
1412 					"local_cert not present in the array",
1413 					Z_STRVAL_P(local_cert)
1414 				);
1415 				return FAILURE;
1416 			}
1417 			convert_to_string_ex(local_cert);
1418 			if (!VCWD_REALPATH(Z_STRVAL_P(local_cert), resolved_cert_path_buff)) {
1419 				php_error_docref(NULL, E_WARNING,
1420 					"failed setting local cert chain file `%s'; file not found"
1421 				);
1422 				return FAILURE;
1423 			}
1424 			local_pk = zend_hash_str_find(Z_ARRVAL_P(current), "local_pk", sizeof("local_pk")-1);
1425 			if (local_pk == NULL) {
1426 				php_error_docref(NULL, E_WARNING,
1427 					"local_pk not present in the array"
1428 				);
1429 				return FAILURE;
1430 			}
1431 			convert_to_string_ex(local_pk);
1432 			if (!VCWD_REALPATH(Z_STRVAL_P(local_pk), resolved_pk_path_buff)) {
1433 				php_error_docref(NULL, E_WARNING,
1434 					"failed setting local private key file `%s'; file not found",
1435 					Z_STRVAL_P(local_pk)
1436 				);
1437 				return FAILURE;
1438 			}
1439 
1440 			ctx = php_openssl_create_sni_server_ctx(resolved_cert_path_buff, resolved_pk_path_buff);
1441 
1442 		} else if (VCWD_REALPATH(Z_STRVAL_P(current), resolved_path_buff)) {
1443 			ctx = php_openssl_create_sni_server_ctx(resolved_path_buff, resolved_path_buff);
1444 		} else {
1445 			php_error_docref(NULL, E_WARNING,
1446 				"failed setting local cert chain file `%s'; file not found",
1447 				Z_STRVAL_P(current)
1448 			);
1449 			return FAILURE;
1450 		}
1451 
1452 		if (ctx == NULL) {
1453 			return FAILURE;
1454 		}
1455 
1456 		sslsock->sni_certs[i].name = pestrdup(ZSTR_VAL(key), php_stream_is_persistent(stream));
1457 		sslsock->sni_certs[i].ctx = ctx;
1458 		++i;
1459 
1460 	} ZEND_HASH_FOREACH_END();
1461 
1462 	SSL_CTX_set_tlsext_servername_callback(sslsock->ctx, php_openssl_server_sni_callback);
1463 
1464 	return SUCCESS;
1465 }
1466 /* }}} */
1467 
php_openssl_enable_client_sni(php_stream * stream,php_openssl_netstream_data_t * sslsock)1468 static void php_openssl_enable_client_sni(php_stream *stream, php_openssl_netstream_data_t *sslsock) /* {{{ */
1469 {
1470 	zval *val;
1471 	char *sni_server_name;
1472 
1473 	/* If SNI is explicitly disabled we're finished here */
1474 	if (GET_VER_OPT("SNI_enabled") && !zend_is_true(val)) {
1475 		return;
1476 	}
1477 
1478 	sni_server_name = sslsock->url_name;
1479 
1480 	GET_VER_OPT_STRING("peer_name", sni_server_name);
1481 
1482 	if (sni_server_name) {
1483 		SSL_set_tlsext_host_name(sslsock->ssl_handle, sni_server_name);
1484 	}
1485 }
1486 /* }}} */
1487 #endif
1488 
1489 #ifdef HAVE_TLS_ALPN
1490 /**
1491  * Parses a comma-separated list of strings into a string suitable for SSL_CTX_set_next_protos_advertised
1492  *   outlen: (output) set to the length of the resulting buffer on success.
1493  *   err: (maybe NULL) on failure, an error message line is written to this BIO.
1494  *   in: a NULL terminated string like "abc,def,ghi"
1495  *
1496  *   returns: an emalloced buffer or NULL on failure.
1497  */
php_openssl_alpn_protos_parse(unsigned short * outlen,const char * in)1498 static unsigned char *php_openssl_alpn_protos_parse(unsigned short *outlen, const char *in) /* {{{ */
1499 {
1500 	size_t len;
1501 	unsigned char *out;
1502 	size_t i, start = 0;
1503 
1504 	len = strlen(in);
1505 	if (len >= 65535) {
1506 		return NULL;
1507 	}
1508 
1509 	out = emalloc(strlen(in) + 1);
1510 
1511 	for (i = 0; i <= len; ++i) {
1512 		if (i == len || in[i] == ',') {
1513 			if (i - start > 255) {
1514 				efree(out);
1515 				return NULL;
1516 			}
1517 			out[start] = i - start;
1518 			start = i + 1;
1519 		} else {
1520 			out[i + 1] = in[i];
1521 		}
1522 	}
1523 
1524 	*outlen = len + 1;
1525 
1526 	return out;
1527 }
1528 /* }}} */
1529 
php_openssl_server_alpn_callback(SSL * ssl_handle,const unsigned char ** out,unsigned char * outlen,const unsigned char * in,unsigned int inlen,void * arg)1530 static int php_openssl_server_alpn_callback(SSL *ssl_handle,
1531 		const unsigned char **out, unsigned char *outlen,
1532 		const unsigned char *in, unsigned int inlen, void *arg) /* {{{ */
1533 {
1534 	php_openssl_netstream_data_t *sslsock = arg;
1535 
1536 	if (SSL_select_next_proto((unsigned char **)out, outlen, sslsock->alpn_ctx.data, sslsock->alpn_ctx.len, in, inlen) != OPENSSL_NPN_NEGOTIATED) {
1537 		return SSL_TLSEXT_ERR_NOACK;
1538 	}
1539 
1540 	return SSL_TLSEXT_ERR_OK;
1541 }
1542 /* }}} */
1543 
1544 #endif
1545 
php_openssl_setup_crypto(php_stream * stream,php_openssl_netstream_data_t * sslsock,php_stream_xport_crypto_param * cparam)1546 int php_openssl_setup_crypto(php_stream *stream,
1547 		php_openssl_netstream_data_t *sslsock,
1548 		php_stream_xport_crypto_param *cparam) /* {{{ */
1549 {
1550 	const SSL_METHOD *method;
1551 	int ssl_ctx_options;
1552 	int method_flags;
1553 	char *cipherlist = NULL;
1554 	char *alpn_protocols = NULL;
1555 	zval *val;
1556 
1557 	if (sslsock->ssl_handle) {
1558 		if (sslsock->s.is_blocked) {
1559 			php_error_docref(NULL, E_WARNING, "SSL/TLS already set-up for this stream");
1560 			return FAILURE;
1561 		} else {
1562 			return SUCCESS;
1563 		}
1564 	}
1565 
1566 	ERR_clear_error();
1567 
1568 	/* We need to do slightly different things based on client/server method
1569 	 * so lets remember which method was selected */
1570 	sslsock->is_client = cparam->inputs.method & STREAM_CRYPTO_IS_CLIENT;
1571 	method_flags = ((cparam->inputs.method >> 1) << 1);
1572 
1573 	/* Should we use a specific crypto method or is generic SSLv23 okay? */
1574 	if ((method_flags & (method_flags-1)) == 0) {
1575 		ssl_ctx_options = SSL_OP_ALL;
1576 		method = php_openssl_select_crypto_method(method_flags, sslsock->is_client);
1577 		if (method == NULL) {
1578 			return FAILURE;
1579 		}
1580 	} else {
1581 		method = sslsock->is_client ? SSLv23_client_method() : SSLv23_server_method();
1582 		ssl_ctx_options = php_openssl_get_crypto_method_ctx_flags(method_flags);
1583 		if (ssl_ctx_options == -1) {
1584 			return FAILURE;
1585 		}
1586 	}
1587 
1588 	sslsock->ctx = SSL_CTX_new(method);
1589 
1590 	if (sslsock->ctx == NULL) {
1591 		php_error_docref(NULL, E_WARNING, "SSL context creation failure");
1592 		return FAILURE;
1593 	}
1594 
1595 	if (GET_VER_OPT("no_ticket") && zend_is_true(val)) {
1596 		ssl_ctx_options |= SSL_OP_NO_TICKET;
1597 	}
1598 
1599 	ssl_ctx_options &= ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS;
1600 
1601 	if (!GET_VER_OPT("disable_compression") || zend_is_true(val)) {
1602 		ssl_ctx_options |= SSL_OP_NO_COMPRESSION;
1603 	}
1604 
1605 	if (GET_VER_OPT("verify_peer") && !zend_is_true(val)) {
1606 		php_openssl_disable_peer_verification(sslsock->ctx, stream);
1607 	} else if (FAILURE == php_openssl_enable_peer_verification(sslsock->ctx, stream)) {
1608 		return FAILURE;
1609 	}
1610 
1611 	/* callback for the passphrase (for localcert) */
1612 	if (GET_VER_OPT("passphrase")) {
1613 		SSL_CTX_set_default_passwd_cb_userdata(sslsock->ctx, stream);
1614 		SSL_CTX_set_default_passwd_cb(sslsock->ctx, php_openssl_passwd_callback);
1615 	}
1616 
1617 	GET_VER_OPT_STRING("ciphers", cipherlist);
1618 #ifndef USE_OPENSSL_SYSTEM_CIPHERS
1619 	if (!cipherlist) {
1620 		cipherlist = OPENSSL_DEFAULT_STREAM_CIPHERS;
1621 	}
1622 #endif
1623 	if (cipherlist) {
1624 		if (SSL_CTX_set_cipher_list(sslsock->ctx, cipherlist) != 1) {
1625 			return FAILURE;
1626 		}
1627 	}
1628 
1629 	if (GET_VER_OPT("security_level")) {
1630 #ifdef HAVE_SEC_LEVEL
1631 		convert_to_long(val);
1632 		if (Z_LVAL_P(val) < 0 || Z_LVAL_P(val) > 5) {
1633 			php_error_docref(NULL, E_WARNING, "Security level must be between 0 and 5");
1634 		}
1635 		SSL_CTX_set_security_level(sslsock->ctx, Z_LVAL_P(val));
1636 #else
1637 		php_error_docref(NULL, E_WARNING,
1638 				"security_level is not supported by the linked OpenSSL library "
1639 				"- it is supported from version 1.1.0");
1640 #endif
1641 	}
1642 
1643 	GET_VER_OPT_STRING("alpn_protocols", alpn_protocols);
1644 	if (alpn_protocols) {
1645 #ifdef HAVE_TLS_ALPN
1646 		{
1647 			unsigned short alpn_len;
1648 			unsigned char *alpn = php_openssl_alpn_protos_parse(&alpn_len, alpn_protocols);
1649 
1650 			if (alpn == NULL) {
1651 				php_error_docref(NULL, E_WARNING, "Failed parsing comma-separated TLS ALPN protocol string");
1652 				SSL_CTX_free(sslsock->ctx);
1653 				sslsock->ctx = NULL;
1654 				return FAILURE;
1655 			}
1656 			if (sslsock->is_client) {
1657 				SSL_CTX_set_alpn_protos(sslsock->ctx, alpn, alpn_len);
1658 			} else {
1659 				sslsock->alpn_ctx.data = (unsigned char *) pestrndup((const char*)alpn, alpn_len, php_stream_is_persistent(stream));
1660 				sslsock->alpn_ctx.len = alpn_len;
1661 				SSL_CTX_set_alpn_select_cb(sslsock->ctx, php_openssl_server_alpn_callback, sslsock);
1662 			}
1663 
1664 			efree(alpn);
1665 		}
1666 #else
1667 		php_error_docref(NULL, E_WARNING,
1668 			"alpn_protocols support is not compiled into the OpenSSL library against which PHP is linked");
1669 #endif
1670 	}
1671 
1672 	if (FAILURE == php_openssl_set_local_cert(sslsock->ctx, stream)) {
1673 		return FAILURE;
1674 	}
1675 
1676 	SSL_CTX_set_options(sslsock->ctx, ssl_ctx_options);
1677 
1678 	if (sslsock->is_client == 0 &&
1679 		PHP_STREAM_CONTEXT(stream) &&
1680 		FAILURE == php_openssl_set_server_specific_opts(stream, sslsock->ctx)
1681 	) {
1682 		return FAILURE;
1683 	}
1684 
1685 	sslsock->ssl_handle = SSL_new(sslsock->ctx);
1686 
1687 	if (sslsock->ssl_handle == NULL) {
1688 		php_error_docref(NULL, E_WARNING, "SSL handle creation failure");
1689 		SSL_CTX_free(sslsock->ctx);
1690 		sslsock->ctx = NULL;
1691 #ifdef HAVE_TLS_ALPN
1692 		if (sslsock->alpn_ctx.data) {
1693 			pefree(sslsock->alpn_ctx.data, php_stream_is_persistent(stream));
1694 			sslsock->alpn_ctx.data = NULL;
1695 		}
1696 #endif
1697 		return FAILURE;
1698 	} else {
1699 		SSL_set_ex_data(sslsock->ssl_handle, php_openssl_get_ssl_stream_data_index(), stream);
1700 	}
1701 
1702 	if (!SSL_set_fd(sslsock->ssl_handle, sslsock->s.socket)) {
1703 		php_openssl_handle_ssl_error(stream, 0, 1);
1704 	}
1705 
1706 #ifdef HAVE_TLS_SNI
1707 	/* Enable server-side SNI */
1708 	if (!sslsock->is_client && php_openssl_enable_server_sni(stream, sslsock) == FAILURE) {
1709 		return FAILURE;
1710 	}
1711 #endif
1712 
1713 	/* Enable server-side handshake renegotiation rate-limiting */
1714 	if (!sslsock->is_client) {
1715 		php_openssl_init_server_reneg_limit(stream, sslsock);
1716 	}
1717 
1718 #ifdef SSL_MODE_RELEASE_BUFFERS
1719 	SSL_set_mode(sslsock->ssl_handle, SSL_get_mode(sslsock->ssl_handle) | SSL_MODE_RELEASE_BUFFERS);
1720 #endif
1721 
1722 	if (cparam->inputs.session) {
1723 		if (cparam->inputs.session->ops != &php_openssl_socket_ops) {
1724 			php_error_docref(NULL, E_WARNING, "supplied session stream must be an SSL enabled stream");
1725 		} else if (((php_openssl_netstream_data_t*)cparam->inputs.session->abstract)->ssl_handle == NULL) {
1726 			php_error_docref(NULL, E_WARNING, "supplied SSL session stream is not initialized");
1727 		} else {
1728 			SSL_copy_session_id(sslsock->ssl_handle, ((php_openssl_netstream_data_t*)cparam->inputs.session->abstract)->ssl_handle);
1729 		}
1730 	}
1731 
1732 	return SUCCESS;
1733 }
1734 /* }}} */
1735 
php_openssl_capture_session_meta(SSL * ssl_handle)1736 static zend_array *php_openssl_capture_session_meta(SSL *ssl_handle) /* {{{ */
1737 {
1738 	zval meta_arr;
1739 	char *proto_str;
1740 	long proto = SSL_version(ssl_handle);
1741 	const SSL_CIPHER *cipher = SSL_get_current_cipher(ssl_handle);
1742 	char version_str[PHP_SSL_MAX_VERSION_LEN];
1743 
1744 	switch (proto) {
1745 #ifdef HAVE_TLS12
1746 		case TLS1_2_VERSION:
1747 			proto_str = "TLSv1.2";
1748 			break;
1749 #endif
1750 #ifdef HAVE_TLS11
1751 		case TLS1_1_VERSION:
1752 			proto_str = "TLSv1.1";
1753 			break;
1754 #endif
1755 		case TLS1_VERSION:
1756 			proto_str = "TLSv1";
1757 			break;
1758 #ifdef HAVE_SSL3
1759 		case SSL3_VERSION:
1760 			proto_str = "SSLv3";
1761 			break;
1762 #endif
1763 		default: proto_str = "UNKNOWN";
1764 	}
1765 
1766 	array_init(&meta_arr);
1767 	add_assoc_string(&meta_arr, "protocol", proto_str);
1768 	add_assoc_string(&meta_arr, "cipher_name", (char *) SSL_CIPHER_get_name(cipher));
1769 	add_assoc_long(&meta_arr, "cipher_bits", SSL_CIPHER_get_bits(cipher, NULL));
1770 	add_assoc_string(&meta_arr, "cipher_version",
1771 			php_openssl_cipher_get_version(cipher, version_str, PHP_SSL_MAX_VERSION_LEN));
1772 
1773 	return Z_ARR(meta_arr);
1774 }
1775 /* }}} */
1776 
php_openssl_capture_peer_certs(php_stream * stream,php_openssl_netstream_data_t * sslsock,X509 * peer_cert)1777 static int php_openssl_capture_peer_certs(php_stream *stream,
1778 		php_openssl_netstream_data_t *sslsock, X509 *peer_cert) /* {{{ */
1779 {
1780 	zval *val, zcert;
1781 	int cert_captured = 0;
1782 
1783 	if (NULL != (val = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream),
1784 			"ssl", "capture_peer_cert")) &&
1785 		zend_is_true(val)
1786 	) {
1787 		ZVAL_RES(&zcert, zend_register_resource(peer_cert, php_openssl_get_x509_list_id()));
1788 		php_stream_context_set_option(PHP_STREAM_CONTEXT(stream), "ssl", "peer_certificate", &zcert);
1789 		zval_ptr_dtor(&zcert);
1790 		cert_captured = 1;
1791 	}
1792 
1793 	if (NULL != (val = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream),
1794 			"ssl", "capture_peer_cert_chain")) &&
1795 		zend_is_true(val)
1796 	) {
1797 		zval arr;
1798 		STACK_OF(X509) *chain;
1799 
1800 		chain = SSL_get_peer_cert_chain(sslsock->ssl_handle);
1801 
1802 		if (chain && sk_X509_num(chain) > 0) {
1803 			int i;
1804 			array_init(&arr);
1805 
1806 			for (i = 0; i < sk_X509_num(chain); i++) {
1807 				X509 *mycert = X509_dup(sk_X509_value(chain, i));
1808 				ZVAL_RES(&zcert, zend_register_resource(mycert, php_openssl_get_x509_list_id()));
1809 				add_next_index_zval(&arr, &zcert);
1810 			}
1811 
1812 		} else {
1813 			ZVAL_NULL(&arr);
1814 		}
1815 
1816 		php_stream_context_set_option(PHP_STREAM_CONTEXT(stream), "ssl", "peer_certificate_chain", &arr);
1817 		zval_ptr_dtor(&arr);
1818 	}
1819 
1820 	return cert_captured;
1821 }
1822 /* }}} */
1823 
php_openssl_enable_crypto(php_stream * stream,php_openssl_netstream_data_t * sslsock,php_stream_xport_crypto_param * cparam)1824 static int php_openssl_enable_crypto(php_stream *stream,
1825 		php_openssl_netstream_data_t *sslsock,
1826 		php_stream_xport_crypto_param *cparam) /* {{{ */
1827 {
1828 	int n;
1829 	int retry = 1;
1830 	int cert_captured = 0;
1831 	X509 *peer_cert;
1832 
1833 	if (cparam->inputs.activate && !sslsock->ssl_active) {
1834 		struct timeval start_time, *timeout;
1835 		int	blocked = sslsock->s.is_blocked, has_timeout = 0;
1836 
1837 #ifdef HAVE_TLS_SNI
1838 		if (sslsock->is_client) {
1839 			php_openssl_enable_client_sni(stream, sslsock);
1840 		}
1841 #endif
1842 
1843 		if (!sslsock->state_set) {
1844 			if (sslsock->is_client) {
1845 				SSL_set_connect_state(sslsock->ssl_handle);
1846 			} else {
1847 				SSL_set_accept_state(sslsock->ssl_handle);
1848 			}
1849 			sslsock->state_set = 1;
1850 		}
1851 
1852 		if (SUCCESS == php_set_sock_blocking(sslsock->s.socket, 0)) {
1853 			sslsock->s.is_blocked = 0;
1854 			/* The following mode are added only if we are able to change socket
1855 			 * to non blocking mode which is also used for read and write */
1856 			SSL_set_mode(
1857 				sslsock->ssl_handle,
1858 				(
1859 					SSL_get_mode(sslsock->ssl_handle) |
1860 					SSL_MODE_ENABLE_PARTIAL_WRITE |
1861 					SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER
1862 				)
1863 			);
1864 		}
1865 
1866 		timeout = sslsock->is_client ? &sslsock->connect_timeout : &sslsock->s.timeout;
1867 		has_timeout = !sslsock->s.is_blocked && (timeout->tv_sec || timeout->tv_usec);
1868 		/* gettimeofday is not monotonic; using it here is not strictly correct */
1869 		if (has_timeout) {
1870 			gettimeofday(&start_time, NULL);
1871 		}
1872 
1873 		do {
1874 			struct timeval cur_time, elapsed_time;
1875 
1876 			ERR_clear_error();
1877 			if (sslsock->is_client) {
1878 				n = SSL_connect(sslsock->ssl_handle);
1879 			} else {
1880 				n = SSL_accept(sslsock->ssl_handle);
1881 			}
1882 
1883 			if (has_timeout) {
1884 				gettimeofday(&cur_time, NULL);
1885 				elapsed_time = php_openssl_subtract_timeval(cur_time, start_time);
1886 
1887 				if (php_openssl_compare_timeval( elapsed_time, *timeout) > 0) {
1888 					php_error_docref(NULL, E_WARNING, "SSL: Handshake timed out");
1889 					return -1;
1890 				}
1891 			}
1892 
1893 			if (n <= 0) {
1894 				/* in case of SSL_ERROR_WANT_READ/WRITE, do not retry in non-blocking mode */
1895 				retry = php_openssl_handle_ssl_error(stream, n, blocked);
1896 				if (retry) {
1897 					/* wait until something interesting happens in the socket. It may be a
1898 					 * timeout. Also consider the unlikely of possibility of a write block  */
1899 					int err = SSL_get_error(sslsock->ssl_handle, n);
1900 					struct timeval left_time;
1901 
1902 					if (has_timeout) {
1903 						left_time = php_openssl_subtract_timeval(*timeout, elapsed_time);
1904 					}
1905 					php_pollfd_for(sslsock->s.socket, (err == SSL_ERROR_WANT_READ) ?
1906 						(POLLIN|POLLPRI) : POLLOUT, has_timeout ? &left_time : NULL);
1907 				}
1908 			} else {
1909 				retry = 0;
1910 			}
1911 		} while (retry);
1912 
1913 		if (sslsock->s.is_blocked != blocked && SUCCESS == php_set_sock_blocking(sslsock->s.socket, blocked)) {
1914 			sslsock->s.is_blocked = blocked;
1915 		}
1916 
1917 		if (n == 1) {
1918 			peer_cert = SSL_get_peer_certificate(sslsock->ssl_handle);
1919 			if (peer_cert && PHP_STREAM_CONTEXT(stream)) {
1920 				cert_captured = php_openssl_capture_peer_certs(stream, sslsock, peer_cert);
1921 			}
1922 
1923 			if (FAILURE == php_openssl_apply_peer_verification_policy(sslsock->ssl_handle, peer_cert, stream)) {
1924 				SSL_shutdown(sslsock->ssl_handle);
1925 				n = -1;
1926 			} else {
1927 				sslsock->ssl_active = 1;
1928 
1929 				if (PHP_STREAM_CONTEXT(stream)) {
1930 					zval *val;
1931 					if (NULL != (val = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream),
1932 						"ssl", "capture_session_meta"))
1933 					) {
1934 						 php_error(E_DEPRECATED,
1935 							"capture_session_meta is deprecated; its information is now available via stream_get_meta_data()"
1936                         );
1937 					}
1938 
1939 					if (val && zend_is_true(val)) {
1940 						zval meta_arr;
1941 						ZVAL_ARR(&meta_arr, php_openssl_capture_session_meta(sslsock->ssl_handle));
1942 						php_stream_context_set_option(PHP_STREAM_CONTEXT(stream), "ssl", "session_meta", &meta_arr);
1943 						zval_ptr_dtor(&meta_arr);
1944 					}
1945 				}
1946 			}
1947 		} else if (errno == EAGAIN) {
1948 			n = 0;
1949 		} else {
1950 			n = -1;
1951 			/* We want to capture the peer cert even if verification fails*/
1952 			peer_cert = SSL_get_peer_certificate(sslsock->ssl_handle);
1953 			if (peer_cert && PHP_STREAM_CONTEXT(stream)) {
1954 				cert_captured = php_openssl_capture_peer_certs(stream, sslsock, peer_cert);
1955 			}
1956 		}
1957 
1958 		if (n && peer_cert && cert_captured == 0) {
1959 			X509_free(peer_cert);
1960 		}
1961 
1962 		return n;
1963 
1964 	} else if (!cparam->inputs.activate && sslsock->ssl_active) {
1965 		/* deactivate - common for server/client */
1966 		SSL_shutdown(sslsock->ssl_handle);
1967 		sslsock->ssl_active = 0;
1968 	}
1969 
1970 	return -1;
1971 }
1972 /* }}} */
1973 
php_openssl_sockop_read(php_stream * stream,char * buf,size_t count)1974 static size_t php_openssl_sockop_read(php_stream *stream, char *buf, size_t count) /* {{{ */
1975 {
1976 	return php_openssl_sockop_io( 1, stream, buf, count );
1977 }
1978 /* }}} */
1979 
php_openssl_sockop_write(php_stream * stream,const char * buf,size_t count)1980 static size_t php_openssl_sockop_write(php_stream *stream, const char *buf, size_t count) /* {{{ */
1981 {
1982 	return php_openssl_sockop_io( 0, stream, (char*)buf, count );
1983 }
1984 /* }}} */
1985 
1986 /**
1987  * Factored out common functionality (blocking, timeout, loop management) for read and write.
1988  * Perform IO (read or write) to an SSL socket. If we have a timeout, we switch to non-blocking mode
1989  * for the duration of the operation, using select to do our waits. If we time out, or we have an error
1990  * report that back to PHP
1991  */
php_openssl_sockop_io(int read,php_stream * stream,char * buf,size_t count)1992 static size_t php_openssl_sockop_io(int read, php_stream *stream, char *buf, size_t count) /* {{{ */
1993 {
1994 	php_openssl_netstream_data_t *sslsock = (php_openssl_netstream_data_t*)stream->abstract;
1995 
1996 	/* Only do this if SSL is active. */
1997 	if (sslsock->ssl_active) {
1998 		int retry = 1;
1999 		struct timeval start_time;
2000 		struct timeval *timeout = NULL;
2001 		int began_blocked = sslsock->s.is_blocked;
2002 		int has_timeout = 0;
2003 		int nr_bytes = 0;
2004 
2005 		/* prevent overflow in openssl */
2006 		if (count > INT_MAX) {
2007 			count = INT_MAX;
2008 		}
2009 
2010 		/* never use a timeout with non-blocking sockets */
2011 		if (began_blocked) {
2012 			timeout = &sslsock->s.timeout;
2013 		}
2014 
2015 		if (timeout && php_set_sock_blocking(sslsock->s.socket, 0) == SUCCESS) {
2016 			sslsock->s.is_blocked = 0;
2017 		}
2018 
2019 		if (!sslsock->s.is_blocked && timeout && (timeout->tv_sec || timeout->tv_usec)) {
2020 			has_timeout = 1;
2021 			/* gettimeofday is not monotonic; using it here is not strictly correct */
2022 			gettimeofday(&start_time, NULL);
2023 		}
2024 
2025 		/* Main IO loop. */
2026 		do {
2027 			struct timeval cur_time, elapsed_time, left_time;
2028 
2029 			/* If we have a timeout to check, figure out how much time has elapsed since we started. */
2030 			if (has_timeout) {
2031 				gettimeofday(&cur_time, NULL);
2032 
2033 				/* Determine how much time we've taken so far. */
2034 				elapsed_time = php_openssl_subtract_timeval(cur_time, start_time);
2035 
2036 				/* and return an error if we've taken too long. */
2037 				if (php_openssl_compare_timeval(elapsed_time, *timeout) > 0 ) {
2038 					/* If the socket was originally blocking, set it back. */
2039 					if (began_blocked) {
2040 						php_set_sock_blocking(sslsock->s.socket, 1);
2041 						sslsock->s.is_blocked = 1;
2042 					}
2043 					sslsock->s.timeout_event = 1;
2044 					return -1;
2045 				}
2046 			}
2047 
2048 			/* Now, do the IO operation. Don't block if we can't complete... */
2049 			ERR_clear_error();
2050 			if (read) {
2051 				nr_bytes = SSL_read(sslsock->ssl_handle, buf, (int)count);
2052 
2053 				if (sslsock->reneg && sslsock->reneg->should_close) {
2054 					/* renegotiation rate limiting triggered */
2055 					php_stream_xport_shutdown(stream, (stream_shutdown_t)SHUT_RDWR);
2056 					nr_bytes = 0;
2057 					stream->eof = 1;
2058 					 break;
2059 				}
2060 			} else {
2061 				nr_bytes = SSL_write(sslsock->ssl_handle, buf, (int)count);
2062 			}
2063 
2064 			/* Now, how much time until we time out? */
2065 			if (has_timeout) {
2066 				left_time = php_openssl_subtract_timeval( *timeout, elapsed_time );
2067 			}
2068 
2069 			/* If we didn't do anything on the last loop (or an error) check to see if we should retry or exit. */
2070 			if (nr_bytes <= 0) {
2071 
2072 				/* Get the error code from SSL, and check to see if it's an error or not. */
2073 				int err = SSL_get_error(sslsock->ssl_handle, nr_bytes );
2074 				retry = php_openssl_handle_ssl_error(stream, nr_bytes, 0);
2075 
2076 				/* If we get this (the above doesn't check) then we'll retry as well. */
2077 				if (errno == EAGAIN && err == SSL_ERROR_WANT_READ && read) {
2078 					retry = 1;
2079 				}
2080 				if (errno == EAGAIN && err == SSL_ERROR_WANT_WRITE && read == 0) {
2081 					retry = 1;
2082 				}
2083 
2084 				/* Also, on reads, we may get this condition on an EOF. We should check properly. */
2085 				if (read) {
2086 					stream->eof = (retry == 0 && errno != EAGAIN && !SSL_pending(sslsock->ssl_handle));
2087 				}
2088 
2089 				/* Don't loop indefinitely in non-blocking mode if no data is available */
2090 				if (began_blocked == 0) {
2091 					break;
2092 				}
2093 
2094 				/* Now, if we have to wait some time, and we're supposed to be blocking, wait for the socket to become
2095 				 * available. Now, php_pollfd_for uses select to wait up to our time_left value only...
2096 				 */
2097 				if (retry) {
2098 					if (read) {
2099 						php_pollfd_for(sslsock->s.socket, (err == SSL_ERROR_WANT_WRITE) ?
2100 							(POLLOUT|POLLPRI) : (POLLIN|POLLPRI), has_timeout ? &left_time : NULL);
2101 					} else {
2102 						php_pollfd_for(sslsock->s.socket, (err == SSL_ERROR_WANT_READ) ?
2103 							(POLLIN|POLLPRI) : (POLLOUT|POLLPRI), has_timeout ? &left_time : NULL);
2104 					}
2105 				}
2106 			} else {
2107 				/* Else, if we got bytes back, check for possible errors. */
2108 				int err = SSL_get_error(sslsock->ssl_handle, nr_bytes);
2109 
2110 				/* If we didn't get any error, then let's return it to PHP. */
2111 				if (err == SSL_ERROR_NONE) {
2112 					break;
2113 				}
2114 
2115 				/* Otherwise, we need to wait again (up to time_left or we get an error) */
2116 				if (began_blocked) {
2117 					if (read) {
2118 						php_pollfd_for(sslsock->s.socket, (err == SSL_ERROR_WANT_WRITE) ?
2119 							(POLLOUT|POLLPRI) : (POLLIN|POLLPRI), has_timeout ? &left_time : NULL);
2120 					} else {
2121 						php_pollfd_for(sslsock->s.socket, (err == SSL_ERROR_WANT_READ) ?
2122 							(POLLIN|POLLPRI) : (POLLOUT|POLLPRI), has_timeout ? &left_time : NULL);
2123 					}
2124 				}
2125 			}
2126 
2127 			/* Finally, we keep going until we got data, and an SSL_ERROR_NONE, unless we had an error. */
2128 		} while (retry);
2129 
2130 		/* Tell PHP if we read / wrote bytes. */
2131 		if (nr_bytes > 0) {
2132 			php_stream_notify_progress_increment(PHP_STREAM_CONTEXT(stream), nr_bytes, 0);
2133 		}
2134 
2135 		/* And if we were originally supposed to be blocking, let's reset the socket to that. */
2136 		if (began_blocked && php_set_sock_blocking(sslsock->s.socket, 1) == SUCCESS) {
2137 			sslsock->s.is_blocked = 1;
2138 		}
2139 
2140 		return 0 > nr_bytes ? 0 : nr_bytes;
2141 	} else {
2142 		size_t nr_bytes = 0;
2143 
2144 		/* This block is if we had no timeout... We will just sit and wait forever on the IO operation. */
2145 		if (read) {
2146 			nr_bytes = php_stream_socket_ops.read(stream, buf, count);
2147 		} else {
2148 			nr_bytes = php_stream_socket_ops.write(stream, buf, count);
2149 		}
2150 
2151 		return nr_bytes;
2152 	}
2153 }
2154 /* }}} */
2155 
php_openssl_subtract_timeval(struct timeval a,struct timeval b)2156 static struct timeval php_openssl_subtract_timeval(struct timeval a, struct timeval b) /* {{{ */
2157 {
2158 	struct timeval difference;
2159 
2160 	difference.tv_sec  = a.tv_sec  - b.tv_sec;
2161 	difference.tv_usec = a.tv_usec - b.tv_usec;
2162 
2163 	if (a.tv_usec < b.tv_usec) {
2164 	  	b.tv_sec  -= 1L;
2165 	   	b.tv_usec += 1000000L;
2166 	}
2167 
2168 	return difference;
2169 }
2170 /* }}} */
2171 
php_openssl_compare_timeval(struct timeval a,struct timeval b)2172 static int php_openssl_compare_timeval( struct timeval a, struct timeval b )
2173 {
2174 	if (a.tv_sec > b.tv_sec || (a.tv_sec == b.tv_sec && a.tv_usec > b.tv_usec) ) {
2175 		return 1;
2176 	} else if( a.tv_sec == b.tv_sec && a.tv_usec == b.tv_usec ) {
2177 		return 0;
2178 	} else {
2179 		return -1;
2180 	}
2181 }
2182 
php_openssl_sockop_close(php_stream * stream,int close_handle)2183 static int php_openssl_sockop_close(php_stream *stream, int close_handle) /* {{{ */
2184 {
2185 	php_openssl_netstream_data_t *sslsock = (php_openssl_netstream_data_t*)stream->abstract;
2186 #ifdef PHP_WIN32
2187 	int n;
2188 #endif
2189 	unsigned i;
2190 
2191 	if (close_handle) {
2192 		if (sslsock->ssl_active) {
2193 			SSL_shutdown(sslsock->ssl_handle);
2194 			sslsock->ssl_active = 0;
2195 		}
2196 		if (sslsock->ssl_handle) {
2197 			SSL_free(sslsock->ssl_handle);
2198 			sslsock->ssl_handle = NULL;
2199 		}
2200 		if (sslsock->ctx) {
2201 			SSL_CTX_free(sslsock->ctx);
2202 			sslsock->ctx = NULL;
2203 		}
2204 #ifdef HAVE_TLS_ALPN
2205 		if (sslsock->alpn_ctx.data) {
2206 			pefree(sslsock->alpn_ctx.data, php_stream_is_persistent(stream));
2207 		}
2208 #endif
2209 #ifdef PHP_WIN32
2210 		if (sslsock->s.socket == -1)
2211 			sslsock->s.socket = SOCK_ERR;
2212 #endif
2213 		if (sslsock->s.socket != SOCK_ERR) {
2214 #ifdef PHP_WIN32
2215 			/* prevent more data from coming in */
2216 			shutdown(sslsock->s.socket, SHUT_RD);
2217 
2218 			/* try to make sure that the OS sends all data before we close the connection.
2219 			 * Essentially, we are waiting for the socket to become writeable, which means
2220 			 * that all pending data has been sent.
2221 			 * We use a small timeout which should encourage the OS to send the data,
2222 			 * but at the same time avoid hanging indefinitely.
2223 			 * */
2224 			do {
2225 				n = php_pollfd_for_ms(sslsock->s.socket, POLLOUT, 500);
2226 			} while (n == -1 && php_socket_errno() == EINTR);
2227 #endif
2228 			closesocket(sslsock->s.socket);
2229 			sslsock->s.socket = SOCK_ERR;
2230 		}
2231 	}
2232 
2233 	if (sslsock->sni_certs) {
2234 		for (i = 0; i < sslsock->sni_cert_count; i++) {
2235 			if (sslsock->sni_certs[i].ctx) {
2236 				SSL_CTX_free(sslsock->sni_certs[i].ctx);
2237 				pefree(sslsock->sni_certs[i].name, php_stream_is_persistent(stream));
2238 			}
2239 		}
2240 		pefree(sslsock->sni_certs, php_stream_is_persistent(stream));
2241 		sslsock->sni_certs = NULL;
2242 	}
2243 
2244 	if (sslsock->url_name) {
2245 		pefree(sslsock->url_name, php_stream_is_persistent(stream));
2246 	}
2247 
2248 	if (sslsock->reneg) {
2249 		pefree(sslsock->reneg, php_stream_is_persistent(stream));
2250 	}
2251 
2252 	pefree(sslsock, php_stream_is_persistent(stream));
2253 
2254 	return 0;
2255 }
2256 /* }}} */
2257 
php_openssl_sockop_flush(php_stream * stream)2258 static int php_openssl_sockop_flush(php_stream *stream) /* {{{ */
2259 {
2260 	return php_stream_socket_ops.flush(stream);
2261 }
2262 /* }}} */
2263 
php_openssl_sockop_stat(php_stream * stream,php_stream_statbuf * ssb)2264 static int php_openssl_sockop_stat(php_stream *stream, php_stream_statbuf *ssb) /* {{{ */
2265 {
2266 	return php_stream_socket_ops.stat(stream, ssb);
2267 }
2268 /* }}} */
2269 
php_openssl_tcp_sockop_accept(php_stream * stream,php_openssl_netstream_data_t * sock,php_stream_xport_param * xparam STREAMS_DC)2270 static inline int php_openssl_tcp_sockop_accept(php_stream *stream, php_openssl_netstream_data_t *sock,
2271 		php_stream_xport_param *xparam STREAMS_DC)  /* {{{ */
2272 {
2273 	int clisock;
2274 	zend_bool nodelay = 0;
2275 	zval *tmpzval = NULL;
2276 
2277 	xparam->outputs.client = NULL;
2278 
2279 	if (PHP_STREAM_CONTEXT(stream) &&
2280 		(tmpzval = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "socket", "tcp_nodelay")) != NULL &&
2281 		zend_is_true(tmpzval)) {
2282 		nodelay = 1;
2283 	}
2284 
2285 	clisock = php_network_accept_incoming(sock->s.socket,
2286 		xparam->want_textaddr ? &xparam->outputs.textaddr : NULL,
2287 		xparam->want_addr ? &xparam->outputs.addr : NULL,
2288 		xparam->want_addr ? &xparam->outputs.addrlen : NULL,
2289 		xparam->inputs.timeout,
2290 		xparam->want_errortext ? &xparam->outputs.error_text : NULL,
2291 		&xparam->outputs.error_code,
2292 		nodelay);
2293 
2294 	if (clisock >= 0) {
2295 		php_openssl_netstream_data_t *clisockdata = (php_openssl_netstream_data_t*) emalloc(sizeof(*clisockdata));
2296 
2297 		/* copy underlying tcp fields */
2298 		memset(clisockdata, 0, sizeof(*clisockdata));
2299 		memcpy(clisockdata, sock, sizeof(clisockdata->s));
2300 
2301 		clisockdata->s.socket = clisock;
2302 
2303 		xparam->outputs.client = php_stream_alloc_rel(stream->ops, clisockdata, NULL, "r+");
2304 		if (xparam->outputs.client) {
2305 			xparam->outputs.client->ctx = stream->ctx;
2306 			if (stream->ctx) {
2307 				GC_REFCOUNT(stream->ctx)++;
2308 			}
2309 		}
2310 
2311 		if (xparam->outputs.client && sock->enable_on_connect) {
2312 			/* remove the client bit */
2313 			if (sock->method & STREAM_CRYPTO_IS_CLIENT) {
2314 				sock->method = ((sock->method >> 1) << 1);
2315 			}
2316 
2317 			clisockdata->method = sock->method;
2318 
2319 			if (php_stream_xport_crypto_setup(xparam->outputs.client, clisockdata->method,
2320 					NULL) < 0 || php_stream_xport_crypto_enable(
2321 					xparam->outputs.client, 1) < 0) {
2322 				php_error_docref(NULL, E_WARNING, "Failed to enable crypto");
2323 
2324 				php_stream_close(xparam->outputs.client);
2325 				xparam->outputs.client = NULL;
2326 				xparam->outputs.returncode = -1;
2327 			}
2328 		}
2329 	}
2330 
2331 	return xparam->outputs.client == NULL ? -1 : 0;
2332 }
2333 /* }}} */
2334 
php_openssl_sockop_set_option(php_stream * stream,int option,int value,void * ptrparam)2335 static int php_openssl_sockop_set_option(php_stream *stream, int option, int value, void *ptrparam)  /* {{{ */
2336 {
2337 	php_openssl_netstream_data_t *sslsock = (php_openssl_netstream_data_t*)stream->abstract;
2338 	php_stream_xport_crypto_param *cparam = (php_stream_xport_crypto_param *)ptrparam;
2339 	php_stream_xport_param *xparam = (php_stream_xport_param *)ptrparam;
2340 
2341 	switch (option) {
2342 		case PHP_STREAM_OPTION_META_DATA_API:
2343 			if (sslsock->ssl_active) {
2344 				zval tmp;
2345 				char *proto_str;
2346 				char version_str[PHP_SSL_MAX_VERSION_LEN];
2347 				const SSL_CIPHER *cipher;
2348 
2349 				array_init(&tmp);
2350 
2351 				switch (SSL_version(sslsock->ssl_handle)) {
2352 #ifdef HAVE_TLS12
2353 					case TLS1_2_VERSION: proto_str = "TLSv1.2"; break;
2354 #endif
2355 #ifdef HAVE_TLS11
2356 					case TLS1_1_VERSION: proto_str = "TLSv1.1"; break;
2357 #endif
2358 					case TLS1_VERSION: proto_str = "TLSv1"; break;
2359 #ifdef HAVE_SSL3
2360 					case SSL3_VERSION: proto_str = "SSLv3"; break;
2361 #endif
2362 					default: proto_str = "UNKNOWN";
2363 				}
2364 
2365 				cipher = SSL_get_current_cipher(sslsock->ssl_handle);
2366 
2367 				add_assoc_string(&tmp, "protocol", proto_str);
2368 				add_assoc_string(&tmp, "cipher_name", (char *) SSL_CIPHER_get_name(cipher));
2369 				add_assoc_long(&tmp, "cipher_bits", SSL_CIPHER_get_bits(cipher, NULL));
2370 				add_assoc_string(&tmp, "cipher_version",
2371 						php_openssl_cipher_get_version(cipher, version_str, PHP_SSL_MAX_VERSION_LEN));
2372 
2373 #ifdef HAVE_TLS_ALPN
2374 				{
2375 					const unsigned char *alpn_proto = NULL;
2376 					unsigned int alpn_proto_len = 0;
2377 
2378 					SSL_get0_alpn_selected(sslsock->ssl_handle, &alpn_proto, &alpn_proto_len);
2379 					if (alpn_proto) {
2380 						add_assoc_stringl(&tmp, "alpn_protocol", (char *)alpn_proto, alpn_proto_len);
2381 					}
2382 				}
2383 #endif
2384 				add_assoc_zval((zval *)ptrparam, "crypto", &tmp);
2385 			}
2386 
2387 			add_assoc_bool((zval *)ptrparam, "timed_out", sslsock->s.timeout_event);
2388 			add_assoc_bool((zval *)ptrparam, "blocked", sslsock->s.is_blocked);
2389 			add_assoc_bool((zval *)ptrparam, "eof", stream->eof);
2390 
2391 			return PHP_STREAM_OPTION_RETURN_OK;
2392 
2393 		case PHP_STREAM_OPTION_CHECK_LIVENESS:
2394 			{
2395 				struct timeval tv;
2396 				char buf;
2397 				int alive = 1;
2398 
2399 				if (value == -1) {
2400 					if (sslsock->s.timeout.tv_sec == -1) {
2401 #ifdef _WIN32
2402 						tv.tv_sec = (long)FG(default_socket_timeout);
2403 #else
2404 						tv.tv_sec = (time_t)FG(default_socket_timeout);
2405 #endif
2406 						tv.tv_usec = 0;
2407 					} else {
2408 						tv = sslsock->connect_timeout;
2409 					}
2410 				} else {
2411 					tv.tv_sec = value;
2412 					tv.tv_usec = 0;
2413 				}
2414 
2415 				if (sslsock->s.socket == -1) {
2416 					alive = 0;
2417 				} else if (php_pollfd_for(sslsock->s.socket, PHP_POLLREADABLE|POLLPRI, &tv) > 0) {
2418 					if (sslsock->ssl_active) {
2419 						int n = SSL_peek(sslsock->ssl_handle, &buf, sizeof(buf));
2420 						if (n <= 0) {
2421 							int err = SSL_get_error(sslsock->ssl_handle, n);
2422 							switch (err) {
2423 								case SSL_ERROR_SYSCALL:
2424 									alive = php_socket_errno() == EAGAIN;
2425 									break;
2426 								case SSL_ERROR_WANT_READ:
2427 								case SSL_ERROR_WANT_WRITE:
2428 									alive = 1;
2429 									break;
2430 								default:
2431 									/* any other problem is a fatal error */
2432 									alive = 0;
2433 							}
2434 						}
2435 					} else if (0 == recv(sslsock->s.socket, &buf, sizeof(buf), MSG_PEEK) && php_socket_errno() != EAGAIN) {
2436 						alive = 0;
2437 					}
2438 				}
2439 				return alive ? PHP_STREAM_OPTION_RETURN_OK : PHP_STREAM_OPTION_RETURN_ERR;
2440 			}
2441 
2442 		case PHP_STREAM_OPTION_CRYPTO_API:
2443 
2444 			switch(cparam->op) {
2445 
2446 				case STREAM_XPORT_CRYPTO_OP_SETUP:
2447 					cparam->outputs.returncode = php_openssl_setup_crypto(stream, sslsock, cparam);
2448 					return PHP_STREAM_OPTION_RETURN_OK;
2449 					break;
2450 				case STREAM_XPORT_CRYPTO_OP_ENABLE:
2451 					cparam->outputs.returncode = php_openssl_enable_crypto(stream, sslsock, cparam);
2452 					return PHP_STREAM_OPTION_RETURN_OK;
2453 					break;
2454 				default:
2455 					/* fall through */
2456 					break;
2457 			}
2458 
2459 			break;
2460 
2461 		case PHP_STREAM_OPTION_XPORT_API:
2462 			switch(xparam->op) {
2463 
2464 				case STREAM_XPORT_OP_CONNECT:
2465 				case STREAM_XPORT_OP_CONNECT_ASYNC:
2466 					/* TODO: Async connects need to check the enable_on_connect option when
2467 					 * we notice that the connect has actually been established */
2468 					php_stream_socket_ops.set_option(stream, option, value, ptrparam);
2469 
2470 					if ((sslsock->enable_on_connect) &&
2471 						((xparam->outputs.returncode == 0) ||
2472 						(xparam->op == STREAM_XPORT_OP_CONNECT_ASYNC &&
2473 						xparam->outputs.returncode == 1 && xparam->outputs.error_code == EINPROGRESS)))
2474 					{
2475 						if (php_stream_xport_crypto_setup(stream, sslsock->method, NULL) < 0 ||
2476 								php_stream_xport_crypto_enable(stream, 1) < 0) {
2477 							php_error_docref(NULL, E_WARNING, "Failed to enable crypto");
2478 							xparam->outputs.returncode = -1;
2479 						}
2480 					}
2481 					return PHP_STREAM_OPTION_RETURN_OK;
2482 
2483 				case STREAM_XPORT_OP_ACCEPT:
2484 					/* we need to copy the additional fields that the underlying tcp transport
2485 					 * doesn't know about */
2486 					xparam->outputs.returncode = php_openssl_tcp_sockop_accept(stream, sslsock, xparam STREAMS_CC);
2487 
2488 
2489 					return PHP_STREAM_OPTION_RETURN_OK;
2490 
2491 				default:
2492 					/* fall through */
2493 					break;
2494 			}
2495 	}
2496 
2497 	return php_stream_socket_ops.set_option(stream, option, value, ptrparam);
2498 }
2499 /* }}} */
2500 
php_openssl_sockop_cast(php_stream * stream,int castas,void ** ret)2501 static int php_openssl_sockop_cast(php_stream *stream, int castas, void **ret)  /* {{{ */
2502 {
2503 	php_openssl_netstream_data_t *sslsock = (php_openssl_netstream_data_t*)stream->abstract;
2504 
2505 	switch(castas)	{
2506 		case PHP_STREAM_AS_STDIO:
2507 			if (sslsock->ssl_active) {
2508 				return FAILURE;
2509 			}
2510 			if (ret)	{
2511 				*ret = fdopen(sslsock->s.socket, stream->mode);
2512 				if (*ret) {
2513 					return SUCCESS;
2514 				}
2515 				return FAILURE;
2516 			}
2517 			return SUCCESS;
2518 
2519 		case PHP_STREAM_AS_FD_FOR_SELECT:
2520 			if (ret) {
2521 				size_t pending;
2522 				if (stream->writepos == stream->readpos
2523 					&& sslsock->ssl_active
2524 					&& (pending = (size_t)SSL_pending(sslsock->ssl_handle)) > 0) {
2525 						php_stream_fill_read_buffer(stream, pending < stream->chunk_size
2526 							? pending
2527 							: stream->chunk_size);
2528 				}
2529 
2530 				*(php_socket_t *)ret = sslsock->s.socket;
2531 			}
2532 			return SUCCESS;
2533 
2534 		case PHP_STREAM_AS_FD:
2535 		case PHP_STREAM_AS_SOCKETD:
2536 			if (sslsock->ssl_active) {
2537 				return FAILURE;
2538 			}
2539 			if (ret) {
2540 				*(php_socket_t *)ret = sslsock->s.socket;
2541 			}
2542 			return SUCCESS;
2543 		default:
2544 			return FAILURE;
2545 	}
2546 }
2547 /* }}} */
2548 
2549 php_stream_ops php_openssl_socket_ops = {
2550 	php_openssl_sockop_write, php_openssl_sockop_read,
2551 	php_openssl_sockop_close, php_openssl_sockop_flush,
2552 	"tcp_socket/ssl",
2553 	NULL, /* seek */
2554 	php_openssl_sockop_cast,
2555 	php_openssl_sockop_stat,
2556 	php_openssl_sockop_set_option,
2557 };
2558 
php_openssl_get_crypto_method(php_stream_context * ctx,zend_long crypto_method)2559 static zend_long php_openssl_get_crypto_method(
2560 		php_stream_context *ctx, zend_long crypto_method)  /* {{{ */
2561 {
2562 	zval *val;
2563 
2564 	if (ctx && (val = php_stream_context_get_option(ctx, "ssl", "crypto_method")) != NULL) {
2565 		convert_to_long_ex(val);
2566 		crypto_method = (zend_long)Z_LVAL_P(val);
2567 		crypto_method |= STREAM_CRYPTO_IS_CLIENT;
2568 	}
2569 
2570 	return crypto_method;
2571 }
2572 /* }}} */
2573 
php_openssl_get_url_name(const char * resourcename,size_t resourcenamelen,int is_persistent)2574 static char *php_openssl_get_url_name(const char *resourcename,
2575 		size_t resourcenamelen, int is_persistent)  /* {{{ */
2576 {
2577 	php_url *url;
2578 
2579 	if (!resourcename) {
2580 		return NULL;
2581 	}
2582 
2583 	url = php_url_parse_ex(resourcename, resourcenamelen);
2584 	if (!url) {
2585 		return NULL;
2586 	}
2587 
2588 	if (url->host) {
2589 		const char * host = url->host;
2590 		char * url_name = NULL;
2591 		size_t len = strlen(host);
2592 
2593 		/* skip trailing dots */
2594 		while (len && host[len-1] == '.') {
2595 			--len;
2596 		}
2597 
2598 		if (len) {
2599 			url_name = pestrndup(host, len, is_persistent);
2600 		}
2601 
2602 		php_url_free(url);
2603 		return url_name;
2604 	}
2605 
2606 	php_url_free(url);
2607 	return NULL;
2608 }
2609 /* }}} */
2610 
php_openssl_ssl_socket_factory(const char * proto,size_t protolen,const char * resourcename,size_t resourcenamelen,const char * persistent_id,int options,int flags,struct timeval * timeout,php_stream_context * context STREAMS_DC)2611 php_stream *php_openssl_ssl_socket_factory(const char *proto, size_t protolen,
2612 		const char *resourcename, size_t resourcenamelen,
2613 		const char *persistent_id, int options, int flags,
2614 		struct timeval *timeout,
2615 		php_stream_context *context STREAMS_DC) /* {{{ */
2616 {
2617 	php_stream *stream = NULL;
2618 	php_openssl_netstream_data_t *sslsock = NULL;
2619 
2620 	sslsock = pemalloc(sizeof(php_openssl_netstream_data_t), persistent_id ? 1 : 0);
2621 	memset(sslsock, 0, sizeof(*sslsock));
2622 
2623 	sslsock->s.is_blocked = 1;
2624 	/* this timeout is used by standard stream funcs, therefor it should use the default value */
2625 #ifdef _WIN32
2626 	sslsock->s.timeout.tv_sec = (long)FG(default_socket_timeout);
2627 #else
2628 	sslsock->s.timeout.tv_sec = (time_t)FG(default_socket_timeout);
2629 #endif
2630 	sslsock->s.timeout.tv_usec = 0;
2631 
2632 	/* use separate timeout for our private funcs */
2633 	sslsock->connect_timeout.tv_sec = timeout->tv_sec;
2634 	sslsock->connect_timeout.tv_usec = timeout->tv_usec;
2635 
2636 	/* we don't know the socket until we have determined if we are binding or
2637 	 * connecting */
2638 	sslsock->s.socket = -1;
2639 
2640 	/* Initialize context as NULL */
2641 	sslsock->ctx = NULL;
2642 
2643 	stream = php_stream_alloc_rel(&php_openssl_socket_ops, sslsock, persistent_id, "r+");
2644 
2645 	if (stream == NULL)	{
2646 		pefree(sslsock, persistent_id ? 1 : 0);
2647 		return NULL;
2648 	}
2649 
2650 	if (strncmp(proto, "ssl", protolen) == 0) {
2651 		sslsock->enable_on_connect = 1;
2652 		sslsock->method = php_openssl_get_crypto_method(context, STREAM_CRYPTO_METHOD_TLS_ANY_CLIENT);
2653 	} else if (strncmp(proto, "sslv2", protolen) == 0) {
2654 		php_error_docref(NULL, E_WARNING, "SSLv2 unavailable in this PHP version");
2655 		php_stream_close(stream);
2656 		return NULL;
2657 	} else if (strncmp(proto, "sslv3", protolen) == 0) {
2658 #ifdef HAVE_SSL3
2659 		sslsock->enable_on_connect = 1;
2660 		sslsock->method = STREAM_CRYPTO_METHOD_SSLv3_CLIENT;
2661 #else
2662 		php_error_docref(NULL, E_WARNING,
2663 			"SSLv3 support is not compiled into the OpenSSL library against which PHP is linked");
2664 		php_stream_close(stream);
2665 		return NULL;
2666 #endif
2667 	} else if (strncmp(proto, "tls", protolen) == 0) {
2668 		sslsock->enable_on_connect = 1;
2669 		sslsock->method = php_openssl_get_crypto_method(context, STREAM_CRYPTO_METHOD_TLS_ANY_CLIENT);
2670 	} else if (strncmp(proto, "tlsv1.0", protolen) == 0) {
2671 		sslsock->enable_on_connect = 1;
2672 		sslsock->method = STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT;
2673 	} else if (strncmp(proto, "tlsv1.1", protolen) == 0) {
2674 #ifdef HAVE_TLS11
2675 		sslsock->enable_on_connect = 1;
2676 		sslsock->method = STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT;
2677 #else
2678 		php_error_docref(NULL, E_WARNING,
2679 			"TLSv1.1 support is not compiled into the OpenSSL library against which PHP is linked");
2680 		php_stream_close(stream);
2681 		return NULL;
2682 #endif
2683 	} else if (strncmp(proto, "tlsv1.2", protolen) == 0) {
2684 #ifdef HAVE_TLS12
2685 		sslsock->enable_on_connect = 1;
2686 		sslsock->method = STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT;
2687 #else
2688 		php_error_docref(NULL, E_WARNING,
2689 			"TLSv1.2 support is not compiled into the OpenSSL library against which PHP is linked");
2690 		php_stream_close(stream);
2691 		return NULL;
2692 #endif
2693 	}
2694 
2695 	sslsock->url_name = php_openssl_get_url_name(resourcename, resourcenamelen, !!persistent_id);
2696 
2697 	return stream;
2698 }
2699 /* }}} */
2700 
2701 /*
2702  * Local variables:
2703  * tab-width: 4
2704  * c-basic-offset: 4
2705  * End:
2706  * vim600: noet sw=4 ts=4 fdm=marker
2707  * vim<600: noet sw=4 ts=4
2708  */
2709