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