check_cert() uses system CA store even if user provided own cert to be used as CA
Personne n'a encore pris cette issue.
- Langage dominant
- C
- Étoiles
- 40.4k
- Forks
- 8.1k
- Merge moyen
- 2 j 13 h
- PR mergées (30 j)
- 96
Description
Description
I was trying to figure out why this code
<?php
$cert = file_get_contents("single-letsencrypt-domain-cert.pem")
print_r(openssl_x509_checkpurpose($cert, X509_PURPOSE_SSL_SERVER, array('letsencrypt-intermediate.pem')));
worked (returned True) on some systems while on other returned False. Turns out the key difference is that one system had CA certificates in a bundle ONLY:
/etc/pki/tls/certs/ca-bundle.crt
while the other system had above bundle BUT also individual hashed CA certs in /etc/openssl/certs/ directory.
/etc/pki/tls/certs/ca-bundle.crt
/etc/openssl/certs/*.0 (bunch of hashes as symlinks to actual individual CA cert files)
(note this is on PLD/Linux, so on your system layout can be different)
Now openssl_x509_checkpurpose() third parameter is "ca_info should be an array of trusted CA files/dirs as described in Certificate Verification."
I assume the goal is to override system CA certs. (My assumption is also based on how/when check_cert() tries to load system CA certs)
openssl_x509_checkpurpose() then uses check_cert() to load CA certs.
Unfortunately the code is like this
[code from php 8.5 git]
parse what user has specified in ca_info (calist), if some files then "nfiles++", if dirs then "ndirs++",
load what user specified (if possible) and then handle system CA certs but do it in such way:
832 if (nfiles == 0) {
833 file_lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file());
834 if (file_lookup == NULL || !X509_LOOKUP_load_file(file_lookup, NULL, X509_FILETYPE_DEFAULT)) {
835 php_openssl_store_errors();
836 }
837 }
838 if (ndirs == 0) {
839 dir_lookup = X509_STORE_add_lookup(store, X509_LOOKUP_hash_dir());
840 if (dir_lookup == NULL || !X509_LOOKUP_add_dir(dir_lookup, NULL, X509_FILETYPE_DEFAULT)) {
841 php_openssl_store_errors();
842 }
843 }
Which means:
- if user specified (in ca_info) any files and only files then sytem CA files won't be loaded BUT sytem directories will (due to ndirs==0)!
- if user specified (in ca_info) any directories and only directories then sytem CA directories won't be loaded BUT sytem files will (due to nfiles==0)!
- if user specified (in ca_info) any files and any directories then no CA files and no CA directories will be used (due to ndirs > 0 and nfiles > 0).
That makes no sense. Partial system CA is getting kind of "randomly" loaded only based on file vs directory type.
I would expect only user provided CA files/dirs to be used and no system CA store if user uses anything valid as ca_info parameter of openssl_x509_checkpurpose()
So the fix - use system CA certs in form of files and directories only if user didn't override these with own ca_info (calist) parameter.
diff --git a/ext/openssl/openssl_backend_common.c b/ext/openssl/openssl_backend_common.c
index c21e64a1306..1f4509f40f0 100644
--- a/ext/openssl/openssl_backend_common.c
+++ b/ext/openssl/openssl_backend_common.c
@@ -829,13 +829,11 @@ X509_STORE *php_openssl_setup_verify(zval *calist, uint32_t arg_num)
}
} ZEND_HASH_FOREACH_END();
}
- if (nfiles == 0) {
+ if (nfiles == 0 && ndirs == 0) {
file_lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file());
if (file_lookup == NULL || !X509_LOOKUP_load_file(file_lookup, NULL, X509_FILETYPE_DEFAULT)) {
php_openssl_store_errors();
}
- }
- if (ndirs == 0) {
dir_lookup = X509_STORE_add_lookup(store, X509_LOOKUP_hash_dir());
if (dir_lookup == NULL || !X509_LOOKUP_add_dir(dir_lookup, NULL, X509_FILETYPE_DEFAULT)) {
php_openssl_store_errors();
PHP Version
$ php84 --version
PHP 8.4.13 (cli) (built: Sep 27 2025 01:01:24) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.4.13, Copyright (c) Zend Technologies
(tests were done on this php)
Operating System
PLD/Linux current Th
Guide de contribution
Ouvrir le guide de contribution
Par où commencer
- Lisez l'issue en entier, puis le guide de contribution du projet.
- Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
- Forkez le dépôt et travaillez sur une branche.
- Ouvrez une pull request qui référence le numéro de l'issue.
Piste de recherche
Commencez dans ext/openssl/openssl_backend_common.c, au niveau de php_openssl_setup_verify() et du chemin check_cert(). Reproduisez l’exemple de openssl_x509_checkpurpose() avec des valeurs de ca_info contenant uniquement un fichier, uniquement un répertoire, puis un mélange des deux. C’est terminé lorsque des fichiers ou répertoires CA valides fournis par l’utilisateur empêchent le chargement partiel du magasin CA du système.
Rédigé par le modèle d'indexation à partir du texte de l'issue.
Évaluation
- Stack technique
- c, php
- Domaine
- backend, security
- Type d'issue
- Bug
- Difficulté
- 3/5
- Temps estimé
- 1-2 jours
- Activité
- À l'abandon
- Clarté
- Plutôt claire
- Accessibilité débutants
- 55/100