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