HOWTO: Reverse engineer the iPhone protocols

A few months back (‘Apple iPhone 2.0: The real story behind MobileMe Push Mail and Jabber/XMPP Chat‘) I analysed how the iPhone interacted with the new MobileMe service with a view to offering the same features to Google Apps customers. Unfortunately this is not yet possible (the APIs don’t exist on both sides of the fence) but we learnt a lot in the process.

For those of you who have been living under a rock, MobileMe (previously known as .Mac) is Apple’s foray into cloud computing. It offers some impressive synchronisation and push services, but for a relatively steep annual subscription. One of the most coveted features is push mail, which makes e-mail behave more like instant messaging; as soon as the mail hits Apple’s servers they notify the clients which then retrieve the item. Technically that’s ‘pull’ with notifications rather than ‘push’ per se, but the result is the same; the user experience for email improves dramatically. They do similar things with contacts and calendar items. Due to popular demand (and making good on my promise to elaborate), here’s a brief explanation of how it was I got ‘under the hood’ of the iPhone’s encrypted communications with the MobileMe servers.

The first problem was to see what it was talking to. We’ve got a Mac household and a bunch of VMs (Windows, Linux and some other strange stuff) so I set up internet sharing on one of them and installed Wireshark. This allowed me to capture the (encrypted) traffic, which was terminating at aosnotify.mac.com:5223. Although we couldn’t decipher the traffic itself we already knew a fair bit from the server name, port number and traffic patterns; whenever a test mail arrived there was a small amount of traffic on this connection followed immediately by an IMAP poll and message retrieval. ‘AOS’ presumably stands for ‘Apple Online Services‘ (a division that’s at least 15 years old assuming it still exists) rather than Australian Online Solutions (which is what I translate ‘AOS’ to) and ‘notify’ tells us that they have a specific notification service, which reconciles with what we observed. Most importantly though, network port tcp/5223 was traditionally used by Jabber (XMPP) chat servers for encrypted (SSL) traffic; that reconciled too because Wireshark dissectors were able to peer into the SSL handshakes (but obviously not the data itself, at least not without the private keys stored safely on Apple’s servers and/or SSL accelerators).

The next problem was to tell the iPhone to talk to us rather than Apple. There’s a number of ways to skin this particular cat but if I remember well I went with dnsmasq running in a Linux VM and simply configured the DHCP server to use this DNS server rather than those of the ISP. Then it was just a case of overriding aosnotify.mac.com’s IP with the address of the VM by adding a line to the /etc/hosts file. That worked nicely and I could not only see the iPhone hitting the server when it started up, but could see that it still worked when I wired port 5223 up to the real Apple servers using a rudimentary Perl/Python proxy script. At this point I could capture the data, but it was still encrypted.

I now needed to convince the iPhone that it was talking to Apple when in fact it was talking to me; without a valid certificate for aosnotify.mac.com this wasn’t going to work unless Apple programmers had foolishly ignored handshake failures (that said, stranger things have happened). Assuming this wasn’t the case and knowing that this would be easily fixed with a patch (thereby blowing my third-party integration service out of the water) I started looking at the options. My iPhone was jailbroken so I could have hacked OS X or the iPhone software (eg by binary patching aosnotify.apple.com with aosnotify.<mydomain>.com) but I wanted a solution that would work OOTB.

Conveniently Apple had provided the solution in the iPhone 2.0 software by way of the new enterprise deployment features. All I needed to do was create my own certification authority and inject the root certificate into the iPhone by creating an enterprise configuration which contained it. I’d already played with both the iPhone Configuration Utility for OS X and the official Ruby on Rails iPhone Configuration Web Utility so this was a walk in the park. Deploying it was just a case of attaching the.mobileconfig file to an email and sending it to the iPhone (you can also deploy over HTTP I believe). Now I just needed to create a fake certificate, point the proxy script at it and start up the iPhone.

Sure enough this worked on the first attempt and I was even able to peer into the live, cleartext connection with Wireshark. Although I was surprised with the choice of XMPP’s publish/subscribe functionality, it makes a good deal of sense to use an existing protocol and what better choice than this one (though I wonder if Cisco’s acquisition of Jabber will have any effect). This discovery would have come as a disappointment for those touting the discovery of the private XMPP libraries (who naturally assumed that this translated to an Instant Messaging client like iChat), but it is interesting for us cloud architects.