Giter Club home page Giter Club logo

pushproxy's Introduction

PushProxy

PushProxy is a man-in-the-middle proxy for iOS and OS X Push Notifications. It decodes the push protocol and outputs messages in a readable form. It also provides APIs for handling messages and sending push notifications directly to devices without sending them via Apple's infrastructure.

For a reference on the push protocol, see apple-push-protocol-ios5-lion.md. iOS4 and earlier used another version of the protocol, described in apple-push-protocol-ios4.md. This proxy only supports the iOS5 protocol.

I tested only using jailbroken iOS devices, but it may be possible to use a push certificate from a jailbroken device and use it to connect a non-jailbroken device to Apple's servers. At least some apps using push notifications will be confused if you do this, but I think this was a way for hacktivated iPhones to get a push certificate.

WARNING: PushProxy doesn't check device certificates properly, so don't put it on the open internet.

'Screenshot'

2013-02-17 21:54:15+0100 [#0] New connection from 192.168.0.120:61321
2013-02-17 21:54:15+0100 [#0] SSL handshake done: Device: B481816D-4650-49EA-977C-9FCBDEB30CB1
2013-02-17 21:54:15+0100 [#0] Connecting to push server: 17.172.232.59:5223
2013-02-17 21:54:15+0100 Starting factory <icl0ud.push.intercept.InterceptClientFactory instance at 0x147d5a8>
2013-02-17 21:54:15+0100 [#0] -> APSConnect presenceFlags: 00000002 state: 01
                                   push token: 4b5543c35b48429bbe770a8af11457f39374bd4e43e94adaa86bd979c50bdb05
2013-02-17 21:54:16+0100 [#0] <- APSConnectResponse 00 messageSize: 4096 unknown5: 0002
2013-02-17 21:54:16+0100 [#0] -> APSTopics for token <none>
                                   enabled topics: 
                                     com.apple.itunesstored
                                     com.apple.madrid
                                     com.apple.mobileme.fmip
                                     com.apple.gamed
                                     com.apple.ess
                                     com.me.keyvalueservice
                                     4357ca2451b7b787caea8a603e51a1f45feaeda4
                                     com.apple.mobileme.fmf1
                                     com.apple.mediastream.subscription.push
                                   disabled topics:
                                     com.apple.store.Jolly
2013-02-17 21:54:16+0100 [#0] -> APSKeepAlive 10min carrier: 31038 iPhone4,1/6.1.1/10B145
2013-02-17 21:54:16+0100 [#0] <- APSKeepAliveResponse
2013-02-17 22:10:04+0100 [#0] <- APSNotification 4357ca2451b7b787caea8a603e51a1f45feaeda4
                                   timestamp: 2013-02-17 22:10:16.642561 expiry: 1970-01-01 00:59:59
                                   messageId: 00000000                   storageFlags: 00
                                   unknown9:  None                       payload decoded (json)
                                   {u'aps': {u'alert': u'Chrome\u2014meeee/pushproxy \xb7 GitHub\nhttps://github.com/meeee/pushproxy',
                                             u'badge': 3,
                                             u'sound': u'elysium.caf'},
                                    u'urlhint': u'1234567'}
2013-02-17 22:10:06+0100 [#0] -> APSNotificationResponse message: 00000000 status: 00

Setup

Overview

Setup on iOS >= 6.0 and OS X >= 10.8 requires several steps:

  1. Install pushproxy including dependencies
  2. Create a CA and issue certificates
  3. Install CA on device
  4. Extract and copy device certificate
  5. Create configuration bag
  6. Redirect DNS

You can find instructions on how to redirect the push connection on iOS < 6.0 and OS X < 10.8 in setup-ios5-10.7.md.

Install pushproxy and dependencies

The proxy is written in Python, I recommend setting up a virtualenv and installing the requirements:

pip install -r src/requirements.txt

Setting up PushProxy requires redirecting push connections to your server and setting up X.509 certificates for SSL authentication.

The push protocol uses SSL for client and server authentication. You need to extract the device certificate and give it to the proxy so it can authenticate itself as device against Apple. You also need to make the device trust your proxy since you are impersonating Apple's servers.

Create CA and issue certificates

Your device has to trust two certificates, so the easiest way is to create a CA and issue the certificates. This way you only need to install one CA certificate on the device.

The first hostname you need to create a SSL server certificate for:

init-p01st.push.apple.com

You will need this certificate later to sign a configuration bag.

iOS <= 6, OS X <= 10.8

You can choose the hostname of the second certificate, the push hostname. When connecting to the push hostname (Apple's default is courier.push.apple.com), apsd prepends a random number to the hostname, perhaps for load balancing and/or fault tolerance (e.g. 22-courier.push.apple.com). You need to configure a DNS server which responds to these hostnames. You can use a wildcard subdomain to redirect all host names with different numbers to the proxy, like *.push.example.com. So in this case, you would create a certificate for:

courier.push.example.com

Store the generated certificate and private key in PEM encoding at the following path:

certs/courier.push.apple.com/server.pem

iOS >= 7, OS X >= 10.9

Beginning with OS X 10.9 and probably iOS 7, apsd does some sort of certificate pinning and checks the root certificate as well as the chain length and some attributes of the leaf certificate. OS X 10.10.1 contains pinned certificates, but the checks are ineffective and a certificate with the right attributes trusted via a chain with the root in the System keychain is enough. I haven't tested this on 10.9, but the checks might also be less effective there than I thought previously.

The certificate chain needs to have a length of 3, so you have to use a CA certificate as well as an additional intermediary CA certificate that signs the leaf.

Create the leaf certificate with the following attributes:

* Common Name: courier.push.apple.com
* Country Name: US
* State/Province Name: California
* Locality Name: Cupertino
* Organization Name: Apple Inc.
* Subject Alternative Name Extension
    * DNS Name: <the hostname you put into the bag>

apsd checks the leaf certificate for these attributes. As it also does normal SSL certificate validation, the certificate must be valid for the host it connects to. This host is the name you put in the configuration bag. Luckily, we can use the Subject Alternative Name extension to make the certificate also valid for our hostname.

Store the generated certificate, the intermediary CA certificate and the private key in PEM encoding at the following path:

certs/courier.push.apple.com/server.pem

Install CA on device

You can install the CA certificate on iOS devices via Safari or iPhone Configuration Utility.

On OS X you can use keychain access to install the certificate, make sure to install it in the System keychain, not your login keychain. Mark it as trusted, Keychain Access should then display it as 'marked as trusted for all users'.

If you can't mark the CA as trusted for all users, you might have to remove the certificate from your login keychain, so you only have it in the system keychain.

Patch apsd (possibly optional)

OS X 10.9 and iOS 7 had some sort of certificate pinning implemented, but this seems to be no longer the case in OS X 10.10.1. I haven't checked for anything else, but you might try without patching first.

This patch replaces the pinned root certificate in the apsd binary with a chosen one having the same or a shorter length than the original certificate.

You can run the script with the following command. When running the script, think about making a backup and make sure to restore permissions afterwards.

setup/osx/patch_apsd.py <path to apsd> <new root CA cert> <new intermediate CA cert> <code signing identity>

<path to apsd>: Path to the apsd binary. Usually stored in `/System/Library/PrivateFrameworks/ApplePushService.framework/apsd`. You might need to copy it/change permissions to patch as a user.
<new root ca cert>: Path to a root certificate in DER form to replace the original root certificate by Entrust. This certificate must be no longer than 1120 bytes (length of the original certificate, file size, not key length). Shorter is ok, the rest will be zero-padded and the certificate size will be adjusted in the code.
<new intermediate CA cert> same as for new root cert, only for the intermediate cert
<code signing identity>: Name of a code signing certificate understood by the `codesign` utility, make sure your machine trusts this cert (root)

Make sure to do this before extracting the device certificate. Once you replaced the apsd binary, the keychain will not allow the apsd daemon to use the existing keychain any more and returns the following or a similar error:

The operation couldn’t be completed. (OSStatus error -25293.)

When you restart/run apsd afterwards (kill or launchctl), after a few failing attempts to access the keychain, apsd will request a new push certificate, which you can then extract as describe in the following section.

Extract and copy device certificate

Extract iOS Certificates

First, download the nimble tool, extract PushFix.zip and place nimble into setup/ios. The following script will copy the tool to your iOS device, run it and copy the extracted certificates back to your computer. It assumes you have SSH running on your device. I recommend setting up key-based authentication, otherwise you will be typing your password a few times.

Make sure you are in the pushproxy root directory, otherwise the script will fail.

cd pushproxy
setup/ios/extract-and-convert-certs.sh root@<device hostname>

You can find the extracted certificates in certs/device. Both public and private key are in one PEM-file.

Alternative to nimble (Keychain-Dumper)

On some newer devices, nimble might refuse to start with a message like Illegal instruction: 4.

Thanks to angelovAlex for having the idea and documenting how to use Keychain-Dumper, here's an alternative using a fork of Keychain-Dumper:

To extract certificate from iOS device you need to download and compile Keychain-Dumper (modified version is here: https://github.com/reinitialized/Keychain-Dumper) and a binary should be signed. There's an instruction of how to sign the binary using self-signed certificate in Keychain-Dumper's README. Upload this binary to device and run it with -k:

./KeychainDumper_signed -k

Find the key where label is APSClientIdentity and copy the key

Key
---
Entitlement Group: com.apple.apsd
Label: APSClientIdentity
Application Label: <XXXX>
Key Class: Private
Permanent Key: True
Key Size: 1024
Effective Key Size: 1024
For Encryption: False
For Decryption: True
For Key Derivation: True
For Signatures: True
For Signature Verification: False
For Key Wrapping: False
For Key Unwrapping: True
-----BEGIN RSA PRIVATE KEY-----
XXXX
-----END RSA PRIVATE KEY-----

Then run this tool with -i and copy certificate

./KeychainDumper_signed -i
Identity
--------
Certificate
-----------
Summary: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXX                   // IDENTIFIER ! ! !
Entitlement Group: com.apple.apsd
Label: APSClientIdentity
Serial Number: XXXX
Subject Key ID: XXXX
Subject Key Hash: XXXX
-----BEGIN CERTIFICATE-----
XXXX
-----END CERTIFICATE-----

Put key and certificate in one file and rename it to the IDENTIFIER.pem and put this file in certs/device.

Extract OS X Certificates

Note: If you want to connect at least one device via a patched push daemon, you need to patch the push daemon on OS X first.

OS X stores the certificates in a keychain in /Library/Keychains, either in applepushserviced.keychain or in apsd.keychain.

This step extracts the push private key and certificate from the keychain. It stores them in certs/device/<UUID>.pem

setup/osx/extract_certificate.py -f

You can remove the -f parameter to get key and certificate on stdout instead of writing them to a file.

Create Configuration Bag

Since iOS 6 and OS X 10.8, apsd loads a signed configuration bag. This bag contains the push domain to connect to among a number of less interesting parameters.

Apple's original bag can be found here: http://init-p01st.push.apple.com/bag (Download)

Run the following command to create a bag for your own domain:

setup/bag.py <push domain> <signing certificate> > bag

push domain: The domain apsd should connect to, e.g. courier.push.example.com. apsd then actually connects to this domain prepended with a random number between 1 and 50, e.g. 22-courier.push.example.com.

signing certificate: the previously created server certificate for init-p01st.push.apple.com. The script signs the bag using this certificate and includes it, so apsd can verify the signature.

You can either upload this bag to your own webserver or run the setup/bag.py command with a -s switch at the end. It starts a webserver on port 80, so you have to run the command as root. The webserver requires flask, which can be installed via pip install flask.

Redirect DNS

You can choose whatever method you want to redirect DNS, pushproxy includes a script to generate an /etc/hosts file. You can run it using the following command:

setup/generate-hosts-file.py <webserver ip> > hosts

webserver ip: IP of your webserver that serves the configuration bag. apsd uses init-p01st.push.apple.com as HTTP host, so you can use a vhost for that domain if you want.

When apsd fails to load the configuration bag, it uses the old iOS 5/OS X 10.7 method as fallback. Thus the generate-hosts-file command redirects all these hosts to 127.0.0.1 to ensure apsd only connects to pushproxy.

You obviously need to copy the generated hosts file to the device.

Running

cd src
./runpush.sh

This should be enough for most cases, if you want it to run as daemon and write output to a logfile in data/, create an empty file in src:

touch production

If you want to change some configuration, just edit `pushserver.py.

API

Send notifications

PushProxy offers a Twisted Perspective Broker API for sending push notification directly to connected devices. It has the following signature:

remote_sendNotification(self, pushToken, topic, payload)

It doesn't implement the store part of the store-and-forward architecture Apple's push notifiction system implements, so notifications sent via this API for will be lost for offline devices.

See src/icl0ud/push/notification_sender.py for the implementation.

Message handler

You can subclass icl0ud.push.dispatch.BaseHandler, look at dispatch.py, pushtoken_handler.py and notification_sender.py in src/icl0ud/push.

Handlers can be configured in src/pushserver.py

Debugging

Apple provides a document on debugging push connections. Especially useful are their instructions on how to enable debug logging on iOS and OS X. You can find the download link to the configuration file for iOS in the upper right corner of the page.

The document is a bit outdated. If you want to enable debug logging on newer OS X versions like 10.8.2, you have to replace applepushserviced with apsd in the defaults and killall commands.

Troubleshooting certificate trust problems

  • The push server certificate must always have a common name (CN) and the other attributes as specified above, even when the host in the bag is another one. The host in the bag has to be in the Subject Alternative Name extension. Since OS X 10.10 or possibly earlier, apsd compares the cert's CN against the hostname it connects to, in addition to an explicit check against courier.push.apple.com and courier.sandbox.push.apple.com.

  • If the logs don't give you enough information and you only see an error message like the following, you can use dtrace for debugging the verification in detail.

    apsd[xx]: Failed to evaluate trust: No error. (0), result=5; retrying with revocation checking optional
    apsd[xx]: Failed to evaluate trust: No error. (0), result=5; retrying with system roots
    apsd[xx]: Failed to evaluate trust: No error. (0), result=5
    

Limitations

Device certificates are not checked

The intermediate certificate (subject=/C=US/O=Apple Inc./OU=Apple iPhone/CN=Apple iPhone Device CA) between Apple's root CA and the push device certificates expired on Apr 16 22:54:46 2014 GMT and I couldn't find a replacement. For a tool that is probably not usually used on the open internet, I thought implementing a workaround was too much effort, so I disabled device certificate checking.

PushProxy only checks there's a device certificate in in certs/device/<common name>.pem and uses it to connect to Apple servers. Notice that the device certificate common names are transmitted in plain text, so they can't be considered secret. A connection with a fake certificate would fail later when pushproxy tries to connect to an Apple server, which hopefully does proper certificate validation. Nevertheless, an attacker could make PushProxy connect to Apple servers with a lot of fake certificates from your server, which you might not want. There might also be other implications I haven't thought about.

Contributors

  • Michael Frister
  • Martin Kreichgauer

Thanks

  • Matt Johnston for writing extractkeychain that is used for deriving the master key and decrypting keys from the OS X keychain
  • Vladimir "Farcaller" Pouzanov for writing python-bplist which is included and helps extracting the push private key from the OS X keychain

pushproxy's People

Contributors

budnik avatar lolsborn avatar mfrister avatar sneak avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

pushproxy's Issues

Can this be used to solve the revoked enterprise certificate problem ?

Dear,

When open app on iPhone, apple will check the certificate validation for app. As I know, the following checking will be made by apple.

Certificate validation
The first time a user opens an app, the distribution certificate is validated by contacting Apple’s OCSP server. Unless the certificate has been revoked, the app is allowed to run. Inability to contact or get a response from the OCSP server isn’t interpreted as a revocation. To verify the status, the device must be able to reach ocsp.apple.com. See “Network Configuration Requirements,” earlier in this appendix.

The OCSP response is cached on the device for the period of time specified by the OCSP server—currently, between three and seven days. The validity of the certificate isn’t checked again until the device has restarted and the cached response has expired.

If a revocation is received at that time, the app is prevented from running.

Revoking a distribution certificate invalidates all of the apps you’ve signed with it. You should revoke a certificate only as a last resort— if you’re sure the private key is lost or the certificate is believed to be compromised.

Can we use this to prevent connecting Apple’s OCSP server ?
Thanks a lot.

Found 1 certificate(s), expected more

I've been trying to set up push proxy locally. I've set up a certificate chain with a root, intermediate, and leaf certificates. However, psd rejects the connection with the message Found 1 certificate(s), expected more. I am also getting Root certificate is not explicitly trusted even though it is marked as trusted in the keychain.

HexdumpHandler non functional

It seems at some point the HexdumpHandler got borked. Right now it is attempting to print hex for APSMessage objects when it expects a file descriptor it can .read() bytes from.

MessageProxy.connectionLost - peer connection lost

From https://github.com/meeee/pushproxy/blob/master/src/icl0ud/push/intercept.py#L47

def connectionLost(self, reason):
    # TODO notify handlers
    # FIXME fix this shutdown
    if self.peer is not None:
        self.peer.transport.loseConnection()
        self.peer = None

This shutdown used to be rare but it is occurring more often now where the iPhone sporadically loses its connection to the proxy server. It seems to happen most during periods of high traffic of APSNotifications. I have been able to find no meaningful info from debugging, and updating biplist (1.0.1), Twisted (15.5) and pyOpenSSL (0.15.1) to latest version had no effect. The 'reason' parameter under connectionLost also reveals no useful info:

Peer connection lost ([Failure instance: Traceback (failure with no frames): <class 'twisted.internet.error.ConnectionDone'>: Connection was closed cleanly. ])

Is it possible to perform more debugging or logging and determine what is triggering the connection closure? Trying to reconnect if you catch it in the InterceptClient factory is not helpful either, it simply starts an endless loop of errors.

One thing to note is that this seems to occur after the server sends a series of APSNotifications to the client, as such:

2016-01-27 15:04:37-0500 [#3] -> APSNotificationResponse message: 00000001 status: 00
2016-01-27 15:04:37-0500 [#3] -> APSNotificationResponse message: 00000001 status: 00
2016-01-27 15:04:37-0500 [#3] -> APSNotificationResponse message: 00000001 status: 00
2016-01-27 15:04:37-0500 [#3] -> APSNotificationResponse message: 00000001 status: 00
2016-01-27 15:04:37-0500 [#3] -> APSNotificationResponse message: 00000001 status: 00
2016-01-27 15:04:37-0500 [#3] -> APSNotificationResponse message: 00000001 status: 00
2016-01-27 15:04:37-0500 [#3] -> APSNotificationResponse message: 00000001 status: 00
2016-01-27 15:04:37-0500 [#3] -> APSNotificationResponse message: 00000001 status: 00
2016-01-27 15:04:37-0500 [#3] -> APSNotificationResponse message: 00000001 status: 00
2016-01-27 15:04:37-0500 [#3] -> APSNotificationResponse message: 00000001 status: 00
2016-01-27 15:04:37-0500 [#3] -> APSNotificationResponse message: 00000001 status: 00
2016-01-27 15:04:37-0500 [#3] -> APSNotificationResponse message: 00000001 status: 00
2016-01-27 15:04:37-0500 [#3] -> APSNotificationResponse message: 00000001 status: 00
2016-01-27 15:04:37-0500 [#3] -> APSNotificationResponse message: 00000001 status: 00
2016-01-27 15:04:37-0500 [#3] -> APSNotificationResponse message: 00000001 status: 00
2016-01-27 15:04:37-0500 [#3] -> APSNotificationResponse message: 00000001 status: 00

connect to apple push server error "key values mismatch"

2015-04-23 09:41:29+0800 Starting factory <twisted.spread.pb.PBServerFactory instance at 0x10fb80998>
2015-04-23 09:41:36+0800 [#0] New connection from 127.0.0.1:49168
2015-04-23 09:41:36+0800 [#0] SSL handshake done: Device: A37E8C14-9C23-4DD1-8D70-A768D5F53BB6
2015-04-23 09:41:36+0800 [#0] Connecting to push server: 17.172.232.218:5223
2015-04-23 09:41:36+0800 '[#0] SSLInfoCallback Exception:'
2015-04-23 09:41:36+0800 'Traceback (most recent call last):\n  File "/work/PyCharm/pushproxy-master/src/icl0ud/push/intercept.py", line 139, in SSLInfoCallback\n    self.connectToServer()\n  File "/work/PyCharm/pushproxy-master/src/icl0ud/push/intercept.py", line 168, in connectToServer\n    self.getClientContextFactory())\n  File "/Library/Python/2.7/site-packages/twisted/internet/posixbase.py", line 452, in connectSSL\n    tlsFactory = tls.TLSMemoryBIOFactory(contextFactory, True, factory)\n  File "/Library/Python/2.7/site-packages/twisted/protocols/tls.py", line 594, in __init__\n    contextFactory.getContext()\n  File "/work/PyCharm/pushproxy-master/src/icl0ud/push/intercept.py", line 105, in getContext\n    ctx.use_privatekey_file(self.cert)\n  File "/Library/Python/2.7/site-packages/OpenSSL/SSL.py", line 458, in use_privatekey_file\n    self._raise_passphrase_exception()\n  File "/Library/Python/2.7/site-packages/OpenSSL/SSL.py", line 429, in _raise_passphrase_exception\n    _raise_current_error()\n  File "/Library/Python/2.7/site-packages/OpenSSL/_util.py", line 22, in exception_from_error_queue\n    raise exceptionType(errors)\nError: [(\'x509 certificate routines\', \'X509_check_private_key\', \'key values mismatch\')]\n'

when patch apsd has a error

Thanks for the great project!
I'm trying to make it work on 10.8.4, when patch apsd ,i got this:

$ setup/osx/patch_apsd.py apsd ca.der server.der louis
Traceback (most recent call last):
  File "setup/osx/patch_apsd.py", line 93, in <module>
    main()
  File "setup/osx/patch_apsd.py", line 34, in main
    patch(apsd_path, dict(replacements), output_path)
  File "setup/osx/patch_apsd.py", line 79, in patch
    " or it occurs multiple times: %s" % repr(needle))
ValueError: Source binary doesn't contain replacement key  or it occurs multiple times: '\xb9`\x04\x00\x00'

and I have copy /System/Library/PrivateFrameworks/ApplePushService.framework/apsd to push proxy-master/apsd.

Find My Friend Play Sound

Hi there,

I can't seem to get this working. ;-[ Could you post a log dump of the push notifications being sent by iCloud when you use Find My Phone 'Play Sound' and 'Lost Mode' features?

Find My Friends

Get PushToken for mac OSX iMessage

Hello, i am trying to send or to connect to iMessage with an python script.
But i can't understand what is the push_token

When i connect i got this message from apple :

messagestatus = 5006, Bogus push token status5006

Custom Project

Sorry this isn't really an issue but I don't see any other means of making contact. I am looking to hire someone to create a small project that is related to this project. I need a TCP client that simply connects to push servers and receives any new notifications for a device (no device powered on). I'd assume a lot of functionality could be borrowed from this project. Please email me, at recruitmentdev33 [/at] live dot com. Thanks

'SSL23_GET_CLIENT_HELLO', 'unknown protocol'

I get the following error when a client connects to the proxy:

2015-08-05 12:45:23+0200 [#0] New connection from 192.168.1.83:49355
2015-08-05 12:45:27+0200 Unable to connect to peer: [Failure instance: Traceback: <class 'OpenSSL.SSL.Error'>: [('SSL routines', 'SSL23_GET_CLIENT_HELLO', 'unknown protocol')]

What gives?

OS X Setup

I'm happy to have found this project as I've spent a day or so trying to do exactly the same thing a few months back without much luck.

My test setup is OS X 10.7.4 running the iMessage beta. I did the following so far to get things setup:

  • ran setup/generate-hosts-file.py 127.0.0.1 and added the entries to my /etc/hosts file
  • ran setup/osx/extract_certificate.py -f to extract my device certificate from the applepushserviced certificate chain
  • generated a self signed certificate and added to my system keychain. The CNAME is courier.push.apple.com and it's trusted by all users.
  • I attempt to run ./runpush.sh but get the stack trace below. It appears to be unhappy with the serverChain which defaults to ../certs/apple/apple-cert-chain.pem and it says "no start line" in the PEM file which would seem like it is complaining about an invalid PEM file, but that doesn't seem like a likely cause.

Any suggestions?

Unhandled Error
Traceback (most recent call last):
  File "/usr/local/Cellar/python/2.7.2/lib/python2.7/site-packages/twisted/application/app.py", line 652, in run
    runApp(config)
  File "/usr/local/Cellar/python/2.7.2/lib/python2.7/site-packages/twisted/scripts/twistd.py", line 23, in runApp
    _SomeApplicationRunner(config).run()
  File "/usr/local/Cellar/python/2.7.2/lib/python2.7/site-packages/twisted/application/app.py", line 386, in run
    self.application = self.createOrGetApplication()
  File "/usr/local/Cellar/python/2.7.2/lib/python2.7/site-packages/twisted/application/app.py", line 451, in createOrGetApplication
    application = getApplication(self.config, passphrase)
--- <exception caught here> ---
  File "/usr/local/Cellar/python/2.7.2/lib/python2.7/site-packages/twisted/application/app.py", line 462, in getApplication
    application = service.loadApplication(filename, style, passphrase)
  File "/usr/local/Cellar/python/2.7.2/lib/python2.7/site-packages/twisted/application/service.py", line 405, in loadApplication
    application = sob.loadValueFromFile(filename, 'application', passphrase)
  File "/usr/local/Cellar/python/2.7.2/lib/python2.7/site-packages/twisted/persisted/sob.py", line 210, in loadValueFromFile
    exec fileObj in d, d
  File "pushserver.py", line 55, in <module>
    contextFactory = factory.getServerContextFactory()
  File "/Volumes/Big/Projects/iChatRev/pushproxy/src/icl0ud/push/intercept.py", line 248, in getServerContextFactory
    self.serverChain
  File "/Volumes/Big/Projects/iChatRev/pushproxy/src/icl0ud/push/intercept.py", line 256, in __init__
    ssl.DefaultOpenSSLContextFactory.__init__(self, cert, cert)
  File "/usr/local/Cellar/python/2.7.2/lib/python2.7/site-packages/twisted/internet/ssl.py", line 68, in __init__
    self.cacheContext()
  File "/usr/local/Cellar/python/2.7.2/lib/python2.7/site-packages/twisted/internet/ssl.py", line 78, in cacheContext
    ctx.use_privatekey_file(self.privateKeyFileName)
OpenSSL.SSL.Error: [('PEM routines', 'PEM_read_bio', 'no start line'), ('SSL routines', 'SSL_CTX_use_PrivateKey_file', 'PEM lib')]

Failed to load application: [('PEM routines', 'PEM_read_bio', 'no start line'), ('SSL routines', 'SSL_CTX_use_PrivateKey_file', 'PEM lib')]

Cannot contact the author

I tried finding out any means to contact the person behind this GitHub account, but without luck. I respect privacy, so this will not be a request for an e-mail address or something.
I would just like to notify you that I've opened a question on security.stackexchange.com:

http://security.stackexchange.com/questions/56749/is-apples-push-notification-service-implementation-vulnerable-to-a-mitm-attack

...that I'm sure you would be more than qualified enough to answer(related to apsd) and pick the running reputation bounty(200) and possible lots of up-votes. If you are participating there already, why not! The bounty is valid for 4 more days and I don't believe there will be anyone else there to take it, judging from the responses till now.

Btw. PushProxy is a superb project! Great work!

Permission to use your protocol documentation

I want to add APNS protocol documentation to the hack-different/apple-knowledge repository. I would like to use apple-push-protocol-ios5-lion.md as a base, to avoid having to write the document from scratch. I will likely edit it a lot to add my own findings later, but it will be easier to use this as a starting point.

The pushproxy repository has GPLv3 under LICENSE so it's presumed to apply to every file in the repository, including the documentation. Could you give us permission to relicense apple-push-protocol*.md under MIT + CC-BY-SA? Credit will be preserved in git history.

Thanks!

Nimble crashes with 'Illegal instruction: 4'

Hi, @meeee. Thank you for the new updates.
So the issue is in the title. I copied nimble binary to /private/var/Keychains on my iPhone, changed permission and got this error 'Illegal instruction: 4'.
What does nimble do? Or where I can find a working version?
Another question is do I have to have device certificate for every device? I already use PushProxy, so can I use a certificate extracted from OS X?
iPhone 6, iOS 8.1.2.

expired iphone3 device certificates don't work with pushproxy

The device certificate is valid for only 3 years, and these never seem to be refreshed once they expire.
So quite a number of older devices have expired client certificates.
Apparently courier.push.apple.com does not care about this.

However with openssl (as used by pushproxy) it does not seem possible to request a clientcertificate ( the 'SSL.VERIFY_PEER' flag passed to set_verify ), and ignore the validity of this client certificate.

Cert issues, ssl handshake failure

I'm really banging my head against the wall here :( I have tried creating certificates using the keychain assistant in OS X and manually using openssl; both have left me defeated. I'm using OS X 10.9.5 and iOS 7.1.2. I have had the most success using the keychain assistant; using openssl I had problems adding the subjectAlt field so the connections weren't being routed properly. The proxy is indeed receiving connections, but I see the following SSL error(s) after the iOS device fetches the bag:

2015-05-12 21:35:13-0700 [#13] New connection from 192.168.1.70:49240
2015-05-12 21:35:14-0700 Unable to connect to peer: [Failure instance: Traceback: <class 'OpenSSL.SSL.Error'>: [('SSL routines', 'SSL3_READ_BYTES', 'ssl handshake failure')]
/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/twisted/internet/posixbase.py:258:_disconnectSelectable
/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/twisted/internet/tcp.py:267:readConnectionLost
/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/twisted/internet/tcp.py:287:connectionLost
/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/twisted/protocols/tls.py:460:connectionLost
--- <exception caught here> ---
/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/twisted/protocols/tls.py:356:_flushReceiveBIO
build/bdist.macosx-10.9-intel/egg/OpenSSL/SSL.py:1320:recv
build/bdist.macosx-10.9-intel/egg/OpenSSL/SSL.py:1187:_raise_ssl_error
build/bdist.macosx-10.9-intel/egg/OpenSSL/_util.py:48:exception_from_error_queue

iOS apsd log: http://pastebin.com/EUwZYBBi

I followed your instructions to the letter (3 times over to ensure I didn't miss anything). My certs/courier.push.apple.com contains server.pem with the intermediate crt/key and the leaf (courier.push.apple.com) crt/key. I created three certs; one root CA, one intermediate CA and a leaf. I added O/L/S entries for all matching your specifications (Apple Inc., Cupertino, etc.). I was not able to patch apsd on the OSX machine; it throws some errors, presumably because your patching routine is out of date with what 10.9.5 has, but I didn't see specific apsd errors like other people with issues had to suggest that apsd needs to be patched. It looks more like the iPhone is not accepting the certs (see iOS log above). It is also worth noting that the iOS device only shows the root (init-p01...) cert as 'Trusted' after being installed; the intermediate CA and leaf both show as 'Not Trusted' for some reason. I did have the intermediate CA showing as trusted during one of my attempts but that still yielded the same errors.

Invalid certificate chain

First, damned cool that you figured all this out. Just wish I could make it work. :)

My iPad is reaching the pushproxy host/port. I simply used the /etc/hosts method, so there's still the DNS wildcard lookup to push.apple.com, but that's moot 'cause all the xxx.courier.push.apple.com entries in hosts, correct? I don't need to modify the push daemon on the device or my host (OSX 10.8), correct? (the README is a little vague on that...)

So as I said, it reaches the proxy, but can't complete the connection. On the server side, I get:

2012-09-07 11:37:09-0400 [InterceptServer (TLSMemoryBIOProtocol),2,172.17.1.65] 
Unable to connect to peer: [Failure instance: Traceback: <class 'OpenSSL.SSL.Error'>: 
[('SSL routines', 'SSL3_READ_BYTES', 'ssl handshake failure')]

followed by some traceback records through twisted (posixbase, tcp, tcp, tls, and finally the exception caught in twisted/protocols/tls.py:352:_flushReceiveBIO).

On the client (the iPad), I see:

Sep  7 11:33:35 David-Schuetzs-iPad apsd[85] <Warning>: 
<APSCourier: 0xd60a0f0>: Stream error occurred for <APSTCPStream: 0xd61b1f0>: 
TLS Error Code=-9807 "invalid certificate chain"

I've also tried simply using openssl s_server (using the server.pem cert, naturally):

  bad gethostbyaddr
  SSL_accept:before/accept initialization
  SSL_accept:SSLv3 read client hello A
  SSL_accept:SSLv3 write server hello A
  SSL_accept:SSLv3 write certificate A
  SSL_accept:SSLv3 write server done A
  SSL_accept:SSLv3 flush data
  SSL_accept:failed in SSLv3 read client certificate A
  ERROR

I've read elsewhere that the gethostbyaddr can be ignored, and that the error in the client certificate may be ambiguous (just that this is where the failure occurred -- in this case, it seems likely because the client rejected the connection because of the certificate chain issue).

To create the server certificate, once used Keychain, making a self-signed root SSL Server cert, and another time I used OpenSSL (using a script I've used successfully for MDM server research). The OpenSSL route involves creating a self-signed CA, then using that to sign the server cert. I've tried it both with "bogus" parameters in the CA (for state, city, ou, etc.), and another time I tried to replicate the relevant paramaters using data in the Apple CA cert extracted from the device.

In all cases, I installed the server cert, or the self-signed CA, or the CA and the server cert, on the local device by firing up an in-place one-line python HTTP sever and tapping on the appropriate certificate file (which launches Settings app and installs the cert). When installing just the Keychain-generated server cert, it subsequently shows in settings as "not trusted," but when using the CA and server cert, they both show as trusted.

So I'm reasonably confident that all my certificates are correct, as well.

I've even tried disabling certificate pinning, in case the apsd process is trying to go farther than simply verifying a good chain (in case it has to be the RIGHT chain). (I used the new iSEC Partners "ios-ssl-kill-switch" mobile substrate hook). That didn't work, either -- but, if pinning is the problem, it's possible that the apsd isn't affected by this substrate hack.

Any thoughts? I'm on iOS 5.0.1, iPad 2, AT&T (inactive SIM, so no 3G).

Thanks!

Untrusted peer, closing connection immediately

Thanks for the great project!
I'm trying to make it work on 10.10, I didn't run it on previous osx's, so I think it doesn't work because I have missed something.

I have generated certificates with the script from the first answer here: http://superuser.com/questions/462295/openssl-ca-and-non-ca-certificate. I deleted -subj options and generated certs with the following CNs: root12.apple.com, second.apple.com, courier.push.apple.com.

Added rootCAcert.pem to system keychain and store the certificate, the intermediary CA and keys to the server.pem and copied it to certs/courier.push.apple.com/server.pem

cat cert/cert.pem cert/private/certkey.pem CA/CAcert.pem CA/private/CAkey.pem > server.pem 

and generated cert for init-p01st.push.apple.com

openssl genrsa -out ca-init-apple.key 1024
openssl req -new -key ca-init-apple.key -out ca-init-apple.scr
openssl x509 -req -days 365 -in ca-init-apple.scr -CA rootCA/rootCAcert.pem -CAkey rootCA/private/rootCAkey.pem -set_serial 01 -out ca-init-apple.crt
cat ca-init-apple.crt ca-init-apple.key > ca-init-apple.pem

here's a link: https://www.dropbox.com/s/rrct0wviiv2esuj/my_cert.zip

Patched apsd

 openssl x509 -in rootCA/rootCAcert.pem -out rootCA/rootCAcert.der -outform DER
sudo setup/osx/patch_apsd.py /System/Library/PrivateFrameworks/ApplePushService.framework/apsd my_cert/rootCA/rootCAcert.der "Mac Developer: XXXX XXX (XXXXXX)”
sudo mv /System/Library/PrivateFrameworks/ApplePushService.framework/apsd-patched /System/Library/PrivateFrameworks/ApplePushService.framework/apsd

Output of sudo python utils/find_certs.py /System/Library/PrivateFrameworks/ApplePushService.framework/apsd

+ 699872 Found cert with CN "courier.sandbox.push.apple.com" and serial "1277027356"
+ 701008 Found cert with CN "courier.push.apple.com" and serial "1277256594"
+ 702128 Found cert with CN "courier.push.apple.com" and serial "1276925395"
+ 703296 Found cert with CN "Entrust Certification Authority - L1C" and serial "946072060"
+ 704576 Found cert with CN "root12.apple.com" and serial "10596108112207272420"
+ 1009884 Found cert with CN "Apple Worldwide Developer Relations Certification Authority" and serial "25"
+ 1010947 Found cert with CN "Apple Root CA" and serial "2"
+ 1012162 Found cert with CN "Mac Developer: XXXX XXX (XXXXXX)” and serial "5931679684XXXX51112"

sudo killall apsd

Extracted OS X Certificates
sudo setup/osx/extract_certificate.py -f

Configurated Bag
sudo setup/bag.py courier.push.apple.com my_cert/ca-init-apple.pem -s

Hosts

setup/generate-hosts-file.py 127.0.0.1 > hosts
added hosts to /etc/hosts

and finally

cd src
./runpush.sh

and I got:

PushProxy:

2014-07-25 22:47:30+0300 [#6] New connection from 127.0.0.1:55338
2014-07-25 22:47:30+0300 Unable to connect to peer: [Failure instance: Traceback: <class 'OpenSSL.SSL.Error'>: [('SSL routines', 'SSL3_READ_BYTES', 'ssl handshake failure')]
/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/twisted/internet/posixbase.py:257:_disconnectSelectable
/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/twisted/internet/tcp.py:279:readConnectionLost
/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/twisted/internet/tcp.py:299:connectionLost
/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/twisted/protocols/tls.py:462:connectionLost
--- <exception caught here> ---
/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/twisted/protocols/tls.py:358:_flushReceiveBIO

Console:

7/25/14 22:46:36.832 apsd[92872]: <APSCUTPowerAssertion: 0x7fe45045f720>: Failed to create power assertion com.apple.apsd-connectionestablish-push.apple.com result = -536870207
7/25/14 22:46:36.843 apsd[92872]: <APSCUTPowerAssertion: 0x7fe450549050>: Failed to create power assertion com.apple.apsd-connectionestablish-push.apple.com result = -536870207
7/25/14 22:46:36.845 apsd[92872]: <APSCUTPowerAssertion: 0x7fe450435600>: Failed to create power assertion com.apple.apsd-connectinguser-push.apple.com result = -536870207
7/25/14 22:46:36.849 apsd[92872]: Failed to evaluate trust: No error. (0), result=5; retrying with revocation checking optional
7/25/14 22:46:36.851 apsd[92872]: Failed to evaluate trust: No error. (0), result=5; retrying with system roots
7/25/14 22:46:36.852 apsd[92872]: Failed to evaluate trust: No error. (0), result=5
7/25/14 22:46:36.852 apsd[92872]: Untrusted peer, closing connection immediately

Charles Proxy:
https://www.dropbox.com/s/bkrlvghq1p6vmj8/Screenshot%202014-07-25%2022.50.47.png

OpenSSL:

openssl s_client -connect 127.0.0.1:5223 -prexit -CAfile my_cert/rootCA/rootCAcert.pem
CONNECTED(00000003)
depth=2 /C=US/ST=California/O=Apple Inc./CN=root12.apple.com
verify return:1
depth=1 /C=US/ST=California/O=Apple Inc./CN=second.apple.com
verify return:1
depth=0 /C=US/ST=California/O=Apple Inc./CN=courier.push.apple.com
verify return:1
93099:error:14094410:SSL routines:SSL3_READ_BYTES:sslv3 alert handshake failure:/SourceCache/OpenSSL098/OpenSSL098-51/src/ssl/s3_pkt.c:1125:SSL alert number 40
93099:error:140790E5:SSL routines:SSL23_WRITE:ssl handshake failure:/SourceCache/OpenSSL098/OpenSSL098-51/src/ssl/s23_lib.c:182:

---
Certificate chain
 0 s:/C=US/ST=California/O=Apple Inc./CN=courier.push.apple.com
   i:/C=US/ST=California/O=Apple Inc./CN=second.apple.com
 1 s:/C=US/ST=California/O=Apple Inc./CN=second.apple.com
   i:/C=US/ST=California/O=Apple Inc./CN=root12.apple.com

---
Server certificate
-----BEGIN CERTIFICATE-----
XXXX
-----END CERTIFICATE-----
subject=/C=US/ST=California/O=Apple Inc./CN=courier.push.apple.com
issuer=/C=US/ST=California/O=Apple Inc./CN=second.apple.com

---
No client certificate CA names sent

---
SSL handshake has read 1544 bytes and written 210 bytes

---
New, TLSv1/SSLv3, Cipher is AES256-SHA
Server public key is 1024 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
SSL-Session:
    Protocol  : TLSv1
    Cipher    : AES256-SHA
    Session-ID: 7A41F7EAFCA6E1628E72C37E0DAC5207D4723FD23575ACC1F15F86680BFBF2BB
    Session-ID-ctx: 
    Master-Key: C0994638E5B1391F83863B37504F55B6EAF6F3C1AA2586AEFFE07BDF14B424D7D4D82FD5B5475475B62610756EC14A2E
    Key-Arg   : None
    Start Time: 1406318733
    Timeout   : 300 (sec)
    Verify return code: 0 (ok)

---

Thanks in advance!

Creating New Messages

I understood that you read all the message structure, and rewrite it to Apple..
I am trying to build a message sender from a cloud service using one ID, device token, phone certificates and whatever.

Do you think that is possible to do it? Or something just can be done at device?

Thanks in advance,

Unknown field suggestion

I wanted to get your opinion before making a pull request. There are still a few message fields that have something like:

Unknown1
Unknown2
...

Would it be helpful if the numerical part of these corresponded to the field identifier? So that unknownString4 became unknownString0A or whatever. It's a small change and I'm not even sure how helpful it will be in practice, but seems more useful than the current scheme.

I'll be happy to make a pull request for it if you find it useful.

[debug-cert-verification-dtrace.md] Probe doesn't exist on 10.12

Hi. I'm trying to debug certificate verification on macOS 10.12.4.
SIP is disabled. Error when executing dtrace script:
dtrace: invalid probe specifier security_debug*:Security:secdebug_internal:log /copyinstr(arg0) != "cmutex"/ { printf("%s %s %s", execname, copyinstr(arg0), copyinstr(arg1)) }: probe description security_debug*:Security:secdebug_internal:log does not match any probes

iOS 9 Incompatibility

Hi, I am unable to successfully get apsd to accept the proxy certificates. I tried adding com.apple.apsd to SSLKillSwitch2, but iOS is still rejecting the certificates for the push proxy. These same certificates and setup work great on iOS 7 and 8. iOS 9 is doing something else, presumably with App Transport Security (ATS). I did already verify that the generated certs are 2048 bit and are TLS 1.2, which is in compliance with ATS. I'm not sure about the 'Perfect forward secrecy cipher suites' requirement of ATS. Here is some log data:

Jan 16 21:06:57 x-iPhone apsd[265]: MS:Notice: Injecting: com.apple.apsd [apsd] (1240.10)
Jan 16 21:06:57 x-iPhone apsd[265]: MS:Notice: Loading:       /Library/MobileSubstrate/DynamicLibraries/SSLKillSwitch2.dylib
Jan 16 21:06:57 x-iPhone apsd[265]: === SSL Kill Switch 2: Preference set to 1.
Jan 16 21:06:57 x-iPhone apsd[265]: === SSL Kill Switch 2: Subtrate hook enabled.

and then when it tries to connect to push server:

Jan 16 21:07:33 x-iPhone apsd[265]: CFNetwork SSLHandshake failed (-9801)

When the device attempts connection, the push proxy server complains with an exception containing ssl handshake failure SSL3_READ_BYTES

codesign

I tried to install it on OS X 10.9.2 and imported all of the certificates I created in key chain. Now I'm at the point where I need to patch apsd I don't know what is meant with code signing identity.
<code signing identity>: Name of a code signing certificate understood by the codesign utility, make sure your machine trusts this cert (root)
I tried Common Name of the cert also name of the file of the cert but there is
a error from the python-program

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.