13
votes

I'm trying to send my phone a push notification using the simple PHP tool which connects to ssl://gateway.push.apple.com:2195, but the connection fails with the following errors:

Warning: stream_socket_client(): SSL operation failed with code 1. OpenSSL Error messages:
error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed in <Users/.../file.php> on line 30

Warning: stream_socket_client(): Failed to enable crypto in <Users/.../file.php> on line 30

Warning: stream_socket_client(): unable to connect to ssl://gateway.sandbox.push.apple.com:2195 (Unknown error) in <Users/.../file.php> on line 30
Failed to connect: 0 

This all started since I upgraded to the GM Seed of macOS Sierra. What's new in macOS Sierra that affects SSL connections? How do I resolve this?

4
Firstly you try to check Push notification works using some APNS Tester if you get notification then all Ok if not then you have to check from both side. You can test using this site pushtry.comashmi123
The exact same folder (which has the certificate etc) works fine in OS X Mavericks but not in macOS Sierra. I think basically the issue is with locating the path of the certificate (.pem) file. I tried providing the absolute path as well as the relative path, and neither try worked.Vinod Vishwanath
Have u try to using this site?ashmi123
That's really besides the point. I just want to get the bottom of why the php connection is failing.Vinod Vishwanath

4 Answers

12
votes

I got same error, and this is what I did:

1) updated my openssl (i think u dont need this) got to step 2, cause this will take about 10 minutes

brew install openssl

make sure u updated it correct:

openssl version

If not, try this or google:

brew link --force openssl

2) check you php default_cert_file path:

php -r "print_r(openssl_get_cert_locations());"

this is what i got:

Array
(
[default_cert_file] => /usr/local/libressl/etc/ssl/cert.pem
[default_cert_file_env] => SSL_CERT_FILE
[default_cert_dir] => /usr/local/libressl/etc/ssl/certs
[default_cert_dir_env] => SSL_CERT_DIR
[default_private_dir] => /usr/local/libressl/etc/ssl/private
[default_default_cert_area] => /usr/local/libressl/etc/ssl
[ini_cafile] => 
[ini_capath] => 
)

3) download cacert.pem from here:

wget http://curl.haxx.se/ca/cacert.pem

4) move cacert.pem file to your default_cert_file path (as root):

sudo mv cacert.pem /usr/local/libressl/etc/ssl/cert.pem

probably i'll need to create this directory first

After this, my php script worked.

12
votes

I got the same error after upgrading to macOS Sierra while using php script to send push notifications.

Solution with installing certificate to

[default_cert_file] => /usr/local/libressl/etc/ssl/cert.pem didn't help as well.


Updated to PHP v. 5.6.27, macOS Sierra 10.12.4


And after all, I found my problem. It was in the fact, that macOS Sierra updated PHP version to 5.6.27

To check it, type in Terminal

php -v

PHP 5.6.27 (cli) (built: Oct 23 2016 11:47:58) 
Copyright (c) 1997-2016 The PHP Group
Zend Engine v2.6.0, Copyright (c) 1998-2016 Zend Technologies

And here is OpenSSL changes in PHP 5.6.x

As the brief workaround, someone suggested disabling brand-new security features in the php script (in the link above, very bottom part).

Safer (and I recommend it) would be a way to setup path to entrust_2048_ca.cer explicitly like

 $streamContext = stream_context_create([
            'ssl' => [
                'verify_peer'      => true,
                'verify_peer_name' => true,
                'cafile'           => '/path/to/bundle/entrust_2048_ca.cer',
            ]
        ]);

It works as well .

1
votes

You can get certificate from Entrust. Download the entrust_2048_ca.cer certificate from: https://www.entrust.com/get-support/ssl-certificate-support/root-certificate-downloads/. After downloading entrust_2048_ca.cer, I copied it in the same directory where my php script was and it all worked.

More details here: https://stackoverflow.com/a/28222783/4253579

0
votes

adding to the answer given by @Sandar you can also set the cafile like this

stream_context_set_option($streamContext, 'ssl', 'cafile', '/path/to/entrust_2048_ca.cer');