Since I don't have any own games, I didn't build a game store but rather an image store that lets you browse image folders on your computer via the OUYA's "discovery" store menu.
- General setup
- API implementation
- SSL woes
I didn't want to hack my OUYA, and also not install a custom launcher. What I wanted was a custom store that replaces the real store, without the OUYA noticing anything, or requiring any modification on it.
All I have to do is to modify the ouya.tv DNS entries and let them point to my web server's IP. With that in place, the OUYA automatically asks my server instead of the real one.
Since all communication is running via HTTPS, I had to generate my own fake SSL certificate for ouya.tv and let the OUYA trust the signing CA.
I already had enough requests and responses to the original store from my mitmproxy usage , and could directly begin implementing the necessary API calls. Actually only two are needed:
- /api/v1/playlists to list all image folders (games), their position in the menu and a small screenshot
- /api/v1/apps with the game details (and all images in the folder as screenshots)
The code is a bit of PHP and can be found on my git server.
Last time I already had SSL problems ("No peer certificate"), which could be solved by upgrading from mitmproxy 0.8 to 0.9.2. Now I had to generate my own certificate, which wasn't as trivial as I thought.
I used the mitmproxy's autogenerated certificate authority for signing the *.ouya.tv certificate, which worked fine - on my laptop's browser.
The OUYA store would nevertheless give me the dreaded error:
java.net.SSL.PeerUnverifiedException: No peer certificate
On the other side, the OUYA browser had no problems, did not show any warning or error, and displayed a secure lock sign. Where was the problem?
I knew that it worked with certificates generated by mitmproxy, so mimicking that would be all I need.
Getting hold of that certificate was not so easy, because mitmproxy only acts as proxy and not normal web server, and openssl s_client does not work with proxies :/ proxytunnel was the solution, with it I was able to obtain the devs.ouya.tv certificate from mitmproxy:
$ proxytunnel -p 127.0.0.1:8080 -d devs.ouya.tv:443 -a 7000 $ openssl s_client -showcerts -connect localhost:7000 -servername devs.ouya.tv
After converting the certificates to plain text, I diffed them, and re-build my own certificate until it looked exactly like the one generated by mitmproxy. It did not help; I still got the SSL error.
SSL negotiation problems?
The peer hasn't sent an SSL certificate. This will be either because it doesn't own one that conforms to the constraints sent by this side, most probably that none of this side's trusted signers signed its certificate: or maybe it doesn't have one at all.
So maybe the OUYA store HTTP client had special restrictions on the allowed SSL encryption methods?
I fired up wireshark and compared the SSL handshakes from the original and my own store's HTTP connections. The result: All the same. I did nothing wrong there; my server provided and accepted the same encryption algorithms as mitmproxy and ouya.tv.
Then, after looking further in the SSL connection setup, I saw a line: Subject: bm.bogo. This is the wrong certificate!
My development apache instance has several SSL certificates setup, and this one was one of those - but not the correct one for *.ouya.tv. After making my ouya-vhost the first to be loaded by apache, it worked.
Conclusion: OUYA's own HTTP client does not support SNI . The stock android browser does, but the OUYA devs did something to not support it in their own client.
Another important conclusion is: No peer certificate does not mean that the server did not send a certificate - it means that the certificate is not valid in some way.
So now the ouya vhost is the first in apache, thus its certificate gets delivered automatically for clients that don't provide a host name during the SSL negotiation phase. The OUYA talks happily with apache and fetches data from my custom image store.
Here are some photos of the TV screen with the OUYA image store: