Skip to content

Commit 6aca6e3

Browse files
authored
ext/openssl: fix OpenSSL 4 build and test compatibility (#22267)
* Fix OpenSSL 4 test compatibility * Fix OpenSSL 4 build compatibility * Use OpenSSL 4 in macOS CI * Fix OpenSSL 1.1 build compatibility * Preserve raw CN matching with OpenSSL 4
1 parent 4999bcb commit 6aca6e3

11 files changed

Lines changed: 129 additions & 33 deletions

File tree

‎.github/actions/brew/action.yml‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,6 @@ runs:
3333
t1lib \
3434
libxml2 \
3535
libjpeg \
36-
libxslt
36+
libxslt \
37+
openssl@4
38+
brew link --force --overwrite openssl@4

‎.github/actions/configure-macos/action.yml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ runs:
1111
set -x
1212
BREW_OPT="$(brew --prefix)"/opt
1313
export PATH="$BREW_OPT/bison/bin:$PATH"
14-
export PKG_CONFIG_PATH="$PKG_CONFIG_PATH:$BREW_OPT/openssl/lib/pkgconfig"
14+
export PKG_CONFIG_PATH="$PKG_CONFIG_PATH:$BREW_OPT/openssl@4/lib/pkgconfig"
1515
export PKG_CONFIG_PATH="$PKG_CONFIG_PATH:$BREW_OPT/curl/lib/pkgconfig"
1616
export PKG_CONFIG_PATH="$PKG_CONFIG_PATH:$BREW_OPT/libffi/lib/pkgconfig"
1717
export PKG_CONFIG_PATH="$PKG_CONFIG_PATH:$BREW_OPT/libxml2/lib/pkgconfig"

‎ext/openssl/openssl.c‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -821,7 +821,7 @@ PHP_MINIT_FUNCTION(openssl)
821821
ssl_stream_data_index = SSL_get_ex_new_index(0, "PHP stream index", NULL, NULL, NULL);
822822

823823
php_stream_xport_register("ssl", php_openssl_ssl_socket_factory);
824-
#ifndef OPENSSL_NO_SSL3
824+
#if OPENSSL_VERSION_NUMBER < 0x40000000L && !defined(OPENSSL_NO_SSL3)
825825
php_stream_xport_register("sslv3", php_openssl_ssl_socket_factory);
826826
#endif
827827
php_stream_xport_register("tls", php_openssl_ssl_socket_factory);
@@ -895,7 +895,7 @@ PHP_MSHUTDOWN_FUNCTION(openssl)
895895
php_unregister_url_stream_wrapper("ftps");
896896

897897
php_stream_xport_unregister("ssl");
898-
#ifndef OPENSSL_NO_SSL3
898+
#if OPENSSL_VERSION_NUMBER < 0x40000000L && !defined(OPENSSL_NO_SSL3)
899899
php_stream_xport_unregister("sslv3");
900900
#endif
901901
php_stream_xport_unregister("tls");
@@ -1395,8 +1395,8 @@ PHP_FUNCTION(openssl_x509_parse)
13951395
zval subitem;
13961396
zval critext;
13971397
int critcount = 0;
1398-
X509_EXTENSION *extension;
1399-
X509_NAME *subject_name;
1398+
PHP_OPENSSL_X509_EXTENSION *extension;
1399+
const X509_NAME *subject_name;
14001400
char *cert_name;
14011401
char *extname;
14021402
BIO *bio_out;
@@ -2383,7 +2383,7 @@ PHP_FUNCTION(openssl_csr_get_subject)
23832383
zend_object *csr_obj;
23842384
zend_string *csr_str;
23852385
bool use_shortnames = 1;
2386-
X509_NAME *subject;
2386+
const X509_NAME *subject;
23872387

23882388
ZEND_PARSE_PARAMETERS_START(1, 2)
23892389
Z_PARAM_OBJ_OF_CLASS_OR_STR(csr_obj, php_openssl_request_ce, csr_str)

‎ext/openssl/openssl_backend_common.c‎

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33,16 +33,16 @@
3333
/* true global; readonly after module startup */
3434
static char default_ssl_conf_filename[MAXPATHLEN];
3535

36-
void php_openssl_add_assoc_name_entry(zval * val, char * key, X509_NAME * name, int shortname)
36+
void php_openssl_add_assoc_name_entry(zval * val, char * key, const X509_NAME * name, int shortname)
3737
{
3838
zval *data;
3939
zval subitem, tmp;
4040
int i;
4141
char *sname;
4242
int nid;
43-
X509_NAME_ENTRY * ne;
44-
ASN1_STRING * str = NULL;
45-
ASN1_OBJECT * obj;
43+
const X509_NAME_ENTRY * ne;
44+
const ASN1_STRING * str = NULL;
45+
const ASN1_OBJECT * obj;
4646

4747
if (key != NULL) {
4848
array_init(&subitem);
@@ -106,7 +106,7 @@ void php_openssl_add_assoc_name_entry(zval * val, char * key, X509_NAME * name,
106106
}
107107
}
108108

109-
void php_openssl_add_assoc_asn1_string(zval * val, char * key, ASN1_STRING * str)
109+
void php_openssl_add_assoc_asn1_string(zval * val, char * key, const ASN1_STRING * str)
110110
{
111111
add_assoc_stringl(val, key, (const char *)ASN1_STRING_get0_data(str), ASN1_STRING_length(str));
112112
}
@@ -622,11 +622,11 @@ zend_string* php_openssl_x509_fingerprint(X509 *peer, const char *method, bool r
622622
/* Special handling of subjectAltName, see CVE-2013-4073
623623
* Christian Heimes
624624
*/
625-
int openssl_x509v3_subjectAltName(BIO *bio, X509_EXTENSION *extension)
625+
int openssl_x509v3_subjectAltName(BIO *bio, PHP_OPENSSL_X509_EXTENSION *extension)
626626
{
627627
GENERAL_NAMES *names;
628628
const X509V3_EXT_METHOD *method = NULL;
629-
ASN1_OCTET_STRING *extension_data;
629+
const ASN1_OCTET_STRING *extension_data;
630630
long i, length, num;
631631
const unsigned char *p;
632632

@@ -982,7 +982,12 @@ zend_result php_openssl_csr_make(struct php_x509_request * req, X509_REQ * csr,
982982
zval *item, *subitem;
983983
zend_string *strindex = NULL;
984984

985-
subj = X509_REQ_get_subject_name(csr);
985+
subj = X509_NAME_new();
986+
if (subj == NULL) {
987+
php_openssl_store_errors();
988+
return FAILURE;
989+
}
990+
986991
/* apply values from the dn hash */
987992
ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(dn), strindex, item) {
988993
if (strindex) {
@@ -991,10 +996,12 @@ zend_result php_openssl_csr_make(struct php_x509_request * req, X509_REQ * csr,
991996
if (Z_TYPE_P(item) == IS_ARRAY) {
992997
ZEND_HASH_FOREACH_NUM_KEY_VAL(Z_ARRVAL_P(item), i, subitem) {
993998
if (php_openssl_csr_add_subj_entry(subitem, subj, nid) == FAILURE) {
999+
X509_NAME_free(subj);
9941000
return FAILURE;
9951001
}
9961002
} ZEND_HASH_FOREACH_END();
9971003
} else if (php_openssl_csr_add_subj_entry(item, subj, nid) == FAILURE) {
1004+
X509_NAME_free(subj);
9981005
return FAILURE;
9991006
}
10001007
} else {
@@ -1045,13 +1052,23 @@ zend_result php_openssl_csr_make(struct php_x509_request * req, X509_REQ * csr,
10451052
if (!X509_NAME_add_entry_by_txt(subj, type, MBSTRING_UTF8, (unsigned char*)v->value, -1, -1, 0)) {
10461053
php_openssl_store_errors();
10471054
php_error_docref(NULL, E_WARNING, "add_entry_by_txt %s -> %s (failed)", type, v->value);
1055+
X509_NAME_free(subj);
10481056
return FAILURE;
10491057
}
10501058
if (!X509_NAME_entry_count(subj)) {
10511059
php_error_docref(NULL, E_WARNING, "No objects specified in config file");
1060+
X509_NAME_free(subj);
10521061
return FAILURE;
10531062
}
10541063
}
1064+
1065+
if (!X509_REQ_set_subject_name(csr, subj)) {
1066+
php_openssl_store_errors();
1067+
X509_NAME_free(subj);
1068+
return FAILURE;
1069+
}
1070+
X509_NAME_free(subj);
1071+
10551072
if (attribs) {
10561073
ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(attribs), strindex, item) {
10571074
int nid;

‎ext/openssl/openssl_backend_v3.c‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -402,7 +402,7 @@ EVP_PKEY *php_openssl_pkey_init_ec(zval *data, bool *is_private) {
402402
}
403403

404404
OPENSSL_PKEY_SET_BN(data, cofactor);
405-
if (!OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_EC_COFACTOR, cofactor) ||
405+
if ((cofactor && !OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_EC_COFACTOR, cofactor)) ||
406406
!EC_GROUP_set_generator(group, point_g, order, cofactor)) {
407407
goto cleanup;
408408
}

‎ext/openssl/php_openssl.h‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ extern zend_module_entry openssl_module_entry;
2323
#include "php_version.h"
2424
#define PHP_OPENSSL_VERSION PHP_VERSION
2525

26+
#include <openssl/opensslconf.h>
2627
#include <openssl/opensslv.h>
2728
/* OpenSSL version check */
2829
#if OPENSSL_VERSION_NUMBER < 0x30000000L

‎ext/openssl/php_openssl_backend.h‎

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,12 @@
3535
#include <openssl/pkcs12.h>
3636
#include <openssl/cms.h>
3737

38+
#if defined(OPENSSL_VERSION_MAJOR) && OPENSSL_VERSION_MAJOR >= 4
39+
typedef const X509_EXTENSION PHP_OPENSSL_X509_EXTENSION;
40+
#else
41+
typedef X509_EXTENSION PHP_OPENSSL_X509_EXTENSION;
42+
#endif
43+
3844
/* number conversion flags checks */
3945
#define PHP_OPENSSL_CHECK_NUMBER_CONVERSION(_cond, _name, _arg_num) \
4046
do { \
@@ -166,8 +172,8 @@ struct php_x509_request {
166172
const EVP_CIPHER * priv_key_encrypt_cipher;
167173
};
168174

169-
void php_openssl_add_assoc_name_entry(zval * val, char * key, X509_NAME * name, int shortname);
170-
void php_openssl_add_assoc_asn1_string(zval * val, char * key, ASN1_STRING * str);
175+
void php_openssl_add_assoc_name_entry(zval * val, char * key, const X509_NAME * name, int shortname);
176+
void php_openssl_add_assoc_asn1_string(zval * val, char * key, const ASN1_STRING * str);
171177
time_t php_openssl_asn1_time_to_time_t(ASN1_UTCTIME * timestr);
172178
int php_openssl_config_check_syntax(const char * section_label, const char * config_filename, const char * section, CONF *config);
173179
char *php_openssl_conf_get_string(CONF *conf, const char *group, const char *name);
@@ -265,7 +271,7 @@ X509 *php_openssl_x509_from_zval(
265271
zend_string* php_openssl_x509_fingerprint(
266272
X509 *peer, const char *method, bool raw, struct _php_stream *stream);
267273

268-
int openssl_x509v3_subjectAltName(BIO *bio, X509_EXTENSION *extension);
274+
int openssl_x509v3_subjectAltName(BIO *bio, PHP_OPENSSL_X509_EXTENSION *extension);
269275

270276
STACK_OF(X509) *php_openssl_load_all_certs_from_file(
271277
char *cert_file, size_t cert_file_len, uint32_t arg_num);

‎ext/openssl/tests/bug28382.phpt‎

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@ openssl
66
<?php
77
$cert = file_get_contents(__DIR__ . "/bug28382cert.txt");
88
$ext = openssl_x509_parse($cert);
9+
10+
if (OPENSSL_VERSION_NUMBER >= 0x40000000) {
11+
$extensions = &$ext['extensions'];
12+
$extensions['crlDistributionPoints'] = preg_replace('/^Full Name:\R\s*/', '', trim($extensions['crlDistributionPoints']));
13+
}
14+
915
var_dump($ext['extensions']);
1016
/*
1117
* The reason for %A at the end of crlDistributionPoints and authorityKeyIdentifier is that
@@ -30,7 +36,7 @@ array(11) {
3036
string(59) "B0:A7:FF:F9:41:15:DE:23:39:BD:DD:31:0F:97:A0:B2:A2:74:E0:FC"
3137
["authorityKeyIdentifier"]=>
3238
string(%d) "DirName:/C=RO/ST=Romania/L=Craiova/O=Sergiu/OU=Sergiu SRL/CN=Sergiu CA/emailAddress=n_sergiu@hotmail.com
33-
serial:00%A"
39+
serial:%A"
3440
["keyUsage"]=>
3541
string(71) "Digital Signature, Non Repudiation, Key Encipherment, Data Encipherment"
3642
["nsBaseUrl"]=>

‎ext/openssl/tests/ecc_custom_params.phpt‎

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,30 @@ openssl
55
--SKIPIF--
66
<?php
77
if (!defined("OPENSSL_KEYTYPE_EC")) die("skip EC disabled");
8+
9+
if (OPENSSL_VERSION_NUMBER >= 0x40000000) {
10+
$d = hex2bin('8D0AC65AAEA0D6B96254C65817D4A143A9E7A03876F1A37D');
11+
$p = hex2bin('BDB6F4FE3E8B1D9E0DA8C0D46F4C318CEFE4AFE3B6B8551F');
12+
$a = hex2bin('BB8E5E8FBC115E139FE6A814FE48AAA6F0ADA1AA5DF91985');
13+
$b = hex2bin('1854BEBDC31B21B7AEFC80AB0ECD10D5B1B3308E6DBF11C1');
14+
$g_x = hex2bin('4AD5F7048DE709AD51236DE65E4D4B482C836DC6E4106640');
15+
$g_y = hex2bin('02BB3A02D4AAADACAE24817A4CA3A1B014B5270432DB27D2');
16+
$order = hex2bin('BDB6F4FE3E8B1D9E0DA8C0D40FC962195DFAE76F56564677');
17+
18+
if (@openssl_pkey_new(array(
19+
'ec' => array(
20+
'p' => $p,
21+
'a' => $a,
22+
'b' => $b,
23+
'order' => $order,
24+
'g_x' => $g_x,
25+
'g_y' => $g_y,
26+
'd' => $d,
27+
),
28+
)) === false) {
29+
die("skip EC custom params unsupported with OpenSSL 4");
30+
}
31+
}
832
?>
933
--FILE--
1034
<?php

‎ext/openssl/tests/openssl_x509_parse_basic_openssl32.phpt‎

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,28 @@ if (OPENSSL_VERSION_NUMBER < 0x30200000) die('skip For OpenSSL >= 3.2');
88
?>
99
--FILE--
1010
<?php
11+
function normalize_openssl4_x509_parse_output(array $cert): array {
12+
if (OPENSSL_VERSION_NUMBER < 0x40000000 || !isset($cert['serialNumberHex'], $cert['extensions']['authorityKeyIdentifier'])) {
13+
return $cert;
14+
}
15+
16+
$serial = strtoupper($cert['serialNumberHex']);
17+
if (strlen($serial) % 2) {
18+
$serial = '0' . $serial;
19+
}
20+
$serial = implode(':', str_split($serial, 2));
21+
$cert['extensions']['authorityKeyIdentifier'] = preg_replace('/^serial:\d+$/m', 'serial:' . $serial, $cert['extensions']['authorityKeyIdentifier']);
22+
23+
return $cert;
24+
}
25+
1126
$cert = "file://" . __DIR__ . "/cert.crt";
1227

1328
$parsedCert = openssl_x509_parse($cert);
14-
var_dump($parsedCert === openssl_x509_parse(openssl_x509_read($cert)));
29+
$parsedCert = normalize_openssl4_x509_parse_output($parsedCert);
30+
var_dump($parsedCert === normalize_openssl4_x509_parse_output(openssl_x509_parse(openssl_x509_read($cert))));
1531
var_dump($parsedCert);
16-
var_dump(openssl_x509_parse($cert, false));
32+
var_dump(normalize_openssl4_x509_parse_output(openssl_x509_parse($cert, false)));
1733
?>
1834
--EXPECTF--
1935
bool(true)

0 commit comments

Comments
 (0)