samedi 18 juin 2016

iOS Push Notifications (APNs) over GAE, SSL Handshake Failures

I am attempting to show proof of concept for iOS Push Notifications from a Google AppEngine application instance using this RPC handler...

CRT_STR = """-----BEGIN CERTIFICATE-----[...]"""
KEY_STR = """-----BEGIN RSA PRIVATE KEY-----[...]"""
PAYLOAD = {'aps': {'alert':'Push!','sound':'default'}}
TOKEN = 'ac174[...]'


class APNsTest(BaseRPCHandler):

  def get(self, context, name):
    self._call_method(context, name)

  def send_push(self):

    # certificate file
    filename = 'VisitorGuidePush.pem'
    abs_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '../archive/certificate'))
    pem = os.path.abspath(os.path.join(abs_path, 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=StringIO.StringIO(KEY_STR),
                                  certfile=StringIO.StringIO(CRT_STR),
                                  server_side=False,
                                  cert_reqs=ssl.CERT_REQUIRED,
                                  ssl_version=ssl.PROTOCOL_TLSv1,
                                  ca_certs=pem)
    _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)

And need help resolving this error when executing "_ssl.connect(apns_address)"

SSLError: [Errno 1] _ssl.c:507: error:14094410:SSL routines:SSL3_READ_BYTES:sslv3 alert handshake failure

My pem file (derived from a p12) and device token were generated a week ago by a mobile developer on our team, suggestions for validating these would be helpful. For now I believe there are current and valid.

I am obtaining the CRT_STR and KEY_STR from this pem and passing the values in via StringIO. For the pem file itself I am supplying an absolute path and passing it in as the ca_certs.

While the TLSv1 protocol is being specified, I've notice the handshake failure identifies sslv3.

I have attempted many variations and combination of wrap_socket and apns_address, and am consistently stopped by the handshake failure. Which leads me to suspect a problem with the way I am applying the pem certificate.


The primary references I have been using for wrap_socket are [Sockets Python API Overview] and TLS/SSL wrapper for socket objects 17.3.1.1. Socket creation, not to mention more than a few StackOverflow posts.


Please provide advice concerning the appropriate keyfile, certfile, and ca_certs values and any other advice or resources available for GAE based APNs communication. Thanks ~

Aucun commentaire:

Enregistrer un commentaire