php / php/php-src

check_cert() uses system CA store even if user provided own cert to be used as CA

Đang mở
#20,586 0 bình luận 0 reaction 0 người được giao Xem trên GitHub

Chưa có ai nhận issue này.

Bug Extension: openssl Status: Needs Triage
Ngôn ngữ chính
C
Star
40.4k
Fork
8.1k
Merge trung bình
2 ngày 13 giờ
Pull request đã merge (30 ngày)
96

Mô tả

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

Hướng dẫn đóng góp

Mở hướng dẫn đóng góp

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Hướng nghiên cứu

Bắt đầu trong ext/openssl/openssl_backend_common.c tại php_openssl_setup_verify() và đường đi check_cert(). Tái hiện ví dụ openssl_x509_checkpurpose() với các giá trị ca_info chỉ chứa tệp, chỉ chứa thư mục và kết hợp cả hai. Hoàn thành khi các tệp hoặc thư mục CA hợp lệ do người dùng cung cấp ngăn kho CA hệ thống được tải một phần.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Đánh giá

Công nghệ
c, php
Lĩnh vực
backend, security
Loại issue
Lỗi
Độ khó
3/5
Thời gian dự kiến
1-2 ngày
Mức độ hoạt động
Đình trệ
Độ rõ ràng
Khá rõ ràng
Mức phù hợp với người mới
55/100

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.