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