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