APNS,当程序在 Mac 上运行时,如何修复树莓派上的“无法获取本地颁发者证书”错误?
Posted
技术标签:
【中文标题】APNS,当程序在 Mac 上运行时,如何修复树莓派上的“无法获取本地颁发者证书”错误?【英文标题】:APNS, how do I fix "unable to get local issuer certificate" error on raspberry Pi when program works on Mac? 【发布时间】:2021-06-01 11:39:00 【问题描述】:我正在尝试通过可在我的 Mac 上运行的 python 脚本发送 ios 推送通知,但程序收到错误“httpcore.ConnectError: [SSL: CERTIFICATE_VERIFY_FAILED] 证书验证失败:无法获取本地颁发者证书 (_ssl .c:1122)”当我在我的树莓派上运行它时。我尝试添加 GeoTrust 和新的 AAACertificateServices 证书,但也许我在那里做错了什么。证书永远让我感到困惑,所以我非常感谢您的帮助。我正在使用基于令牌的身份验证,所以我对错误首先指的是什么证书有点困惑......
在带有 Debian 的 Raspberry Pi 3 Model B 上运行。
整个 Traceback 是:
Traceback (most recent call last):
File "/home/jake/.local/lib/python3.9/site-packages/httpx/_exceptions.py", line 326, in map_exceptions
yield
File "/home/jake/.local/lib/python3.9/site-packages/httpx/_client.py", line 861, in _send_single_request
(status_code, headers, stream, ext) = transport.request(
File "/home/jake/.local/lib/python3.9/site-packages/httpcore/_sync/connection_pool.py", line 218, in request
response = connection.request(
File "/home/jake/.local/lib/python3.9/site-packages/httpcore/_sync/connection.py", line 93, in request
self.socket = self._open_socket(timeout)
File "/home/jake/.local/lib/python3.9/site-packages/httpcore/_sync/connection.py", line 119, in _open_socket
return self.backend.open_tcp_stream(
File "/home/jake/.local/lib/python3.9/site-packages/httpcore/_backends/sync.py", line 143, in open_tcp_stream
return SyncSocketStream(sock=sock)
File "/usr/local/opt/python-3.9.0/lib/python3.9/contextlib.py", line 135, in __exit__
self.gen.throw(type, value, traceback)
File "/home/jake/.local/lib/python3.9/site-packages/httpcore/_exceptions.py", line 12, in map_exceptions
raise to_exc(exc) from None
httpcore.ConnectError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1122)
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/home/jake/Programming/Security/MQTT/NotificationServer.py", line 73, in <module>
sendAlarmNotification()
File "/home/jake/Programming/Security/MQTT/NotificationServer.py", line 66, in sendAlarmNotification
r = client.post('/3/device/'.format(server, deviceToken), json=notification, headers=headers)
File "/home/jake/.local/lib/python3.9/site-packages/httpx/_client.py", line 992, in post
return self.request(
File "/home/jake/.local/lib/python3.9/site-packages/httpx/_client.py", line 733, in request
return self.send(
File "/home/jake/.local/lib/python3.9/site-packages/httpx/_client.py", line 767, in send
response = self._send_handling_auth(
File "/home/jake/.local/lib/python3.9/site-packages/httpx/_client.py", line 805, in _send_handling_auth
response = self._send_handling_redirects(
File "/home/jake/.local/lib/python3.9/site-packages/httpx/_client.py", line 837, in _send_handling_redirects
response = self._send_single_request(request, timeout)
File "/home/jake/.local/lib/python3.9/site-packages/httpx/_client.py", line 861, in _send_single_request
(status_code, headers, stream, ext) = transport.request(
File "/usr/local/opt/python-3.9.0/lib/python3.9/contextlib.py", line 135, in __exit__
self.gen.throw(type, value, traceback)
File "/home/jake/.local/lib/python3.9/site-packages/httpx/_exceptions.py", line 343, in map_exceptions
raise mapped_exc(message, **kwargs) from exc # type: ignore
httpx.ConnectError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1122)
我的代码是
import httpx
import time
from jwcrypto import jwt, jwk
devServer = "https://api.sandbox.push.apple.com:443"
prodServer = "https://api.push.apple.com:443"
server = devServer
pemFilePath = "pushCerts/PushNotificationAuthKey_**********.p8"
# This generates an auth token with the current time, using our pem files
def generateAuthToken():
issueTime = int(time.time())
token = jwt.JWT( header= "alg" : "ES256", "kid" : "**********", claims= "iss": "********", "iat": issueTime )
with open(pemFilePath, "rb") as pemfile:
key = jwk.JWK.from_pem(pemfile.read())
token.make_signed_token(key)
return token.serialize()
deviceToken = "long device token"
authToken = 'bearer ' + generateAuthToken()
pushType = 'alert'
expiration = '3600'
priority = '10'
topic = 'com.MyName.MyAppName'
headers =
'authorization' : authToken,
'apns-push-type' : pushType,
'apns-expiration' : expiration,
'apns-priority' : priority,
'apns-topic' : topic
def sendAlarmNotification():
notification = "aps" : "alert": "Alarm Triggered!", "sound" : "critical": 1, "name": "Alarm.caf", "volume": 1.0
client = httpx.Client(http2=True)
try:
r = client.post('/3/device/'.format(server, deviceToken), json=notification, headers=headers)
print(r)
finally:
client.close()
sendAlarmNotification()
另外,运行 openssl s_client -connect api.sandbox.push.apple.com:443
后返回成功验证,所以我真的很困惑。
【问题讨论】:
【参考方案1】:从这里:https://www.python-httpx.org/advanced/ 看起来您需要在 httpx 调用中指定 pem 文件:
导入httpx
r = httpx.get("https://example.org", verify="path/to/client.pem")
【讨论】:
那么为什么我需要在 Pi 而不是我的 Mac 上执行此操作,因为程序在我的 Mac 上完美运行?由于我通过令牌进行身份验证,因此我将提供 GeoTrust pem 文件? 尝试使用 GeoTrust 证书无济于事:/ 您将访问 apple.com 地址,并且 MAC 默认情况下可能具有该证书链,因此它可以与 Apple 通信,而 Pi 默认情况下不会。使用基于令牌的身份验证时出现此问题的原因是连接是 SSL,需要首先验证。不确定为什么存在 GeoTrust,您需要验证 api.push.apple.com 使用的证书,该证书看起来是由 Apple 颁发的。您可以尝试 verify=False 如果可行,则说明您没有正确的证书更改来验证 api.push.apple.com 使用的 ssl GeoTrust 是您需要的 Apple 的 APNS 证书,他们的网站声明“创建该连接需要在您的每个提供商服务器上安装 GeoTrust Global CA 根证书。”如果我理解正确?我不知道我会使用什么其他证书......我试过 verify=False 并没有改变任何东西。还有更多见解吗?以上是关于APNS,当程序在 Mac 上运行时,如何修复树莓派上的“无法获取本地颁发者证书”错误?的主要内容,如果未能解决你的问题,请参考以下文章