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