"No valid certs found for cafile stream..." doing fopen(), but SSL works

My sites with https:// all open and all seems good, but when my PHP code attempts some file access, I get:

Warning: no valid certs found cafile stream: `/verified/correct/path/to/certs/folder'

My code (simple test script) is just this, to get a handle, substituting for this post "mydomain" for the real domain:

$handle = fopen('https://mydomain/enfeedia.xml', 'r');

located at in /srv/www/mydomain/public_html/test_fhandle.php

My sites open, and I checked the path using command line to navigate to the folder using sudo along the way. Even with sudo, was unable to cd to the folder contain the cert stuff, but successfully was able to inspect by doing "ls -l /live/mydomain" and see the four files flashing.

Reveals path as

cert.pem -> ../../archive/mydomain/cert7.pem

and similarly for chain.pem, fullchain.pem and privkey.pem.
Permissions 777 and root:root.

Is that "archive" folder in the path correct? If not, how could that have gotten there? I don't fiddle with the paths for obvious reasons, like death-by-ssl.

Also, why the "7" in cert7 and ditto for the other three?

I keep my certs renewed (otherwise my sites wouldn't open) suggesting "archive" in the path is fine, ditto the "7" in the filename.

Apache and CentOS 7, ver 2.4.6

11 Replies

@k4c4gorman writes:

My code (simple test script) is just this, to get a handle, substituting for this post "mydomain" for the real domain:
 
$handle = fopen('https://mydomain/enfeedia.xml', 'r');

My guess is that there's something in php.ini you have to set/modify. See:

https://www.php.net/manual/en/wrappers.http.php

Reveals path as
 
cert.pem -> ../../archive/mydomain/cert7.pem
 
and similarly for chain.pem, fullchain.pem and privkey.pem.
Permissions 777 and root:root.
 
Is that "archive" folder in the path correct? If not, how could that have gotten there? I don't fiddle with the paths for obvious reasons, like death-by-ssl.
 
Also, why the "7" in cert7 and ditto for the other three?
 
I keep my certs renewed (otherwise my sites wouldn't open) suggesting "archive" in the path is fine, ditto the "7" in the filename.

This is all correct…it's as certbot intended it to be. Don't mess with it. certbot keeps backups of cert.pem, chain.pem, fullchain.pem and privkey.pem…that's why the numbers in the file names.

Thank you for your prompt reply!

I have not tinkered with my php.ini file in a long time except for making some changes to error reporting. I do not change what you see below. I also reboot the server after saving a modified php.ini file. FWIW, I use vim.

I copied this from my php.ini file:

; Whether to allow the treatment of URLs (like http:// or ftp://) as files.
; http://php.net/allow-url-fopen
allow_url_fopen = On
; Whether to allow include/require to open URLs (like http:// or ftp://) as files.
; http://php.net/allow-url-include
allow_url_include = On

Also this:

openssl.cafile=/etc/letsencrypt/live/{mydomain.com}/

Regarding your last paragraph, I believe you are confirming "archive" being in the path. It suggested to me this is all about previous renewals, and the pertinent/current ones are elsewhere.

Again, thank you.

openssl.cafile=/etc/letsencrypt/live/{mydomain.com}/
 
Regarding your last paragraph, I believe you are confirming "archive" being in the path.

No, "live" is the correct path. The files in /etc/letsencrypt/live/{mydomain.com}/ are symlinks to files in /etc/letsencrypt/archive/{mydomain.com}/. You always want to specify the files in /etc/letsencrypt/live/{mydomain.com}/ where they're needed. certbot adjusts the symlinks correctly on renewals.

I believe the cafile is /etc/letsencrypt/live/{mydomain.com}/chain.pem.

-- sw

Steve, thank you for those comments.

I remain puzzled why file operations don't work because, as the warning message says, "No valid certs found for cafile stream". It's crippling some of my websites.

The paths are right, my https websites open (that should say enough right there), relevant php.ini settings are correct, server software has not changed, and file operations have been working for a decade up to about a month ago. I've renewed the certs on time, and just in case, I ran the "dry run" successfully and was told it was too early to actually renew again. Is there a way to force an early renewal (thinking that might knock out the 'glitch')?

What am I missing? I don't know even where to do troubleshooting at this point.

This may help you out:

https://stackoverflow.com/questions/55526568/failed-loading-cafile-stream-in-file-get-contents

This answer is for Windows but it references some relevant php.ini entries you may also need to change.

See also:

https://community.letsencrypt.org/t/is-lets-encrypt-ca-certificate-included-in-cacert-pem-file/44947/8

I don't think early renewal is the answer…I think this is some kind of PHP configuration problem.

I haven't used PHP for a long time and I've never attempted anything like this so I'm somewhat fumbling in the dark too. I'm afraid that you're in for some trial and error here.

You also might try searching your filesystem for a file called cacert.pem and try that path as well. I have one in /usr/local/lib/perl5/site_perl/Mozilla/CA/cacert.pem. cacert.pem is described as follows:

##
## Bundle of CA Root Certificates
##
## Certificate data from Mozilla as of: Fri Oct 1 13:46:52 2021 GMT
##
## This is a bundle of X.509 certificates of public Certificate Authorities
## (CA). These were automatically extracted from Mozilla's root certificates
## file (certdata.txt). This file can be found in the mozilla source tree:
## https://hg.mozilla.org/releases/mozilla-release/raw-file/default/security/nss/lib/ckfw/builtins/certdata.txt
##
## It contains the certificates in PEM format and therefore
## can be directly used with curl / libcurl / php_curl, or with
## an Apache+mod_ssl webserver for SSL client authentication.
## Just configure this file as the SSLCACertificateFile.
##
## Conversion done with mk-ca-bundle.pl version 1.28.
## SHA256: c8f6733d1ff4e6a4769c182971a1234f95ae079247a9c439a13423fe8ba5c24f
##

If you don't have one, install one…I believe installing curl/libcurl will do the trick…or you can get it from:

https://ccadb-public.secure.force.com/mozilla/IncludedRootsPEMTxt?TrustBitsInclude=Websites

From reading the comments, it sounds like this is a file used by lots of things that use SSL so my guess is you probably have one somewhere.

Also, earlier, I said:

I believe the cafile is /etc/letsencrypt/live/{mydomain.com}/fullchain.pem.

This is incorrect. The cafile is /etc/letsencrypt/live/{mydomain.com}/chain.pem.. I corrected my earlier post.

The differences between chain.pem and fullchain.pem are explained here:

https://crypto.stackexchange.com/questions/87205/what-exactly-is-lets-encrypts-chain-pem-file

-- sw

Regarding "After, check the php.ini on the config key named : curl.cainfo and openssl.cafile and make this config"

I have the openssl.cafile line in php.ini, so I added the curl.cainfo line as well, using the same path. Made no difference, so I removed it because I don't like the idea of leaving experiments in live code not knowing if they might have unintended consequences elsewhere.

I downloaded the file using the last link in your message, and it turned out to be a humongous file of a whole bunch of keys (I presume). Seems not related to my issue. Remember, I have not trouble opening my SSL-secured sites.

I have the openssl.cafile line in php.ini, so I added the curl.cainfo line as well, using the same path. Made no difference, so I removed it because I don't like the idea of leaving experiments in live code not knowing if they might have unintended consequences elsewhere.

The openssl.cafile setting in php.ini is preceded by the following comments:

; The location of a Certificate Authority (CA) file on the local filesystem
; to use when verifying the identity of SSL/TLS peers. Most users should
; not specify a value for this directive as PHP will attempt to use the
; OS-managed cert stores in its absence. If specified, this value may still
; be overridden on a per-stream basis via the "cafile" SSL stream context
; option.
; openssl.cafile=

This leads me to believe that your OS-managed cert stores are either non-existent or corrupt.

I downloaded the file using the last link in your message, and it turned out to be a humongous file of a whole bunch of keys (I presume).

That's exactly what it is.

Seems not related to my issue. Remember, I have not trouble opening my SSL-secured sites.

Usually, for an SSL site you have to specify the CA cert in the site configuration (for apache2):

SSLCACertificateFile /etc/letsencrypt/live/mydomain.com/chain.pem

I'm really at a loss too… My only suggestion would be to install curl/libcurl. Maybe that will setup/fix your OS-managed cert stores…whatever those are…

With this line commented out:

openssl.cafile=/etc/letsencrypt/live/{mydomain.com}/

I get:

Warning: fopen(): SSL operation failed with code 1. OpenSSL Error messages: error:14090086:SSL routines:ssl3_get_server_certificate:certificate verify failed in /srv/www/[mydomain]/public_html/test_fhandle.php on line 2

Warning: fopen(): Failed to enable crypto in /srv/www/[mydomain]/public_html/test_fhandle.php on line 2

However, when I don't comment it out, I get

Warning: no valid certs found cafile stream: `/etc/letsencrypt/live/enfeedia.com/' in /srv/www/enfeedia.com/public_html/test_fhandle.php on line 2

Warning: fopen(): Failed to enable crypto in /srv/www/enfeedia.com/public_html/test_fhandle.php on line 2

Warning: fopen(https://enfeedia.com/enfeedia.xml): failed to open stream: operation failed in /srv/www/enfeedia.com/public_html/test_fhandle.php on line 2

In my next post, I'm gonna try inserting "archive" into the path, like this:

openssl.cafile=/etc/letsencrypt/live/archive/{mydomain.com}/

…thinking that, if it's required, that's the right place.

Using:

openssl.cafile=/etc/letsencrypt/live/archive/{mydomain.com}/

I get this

Warning: failed loading cafile stream: `/etc/letsencrypt/live/archive/{mydomain.com}//' in /srv/www/{mydomain.com}//public_html/test_fhandle.php on line 2

Warning: fopen(): Failed to enable crypto in /srv/www/{mydomain.com}//public_html/test_fhandle.php on line 2

Warning: fopen(https://{mydomain.com}//enfeedia.xml): failed to open stream: operation failed in /srv/www/{mydomain.com}//public_html/test_fhandle.php on line 2

Notice the warning in the first line above, WARNING: failed loading cafile stream versus Warning: no valid certs found cafile stream: It seems to verify in that first case with "archive" in the path, the path was incorrect.

Whereas, without "archive" in the path, the message Warning: no valid certs found cafile stream the path was correct but there were no valid certs found there.

So, the idea of putting "archive" in the path was a wrong move on my part. The path was correct, the problem is not finding valid certs in that path. I guess that can either mean no certs were found, or certs were found but the are invalid.

Given I've not made changes to my code pertaining to file operations, that the server software has not changed, php.ini file only changed in the area if error reporting, that I certaingly did not change paths or files in the whole area of encryption stuff, and that my website opened and worked correctly including file operations until recently, I think all of the above is a distraction from troubleshooting elsewhere.

I know not where. I'm back at square 1.

For giggles, I ran the renewal dry run (it was successful):


Processing /etc/letsencrypt/renewal/enfeedia.com.conf


Cert not due for renewal, but simulating renewal for dry run
Plugins selected: Authenticator apache, Installer apache
Starting new HTTPS connection (1): acme-staging-v02.api.letsencrypt.org
Renewing an existing certificate
Performing the following challenges:
http-01 challenge for {domain-1}
http-01 challenge for {domain-2}
http-01 challenge for {domain-3}
http-01 challenge for {domain-4}
.
.
.

Waiting for verification…
Cleaning up challenges


new certificate deployed with reload of apache server; fullchain is
/etc/letsencrypt/live/{mydomain}/fullchain.pem



** DRY RUN: simulating 'certbot renew' close to cert expiry
** (The test certificates below have not been saved.)

Congratulations, all renewals succeeded. The following certs have been renewed:
/etc/letsencrypt/live/{mydomain}/fullchain.pem (success)
** DRY RUN: simulating 'certbot renew' close to cert expiry
** (The test certificates above have not been saved.)


Just curious… Does this work with an http url?

Maybe you can post all this at stackexchange.com or some such. They probably have a much wider audience. Your problem seems to not be specific to Linode or your distro but to your app configuration.

-- sw

Reply

Please enter an answer
Tips:

You can mention users to notify them: @username

You can use Markdown to format your question. For more examples see the Markdown Cheatsheet.

> I’m a blockquote.

I’m a blockquote.

[I'm a link] (https://www.google.com)

I'm a link

**I am bold** I am bold

*I am italicized* I am italicized

Community Code of Conduct