[英]iOS Push Notifications (APNs) over GAE, SSL Handshake Failure
我試圖使用此RPC處理程序從Google AppEngine應用程序實例中顯示iOS推送通知的概念證明...
PAYLOAD = {'aps': {'alert':'Push!','sound':'default'}}
TOKEN = '[...]'
class APNsTest(BaseRPCHandler):
def get(self, context, name):
self._call_method(context, name)
def send_push(self):
# certificate files
filename = 'VisitorGuidePush'
abs_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '../archive/certificate'))
ca_certs = os.path.abspath(os.path.join(abs_path, '%s.ca'%filename))
certfile = os.path.abspath(os.path.join(abs_path, '%s.crt'%filename))
keyfile = os.path.abspath(os.path.join(abs_path, '%s.key'%filename))
# serialize payload
payload = json.dumps(PAYLOAD)
# APNS server address...
# apns_address = ('api.development.push.apple.com', 443) # Development server
# apns_address = ('api.development.push.apple.com', 2197) # Development server
# apns_address = ('api.push.apple.com', 443) # Production server
apns_address = ('api.push.apple.com', 2197) # Production server
# a socket to connect to APNS over SSL
_sock = socket.socket()
_ssl = ssl.wrap_socket(_sock, keyfile=keyfile,
certfile=certfile,
server_side=False,
cert_reqs=ssl.CERT_REQUIRED,
ssl_version=ssl.PROTOCOL_TLSv1,
ca_certs=ca_certs)
_ssl.connect(apns_address)
# Generate a notification packet
token = binascii.unhexlify(TOKEN)
fmt = '!cH32sH{0:d}s'.format(len(payload))
cmd = '\x00'
message = struct.pack(fmt, cmd, len(token), token, len(payload), payload)
_ssl.write(message)
_ssl.close()
return self.response_result(PAYLOAD)
執行“_ssl.connect(apns_address)”時需要幫助解決此錯誤
SSLError: [Errno 1] _ssl.c:507: error:14094410:SSL routines:SSL3_READ_BYTES:sslv3 alert handshake failure
我的PEM文件(源自.p12)和設備令牌是我們團隊的移動開發人員一周前生成的,驗證這些內容的建議會很有幫助。 現在我相信目前有效。
在指定TLSv1協議時,我注意到握手失敗標識了sslv3。
我嘗試過wrap_socket和apns_address的許多變體和組合,並且由於握手失敗而一直停止。 這導致我懷疑我使用pem證書的方式有問題。
我一直用於wrap_socket的主要引用是對套接字對象 使用OpenSSL和TLS / SSL包裝器 ,更不用說幾個StackOverflow帖子了。
請提供有關適當的密鑰文件,certfile和ca_certs值以及可用於基於GAE的APN通信的任何其他建議或資源的建議。 謝謝〜
最初的.p12已經使用Pusher進行了驗證,並通過openssl進行了划分...
openssl pkcs12 -in vgp.p12 -out VisitorGuidePush.key -nodes -nocerts
openssl pkcs12 -in vgp.p12 -out VisitorGuidePush.crt -nodes -nokeys
openssl pkcs12 -in vgp.p12 -out VisitorGuidePush.ca -nodes -cacerts
我收到一個與ca_certs相關的新錯誤...
SSLError: [Errno 0] _ssl.c:343: error:00000000:lib(0):func(0):reason(0)
刪除ca_certs要求或傳入.p12或.crt等其他文件會導致返回原始握手失敗。
相應的支持文件以創建通用推送通知客戶端SSL證書作為p12文件開始。
接下來,利用命令行openssl將p12解析為所需的證書和密鑰文件......
openssl pkcs12 -in VisitorGuide.p12 -out VisitorGuide.key -nodes -nocerts
openssl pkcs12 -in VisitorGuide.p12 -out VisitorGuide.crt -nodes -nokeys
openssl pkcs12 -in VisitorGuide.p12 -out VisitorGuide.pem -nodes
最后獲取合格的證書頒發機構文件(來自故障排除推送通知 )
除了由成員中心創建的SSL身份(證書和關聯的私鑰)之外,您還應該在提供者上安裝Entrust CA(2048)根證書。
Entrust.net證書頒發機構(2048)下載 ~encoust_2048_ca.cer
請注意,每個GAE實例都在/etc/ca-certificates.crt上托管自己的證書頒發機構,如此處所述, 使用OpenSSL 。
將這些文件添加到項目中,您可以創建兩個同樣有效的ssl套接字對象中的一個...
_ssl = ssl.wrap_socket(_sock, keyfile=VisitorGuide.key,
certfile=VisitorGuide.crt,
server_side=False,
cert_reqs=ssl.CERT_REQUIRED,
ssl_version=ssl.PROTOCOL_TLSv1,
ca_certs=entrust_2048_ca.cer)
...要么...
_ssl = ssl.wrap_socket(_sock, certfile=VisitorGuide.pem,
server_side=False,
cert_reqs=ssl.CERT_REQUIRED,
ssl_version=ssl.PROTOCOL_TLSv1,
ca_certs=entrust_2048_ca.cer)
套接字對象的TLS / SSL包裝器17.3.4.3。 組合鍵和證書解釋了為什么兩者都是有效的參數選項。
在我提供最終代碼塊之前,我必須指出有關APNs地址的事情(這被證明是關鍵點,允許我解決握手失敗並獲得GAE和APN之間的SSL連接)
根據iOS Developer Library APNs Provider API
發送遠程通知的第一步是與相應的APN服務器建立連接:
開發服務器:api.development.push.apple.com:443
生產服務器:api.push.apple.com:443
注意:您也可以在與APN通信時使用端口2197。 例如,您可以執行此操作,以允許APN通過防火牆進行流量,但阻止其他HTTPS流量。
但直到我挖掘Pusher來源,才發現我可以連接的APNs地址......
gateway.sandbox.push.apple.com:2195
gateway.push.apple.com:2195
無需再費周折...
class APNsTest(BaseRPCHandler):
def get(self, context, name):
self._call_method(context, name)
def send_push(self):
# certificate files
abs_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '../cert'))
pem_file = os.path.abspath(os.path.join(abs_path, 'VisitorGuide.pem'))
ca_certs = '/etc/ca-certificates.crt'
# APNS server address...
apns_address = ('gateway.sandbox.push.apple.com', 2195)
# apns_address = ('gateway.push.apple.com', 2195)
# a socket to connect to APNS over SSL
_sock = socket.socket()
_ssl = ssl.wrap_socket(_sock, certfile=pem_file,
server_side=False,
cert_reqs=ssl.CERT_REQUIRED,
ssl_version=ssl.PROTOCOL_TLSv1,
ca_certs=ca_certs)
_ssl.connect(apns_address)
# a notification packet
payload = json.dumps(PAYLOAD)
token = binascii.unhexlify(TOKEN)
fmt = '!cH32sH{0:d}s'.format(len(payload))
cmd = '\x00'
message = struct.pack(fmt, cmd, len(token), token, len(payload), payload)
_ssl.write(message)
_ssl.close()
return self.response_result(PAYLOAD)
...執行沒有錯誤。
此外,通過實驗,我發現當我應用內置的第三方ssl lib時,App Engine上的SSL相關錯誤通常會消失:
libraries:
- name: ssl
version: latest
要么:
libraries:
- name: ssl
version: "2.7"
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.