Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .github/actions/brew/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,6 @@ runs:
t1lib \
libxml2 \
libjpeg \
libxslt
libxslt \
openssl@4
brew link --force --overwrite openssl@4
2 changes: 1 addition & 1 deletion .github/actions/configure-macos/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ runs:
set -x
BREW_OPT="$(brew --prefix)"/opt
export PATH="$BREW_OPT/bison/bin:$PATH"
export PKG_CONFIG_PATH="$PKG_CONFIG_PATH:$BREW_OPT/openssl/lib/pkgconfig"
export PKG_CONFIG_PATH="$PKG_CONFIG_PATH:$BREW_OPT/openssl@4/lib/pkgconfig"
export PKG_CONFIG_PATH="$PKG_CONFIG_PATH:$BREW_OPT/curl/lib/pkgconfig"
export PKG_CONFIG_PATH="$PKG_CONFIG_PATH:$BREW_OPT/libffi/lib/pkgconfig"
export PKG_CONFIG_PATH="$PKG_CONFIG_PATH:$BREW_OPT/libxml2/lib/pkgconfig"
Expand Down
10 changes: 5 additions & 5 deletions ext/openssl/openssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -810,7 +810,7 @@ PHP_MINIT_FUNCTION(openssl)
ssl_stream_data_index = SSL_get_ex_new_index(0, "PHP stream index", NULL, NULL, NULL);

php_stream_xport_register("ssl", php_openssl_ssl_socket_factory);
#ifndef OPENSSL_NO_SSL3
#if OPENSSL_VERSION_NUMBER < 0x40000000L && !defined(OPENSSL_NO_SSL3)
php_stream_xport_register("sslv3", php_openssl_ssl_socket_factory);
#endif
php_stream_xport_register("tls", php_openssl_ssl_socket_factory);
Expand Down Expand Up @@ -884,7 +884,7 @@ PHP_MSHUTDOWN_FUNCTION(openssl)
php_unregister_url_stream_wrapper("ftps");

php_stream_xport_unregister("ssl");
#ifndef OPENSSL_NO_SSL3
#if OPENSSL_VERSION_NUMBER < 0x40000000L && !defined(OPENSSL_NO_SSL3)
php_stream_xport_unregister("sslv3");
#endif
php_stream_xport_unregister("tls");
Expand Down Expand Up @@ -1384,8 +1384,8 @@ PHP_FUNCTION(openssl_x509_parse)
zval subitem;
zval critext;
int critcount = 0;
X509_EXTENSION *extension;
X509_NAME *subject_name;
PHP_OPENSSL_X509_EXTENSION *extension;
const X509_NAME *subject_name;
char *cert_name;
char *extname;
BIO *bio_out;
Expand Down Expand Up @@ -2359,7 +2359,7 @@ PHP_FUNCTION(openssl_csr_get_subject)
zend_object *csr_obj;
zend_string *csr_str;
bool use_shortnames = 1;
X509_NAME *subject;
const X509_NAME *subject;

ZEND_PARSE_PARAMETERS_START(1, 2)
Z_PARAM_OBJ_OF_CLASS_OR_STR(csr_obj, php_openssl_request_ce, csr_str)
Expand Down
33 changes: 25 additions & 8 deletions ext/openssl/openssl_backend_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,16 @@
/* true global; readonly after module startup */
static char default_ssl_conf_filename[MAXPATHLEN];

void php_openssl_add_assoc_name_entry(zval * val, char * key, X509_NAME * name, int shortname)
void php_openssl_add_assoc_name_entry(zval * val, char * key, const X509_NAME * name, int shortname)
{
zval *data;
zval subitem, tmp;
int i;
char *sname;
int nid;
X509_NAME_ENTRY * ne;
ASN1_STRING * str = NULL;
ASN1_OBJECT * obj;
const X509_NAME_ENTRY * ne;
const ASN1_STRING * str = NULL;
const ASN1_OBJECT * obj;

if (key != NULL) {
array_init(&subitem);
Expand Down Expand Up @@ -106,7 +106,7 @@ void php_openssl_add_assoc_name_entry(zval * val, char * key, X509_NAME * name,
}
}

void php_openssl_add_assoc_asn1_string(zval * val, char * key, ASN1_STRING * str)
void php_openssl_add_assoc_asn1_string(zval * val, char * key, const ASN1_STRING * str)
{
add_assoc_stringl(val, key, (const char *)ASN1_STRING_get0_data(str), ASN1_STRING_length(str));
}
Expand Down Expand Up @@ -612,11 +612,11 @@ zend_string* php_openssl_x509_fingerprint(X509 *peer, const char *method, bool r
/* Special handling of subjectAltName, see CVE-2013-4073
* Christian Heimes
*/
int openssl_x509v3_subjectAltName(BIO *bio, X509_EXTENSION *extension)
int openssl_x509v3_subjectAltName(BIO *bio, PHP_OPENSSL_X509_EXTENSION *extension)
{
GENERAL_NAMES *names;
const X509V3_EXT_METHOD *method = NULL;
ASN1_OCTET_STRING *extension_data;
const ASN1_OCTET_STRING *extension_data;
long i, length, num;
const unsigned char *p;

Expand Down Expand Up @@ -972,7 +972,12 @@ zend_result php_openssl_csr_make(struct php_x509_request * req, X509_REQ * csr,
zval *item, *subitem;
zend_string *strindex = NULL;

subj = X509_REQ_get_subject_name(csr);
subj = X509_NAME_new();
if (subj == NULL) {
php_openssl_store_errors();
return FAILURE;
}

/* apply values from the dn hash */
ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(dn), strindex, item) {
if (strindex) {
Expand All @@ -981,10 +986,12 @@ zend_result php_openssl_csr_make(struct php_x509_request * req, X509_REQ * csr,
if (Z_TYPE_P(item) == IS_ARRAY) {
ZEND_HASH_FOREACH_NUM_KEY_VAL(Z_ARRVAL_P(item), i, subitem) {
if (php_openssl_csr_add_subj_entry(subitem, subj, nid) == FAILURE) {
X509_NAME_free(subj);
return FAILURE;
}
} ZEND_HASH_FOREACH_END();
} else if (php_openssl_csr_add_subj_entry(item, subj, nid) == FAILURE) {
X509_NAME_free(subj);
return FAILURE;
}
} else {
Expand Down Expand Up @@ -1035,13 +1042,23 @@ zend_result php_openssl_csr_make(struct php_x509_request * req, X509_REQ * csr,
if (!X509_NAME_add_entry_by_txt(subj, type, MBSTRING_UTF8, (unsigned char*)v->value, -1, -1, 0)) {
php_openssl_store_errors();
php_error_docref(NULL, E_WARNING, "add_entry_by_txt %s -> %s (failed)", type, v->value);
X509_NAME_free(subj);
return FAILURE;
}
if (!X509_NAME_entry_count(subj)) {
php_error_docref(NULL, E_WARNING, "No objects specified in config file");
X509_NAME_free(subj);
return FAILURE;
}
}

if (!X509_REQ_set_subject_name(csr, subj)) {
php_openssl_store_errors();
X509_NAME_free(subj);
return FAILURE;
}
X509_NAME_free(subj);

if (attribs) {
ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(attribs), strindex, item) {
int nid;
Expand Down
2 changes: 1 addition & 1 deletion ext/openssl/openssl_backend_v3.c
Original file line number Diff line number Diff line change
Expand Up @@ -402,7 +402,7 @@ EVP_PKEY *php_openssl_pkey_init_ec(zval *data, bool *is_private) {
}

OPENSSL_PKEY_SET_BN(data, cofactor);
if (!OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_EC_COFACTOR, cofactor) ||
if ((cofactor && !OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_EC_COFACTOR, cofactor)) ||
!EC_GROUP_set_generator(group, point_g, order, cofactor)) {
goto cleanup;
}
Expand Down
1 change: 1 addition & 0 deletions ext/openssl/php_openssl.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ extern zend_module_entry openssl_module_entry;
#include "php_version.h"
#define PHP_OPENSSL_VERSION PHP_VERSION

#include <openssl/opensslconf.h>
#include <openssl/opensslv.h>
/* OpenSSL version check */
#if OPENSSL_VERSION_NUMBER < 0x30000000L
Expand Down
12 changes: 9 additions & 3 deletions ext/openssl/php_openssl_backend.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@
#include <openssl/pkcs12.h>
#include <openssl/cms.h>

#if defined(OPENSSL_VERSION_MAJOR) && OPENSSL_VERSION_MAJOR >= 4
typedef const X509_EXTENSION PHP_OPENSSL_X509_EXTENSION;
#else
typedef X509_EXTENSION PHP_OPENSSL_X509_EXTENSION;
#endif

/* number conversion flags checks */
#define PHP_OPENSSL_CHECK_NUMBER_CONVERSION(_cond, _name, _arg_num) \
do { \
Expand Down Expand Up @@ -166,8 +172,8 @@ struct php_x509_request {
const EVP_CIPHER * priv_key_encrypt_cipher;
};

void php_openssl_add_assoc_name_entry(zval * val, char * key, X509_NAME * name, int shortname);
void php_openssl_add_assoc_asn1_string(zval * val, char * key, ASN1_STRING * str);
void php_openssl_add_assoc_name_entry(zval * val, char * key, const X509_NAME * name, int shortname);
void php_openssl_add_assoc_asn1_string(zval * val, char * key, const ASN1_STRING * str);
time_t php_openssl_asn1_time_to_time_t(ASN1_UTCTIME * timestr);
int php_openssl_config_check_syntax(const char * section_label, const char * config_filename, const char * section, CONF *config);
char *php_openssl_conf_get_string(CONF *conf, const char *group, const char *name);
Expand Down Expand Up @@ -264,7 +270,7 @@ X509 *php_openssl_x509_from_zval(

zend_string* php_openssl_x509_fingerprint(X509 *peer, const char *method, bool raw);

int openssl_x509v3_subjectAltName(BIO *bio, X509_EXTENSION *extension);
int openssl_x509v3_subjectAltName(BIO *bio, PHP_OPENSSL_X509_EXTENSION *extension);

STACK_OF(X509) *php_openssl_load_all_certs_from_file(
char *cert_file, size_t cert_file_len, uint32_t arg_num);
Expand Down
8 changes: 7 additions & 1 deletion ext/openssl/tests/bug28382.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@ openssl
<?php
$cert = file_get_contents(__DIR__ . "/bug28382cert.txt");
$ext = openssl_x509_parse($cert);

if (OPENSSL_VERSION_NUMBER >= 0x40000000) {
$extensions = &$ext['extensions'];
$extensions['crlDistributionPoints'] = preg_replace('/^Full Name:\R\s*/', '', trim($extensions['crlDistributionPoints']));
}

var_dump($ext['extensions']);
/*
* The reason for %A at the end of crlDistributionPoints and authorityKeyIdentifier is that
Expand All @@ -30,7 +36,7 @@ array(11) {
string(59) "B0:A7:FF:F9:41:15:DE:23:39:BD:DD:31:0F:97:A0:B2:A2:74:E0:FC"
["authorityKeyIdentifier"]=>
string(%d) "DirName:/C=RO/ST=Romania/L=Craiova/O=Sergiu/OU=Sergiu SRL/CN=Sergiu CA/emailAddress=n_sergiu@hotmail.com
serial:00%A"
serial:%A"
["keyUsage"]=>
string(71) "Digital Signature, Non Repudiation, Key Encipherment, Data Encipherment"
["nsBaseUrl"]=>
Expand Down
24 changes: 24 additions & 0 deletions ext/openssl/tests/ecc_custom_params.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,30 @@ openssl
--SKIPIF--
<?php
if (!defined("OPENSSL_KEYTYPE_EC")) die("skip EC disabled");

if (OPENSSL_VERSION_NUMBER >= 0x40000000) {
$d = hex2bin('8D0AC65AAEA0D6B96254C65817D4A143A9E7A03876F1A37D');
$p = hex2bin('BDB6F4FE3E8B1D9E0DA8C0D46F4C318CEFE4AFE3B6B8551F');
$a = hex2bin('BB8E5E8FBC115E139FE6A814FE48AAA6F0ADA1AA5DF91985');
$b = hex2bin('1854BEBDC31B21B7AEFC80AB0ECD10D5B1B3308E6DBF11C1');
$g_x = hex2bin('4AD5F7048DE709AD51236DE65E4D4B482C836DC6E4106640');
$g_y = hex2bin('02BB3A02D4AAADACAE24817A4CA3A1B014B5270432DB27D2');
$order = hex2bin('BDB6F4FE3E8B1D9E0DA8C0D40FC962195DFAE76F56564677');

if (@openssl_pkey_new(array(
'ec' => array(
'p' => $p,
'a' => $a,
'b' => $b,
'order' => $order,
'g_x' => $g_x,
'g_y' => $g_y,
'd' => $d,
),
)) === false) {
die("skip EC custom params unsupported with OpenSSL 4");
}
}
?>
--FILE--
<?php
Expand Down
20 changes: 18 additions & 2 deletions ext/openssl/tests/openssl_x509_parse_basic_openssl32.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,28 @@ if (OPENSSL_VERSION_NUMBER < 0x30200000) die('skip For OpenSSL >= 3.2');
?>
--FILE--
<?php
function normalize_openssl4_x509_parse_output(array $cert): array {
if (OPENSSL_VERSION_NUMBER < 0x40000000 || !isset($cert['serialNumberHex'], $cert['extensions']['authorityKeyIdentifier'])) {
return $cert;
}

$serial = strtoupper($cert['serialNumberHex']);
if (strlen($serial) % 2) {
$serial = '0' . $serial;
}
$serial = implode(':', str_split($serial, 2));
$cert['extensions']['authorityKeyIdentifier'] = preg_replace('/^serial:\d+$/m', 'serial:' . $serial, $cert['extensions']['authorityKeyIdentifier']);

return $cert;
}

$cert = "file://" . __DIR__ . "/cert.crt";

$parsedCert = openssl_x509_parse($cert);
var_dump($parsedCert === openssl_x509_parse(openssl_x509_read($cert)));
$parsedCert = normalize_openssl4_x509_parse_output($parsedCert);
var_dump($parsedCert === normalize_openssl4_x509_parse_output(openssl_x509_parse(openssl_x509_read($cert))));
var_dump($parsedCert);
var_dump(openssl_x509_parse($cert, false));
var_dump(normalize_openssl4_x509_parse_output(openssl_x509_parse($cert, false)));
?>
--EXPECTF--
bool(true)
Expand Down
42 changes: 31 additions & 11 deletions ext/openssl/xp_ssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@
#define HAVE_SEC_LEVEL 1
#endif

#ifndef OPENSSL_NO_SSL3
#if OPENSSL_VERSION_NUMBER < 0x40000000L && !defined(OPENSSL_NO_SSL3)
#define HAVE_SSL3 1
#define PHP_OPENSSL_MIN_PROTO_VERSION STREAM_CRYPTO_METHOD_SSLv3
#else
Expand Down Expand Up @@ -273,7 +273,7 @@ static int php_openssl_handle_ssl_error(php_stream *stream, int nr_bytes, bool i
errno = EAGAIN;
retry = is_init ? true : sslsock->s.is_blocked;
if (!retry) {
sslsock->last_status = err == SSL_ERROR_WANT_READ ?
sslsock->last_status = err == SSL_ERROR_WANT_READ ?
STREAM_CRYPTO_STATUS_WANT_READ : STREAM_CRYPTO_STATUS_WANT_WRITE;
}
break;
Expand Down Expand Up @@ -557,26 +557,46 @@ static bool php_openssl_matches_san_list(X509 *peer, const char *subject_name) /

static bool php_openssl_matches_common_name(X509 *peer, const char *subject_name) /* {{{ */
{
char buf[1024];
X509_NAME *cert_name;
unsigned char *cert_name = NULL;
const X509_NAME *name;
const X509_NAME_ENTRY *name_entry;
const ASN1_STRING *name_asn1;
bool is_match = false;
int name_index;
int cert_name_len;

cert_name = X509_get_subject_name(peer);
cert_name_len = X509_NAME_get_text_by_NID(cert_name, NID_commonName, buf, sizeof(buf));
name = X509_get_subject_name(peer);
name_index = X509_NAME_get_index_by_NID(name, NID_commonName, -1);
if (name_index == -1) {
php_error_docref(NULL, E_WARNING, "Unable to locate peer certificate CN");
return false;
}

if (cert_name_len == -1) {
name_entry = X509_NAME_get_entry(name, name_index);
if (name_entry == NULL) {
php_error_docref(NULL, E_WARNING, "Unable to locate peer certificate CN");
} else if ((size_t)cert_name_len != strlen(buf)) {
php_error_docref(NULL, E_WARNING, "Peer certificate CN=`%.*s' is malformed", cert_name_len, buf);
} else if (php_openssl_matches_wildcard_name(subject_name, buf)) {
return false;
}
name_asn1 = X509_NAME_ENTRY_get_data(name_entry);
cert_name_len = ASN1_STRING_to_UTF8(&cert_name, name_asn1);
if (cert_name_len < 0) {
php_openssl_store_errors();
php_error_docref(NULL, E_WARNING, "Unable to locate peer certificate CN");
return false;
}

if ((size_t)cert_name_len != strlen((const char *)cert_name)) {
php_error_docref(NULL, E_WARNING, "Peer certificate CN=`%.*s' is malformed", cert_name_len, (const char *)cert_name);
} else if (php_openssl_matches_wildcard_name(subject_name, (const char *)cert_name)) {
is_match = true;
} else {
php_error_docref(NULL, E_WARNING,
"Peer certificate CN=`%.*s' did not match expected CN=`%s'",
cert_name_len, buf, subject_name);
cert_name_len, (const char *)cert_name, subject_name);
}

OPENSSL_free(cert_name);

return is_match;
}
/* }}} */
Expand Down
Loading