I'm currently receiving this error when running an instance of gorush on Heroku.
{
"counts": 1,
"logs": [
{
"type": "failed-push",
"platform": "ios",
"token": "7027a0ec534ac263e1de4b0fdad50e7dba0b894c96ab51173958640e6ade049b",
"message": "Hello World iOS!",
"error": "Post https://api.push.apple.com/3/device/....: x509: certificate signed by unknown authority"
}
],
"success": "ok"
}
Attaching information from Heroku support team:
The certificate signed by unknown authority error means that the Certificate Authority being presented by the server is not recognised by the client/the OS root certificates store it's using.
Checking api.push.apple.com I see it's using the GeoTrust Global CA CA:
$ echo 'Q' | openssl s_client -connect api.push.apple.com:443
...
Certificate chain
0 s:CN = api.push.apple.com, OU = management:idms.group.533599, O = Apple Inc., ST = California, C = US
i:CN = Apple IST CA 2 - G1, OU = Certification Authority, O = Apple Inc., C = US
1 s:CN = Apple IST CA 2 - G1, OU = Certification Authority, O = Apple Inc., C = US
i:C = US, O = GeoTrust Inc., CN = GeoTrust Global CA
Roughly twice a month we release an updated stack image, that pulls in any security/bug fixes from the upstream Ubuntu LTS releases on which the Heroku stack images are based. Yesterday's release included an updated ca-certificates package:
https://devcenter.heroku.com/changelog-items/2028
That is to say, Apple are using a CA that's coming to the end of a multi-year phasing out/distrust process, for which large parts of the ecosystem have already dropped support. It appears that https://api.push.apple.com works in browsers only because they have given a special (presumably temporary) exemption to the Apple intermediate certificate in the certificate chain.
To demonstrate this issue isn't Heroku-specific, I can reproduce using the upstream Ubuntu docker image:
$ docker run --rm -it ubuntu:20.04 bash
root@1b98119cc104:/# apt-get update -qq
root@1b98119cc104:/# apt-get install -yqq curl
...
root@1b98119cc104:/# curl -I https://api.push.apple.com
curl: (60) 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.
And also other common Docker images, such as the official Go images (in the case of this tag, based on Debian Buster):
$ docker run --rm -it golang:1.15.8 curl -I https://api.push.apple.com
curl: (60) SSL certificate problem: unable to get local issuer certificate
...
It appears Apple are aware of this potential incompatibility, since the Apple Push Notification service docs say:
To establish HTTP/2-based TLS sessions with APNs, you must ensure that a GeoTrust Global CA root certificate is installed on each of your providers. If a provider is running macOS, this root certificate is in the keychain by default. On other systems, this certificate might require explicit installation. You can download this certificate from the GeoTrust Root Certificates website. Here is a direct link to the certificate.
I'm presuming there must be backwards compatibility reasons (eg old clients with an outdated root cert stores or that have unfortunately hardcoded the CA) that has meant Apple hasn't updated the certificate sooner.
It seems like until Apple fix the CA they are using, push clients may need to bundle the necessary CA certs themselves, such as prototyped here:
https://github.com/jchambers/pushy/pull/810
I would recommend filing an issue against https://github.com/appleboy/gorush or perhaps more likely the upstream package it uses for the Apple-specific parts (https://github.com/sideshow/apns2) describing the issue and asking that the client bundle the CA certs. Alternatively if there is a way to pass in a CA cert to gorush, you may be able to work around the issue before they fix it upstream.
I'm currently receiving this error when running an instance of gorush on Heroku.
Attaching information from Heroku support team: