Safari's Reading List protocol: CalDAV + XBELs

Safari on desktop and iOS has a feature called "Reading List". It is a way to store URLs in iCloud, synchronize them between Safaris, and mark them as read or not. Somewhat like Instapaper maybe.

I was a bit surprised that there is no Chrome or Firefox extensions for tapping into Safari's Reading List. So I wanted to try poking a bit into the protocol, maybe something interesting would appear or someone could get some headstart from this.

Safari always seem to start contacting p05-bookmarks.icloud.com, which resolves to the Akamai CDN, some p05-bookmarks.icloud.com.akadns.net. Luckily the IP always was the same, and there is no client certificate check, so I could mount a little Man In The Middle via /etc/hosts.

Then, a couple of socats: one to pose as the original SSL server and resend the plaintext; and the second to receive the plaintext and send it to the original IP. The first socat shows everything that goes out of it (in plaintext) thanks to the -vx option.

socat -vx OPENSSL-LISTEN:443,cert=certs/server.pem,verify=0,reuseaddr,fork TCP:localhost:50000 

socat -v TCP-LISTEN:50000,reuseaddr,fork OPENSSL:

I tried tcpflow instead of the -vx, but tcpflow won't show anything when capturing on the loopback interface on OS X. Seems to be a bug.

So now we can see the exchanges between Safari and iCloud. I was half-expecting something encrypted, but it isn't (apart from the SSL connection). It seems to be CalDAV, used to exchange small XBEL files, gzipped; which can be quickly unzipped by copying the hex from the socat dump and pasting into a "xxd -r -p | zcat ". Each XBEL file is a small XML file with an URL and its status.

I expected this to be much quicker, but socat and tcpflow kind of conspired against it. I started expecting to use named pipes and tee's to connect the socats while showing the exchanges, but each update in the Reading List causes between 3 and 5 connections, which needs the socat option fork, which forks new socats for each connection, which won't play nice with the pipes.

I guess I should have switched to some python earlier... next time I will. And at this point anyway, if I wanted to keep going into this protocol, looks like throwing together some small client with Python would be the best way forward.

But I am not currently interested in JavaScript, so I guess I won't be making any extension myself, so I guess I should move on to other things.

So, dear Lazyweb... :)


  1. Note to self: there are lots of MITM proxies and whatnots that would have made this easier/quicker. Next time, check https://news.ycombinator.com/item?id=3556688 (mitmproxy, for example)

  2. Hi,

    I'm interested in this. I tried using Charles, but I cannot get it to do the MITM SSL "attack" right.

    Can you make another post on this topic ?

    Razvan Aurariu

  3. I can try. What exactly would you like to know?