Crunching Apple Pay tokens in PHP
Etsy is always trying to make it easier for members to buy and sell unique goods. And with 60% of our traffic now coming from mobile devices, making it easier to buy things on phones and tablets is a top priority. So when Apple Pay launched last year, we knew right away we wanted to offer it for our iOS users, and shipped it in April. Today we’re open sourcing part of our server-side solution, applepay-php, a PHP extension that verifies and decrypts Apple Pay payment tokens.
Integrating with Apple Pay comes down to two main areas of development: device side and payment-processing side. On the device side, at a high level, your app uses the PassKit framework to obtain an encrypted payment token which represents a user’s credit card info. On the payment-processing side, the goal is to make funds move between bank accounts. The first step here is to decrypt the payment token.
Many payment processors offer APIs to decrypt Apple Pay tokens on your behalf, but in our case, we wanted the flexibility of reading the tokens in-house. It turns out that doing this properly is pretty involved (to get an idea of the complexity, our solution defines 63 unique error codes), so we set out to find a pre-existing solution. Our search yielded a couple of open source projects, but none that fully complied with Apple’s spec. Notably, we couldn’t find any examples of verifying the chain of trust between Apple’s root CA and the payment signature, a critical component in guarding against forged payment tokens. We also couldn’t find any examples written in PHP (our primary language) or C (which could serve as the basis for a PHP extension). To meet our needs, we wrote a custom PHP extension on top of OpenSSL that exposes just two functions: applepay_verify_and_decrypt and applepay_last_error. This solution has worked really well for us over the past six months, so we figured we’d share it to make life easier for anyone else in a similar position.
Before releasing the code, we asked Syndis, a security consultancy based out of Iceland, to perform an external code review in addition to our everyday in-house code reviews. Syndis surveyed the code for both design flaws and implementation flaws. They found a few minor bugs but no actual vulnerabilities. Knowing that we wouldn’t be exposing users to undue risk gave us greater confidence to publish the code.
We’ve committed to using the open source version internally to avoid divergence, so expect to see future development on Github. Future work includes splitting off a generalized libapplepay (making it easier to write wrapper libraries for other languages), PHP7 compatibility, and an HHVM port. (By the way, if any of this sounds fun to you, we’d love for you to come work with us.)
We hope this release provides merchants with a solid solution for handling Apple Pay tokens. We also hope it inspires other organizations to consider open sourcing parts of their payment infrastructure.
You can follow Adam on Github @adsr.
Special thanks to Stephen Buckley, Keyur Govande, and Rasmus Lerdorf.