Use OpenSSL libctx for various BIO readers (#19448)

This converts mostly PEM readers but also DER for CMS
This commit is contained in:
Jakub Zelenka 2025-08-11 17:21:38 +01:00 committed by GitHub
parent 6280dfc025
commit c5f79b8cf9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 204 additions and 30 deletions

View file

@ -2749,7 +2749,7 @@ PHP_FUNCTION(openssl_pkcs7_read)
goto clean_exit; goto clean_exit;
} }
p7 = PEM_read_bio_PKCS7(bio_in, NULL, NULL, NULL); p7 = php_openssl_pem_read_bio_pkcs7(bio_in);
if (p7 == NULL) { if (p7 == NULL) {
php_openssl_store_errors(); php_openssl_store_errors();
goto clean_exit; goto clean_exit;
@ -3071,19 +3071,19 @@ PHP_FUNCTION(openssl_cms_verify)
switch (encoding) { switch (encoding) {
case ENCODING_PEM: case ENCODING_PEM:
cms = PEM_read_bio_CMS(sigbio, NULL, 0, NULL); cms = php_openssl_pem_read_bio_cms(sigbio);
datain = in; datain = in;
break; break;
case ENCODING_DER: case ENCODING_DER:
cms = d2i_CMS_bio(sigbio, NULL); cms = php_openssl_d2i_bio_cms(sigbio);
datain = in; datain = in;
break; break;
case ENCODING_SMIME: case ENCODING_SMIME:
cms = SMIME_read_CMS(sigbio, &datain); cms = php_openssl_smime_read_cms(sigbio, &datain);
break; break;
default: default:
php_error_docref(NULL, E_WARNING, "Unknown encoding"); php_error_docref(NULL, E_WARNING, "Unknown encoding");
goto clean_exit; goto clean_exit;
} }
if (cms == NULL) { if (cms == NULL) {
php_openssl_store_errors(); php_openssl_store_errors();
@ -3398,7 +3398,7 @@ PHP_FUNCTION(openssl_cms_read)
goto clean_exit; goto clean_exit;
} }
cms = PEM_read_bio_CMS(bio_in, NULL, NULL, NULL); cms = php_openssl_pem_read_bio_cms(bio_in);
if (cms == NULL) { if (cms == NULL) {
php_openssl_store_errors(); php_openssl_store_errors();
goto clean_exit; goto clean_exit;
@ -3703,13 +3703,13 @@ PHP_FUNCTION(openssl_cms_decrypt)
switch (encoding) { switch (encoding) {
case ENCODING_DER: case ENCODING_DER:
cms = d2i_CMS_bio(in, NULL); cms = php_openssl_d2i_bio_cms(in);
break; break;
case ENCODING_PEM: case ENCODING_PEM:
cms = PEM_read_bio_CMS(in, NULL, 0, NULL); cms = php_openssl_pem_read_bio_cms(in);
break; break;
case ENCODING_SMIME: case ENCODING_SMIME:
cms = SMIME_read_CMS(in, &datain); cms = php_openssl_smime_read_cms(in, &datain);
break; break;
default: default:
zend_argument_value_error(5, "must be an OPENSSL_ENCODING_* constant"); zend_argument_value_error(5, "must be an OPENSSL_ENCODING_* constant");

View file

@ -541,18 +541,14 @@ X509 *php_openssl_x509_from_str(
php_openssl_store_errors(); php_openssl_store_errors();
return NULL; return NULL;
} }
cert = PEM_read_bio_X509(in, NULL, NULL, NULL); cert = php_openssl_pem_read_bio_x509(in);
} else { } else {
in = BIO_new_mem_buf(ZSTR_VAL(cert_str), (int) ZSTR_LEN(cert_str)); in = BIO_new_mem_buf(ZSTR_VAL(cert_str), (int) ZSTR_LEN(cert_str));
if (in == NULL) { if (in == NULL) {
php_openssl_store_errors(); php_openssl_store_errors();
return NULL; return NULL;
} }
#ifdef TYPEDEF_D2I_OF cert = php_openssl_pem_read_asn1_bio_x509(in);
cert = (X509 *) PEM_ASN1_read_bio((d2i_of_void *)d2i_X509, PEM_STRING_X509, in, NULL, NULL, NULL);
#else
cert = (X509 *) PEM_ASN1_read_bio((char *(*)())d2i_X509, PEM_STRING_X509, in, NULL, NULL, NULL);
#endif
} }
if (!BIO_free(in)) { if (!BIO_free(in)) {
@ -1127,7 +1123,7 @@ X509_REQ *php_openssl_csr_from_str(zend_string *csr_str, uint32_t arg_num)
return NULL; return NULL;
} }
csr = PEM_read_bio_X509_REQ(in, NULL,NULL,NULL); csr = php_openssl_pem_read_bio_x509_req(in);
if (csr == NULL) { if (csr == NULL) {
php_openssl_store_errors(); php_openssl_store_errors();
} }
@ -1158,7 +1154,7 @@ EVP_PKEY *php_openssl_extract_public_key(EVP_PKEY *priv_key)
return NULL; return NULL;
} }
EVP_PKEY *pub_key = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL); EVP_PKEY *pub_key = php_openssl_pem_read_bio_public_key(bio);
BIO_free(bio); BIO_free(bio);
return pub_key; return pub_key;
} }
@ -1290,7 +1286,7 @@ EVP_PKEY *php_openssl_pkey_from_zval(
zend_string_release_ex(val_str, false); zend_string_release_ex(val_str, false);
TMP_CLEAN; TMP_CLEAN;
} }
key = PEM_read_bio_PUBKEY(in, NULL,NULL, NULL); key = php_openssl_pem_read_bio_public_key(in);
BIO_free(in); BIO_free(in);
} }
} else { } else {
@ -1308,12 +1304,12 @@ EVP_PKEY *php_openssl_pkey_from_zval(
TMP_CLEAN; TMP_CLEAN;
} }
if (passphrase == NULL) { if (passphrase == NULL) {
key = PEM_read_bio_PrivateKey(in, NULL, NULL, NULL); key = php_openssl_pem_read_bio_private_key(in, NULL, NULL);
} else { } else {
struct php_openssl_pem_password password; struct php_openssl_pem_password password;
password.key = passphrase; password.key = passphrase;
password.len = passphrase_len; password.len = passphrase_len;
key = PEM_read_bio_PrivateKey(in, NULL, php_openssl_pem_password_cb, &password); key = php_openssl_pem_read_bio_private_key(in, php_openssl_pem_password_cb, &password);
} }
BIO_free(in); BIO_free(in);
} }

View file

@ -692,4 +692,49 @@ CONF *php_openssl_nconf_new(void)
return NCONF_new(NULL); return NCONF_new(NULL);
} }
X509 *php_openssl_pem_read_asn1_bio_x509(BIO *in)
{
return PEM_ASN1_read_bio((d2i_of_void *)d2i_X509, PEM_STRING_X509, in, NULL, NULL, NULL);
}
X509 *php_openssl_pem_read_bio_x509(BIO *in)
{
return PEM_read_bio_X509(in, NULL, NULL, NULL);
}
X509_REQ *php_openssl_pem_read_bio_x509_req(BIO *in)
{
return PEM_read_bio_X509_REQ(in, NULL, NULL, NULL);
}
EVP_PKEY *php_openssl_pem_read_bio_public_key(BIO *in)
{
return PEM_read_bio_PUBKEY(in, NULL, NULL, NULL);
}
EVP_PKEY *php_openssl_pem_read_bio_private_key(BIO *in, pem_password_cb *cb, void *u)
{
return PEM_read_bio_PrivateKey(in, NULL, cb, u);
}
PKCS7 *php_openssl_pem_read_bio_pkcs7(BIO *in)
{
return PEM_read_bio_PKCS7(in, NULL, NULL, NULL);
}
CMS_ContentInfo *php_openssl_pem_read_bio_cms(BIO *in)
{
return PEM_read_bio_CMS(in, NULL, NULL, NULL);
}
CMS_ContentInfo *php_openssl_d2i_bio_cms(BIO *in)
{
return d2i_CMS_bio(in, NULL);
}
CMS_ContentInfo *php_openssl_smime_read_cms(BIO *bio, BIO **bcont)
{
return SMIME_read_CMS(bio, bcont);
}
#endif #endif

View file

@ -843,4 +843,126 @@ CONF *php_openssl_nconf_new(void)
return NCONF_new_ex(PHP_OPENSSL_LIBCTX, NULL); return NCONF_new_ex(PHP_OPENSSL_LIBCTX, NULL);
} }
X509 *php_openssl_pem_read_asn1_bio_x509(BIO *in)
{
X509 *x = X509_new_ex(PHP_OPENSSL_LIBCTX, PHP_OPENSSL_PROPQ);
if (x == NULL) {
return NULL;
}
if (PEM_ASN1_read_bio((d2i_of_void *)d2i_X509, PEM_STRING_X509, in, (void **) &x, NULL, NULL) == NULL) {
X509_free(x);
return NULL;
}
return x;
}
X509 *php_openssl_pem_read_bio_x509(BIO *in)
{
X509 *x = X509_new_ex(PHP_OPENSSL_LIBCTX, PHP_OPENSSL_PROPQ);
if (x == NULL) {
return NULL;
}
if (PEM_read_bio_X509(in, &x, NULL, NULL) == NULL) {
X509_free(x);
return NULL;
}
return x;
}
X509_REQ *php_openssl_pem_read_bio_x509_req(BIO *in)
{
X509_REQ *xr = X509_REQ_new_ex(PHP_OPENSSL_LIBCTX, PHP_OPENSSL_PROPQ);
if (xr == NULL) {
return NULL;
}
if (PEM_read_bio_X509_REQ(in, &xr, NULL, NULL) == NULL) {
X509_REQ_free(xr);
return NULL;
}
return xr;
}
EVP_PKEY *php_openssl_pem_read_bio_public_key(BIO *in)
{
return PEM_read_bio_PUBKEY_ex(in, NULL, NULL, NULL, PHP_OPENSSL_LIBCTX, PHP_OPENSSL_PROPQ);
}
EVP_PKEY *php_openssl_pem_read_bio_private_key(BIO *in, pem_password_cb *cb, void *u)
{
return PEM_read_bio_PrivateKey_ex(in, NULL, cb, u, PHP_OPENSSL_LIBCTX, PHP_OPENSSL_PROPQ);
}
PKCS7 *php_openssl_pem_read_bio_pkcs7(BIO *in)
{
PKCS7 *p = PKCS7_new_ex(PHP_OPENSSL_LIBCTX, PHP_OPENSSL_PROPQ);
if (p == NULL) {
return NULL;
}
if (PEM_read_bio_PKCS7(in, &p, NULL, NULL) == NULL) {
PKCS7_free(p);
return NULL;
}
return p;
}
CMS_ContentInfo *php_openssl_pem_read_bio_cms(BIO *in)
{
CMS_ContentInfo *ci = CMS_ContentInfo_new_ex(PHP_OPENSSL_LIBCTX, PHP_OPENSSL_PROPQ);
if (ci == NULL) {
return NULL;
}
if (PEM_read_bio_CMS(in, &ci, NULL, NULL) == NULL) {
CMS_ContentInfo_free(ci);
return NULL;
}
return ci;
}
CMS_ContentInfo *php_openssl_d2i_bio_cms(BIO *in)
{
CMS_ContentInfo *ci = CMS_ContentInfo_new_ex(PHP_OPENSSL_LIBCTX, PHP_OPENSSL_PROPQ);
if (ci == NULL) {
return NULL;
}
if (d2i_CMS_bio(in, &ci) == NULL) {
CMS_ContentInfo_free(ci);
return NULL;
}
return ci;
}
CMS_ContentInfo *php_openssl_smime_read_cms(BIO *bio, BIO **bcont)
{
CMS_ContentInfo *ci = CMS_ContentInfo_new_ex(PHP_OPENSSL_LIBCTX, PHP_OPENSSL_PROPQ);
if (ci == NULL) {
return NULL;
}
if (SMIME_read_CMS_ex(bio, 0, bcont, &ci) == NULL) {
CMS_ContentInfo_free(ci);
return NULL;
}
return ci;
}
#endif #endif

View file

@ -192,6 +192,16 @@ STACK_OF(X509) * php_openssl_load_all_certs_from_file(
EVP_PKEY * php_openssl_generate_private_key(struct php_x509_request * req); EVP_PKEY * php_openssl_generate_private_key(struct php_x509_request * req);
zend_string *php_openssl_pkey_derive(EVP_PKEY *key, EVP_PKEY *peer_key, size_t requested_key_size); zend_string *php_openssl_pkey_derive(EVP_PKEY *key, EVP_PKEY *peer_key, size_t requested_key_size);
X509 *php_openssl_pem_read_asn1_bio_x509(BIO *in);
X509 *php_openssl_pem_read_bio_x509(BIO *in);
X509_REQ *php_openssl_pem_read_bio_x509_req(BIO *in);
EVP_PKEY *php_openssl_pem_read_bio_public_key(BIO *in);
EVP_PKEY *php_openssl_pem_read_bio_private_key(BIO *in, pem_password_cb *cb, void *u);
PKCS7 *php_openssl_pem_read_bio_pkcs7(BIO *in);
CMS_ContentInfo *php_openssl_pem_read_bio_cms(BIO *in);
CMS_ContentInfo *php_openssl_d2i_bio_cms(BIO *in);
CMS_ContentInfo *php_openssl_smime_read_cms(BIO *bio, BIO **bcont);
#define PHP_SSL_REQ_INIT(req) memset(req, 0, sizeof(*req)) #define PHP_SSL_REQ_INIT(req) memset(req, 0, sizeof(*req))
#define PHP_SSL_REQ_DISPOSE(req) php_openssl_dispose_config(req) #define PHP_SSL_REQ_DISPOSE(req) php_openssl_dispose_config(req)
#define PHP_SSL_REQ_PARSE(req, zval) php_openssl_parse_config(req, zval) #define PHP_SSL_REQ_PARSE(req, zval) php_openssl_parse_config(req, zval)

View file

@ -27,6 +27,7 @@
#include "streams/php_streams_int.h" #include "streams/php_streams_int.h"
#include "zend_smart_str.h" #include "zend_smart_str.h"
#include "php_openssl.h" #include "php_openssl.h"
#include "php_openssl_backend.h"
#include "php_network.h" #include "php_network.h"
#include <openssl/ssl.h> #include <openssl/ssl.h>
#include <openssl/rsa.h> #include <openssl/rsa.h>
@ -850,7 +851,7 @@ static long php_openssl_load_stream_cafile(X509_STORE *cert_store, const char *c
add_cert: { add_cert: {
BIO_puts(buffer, line); BIO_puts(buffer, line);
efree(line); efree(line);
cert = PEM_read_bio_X509(buffer, NULL, 0, NULL); cert = php_openssl_pem_read_bio_x509(buffer);
BIO_free(buffer); BIO_free(buffer);
buffer_active = 0; buffer_active = 0;
if (cert && X509_STORE_add_cert(cert_store, cert)) { if (cert && X509_STORE_add_cert(cert_store, cert)) {