31#include <openssl/ssl.h>
32#include <openssl/rsa.h>
33#include <openssl/x509.h>
34#include <openssl/x509v3.h>
35#include <openssl/err.h>
36#include <openssl/bn.h>
37#include <openssl/dh.h>
51# define MSG_DONTWAIT 0
54#ifdef HAVE_ARPA_INET_H
59#define STREAM_CRYPTO_IS_CLIENT (1<<0)
60#define STREAM_CRYPTO_METHOD_SSLv2 (1<<1)
61#define STREAM_CRYPTO_METHOD_SSLv3 (1<<2)
62#define STREAM_CRYPTO_METHOD_TLSv1_0 (1<<3)
63#define STREAM_CRYPTO_METHOD_TLSv1_1 (1<<4)
64#define STREAM_CRYPTO_METHOD_TLSv1_2 (1<<5)
65#define STREAM_CRYPTO_METHOD_TLSv1_3 (1<<6)
67#ifndef OPENSSL_NO_TLS1_METHOD
71#ifndef OPENSSL_NO_TLS1_1_METHOD
75#ifndef OPENSSL_NO_TLS1_2_METHOD
79#ifndef OPENSSL_NO_TLS1_3
83#ifndef OPENSSL_NO_ECDH
87#ifndef OPENSSL_NO_TLSEXT
89#define HAVE_TLS_ALPN 1
92#ifndef LIBRESSL_VERSION_NUMBER
93#define HAVE_SEC_LEVEL 1
96#ifndef OPENSSL_NO_SSL3
98#define PHP_OPENSSL_MIN_PROTO_VERSION STREAM_CRYPTO_METHOD_SSLv3
100#define PHP_OPENSSL_MIN_PROTO_VERSION STREAM_CRYPTO_METHOD_TLSv1_0
103#define PHP_OPENSSL_MAX_PROTO_VERSION STREAM_CRYPTO_METHOD_TLSv1_3
105#define PHP_OPENSSL_MAX_PROTO_VERSION STREAM_CRYPTO_METHOD_TLSv1_2
109#define GET_VER_OPT(_name) \
110 (PHP_STREAM_CONTEXT(stream) && (val = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "ssl", _name)) != NULL)
111#define GET_VER_OPT_STRING(_name, _str) \
113 if (GET_VER_OPT(_name)) { \
114 if (try_convert_to_string(val)) _str = Z_STRVAL_P(val); \
117#define GET_VER_OPT_STRINGL(_name, _str, _len) \
119 if (GET_VER_OPT(_name)) { \
120 if (try_convert_to_string(val)) { \
121 _str = Z_STRVAL_P(val); \
122 _len = Z_STRLEN_P(val); \
126#define GET_VER_OPT_LONG(_name, _num) \
127 if (GET_VER_OPT(_name)) _num = zval_get_long(val)
130#define PHP_X509_NAME_ENTRY_TO_UTF8(ne, i, out) \
131 ASN1_STRING_to_UTF8(&out, X509_NAME_ENTRY_get_data(X509_NAME_get_entry(ne, i)))
135#define EXPAND_IPV6_ADDRESS(_str, _bytes) \
137 snprintf(_str, 40, "%X:%X:%X:%X:%X:%X:%X:%X", \
138 _bytes[0] << 8 | _bytes[1], \
139 _bytes[2] << 8 | _bytes[3], \
140 _bytes[4] << 8 | _bytes[5], \
141 _bytes[6] << 8 | _bytes[7], \
142 _bytes[8] << 8 | _bytes[9], \
143 _bytes[10] << 8 | _bytes[11], \
144 _bytes[12] << 8 | _bytes[13], \
145 _bytes[14] << 8 | _bytes[15] \
148#define HAVE_IPV6_SAN 1
151#if PHP_OPENSSL_API_VERSION < 0x10100
152static RSA *php_openssl_tmp_rsa_cb(SSL *
s,
int is_export,
int keylength);
158static struct timeval php_openssl_subtract_timeval(struct timeval
a, struct timeval b);
159static int php_openssl_compare_timeval(
struct timeval
a,
struct timeval b);
160static ssize_t php_openssl_sockop_io(
int read,
php_stream *stream,
char *
buf,
size_t count);
213static int php_openssl_is_http_stream_talking_to_iis(
php_stream *stream)
222#define SERVER_MICROSOFT_IIS "Server: Microsoft-IIS"
223#define SERVER_GOOGLE "Server: GFE/"
237static int php_openssl_handle_ssl_error(
php_stream *stream,
int nr_bytes,
bool is_init)
240 int err = SSL_get_error(sslsock->ssl_handle, nr_bytes);
247 case SSL_ERROR_ZERO_RETURN:
251 case SSL_ERROR_WANT_READ:
252 case SSL_ERROR_WANT_WRITE:
256 retry = is_init ? 1 : sslsock->s.is_blocked;
258 case SSL_ERROR_SYSCALL:
259 if (ERR_peek_error() == 0) {
261 if (!php_openssl_is_http_stream_talking_to_iis(stream) && ERR_get_error() != 0) {
264 SSL_set_shutdown(sslsock->ssl_handle, SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN);
282 ecode = ERR_get_error();
284 switch (ERR_GET_REASON(ecode)) {
285 case SSL_R_NO_SHARED_CIPHER:
287 "SSL_R_NO_SHARED_CIPHER: no suitable shared cipher could be used. "
288 "This could be because the server is missing an SSL certificate "
289 "(local_cert context option)");
296 ERR_error_string_n(ecode, esbuf,
sizeof(esbuf));
298 smart_str_appendc(&ebuf,
'\n');
300 smart_str_appends(&ebuf, esbuf);
301 }
while ((ecode = ERR_get_error()) != 0);
306 "SSL operation failed with code %d. %s%s",
308 ebuf.
s ?
"OpenSSL Error messages:\n" :
"",
311 smart_str_free(&ebuf);
322static int verify_callback(
int preverify_ok, X509_STORE_CTX *ctx)
328 zend_ulong allowed_depth = OPENSSL_DEFAULT_STREAM_VERIFY_DEPTH;
334 err = X509_STORE_CTX_get_error(ctx);
335 depth = X509_STORE_CTX_get_error_depth(ctx);
338 ssl = X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
342 if (
err == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT &&
353 X509_STORE_CTX_set_error(ctx, X509_V_ERR_CERT_CHAIN_TOO_LONG);
360static int php_openssl_x509_fingerprint_cmp(X509 *peer,
const char *method,
const char *expected)
374static bool php_openssl_x509_fingerprint_match(X509 *peer,
zval *
val)
377 const char *method =
NULL;
389 return method && php_openssl_x509_fingerprint_cmp(peer, method,
Z_STRVAL_P(
val)) == 0;
412 "Invalid peer_fingerprint value; fingerprint string or array of the form [algo => fingerprint] required");
418static bool php_openssl_matches_wildcard_name(
const char *subjectname,
const char *certname)
420 char *wildcard =
NULL;
422 size_t suffix_len, subject_len;
429 if (!(wildcard =
strchr(certname,
'*')) || memchr(certname,
'.', wildcard - certname)) {
434 prefix_len = wildcard - certname;
435 if (prefix_len &&
strncasecmp(subjectname, certname, prefix_len) != 0) {
439 suffix_len =
strlen(wildcard + 1);
440 subject_len =
strlen(subjectname);
441 if (suffix_len <= subject_len) {
445 return strcasecmp(wildcard + 1, subjectname + subject_len - suffix_len) == 0 &&
446 memchr(subjectname + prefix_len,
'.', subject_len - suffix_len - prefix_len) ==
NULL;
453static bool php_openssl_matches_san_list(X509 *peer,
const char *subject_name)
456 unsigned char *cert_name =
NULL;
459 GENERAL_NAMES *alt_names = X509_get_ext_d2i(peer, NID_subject_alt_name, 0, 0);
460 int alt_name_count = sk_GENERAL_NAME_num(alt_names);
464 char subject_name_ipv6_expanded[40];
465 unsigned char ipv6[16];
466 bool subject_name_is_ipv6 =
false;
467 subject_name_ipv6_expanded[0] = 0;
470 EXPAND_IPV6_ADDRESS(subject_name_ipv6_expanded, ipv6);
471 subject_name_is_ipv6 =
true;
475 for (i = 0; i < alt_name_count; i++) {
476 GENERAL_NAME *san = sk_GENERAL_NAME_value(alt_names, i);
478 if (san->type == GEN_DNS) {
479 ASN1_STRING_to_UTF8(&cert_name, san->d.dNSName);
480 if ((
size_t)ASN1_STRING_length(san->d.dNSName) !=
strlen((
const char*)cert_name)) {
481 OPENSSL_free(cert_name);
488 if (
len &&
strcmp((
const char *)&cert_name[
len-1],
".") == 0) {
489 cert_name[
len-1] =
'\0';
492 if (php_openssl_matches_wildcard_name(subject_name, (
const char *)cert_name)) {
493 OPENSSL_free(cert_name);
494 sk_GENERAL_NAME_pop_free(alt_names, GENERAL_NAME_free);
498 OPENSSL_free(cert_name);
499 }
else if (san->type == GEN_IPADD) {
500 if (san->d.iPAddress->length == 4) {
501 snprintf(ipbuffer,
sizeof(ipbuffer),
"%d.%d.%d.%d",
502 san->d.iPAddress->data[0],
503 san->d.iPAddress->data[1],
504 san->d.iPAddress->data[2],
505 san->d.iPAddress->data[3]
507 if (
strcasecmp(subject_name, (
const char*)ipbuffer) == 0) {
508 sk_GENERAL_NAME_pop_free(alt_names, GENERAL_NAME_free);
514 else if (san->d.ip->length == 16 && subject_name_is_ipv6) {
516 EXPAND_IPV6_ADDRESS(ipbuffer, san->d.iPAddress->data);
517 if (
strcasecmp((
const char*)subject_name_ipv6_expanded, (
const char*)ipbuffer) == 0) {
518 sk_GENERAL_NAME_pop_free(alt_names, GENERAL_NAME_free);
527 sk_GENERAL_NAME_pop_free(alt_names, GENERAL_NAME_free);
533static bool php_openssl_matches_common_name(X509 *peer,
const char *subject_name)
536 X509_NAME *cert_name;
540 cert_name = X509_get_subject_name(peer);
541 cert_name_len = X509_NAME_get_text_by_NID(cert_name, NID_commonName,
buf,
sizeof(
buf));
543 if (cert_name_len == -1) {
545 }
else if ((
size_t)cert_name_len !=
strlen(
buf)) {
547 }
else if (php_openssl_matches_wildcard_name(subject_name,
buf)) {
551 "Peer certificate CN=`%.*s' did not match expected CN=`%s'",
552 cert_name_len,
buf, subject_name);
559static zend_result php_openssl_apply_peer_verification_policy(SSL *ssl, X509 *peer,
php_stream *stream)
562 zval *peer_fingerprint;
563 char *peer_name =
NULL;
566 must_verify_peer_name,
567 must_verify_fingerprint;
573 : sslsock->is_client;
575 must_verify_peer_name =
GET_VER_OPT(
"verify_peer_name")
577 : sslsock->is_client;
579 must_verify_fingerprint =
GET_VER_OPT(
"peer_fingerprint");
580 peer_fingerprint =
val;
582 if ((must_verify_peer || must_verify_peer_name || must_verify_fingerprint) && peer ==
NULL) {
588 if (must_verify_peer) {
589 err = SSL_get_verify_result(ssl);
594 case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
603 "Could not verify peer: code:%d %s",
605 X509_verify_cert_error_string(
err)
612 if (must_verify_fingerprint) {
614 if (!php_openssl_x509_fingerprint_match(peer, peer_fingerprint)) {
616 "peer_fingerprint match failure"
622 "Expected peer fingerprint must be a string or an array"
629 if (must_verify_peer_name) {
633 if (peer_name ==
NULL && sslsock->is_client) {
634 peer_name = sslsock->url_name;
638 if (php_openssl_matches_san_list(peer, peer_name)) {
640 }
else if (php_openssl_matches_common_name(peer, peer_name)) {
654static int php_openssl_passwd_callback(
char *
buf,
int num,
int verify,
void *
data)
658 char *passphrase =
NULL;
674#define RETURN_CERT_VERIFY_FAILURE(code) X509_STORE_CTX_set_error(x509_store_ctx, code); return 0;
675static int php_openssl_win_cert_verify_callback(X509_STORE_CTX *x509_store_ctx,
void *
arg)
677 PCCERT_CONTEXT cert_ctx =
NULL;
678 PCCERT_CHAIN_CONTEXT cert_chain_ctx =
NULL;
679 X509 *cert = X509_STORE_CTX_get0_cert(x509_store_ctx);
684 bool is_self_signed = 0;
691 unsigned char *der_buf =
NULL;
694 der_len = i2d_X509(cert, &der_buf);
696 unsigned long err_code, e;
699 while ((e = ERR_get_error()) != 0) {
704 RETURN_CERT_VERIFY_FAILURE(SSL_R_CERTIFICATE_VERIFY_FAILED);
707 cert_ctx = CertCreateCertificateContext(X509_ASN_ENCODING, der_buf, der_len);
708 OPENSSL_free(der_buf);
710 if (cert_ctx ==
NULL) {
714 RETURN_CERT_VERIFY_FAILURE(SSL_R_CERTIFICATE_VERIFY_FAILED);
719 CERT_ENHKEY_USAGE enhkey_usage = {0};
720 CERT_USAGE_MATCH cert_usage = {0};
721 CERT_CHAIN_PARA chain_params = {
sizeof(CERT_CHAIN_PARA)};
722 LPSTR usages[] = {szOID_PKIX_KP_SERVER_AUTH, szOID_SERVER_GATED_CRYPTO, szOID_SGC_NETSCAPE};
723 DWORD chain_flags = 0;
724 unsigned long allowed_depth = OPENSSL_DEFAULT_STREAM_VERIFY_DEPTH;
727 enhkey_usage.cUsageIdentifier = 3;
728 enhkey_usage.rgpszUsageIdentifier = usages;
729 cert_usage.dwType = USAGE_MATCH_TYPE_OR;
730 cert_usage.Usage = enhkey_usage;
731 chain_params.RequestedUsage = cert_usage;
732 chain_flags = CERT_CHAIN_CACHE_END_CERT | CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT;
734 if (!CertGetCertificateChain(
NULL, cert_ctx,
NULL,
NULL, &chain_params, chain_flags,
NULL, &cert_chain_ctx)) {
738 CertFreeCertificateContext(cert_ctx);
739 RETURN_CERT_VERIFY_FAILURE(SSL_R_CERTIFICATE_VERIFY_FAILED);
743 if (cert_chain_ctx->cChain > 0 && cert_chain_ctx->rgpChain[0]->cElement > 0
744 && (cert_chain_ctx->rgpChain[0]->rgpElement[0]->TrustStatus.dwInfoStatus & CERT_TRUST_IS_SELF_SIGNED) != 0) {
751 for (i = 0; i < cert_chain_ctx->cChain; i++) {
752 if (cert_chain_ctx->rgpChain[i]->cElement > allowed_depth) {
753 CertFreeCertificateChain(cert_chain_ctx);
754 CertFreeCertificateContext(cert_ctx);
755 RETURN_CERT_VERIFY_FAILURE(X509_V_ERR_CERT_CHAIN_TOO_LONG);
761 SSL_EXTRA_CERT_CHAIN_POLICY_PARA ssl_policy_params = {
sizeof(SSL_EXTRA_CERT_CHAIN_POLICY_PARA)};
762 CERT_CHAIN_POLICY_PARA chain_policy_params = {
sizeof(CERT_CHAIN_POLICY_PARA)};
763 CERT_CHAIN_POLICY_STATUS chain_policy_status = {
sizeof(CERT_CHAIN_POLICY_STATUS)};
766 ssl_policy_params.dwAuthType = (sslsock->is_client) ? AUTHTYPE_SERVER : AUTHTYPE_CLIENT;
769 ssl_policy_params.pwszServerName =
NULL;
770 chain_policy_params.pvExtraPolicyPara = &ssl_policy_params;
772 verify_result = CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_SSL, cert_chain_ctx, &chain_policy_params, &chain_policy_status);
774 CertFreeCertificateChain(cert_chain_ctx);
775 CertFreeCertificateContext(cert_ctx);
777 if (!verify_result) {
781 RETURN_CERT_VERIFY_FAILURE(SSL_R_CERTIFICATE_VERIFY_FAILED);
784 if (chain_policy_status.dwError != 0) {
786 if (is_self_signed && chain_policy_status.dwError == CERT_E_UNTRUSTEDROOT
789 X509_STORE_CTX_set_error(x509_store_ctx, X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT);
791 RETURN_CERT_VERIFY_FAILURE(SSL_R_CERTIFICATE_VERIFY_FAILED);
801static long php_openssl_load_stream_cafile(X509_STORE *cert_store,
const char *cafile)
806 int buffer_active = 0;
809 long certs_added = 0;
813 if (stream ==
NULL) {
825 goto stream_complete;
826 }
else if (!
strcmp(
line,
"-----BEGIN CERTIFICATE-----\n") ||
827 !
strcmp(
line,
"-----BEGIN CERTIFICATE-----\r\n")
829 buffer = BIO_new(BIO_s_mem());
843 goto stream_complete;
844 }
else if (!
strcmp(
line,
"-----END CERTIFICATE-----") ||
845 !
strcmp(
line,
"-----END CERTIFICATE-----\n") ||
846 !
strcmp(
line,
"-----END CERTIFICATE-----\r\n")
860 if (cert && X509_STORE_add_cert(cert_store, cert)) {
869 if (buffer_active == 1) {
874 if (certs_added == 0) {
892 if (cafile ==
NULL) {
893 cafile =
zend_ini_string(
"openssl.cafile",
sizeof(
"openssl.cafile")-1, 0);
895 }
else if (!sslsock->is_client) {
897 STACK_OF(X509_NAME) *cert_names = SSL_load_client_CA_file(cafile);
898 if (cert_names !=
NULL) {
899 SSL_CTX_set_client_CA_list(ctx, cert_names);
906 if (capath ==
NULL) {
907 capath =
zend_ini_string(
"openssl.capath",
sizeof(
"openssl.capath")-1, 0);
911 if (cafile || capath) {
912 if (!SSL_CTX_load_verify_locations(ctx, cafile, capath)) {
914 if (cafile && !php_openssl_load_stream_cafile(SSL_CTX_get_cert_store(ctx), cafile)) {
920 SSL_CTX_set_cert_verify_callback(ctx, php_openssl_win_cert_verify_callback, (
void *)stream);
922 if (sslsock->is_client && !SSL_CTX_set_default_verify_paths(ctx)) {
924 "Unable to set default verify locations and no CA settings specified");
930 SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, verify_callback);
936static void php_openssl_disable_peer_verification(SSL_CTX *ctx,
php_stream *stream)
938 SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE,
NULL);
945 char *certfile =
NULL;
952 const char *private_key =
NULL;
953 size_t private_key_len;
956 certfile, certfile_len, resolved_path_buff, 0,
false,
false,
957 "local_cert in ssl stream context")) {
962 if (SSL_CTX_use_certificate_chain_file(ctx, resolved_path_buff) != 1) {
964 "Unable to set local cert chain file `%s'; Check that your cafile/capath "
965 "settings include details of your certificate and its issuer",
972 private_key, private_key_len, resolved_path_buff, 0,
false,
false,
973 "local_pk in ssl stream context")) {
977 if (SSL_CTX_use_PrivateKey_file(ctx, resolved_path_buff, SSL_FILETYPE_PEM) != 1) {
981 if (!SSL_CTX_check_private_key(ctx)) {
990#if PHP_OPENSSL_API_VERSION < 0x10100
991static int php_openssl_get_crypto_method_ctx_flags(
int method_flags)
993 int ssl_ctx_options = SSL_OP_ALL;
995#ifdef SSL_OP_NO_SSLv2
996 ssl_ctx_options |= SSL_OP_NO_SSLv2;
1000 ssl_ctx_options |= SSL_OP_NO_SSLv3;
1005 ssl_ctx_options |= SSL_OP_NO_TLSv1;
1010 ssl_ctx_options |= SSL_OP_NO_TLSv1_1;
1015 ssl_ctx_options |= SSL_OP_NO_TLSv1_2;
1020 ssl_ctx_options |= SSL_OP_NO_TLSv1_3;
1024 return ssl_ctx_options;
1029static inline int php_openssl_get_min_proto_version_flag(
int flags)
1041static inline int php_openssl_get_max_proto_version_flag(
int flags)
1053#if PHP_OPENSSL_API_VERSION >= 0x10100
1054static inline int php_openssl_map_proto_version(
int flag)
1059 return TLS1_3_VERSION;
1062 return TLS1_2_VERSION;
1064 return TLS1_1_VERSION;
1066 return TLS1_VERSION;
1069 return SSL3_VERSION;
1072 return TLS1_2_VERSION;
1077static int php_openssl_get_min_proto_version(
int flags)
1079 return php_openssl_map_proto_version(php_openssl_get_min_proto_version_flag(
flags));
1083static int php_openssl_get_max_proto_version(
int flags)
1085 return php_openssl_map_proto_version(php_openssl_get_max_proto_version_flag(
flags));
1090static int php_openssl_get_proto_version_flags(
int flags,
int min,
int max)
1095 min = php_openssl_get_min_proto_version_flag(
flags);
1098 max = php_openssl_get_max_proto_version_flag(
flags);
1102 if (ver >=
min && ver <=
max) {
1103 if (!(
flags & ver)) {
1106 }
else if (
flags & ver) {
1115static void php_openssl_limit_handshake_reneg(
const SSL *ssl)
1127 if (sslsock->reneg->prev_handshake == 0) {
1128 sslsock->reneg->prev_handshake =
now.tv_sec;
1132 elapsed_time = (
now.tv_sec - sslsock->reneg->prev_handshake);
1133 sslsock->reneg->prev_handshake =
now.tv_sec;
1134 sslsock->reneg->tokens -= (elapsed_time * (sslsock->reneg->limit / sslsock->reneg->window));
1136 if (sslsock->reneg->tokens < 0) {
1137 sslsock->reneg->tokens = 0;
1139 ++sslsock->reneg->tokens;
1142 if (sslsock->reneg->tokens > sslsock->reneg->limit) {
1146 sslsock->reneg->should_close = 1;
1149 "ssl",
"reneg_limit_callback")) !=
NULL
1164 sslsock->reneg->should_close = 0;
1170 "SSL: client-initiated handshake rate limit exceeded by peer");
1176static void php_openssl_info_callback(
const SSL *ssl,
int where,
int ret)
1179 if (where & SSL_CB_HANDSHAKE_START) {
1180 php_openssl_limit_handshake_reneg(ssl);
1188 zend_long limit = OPENSSL_DEFAULT_RENEG_LIMIT;
1189 zend_long window = OPENSSL_DEFAULT_RENEG_WINDOW;
1194 limit = zval_get_long(
val);
1205 window = zval_get_long(
val);
1218 SSL_set_info_callback(sslsock->
ssl_handle, php_openssl_info_callback);
1222#if PHP_OPENSSL_API_VERSION < 0x10100
1223static RSA *php_openssl_tmp_rsa_cb(SSL *
s,
int is_export,
int keylength)
1226 static RSA *rsa_tmp =
NULL;
1228 if (!rsa_tmp && ((bn = BN_new()) ==
NULL)) {
1231 if (!rsa_tmp && bn) {
1232 if (!BN_set_word(bn, RSA_F4) || ((rsa_tmp = RSA_new()) ==
NULL) ||
1233 !RSA_generate_key_ex(rsa_tmp, keylength, bn,
NULL)) {
1249 if (zdhpath ==
NULL) {
1254 SSL_CTX_set_dh_auto(ctx, 1);
1259 if (!try_convert_to_string(zdhpath)) {
1270#if PHP_OPENSSL_API_VERSION >= 0x30000
1271 EVP_PKEY *pkey = PEM_read_bio_Parameters(bio,
NULL);
1279 if (SSL_CTX_set0_tmp_dh_pkey(ctx, pkey) == 0) {
1281 EVP_PKEY_free(pkey);
1293 if (SSL_CTX_set_tmp_dh(ctx, dh) == 0) {
1306#if defined(HAVE_ECDH) && PHP_OPENSSL_API_VERSION < 0x10100
1314 if (zvcurve ==
NULL) {
1315 SSL_CTX_set_ecdh_auto(ctx, 1);
1318 if (!try_convert_to_string(zvcurve)) {
1323 if (curve_nid == NID_undef) {
1329 ecdh = EC_KEY_new_by_curve_name(curve_nid);
1335 SSL_CTX_set_tmp_ecdh(ctx, ecdh);
1346 long ssl_ctx_options = SSL_CTX_get_options(ctx);
1348#if defined(HAVE_ECDH) && PHP_OPENSSL_API_VERSION < 0x10100
1349 if (php_openssl_set_server_ecdh_curve(stream, ctx) ==
FAILURE) {
1354#if PHP_OPENSSL_API_VERSION < 0x10100
1355 SSL_CTX_set_tmp_rsa_callback(ctx, php_openssl_tmp_rsa_cb);
1362 if (php_openssl_set_server_dh_param(stream, ctx) ==
FAILURE) {
1368 ssl_ctx_options |= SSL_OP_SINGLE_DH_USE;
1373 ssl_ctx_options |= SSL_OP_CIPHER_SERVER_PREFERENCE;
1376 SSL_CTX_set_options(ctx, ssl_ctx_options);
1383static int php_openssl_server_sni_callback(SSL *ssl_handle,
int *al,
void *
arg)
1388 const char *server_name;
1390 server_name = SSL_get_servername(ssl_handle, TLSEXT_NAMETYPE_host_name);
1393 return SSL_TLSEXT_ERR_NOACK;
1400 return SSL_TLSEXT_ERR_NOACK;
1404 if (php_openssl_matches_wildcard_name(server_name, sslsock->
sni_certs[i].
name)) {
1405 SSL_set_SSL_CTX(ssl_handle, sslsock->
sni_certs[i].
ctx);
1406 return SSL_TLSEXT_ERR_OK;
1410 return SSL_TLSEXT_ERR_NOACK;
1414static SSL_CTX *php_openssl_create_sni_server_ctx(
char *cert_path,
char *key_path)
1418 SSL_CTX *ctx = SSL_CTX_new(SSLv23_server_method());
1420 if (SSL_CTX_use_certificate_chain_file(ctx, cert_path) != 1) {
1422 "Failed setting local cert chain file `%s'; " \
1423 "check that your cafile/capath settings include " \
1424 "details of your certificate and its issuer",
1429 }
else if (SSL_CTX_use_PrivateKey_file(ctx, key_path, SSL_FILETYPE_PEM) != 1) {
1431 "Failed setting private key from file `%s'",
1464 "SNI_server_certs requires an array mapping host names to cert paths"
1472 "SNI_server_certs host cert array must not be empty"
1487 "SNI_server_certs array requires string host name keys"
1493 zval *local_pk, *local_cert;
1498 if (local_cert ==
NULL) {
1500 "local_cert not present in the array"
1505 local_cert_str = zval_try_get_string(local_cert);
1509 if (!php_openssl_check_path_str_ex(
1510 local_cert_str, resolved_cert_path_buff, 0,
false,
false,
1511 "SNI_server_certs local_cert in ssl stream context")) {
1513 "Failed setting local cert chain file `%s'; could not open file",
1516 zend_string_release(local_cert_str);
1519 zend_string_release(local_cert_str);
1522 if (local_pk ==
NULL) {
1524 "local_pk not present in the array"
1529 local_pk_str = zval_try_get_string(local_pk);
1533 if (!php_openssl_check_path_str_ex(
1534 local_pk_str, resolved_pk_path_buff, 0,
false,
false,
1535 "SNI_server_certs local_pk in ssl stream context")) {
1537 "Failed setting local private key file `%s'; could not open file",
1540 zend_string_release(local_pk_str);
1543 zend_string_release(local_pk_str);
1545 ctx = php_openssl_create_sni_server_ctx(resolved_cert_path_buff, resolved_pk_path_buff);
1547 }
else if (php_openssl_check_path_str_ex(
1549 "SNI_server_certs in ssl stream context")) {
1550 ctx = php_openssl_create_sni_server_ctx(resolved_path_buff, resolved_path_buff);
1553 "Failed setting local cert chain file `%s'; file not found",
1569 SSL_CTX_set_tlsext_servername_callback(sslsock->
ctx, php_openssl_server_sni_callback);
1578 char *sni_server_name;
1585 sni_server_name = sslsock->
url_name;
1589 if (sni_server_name) {
1590 SSL_set_tlsext_host_name(sslsock->
ssl_handle, sni_server_name);
1605static unsigned char *php_openssl_alpn_protos_parse(
unsigned short *outlen,
const char *in)
1609 size_t i,
start = 0;
1618 for (i = 0; i <=
len; ++i) {
1619 if (i ==
len || in[i] ==
',') {
1620 if (i -
start > 255) {
1637static int php_openssl_server_alpn_callback(SSL *ssl_handle,
1638 const unsigned char **
out,
unsigned char *outlen,
1639 const unsigned char *in,
unsigned int inlen,
void *
arg)
1643 if (SSL_select_next_proto((
unsigned char **)
out, outlen, sslsock->
alpn_ctx.
data, sslsock->
alpn_ctx.
len, in, inlen) != OPENSSL_NPN_NEGOTIATED) {
1644 return SSL_TLSEXT_ERR_NOACK;
1647 return SSL_TLSEXT_ERR_OK;
1657 const SSL_METHOD *method;
1658 int ssl_ctx_options;
1662 char *cipherlist =
NULL;
1663 char *alpn_protocols =
NULL;
1682 method = sslsock->
is_client ? SSLv23_client_method() : SSLv23_server_method();
1683 sslsock->
ctx = SSL_CTX_new(method);
1692 method_flags = php_openssl_get_proto_version_flags(method_flags, min_version, max_version);
1693#if PHP_OPENSSL_API_VERSION < 0x10100
1694 ssl_ctx_options = php_openssl_get_crypto_method_ctx_flags(method_flags);
1696 ssl_ctx_options = SSL_OP_ALL;
1700 ssl_ctx_options |= SSL_OP_NO_TICKET;
1703 ssl_ctx_options &= ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS;
1705#ifdef SSL_OP_IGNORE_UNEXPECTED_EOF
1707 ssl_ctx_options |= SSL_OP_IGNORE_UNEXPECTED_EOF;
1711 ssl_ctx_options |= SSL_OP_NO_COMPRESSION;
1715 php_openssl_disable_peer_verification(sslsock->
ctx, stream);
1716 }
else if (
FAILURE == php_openssl_enable_peer_verification(sslsock->
ctx, stream)) {
1722 SSL_CTX_set_default_passwd_cb_userdata(sslsock->
ctx, stream);
1723 SSL_CTX_set_default_passwd_cb(sslsock->
ctx, php_openssl_passwd_callback);
1727#ifndef USE_OPENSSL_SYSTEM_CIPHERS
1733 if (SSL_CTX_set_cipher_list(sslsock->
ctx, cipherlist) != 1) {
1740 if (lval < 0 || lval > 5) {
1743#ifdef HAVE_SEC_LEVEL
1744 SSL_CTX_set_security_level(sslsock->
ctx, lval);
1749 if (alpn_protocols) {
1752 unsigned short alpn_len;
1753 unsigned char *alpn = php_openssl_alpn_protos_parse(&alpn_len, alpn_protocols);
1757 SSL_CTX_free(sslsock->
ctx);
1762 SSL_CTX_set_alpn_protos(sslsock->
ctx, alpn, alpn_len);
1766 SSL_CTX_set_alpn_select_cb(sslsock->
ctx, php_openssl_server_alpn_callback, sslsock);
1773 "alpn_protocols support is not compiled into the OpenSSL library against which PHP is linked");
1777 if (
FAILURE == php_openssl_set_local_cert(sslsock->
ctx, stream)) {
1781 SSL_CTX_set_options(sslsock->
ctx, ssl_ctx_options);
1783#if PHP_OPENSSL_API_VERSION >= 0x10100
1784 SSL_CTX_set_min_proto_version(sslsock->
ctx, php_openssl_get_min_proto_version(method_flags));
1785 SSL_CTX_set_max_proto_version(sslsock->
ctx, php_openssl_get_max_proto_version(method_flags));
1790 FAILURE == php_openssl_set_server_specific_opts(stream, sslsock->
ctx)
1799 SSL_CTX_free(sslsock->
ctx);
1813 php_openssl_handle_ssl_error(stream, 0, 1);
1818 if (!sslsock->
is_client && php_openssl_enable_server_sni(stream, sslsock) ==
FAILURE) {
1825 php_openssl_init_server_reneg_limit(stream, sslsock);
1828#ifdef SSL_MODE_RELEASE_BUFFERS
1829 SSL_set_mode(sslsock->
ssl_handle, SSL_MODE_RELEASE_BUFFERS);
1846static int php_openssl_capture_peer_certs(
php_stream *stream,
1850 php_openssl_certificate_object *cert_object;
1851 int cert_captured = 0;
1854 "ssl",
"capture_peer_cert")) &&
1858 cert_object = Z_OPENSSL_CERTIFICATE_P(&zcert);
1859 cert_object->x509 = peer_cert;
1867 "ssl",
"capture_peer_cert_chain")) &&
1871 STACK_OF(X509) *chain;
1873 chain = SSL_get_peer_cert_chain(sslsock->
ssl_handle);
1875 if (chain && sk_X509_num(chain) > 0) {
1879 for (i = 0; i < sk_X509_num(chain); i++) {
1880 X509 *mycert = X509_dup(sk_X509_value(chain, i));
1883 cert_object = Z_OPENSSL_CERTIFICATE_P(&zcert);
1884 cert_object->x509 = mycert;
1885 add_next_index_zval(&arr, &zcert);
1896 return cert_captured;
1909static int php_openssl_enable_crypto(
php_stream *stream,
1915 int cert_captured = 0;
1919 struct timeval start_time, *timeout;
1920 int blocked = sslsock->
s.
is_blocked, has_timeout = 0;
1924 php_openssl_enable_client_sni(stream, sslsock);
1937 if (
SUCCESS == php_openssl_set_blocking(sslsock, 0)) {
1940 SSL_set_mode(sslsock->
ssl_handle, SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
1944 has_timeout = !sslsock->
s.
is_blocked && (timeout->tv_sec > 0 || (timeout->tv_sec == 0 && timeout->tv_usec));
1951 struct timeval cur_time, elapsed_time;
1962 elapsed_time = php_openssl_subtract_timeval(cur_time, start_time);
1964 if (php_openssl_compare_timeval( elapsed_time, *timeout) > 0) {
1972 retry = php_openssl_handle_ssl_error(stream,
n, blocked);
1977 struct timeval left_time;
1980 left_time = php_openssl_subtract_timeval(*timeout, elapsed_time);
1982 php_pollfd_for(sslsock->
s.
socket, (
err == SSL_ERROR_WANT_READ) ?
1991 php_openssl_set_blocking(sslsock, blocked);
1995 peer_cert = SSL_get_peer_certificate(sslsock->
ssl_handle);
1997 cert_captured = php_openssl_capture_peer_certs(stream, sslsock, peer_cert);
2000 if (
FAILURE == php_openssl_apply_peer_verification_policy(sslsock->
ssl_handle, peer_cert, stream)) {
2011 peer_cert = SSL_get_peer_certificate(sslsock->
ssl_handle);
2013 cert_captured = php_openssl_capture_peer_certs(stream, sslsock, peer_cert);
2017 if (
n && peer_cert && cert_captured == 0) {
2018 X509_free(peer_cert);
2035 return php_openssl_sockop_io( 1, stream,
buf,
count );
2039static ssize_t php_openssl_sockop_write(
php_stream *stream,
const char *
buf,
size_t count)
2041 return php_openssl_sockop_io( 0, stream, (
char*)
buf,
count );
2051static ssize_t php_openssl_sockop_io(
int read,
php_stream *stream,
char *
buf,
size_t count)
2058 struct timeval start_time;
2059 struct timeval *timeout =
NULL;
2061 int has_timeout = 0;
2070 if (began_blocked) {
2075 php_openssl_set_blocking(sslsock, 0);
2078 if (!sslsock->
s.
is_blocked && timeout && (timeout->tv_sec > 0 || (timeout->tv_sec == 0 && timeout->tv_usec))) {
2086 struct timeval cur_time, elapsed_time, left_time;
2093 elapsed_time = php_openssl_subtract_timeval(cur_time, start_time);
2096 if (php_openssl_compare_timeval(elapsed_time, *timeout) > 0 ) {
2098 if (began_blocked) {
2099 php_openssl_set_blocking(sslsock, 1);
2124 left_time = php_openssl_subtract_timeval( *timeout, elapsed_time );
2128 if (nr_bytes <= 0) {
2132 retry = php_openssl_handle_ssl_error(stream, nr_bytes, 0);
2138 if (
errno ==
EAGAIN &&
err == SSL_ERROR_WANT_WRITE && read == 0) {
2148 if (began_blocked == 0) {
2157 php_pollfd_for(sslsock->
s.
socket, (
err == SSL_ERROR_WANT_WRITE) ?
2160 php_pollfd_for(sslsock->
s.
socket, (
err == SSL_ERROR_WANT_READ) ?
2169 if (
err == SSL_ERROR_NONE) {
2174 if (began_blocked) {
2176 php_pollfd_for(sslsock->
s.
socket, (
err == SSL_ERROR_WANT_WRITE) ?
2179 php_pollfd_for(sslsock->
s.
socket, (
err == SSL_ERROR_WANT_READ) ?
2194 if (began_blocked) {
2195 php_openssl_set_blocking(sslsock, 1);
2198 return 0 > nr_bytes ? 0 : nr_bytes;
2200 size_t nr_bytes = 0;
2214static struct timeval php_openssl_subtract_timeval(struct timeval
a, struct timeval b)
2216 struct timeval difference;
2218 difference.tv_sec =
a.tv_sec - b.tv_sec;
2219 difference.tv_usec =
a.tv_usec - b.tv_usec;
2221 if (
a.tv_usec < b.tv_usec) {
2222 difference.tv_sec -= 1L;
2223 difference.tv_usec += 1000000L;
2230static int php_openssl_compare_timeval(
struct timeval
a,
struct timeval b )
2232 if (
a.tv_sec > b.tv_sec || (
a.tv_sec == b.tv_sec &&
a.tv_usec > b.tv_usec) ) {
2234 }
else if(
a.tv_sec == b.tv_sec &&
a.tv_usec == b.tv_usec ) {
2241static int php_openssl_sockop_close(
php_stream *stream,
int close_handle)
2259 SSL_CTX_free(sslsock->
ctx);
2306 if (sslsock->
reneg) {
2316static int php_openssl_sockop_flush(
php_stream *stream)
2335 xparam->outputs.client =
NULL;
2344 xparam->want_textaddr ? &xparam->outputs.textaddr :
NULL,
2345 xparam->want_addr ? &xparam->outputs.addr :
NULL,
2346 xparam->want_addr ? &xparam->outputs.addrlen :
NULL,
2347 xparam->inputs.timeout,
2348 xparam->want_errortext ? &xparam->outputs.error_text :
NULL,
2349 &xparam->outputs.error_code,
2356 memset(clisockdata, 0,
sizeof(*clisockdata));
2357 memcpy(clisockdata, sock,
sizeof(clisockdata->
s));
2359 clisockdata->
s.
socket = clisock;
2366 if (xparam->outputs.client) {
2367 xparam->outputs.client->ctx = stream->
ctx;
2381 xparam->outputs.client, 1) < 0) {
2385 xparam->outputs.client =
NULL;
2386 xparam->outputs.returncode = -1;
2391 return xparam->outputs.client ==
NULL ? -1 : 0;
2395static int php_openssl_sockop_set_option(
php_stream *stream,
int option,
int value,
void *ptrparam)
2406 const SSL_CIPHER *cipher;
2412 case TLS1_3_VERSION: proto_str =
"TLSv1.3";
break;
2415 case TLS1_2_VERSION: proto_str =
"TLSv1.2";
break;
2418 case TLS1_1_VERSION: proto_str =
"TLSv1.1";
break;
2420 case TLS1_VERSION: proto_str =
"TLSv1";
break;
2422 case SSL3_VERSION: proto_str =
"SSLv3";
break;
2424 default: proto_str =
"UNKNOWN";
2427 cipher = SSL_get_current_cipher(sslsock->
ssl_handle);
2429 add_assoc_string(&tmp,
"protocol", proto_str);
2430 add_assoc_string(&tmp,
"cipher_name", (
char *) SSL_CIPHER_get_name(cipher));
2431 add_assoc_long(&tmp,
"cipher_bits", SSL_CIPHER_get_bits(cipher,
NULL));
2432 add_assoc_string(&tmp,
"cipher_version", SSL_CIPHER_get_version(cipher));
2436 const unsigned char *alpn_proto =
NULL;
2437 unsigned int alpn_proto_len = 0;
2439 SSL_get0_alpn_selected(sslsock->
ssl_handle, &alpn_proto, &alpn_proto_len);
2441 add_assoc_stringl(&tmp,
"alpn_protocol", (
char *)alpn_proto, alpn_proto_len);
2445 add_assoc_zval((
zval *)ptrparam,
"crypto", &tmp);
2450 add_assoc_bool((
zval *)ptrparam,
"eof", stream->
eof);
2461 if (sslsock->
s.
timeout.tv_sec == -1) {
2463 tv.tv_sec = (long)
FG(default_socket_timeout);
2465 tv.tv_sec = (time_t)
FG(default_socket_timeout);
2476 if (sslsock->
s.
socket == -1) {
2491 struct timeval start_time;
2492 struct timeval *timeout =
NULL;
2494 int has_timeout = 0;
2497 if (began_blocked) {
2502 php_openssl_set_blocking(sslsock, 0);
2505 if (!sslsock->
s.
is_blocked && timeout && (timeout->tv_sec > 0 || (timeout->tv_sec == 0 && timeout->tv_usec))) {
2513 struct timeval cur_time, elapsed_time, left_time;
2520 elapsed_time = php_openssl_subtract_timeval(cur_time, start_time);
2523 if (php_openssl_compare_timeval(elapsed_time, *timeout) > 0 ) {
2525 if (began_blocked) {
2526 php_openssl_set_blocking(sslsock, 1);
2539 case SSL_ERROR_SYSCALL:
2542 case SSL_ERROR_WANT_READ:
2543 case SSL_ERROR_WANT_WRITE:
2552 if (began_blocked == 0 || !has_timeout) {
2562 left_time = php_openssl_subtract_timeval(*timeout, elapsed_time);
2577 php_openssl_set_blocking(sslsock, 1);
2590 }
else if (0 >
ret) {
2604 switch(cparam->
op) {
2606 case STREAM_XPORT_CRYPTO_OP_SETUP:
2610 case STREAM_XPORT_CRYPTO_OP_ENABLE:
2611 cparam->
outputs.
returncode = php_openssl_enable_crypto(stream, sslsock, cparam);
2622 switch(xparam->
op) {
2624 case STREAM_XPORT_OP_CONNECT:
2625 case STREAM_XPORT_OP_CONNECT_ASYNC:
2632 (xparam->
op == STREAM_XPORT_OP_CONNECT_ASYNC &&
2643 case STREAM_XPORT_OP_ACCEPT:
2661static int php_openssl_sockop_cast(
php_stream *stream,
int castas,
void **
ret)
2684 && (pending = (
size_t)SSL_pending(sslsock->
ssl_handle)) > 0) {
2710 php_openssl_sockop_write, php_openssl_sockop_read,
2711 php_openssl_sockop_close, php_openssl_sockop_flush,
2714 php_openssl_sockop_cast,
2715 php_openssl_sockop_stat,
2716 php_openssl_sockop_set_option,
2719static zend_long php_openssl_get_crypto_method(
2725 crypto_method = zval_get_long(
val);
2729 return crypto_method;
2733static char *php_openssl_get_url_name(
const char *resourcename,
2734 size_t resourcenamelen,
int is_persistent)
2738 if (!resourcename) {
2749 char * url_name =
NULL;
2753 while (
len && host[
len-1] ==
'.') {
2771 const char *resourcename,
size_t resourcenamelen,
2773 struct timeval *timeout,
2780 memset(sslsock, 0,
sizeof(*sslsock));
2785 sslsock->
s.
timeout.tv_sec = (long)
FG(default_socket_timeout);
2787 sslsock->
s.
timeout.tv_sec = (time_t)
FG(default_socket_timeout);
2804 if (stream ==
NULL) {
2805 pefree(sslsock, persistent_id ? 1 : 0);
2809 if (
strncmp(proto,
"ssl", protolen) == 0) {
2812 }
else if (
strncmp(proto,
"sslv2", protolen) == 0) {
2816 }
else if (
strncmp(proto,
"sslv3", protolen) == 0) {
2822 "SSLv3 support is not compiled into the OpenSSL library against which PHP is linked");
2826 }
else if (
strncmp(proto,
"tls", protolen) == 0) {
2829 }
else if (
strncmp(proto,
"tlsv1.0", protolen) == 0) {
2832 }
else if (
strncmp(proto,
"tlsv1.1", protolen) == 0) {
2838 "TLSv1.1 support is not compiled into the OpenSSL library against which PHP is linked");
2842 }
else if (
strncmp(proto,
"tlsv1.2", protolen) == 0) {
2848 "TLSv1.2 support is not compiled into the OpenSSL library against which PHP is linked");
2852 }
else if (
strncmp(proto,
"tlsv1.3", protolen) == 0) {
2858 "TLSv1.3 support is not compiled into the OpenSSL library against which PHP is linked");
2864 sslsock->
url_name = php_openssl_get_url_name(resourcename, resourcenamelen, !!persistent_id);
gettimeofday(bool $as_float=false)
count(Countable|array $value, int $mode=COUNT_NORMAL)
strchr(string $haystack, string $needle, bool $before_needle=false)
memset(ptr, 0, type->size)
zend_ffi_ctype_name_buf buf
PHPAPI ZEND_COLD void php_error_docref(const char *docref, int type, const char *format,...)
PHPAPI zend_result php_set_sock_blocking(php_socket_t socketd, bool block)
PHPAPI char * php_socket_strerror(long err, char *buf, size_t bufsize)
PHPAPI php_socket_t php_network_accept_incoming(php_socket_t srvsock, zend_string **textaddr, struct sockaddr **addr, socklen_t *addrlen, struct timeval *timeout, zend_string **error_string, int *error_code, int tcp_nodelay)
zend_class_entry * php_openssl_certificate_ce
int php_openssl_get_ssl_stream_data_index(void)
bool php_openssl_check_path_ex(const char *file_path, size_t file_path_len, char *real_path, uint32_t arg_num, bool contains_file_protocol, bool is_from_array, const char *option_name)
const OPENSSL_DEFAULT_STREAM_CIPHERS
PHP_JSON_API size_t int options
struct _php_netstream_data_t php_netstream_data_t
PHPAPI const php_stream_ops php_stream_socket_ops
#define php_socket_errno()
unsigned char key[REFLECTION_KEY_LEN]
#define php_stream_notify_progress_increment(context, dsofar, dmax)
PHPAPI zval * php_stream_context_get_option(php_stream_context *context, const char *wrappername, const char *optionname)
PHPAPI void php_stream_context_set_option(php_stream_context *context, const char *wrappername, const char *optionname, zval *optionvalue)
struct _php_stream_xport_crypto_param php_stream_xport_crypto_param
PHPAPI int php_stream_xport_crypto_enable(php_stream *stream, int activate)
php_stream_xport_crypt_method_t
@ STREAM_CRYPTO_METHOD_SSLv3_CLIENT
@ STREAM_CRYPTO_METHOD_TLS_ANY_CLIENT
@ STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT
@ STREAM_CRYPTO_METHOD_TLSv1_3_CLIENT
@ STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT
@ STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT
PHPAPI int php_stream_xport_shutdown(php_stream *stream, stream_shutdown_t how)
struct _php_stream_xport_param php_stream_xport_param
PHPAPI int php_stream_xport_crypto_setup(php_stream *stream, php_stream_xport_crypt_method_t crypto_method, php_stream *session_stream)
struct _php_stream php_stream
struct _php_stream_context php_stream_context
#define PHP_STREAM_AS_FD_FOR_SELECT
#define php_stream_alloc_rel(ops, thisptr, persistent, mode)
#define PHP_STREAM_OPTION_XPORT_API
#define php_stream_get_line(stream, buf, maxlen, retlen)
#define PHP_STREAM_OPTION_CRYPTO_API
#define php_stream_to_zval(stream, zval)
#define PHP_STREAM_FLAG_NO_IO
#define php_stream_close(stream)
#define PHP_STREAM_CONTEXT(stream)
#define php_stream_is_persistent(stream)
struct _php_stream_ops php_stream_ops
#define PHP_STREAM_OPTION_META_DATA_API
#define php_stream_open_wrapper(path, mode, options, opened)
#define PHP_STREAM_OPTION_RETURN_ERR
#define PHP_STREAM_OPTION_CHECK_LIVENESS
#define PHP_STREAM_AS_SOCKETD
#define PHP_STREAM_FLAG_NO_FCLOSE
#define PHP_STREAM_OPTION_RETURN_OK
#define php_stream_fill_read_buffer(stream, size)
#define PHP_STREAM_AS_STDIO
struct _php_stream_statbuf php_stream_statbuf
struct @010122165316201240231237266310115370127155020222 err_buf
php_stream_xport_crypt_method_t method
php_openssl_alpn_ctx alpn_ctx
php_openssl_sni_cert_t * sni_certs
php_openssl_handshake_bucket_t * reneg
struct timeval connect_timeout
const php_stream_wrapper_ops * wops
enum _php_stream_xport_crypto_param::@140346054352235315366005246212154160231254101314 op
struct _php_stream_xport_crypto_param::@234115165332033214161101206371265150065200217213 outputs
php_stream_xport_crypt_method_t method
struct _php_stream_xport_crypto_param::@042362176013144336133052271202115307340250073237 inputs
struct _php_stream_xport_param::@000113327003134033162122300162113175151127354335 outputs
enum _php_stream_xport_param::@374135164235347147303334377011004260152245232316 op
const php_stream_ops * ops
php_stream_wrapper * wrapper
PHPAPI php_url * php_url_parse_ex(char const *str, size_t length)
PHPAPI void php_url_free(php_url *theurl)
#define php_win_err_free(err)
#define SERVER_MICROSOFT_IIS
php_stream * 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)
struct _php_openssl_sni_cert_t php_openssl_sni_cert_t
#define GET_VER_OPT_LONG(_name, _num)
#define PHP_OPENSSL_MIN_PROTO_VERSION
zend_string * php_openssl_x509_fingerprint(X509 *peer, const char *method, bool raw)
#define STREAM_CRYPTO_IS_CLIENT
#define GET_VER_OPT(_name)
#define GET_VER_OPT_STRINGL(_name, _str, _len)
php_stream * php_openssl_get_stream_from_ssl_handle(const SSL *ssl)
struct _php_openssl_handshake_bucket_t php_openssl_handshake_bucket_t
#define STREAM_CRYPTO_METHOD_TLSv1_0
#define PHP_OPENSSL_MAX_PROTO_VERSION
#define STREAM_CRYPTO_METHOD_TLSv1_3
#define STREAM_CRYPTO_METHOD_TLSv1_1
#define STREAM_CRYPTO_METHOD_TLSv1_2
#define GET_VER_OPT_STRING(_name, _str)
#define STREAM_CRYPTO_METHOD_SSLv3
struct _php_openssl_netstream_data_t php_openssl_netstream_data_t
int php_openssl_get_ssl_stream_data_index(void)
struct _php_openssl_alpn_ctx_t php_openssl_alpn_ctx
ZEND_API zend_result object_init_ex(zval *arg, zend_class_entry *class_type)
#define call_user_function(function_table, object, function_name, retval_ptr, param_count, params)
#define pestrdup(s, persistent)
#define pestrndup(s, length, persistent)
#define pefree(ptr, persistent)
#define pemalloc(size, persistent)
#define safe_pemalloc(nmemb, size, offset, persistent)
strncmp(string $string1, string $string2, int $length)
strcmp(string $string1, string $string2)
zend_string_release_ex(func->internal_function.function_name, 0)
#define strncasecmp(s1, s2, n)
#define strcasecmp(s1, s2)
ZEND_API void(ZEND_FASTCALL *zend_touch_vm_stack_data)(void *vm_stack_data)
ZEND_API zval *ZEND_FASTCALL zend_hash_str_find(const HashTable *ht, const char *str, size_t len)
#define ZEND_HASH_FOREACH_KEY_VAL(ht, _h, _key, _val)
#define ZEND_HASH_FOREACH_STR_KEY_VAL(ht, _key, _val)
#define ZEND_HASH_FOREACH_END()
#define ZEND_HASH_FOREACH_VAL(ht, _val)
ZEND_API char * zend_ini_string(const char *name, size_t name_length, int orig)
struct _zend_string zend_string
ZEND_API bool ZEND_FASTCALL zend_is_true(const zval *op)
#define EXPECTED(condition)
#define UNEXPECTED(condition)
#define zend_string_equals_literal_ci(str, c)
#define Z_STRVAL_P(zval_p)
#define Z_ARRVAL_P(zval_p)
#define Z_STRLEN_P(zval_p)
ZEND_RESULT_CODE zend_result
ZEND_API void zval_ptr_dtor(zval *zval_ptr)