APNS Openssl Connection from PHP for Apple Push Notification? - php

Finally i have sent a notification from my local server to my device. I followed this tutorial http://www.raywenderlich.com/3525/apple-push-notification-services-tutorial-part-2 and many of the peoples from stack overflow helped me to reach this. I Thank you all my friends.
I have one doubt on the server setup. For my local use i have used MAMP for Apache and MySQL servers. Finally i open the ssl from Terminal used certificate.pem and key.pem. Is there any way to open ssl from php script. But, i don't know any single script of php because i am ios developer. Sorry for this.
Yesterday i have used below commands in my Terminal to open ssl and connect to APNS,
unknownc42c032e8297:~ gopi$ /Applications/MAMP/bin/php/php5.3.6/bin/php /Users/gopi/Desktop/PushChatServer/push/push.php development
unknownc42c032e8297:~ gopi$ cd /Users/gopi/Desktop/PushChatServer/push
unknownc42c032e8297:push gopi$ telnet gateway.sandbox.push.apple.com 2195
Trying 17.149.34.66...
Connected to gateway.sandbox.push-apple.com.akadns.net.
Escape character is '^]'.
Connection closed by foreign host.
unknownc42c032e8297:push **gopi$ openssl s_client -connect gateway.sandbox.push.apple.com:2195 -cert gopiAPNCert.pem -key gopiAPNKey.pem**
Enter pass phrase for gopiAPNKey.pem:
CONNECTED(00000003)
.
.
.
.
Verify return code: 0 (ok)
---
creagx
closed
unknownc42c032e8297:push gopi$ /Applications/MAMP/bin/php/php5.3.6/bin/php /Users/gopi/Desktop/PushChatServer/push/push.php development
^C
Is there any way to openssl from our php file? It is possible or Terminal usage is better and is the only way for this? Can anyone please help me on this? Thanks in advance.

To post the Terminal output from a command to PHP , you can use exec() , system() or passthru(). The usage is slightly different among these functions, but they basically do the same job.

Related

curl https://SERVER_IP:8443 works on Mac but not when I SSH into server

Via terminal on a Mac (PHP 7.1.23), I can issue a curl (curl 7.54.0) command via the CLI such as:
curl https://www.SERVER_HOSTNAME:8443
and it works without error.
I SSH into the VPS Linux server running x86_64-redhat-linux-gnu with curl 7.61.1 and PHP 7.3.5 and if I do a curl command without the port:
curl https://www.SERVER_HOSTNAME
it works fine but as soon as I add the port it chokes.
curl https://www.SERVER_HOSTNAME:8443
gives this error:
"SSL certificate problem: unable to get local issuer certificate
More details here: https://curl.haxx.se/docs/sslcerts.html
curl failed to verify the legitimacy of the server and therefore could not establish a secure connection to it. To learn more about this situation and how to fix it, please visit the web page mentioned above.
The actual certificate is not self signed. It is via Godaddy with a Bundle and a good CA.
Any suggestions on what I need to fix or set?
Thanks in advance.

Only from PHP: Unable to connect APNS gateway.push.apple.com:2195

It's a late night. I just spent 10 hours in google/stackoverflow search and experiments. And seems I hate Apple Push Notifications. I'm totally frustrated and will appreciate any help.
Thank you.
The problem:
The PHP code for sending Apple Push Notifications, which successfully worked two weeks ago stopped to work now and throws following errors:
PHP Warning: stream_socket_client(): Failed to enable crypto in /home/...
PHP Warning: stream_socket_client(): unable to connect to ssl://gateway.push.apple.com:2195 (Unknown error) in /home/...
It stopped to work on two separate servers, which are using separate scripts for APNs sending.
Environment:
Servers: CentOS 6.5 with PHP 5.4.32 and Ubuntu 14.04.3 with PHP 5.5.9
APN: In production mode
Certificates: tested with 700+ push notifications.
One of the servers is using https://github.com/immobiliare/ApnsPHP, other - https://github.com/antongorodezkiy/wp-apn, on localhost I tested simple file without using any third party code.
Investigation:
For all cases below I used the same active device token and the same production PEM certificate.
php
However, even this simple code doesn't work on both servers and localhost and return the same error as above:
$ctx = stream_context_create();
stream_context_set_option($ctx, 'ssl', 'local_cert', '/absolute/path/to/apn_prod.pem');
// Open a connection to the APNS server
$fp = stream_socket_client(
'ssl://gateway.push.apple.com:2195', $err,
$errstr, 60, STREAM_CLIENT_CONNECT|STREAM_CLIENT_PERSISTENT, $ctx);
I also tried to play with stream_context_set_option() options, include entrust_2048_ca.cer, etc, and even some options from this article. Although provided code worked without any modifications before August 2015.
openssl
Connection worked with openssl (link):
openssl s_client -connect gateway.push.apple.com:2195 -cert /absolute/path/to/apn_prod.pem -debug -showcerts -CAfile /absolute/path/to/server-ca-cert.pem
And got with CONNECTED(00000003) and Verify return code: 0 ( ok ).
telnet
Connection worked with telnet:
-sh-4.1$ telnet gateway.push.apple.com 2195
Trying 17.172.233.150...
Connected to gateway.push.apple.com.
pecl apn
It didn't send push notification. I just tried to use adaptation of sample code, but got the error Invalid token. The token is active and same token I used everywhere and for Houston and Ruby too.
houston
It worked with Houston
apn push "0346a53f...231d9d6abe11" -c /absolute/path/to/apn_prod.pem -m "Hello from the command line!" -e "production"
ruby
I'm not a Ruby programmer (yet at least), but after success with Houston, I found and adapted Ruby code without Houston dependency.
And it worked:
#!/usr/bin/env ruby
require 'openssl'
require 'socket'
require 'json'
token = "0346a53f...231d9d6abe11"
cert = File.read("/absolute/path/to/apn_prod.pem")
ctx = OpenSSL::SSL::SSLContext.new
ctx.key = OpenSSL::PKey::RSA.new(cert, '') #set passphrase here, if any
ctx.cert = OpenSSL::X509::Certificate.new(cert)
sock = TCPSocket.new('gateway.push.apple.com', 2195) #development gateway
ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx)
ssl.connect
payload = {"aps" => {"alert" => "Oh hai!", "badge" => 1, "sound" => 'default'}}
json = payload.to_json()
token = [token.delete(' ')].pack('H*') #something like 2c0cad 01d1465 346786a9 3a07613f2 b03f0b94b6 8dde3993 d9017224 ad068d36
apnsMessage = "\0\0 #{token}\0#{json.length.chr}#{json}"
ssl.write(apnsMessage)
ssl.close
sock.close
puts "End"
Questions:
What's wrong with PHP? Is there some bug related to this issue? (I didn't find bug report though)
Any ideas how to solve this issue?
Any ideas what could be the difference in PHP and Ruby cases (I assume that Python or Perl could work fine too)? I even tried to read PHP sources, but without success to understand how stream_socket_client() implemented.
Please help.
I've found the issue and fixed it.
The problem was in .pem certificate. Somehow there were two certificates in one file for both production and development .pem files. The same .pem file with two certificates was in the repo for a long time but APNs stopped to work only few months ago. Maybe something was upgraded/changed on the Apple's side.
I assume the Ruby code somehow removes certificate duplication or maybe it took only first certificate, so it worked in Ruby.
However, the solution was to remove the second certificate from the .pem file. After that APNs started to work and they work now (I received some just yesterday).
If you're just reusing an old Certificate Signing Request (CSR), make sure to remove the expired/old APNs certificate from your Keychain before exporting the new one and its private key as p12 file. If you don't do that, the PEM file you generated out from the exported p12 will still contain the expired/old certificate which doesn't goes well with Apple's Push provider. Thus resulting to unable to connect to ssl....

How the server must be configured to be able to connect to mailbox via php script

I have spent 8 hours on this, and still can't get it right.
My situation:
My server is running on Linux xrm 2.6.32-5-amd64;
In console: openssl s_client -connect ns1.example.com:995 works flawlessly, successful connection.
But when i execute this script:
a)
$res = imap_open("{ns1.example.com:993}",
"user#example.lv", "password");
Response is: Array ( [0] => [CLOSED] IMAP connection broken (server response) )
b)
$res = imap_open("{ns1.example.com:993/ssl}",
"user#example.lv", "password");
Response: Array ( [0] => Certificate failure for ns1.example.com: self signed certificate: /CN=ns1.example.com/emailAddress=ssl#ns1.example.com )
Is it connected with the fact that, this script is under drupal directory?
And it uses different php.ini than server does?
Even though when i execute php_info(), it says that imap and imap/ssl is enbaled.
i have tried all the imap_open() flags, but still no luck.
I even can't connect to a standart gmail mailbox.
Please get me out of here.
How the server must be configured to be able to connect to mailbox
It depends. The server can use a certificate signed by a public CA if the CA is a trust anchor on the client. The server can use a certifcate signed by a non-public CA used in a private PKI as long as the client uses it as a trust anchor.
The server can also use a self signed certificate if the client trusts the certificate. See Marc B's comments.
In the case of the mail protocols, opportunistic encryption is the next big push. As such, your script should be using DNSSEC and DANE to fetch the certificate from DNS's CERT resource record. See, for example, RFC 6944 and RFC 7218.
As a fallback, the script should be using security diversification techniques like Trust on First Use (TOFU), certificate pinning or public key pinning. Peter Gutmann talks about it in his book Engineering Security. (The other choice - disable validation - is really bad).
... via php script
This is likely your problem. Its not robust and it does not do the right thing.
In console: openssl s_client -connect ns1.example.com:995 works flawlessly
Probably not. Are you certain about that? I would have expected s_client to return non-0. At minimum, you would have needed the -CAfile option to tell OpenSSL what certificate to use as a trust anchor.
Also, OpenSSL prior to OpenSSL 1.1.0 does not perform hostname matching. So the name in the certifcate could be anything and s_client would accept it as long as its signed by a CA (modulo the -CAfile option). That mistake does not show up anywhere. You have to manually inspect the end entity certificate to discover the problem (if its present).

How to connect to Heroku postgres database from a local connection in php

I'm trying to access to my Heroku Postgres database from a php code that runs locally.
pg_connect("host=myhost port=5432 dbname=mydb user=me password=*** sslmode=require options='--client_encoding=UTF8'")
works well when the code runs on Heroku, but not locally. (the value are those given by Heroku)
I get this error :
Unable to connect to PostgreSQL server: sslmode value "require"
invalid when SSL support is not compiled in
If I delete sslmode, I get this error :
Network is unreachable Is the server running on host "myhost" and
accepting TCP/IP connections on port 5432?
Does someone has a clue ? It would help a lot !
Heroku Postgres requires sslmode for external connections. You likely need to compile PHP with the --with-openssl[=dir] compile flag. See here for more information: http://www.php.net/manual/en/book.openssl.php
Can you verify your installation of PHP has openssl compiled in with it? The only way I know to check this is with a phpinfo() page and look for the --with-openssl flag.

Workaround for PHP IMAP functions? Trying to work with incoming email on localhost using XAMPP

In the project I am working on right now, I am trying to add the functionality where I can change the status of a ticket from 'closed' to 'reopened' when the user sends an email to the support desk. I would also like to save their email reply to the database.
The problem I am running into is that I cannot get PHP's IMAP functions to work on my current Apache configuration. From looking at quite a few posts here at stackoverflow and other places, it seems that the problem is OpenSSL is not enabled in the standard configuration. So for example, when I run this code:
<h1>IMAP testing!</h1>
<?php
$connect = "{imap.gmail.com:993/imap/ssl/novalidate-cert}INBOX";
$user = "my email address #gmail.com";
$pass = "my password";
$mailbox = imap_open($connect, $user, $pass);
?>
I get the error:
Can't open mailbox {imap.gmail.com:993/imap/ssl/novalidate-cert}INBOX: invalid remote specification.
Is there anything I can do, short of recompiling PHP, to mimic IMAP functionality on my local machine to be able to continue developing the functionality of working with email (email piping)?
Some notes on my current configuration, just in case it helps:
OS X 10.7.4
PHP v.5.3.1
UPDATE -
I am almost there (thanks to dAm2K)!
I installed Stunnel (using Mac Ports), got everything configured finally and ran the command:
sudo stunnel /opt/local/etc/stunnel/stunnel.conf -c -d 127.0.0.1:443 -r imap.gmail.com:993
(For whatever reason I had to add the path to the .conf file)
Now my code looks like this:
<?php
$connect = "{localhost:443}INBOX";
$user = "my email address #gmail.com";
$pass = "my password";
$mailbox = imap_open($connect, $user, $pass);
?>
Now when I load the page, it just hangs for 30 seconds or so and gives the warning:
Notice: Unknown: Connection failed to localhost,443: Operation timed out (errflg=2) in Unknown on line 0
What is interesting is that if I change $connect to:
$connect = "{localhost:443/ssl}INBOX";
or
$connect = "{localhost:443/novalidate-cert}INBOX";
I get the original error, which was:
Notice: Unknown: Can't open mailbox {localhost:443/novalidate-cert}INBOX: invalid remote specification (errflg=2) in Unknown on line 0
Any ideas? Just a guess but could it maybe be something to do with the setup of stunnel, like having a self-signed cert or something with the stunnel.conf file I am missing?
Thanks a lot.
Tim
You probably have a firewall that blocks outgoing TCP packets going to imap.gmail.com on port 993.
Ask your sysadmin to check for outgoing TCP on dport 993 (imaps).
Also check if your DNS is resolving imap.gmail.com:
The command:
telnet imap.gmail.com 993
should give you a valid connection. If it doesn't succeed you found the problem.
You may want to install a IMAP server on your development machine so to continue the development offline... you can install "courier imap" package but it's not a very simple task...
If the connection succeded and the command:
openssl s_client -connect imap.gmail.com:993
give you a valid connection, the problem could be that your libc-client doesn't have SSL support compiled in. In this case you cannot use imaps with PHP, and you could use the "stunnel" command to forward clear traffic originating on your local machine going encrypted to gmail IMAP servers.
The command:
stunnel -c -d 127.0.0.1:443 -r imap.gmail.com:993
should do the trick. This way you can connect your PHP script to 127.0.0.1:443:
<?
$connect = "{localhost:443}INBOX";
?>

Categories