spreedly / gala Goto Github PK
View Code? Open in Web Editor NEWRuby library for decrypting Apple Pay payment tokens
License: MIT License
Ruby library for decrypting Apple Pay payment tokens
License: MIT License
Hello, thank you for this wonderful gem!
Would you mind releasing a new gem version so that we can point to a RubyGems version rather than GitHub repo?
Per step one here
Verify the signature as follows:
- Ensure that the certificates contain the correct custom OIDs: 1.2.840.113635.100.6.29 for the leaf certificate and 1.2.840.113635.100.6.2.14 for the intermediate CA. The value for these marker OIDs doesn’t matter, only their presence.
- Ensure that the root CA is the Apple Root CA - G3. This certificate is available from apple.com/certificateauthority.
- Ensure that there is a valid X.509 chain of trust from the signature to the root CA. Specifically, ensure that the signature was created using the private key corresponding to the leaf certificate, that the leaf certificate is signed by the intermediate CA, and that the intermediate CA is signed by the Apple Root CA - G3.
- Ensure that the signature is a valid ECDSA signature (ecdsa-with-SHA256 1.2.840.10045.4.3.2) of the concatenated values of the ephemeralPublicKey, data, transactionId, and applicationData keys.
Inspect the CMS signing time of the signature, as defined by section 11.3 of RFC 5652. If the time signature and the transaction time differ by more than a few minutes, it's possible that the token is a replay attack.
Hey @rwdaigle, any chance we could bump the OpenSSL gem to version 3 (or loosen the dependency)? Thanks!
It appears the aead
gem is unmaintained. OneLogin is no longer accepting PRs, and Shopify doesn't maintain an issue tracker. There are test failures on both, and we're getting ArgumentError: ArgumentError: ciphertext failed authentication step
errors now in a way that's hard to trace down when we attempt to decrypt.
Is there some other way of doing what the aead gem does?
In Ruby 2.3.7 I'm hitting some significant problems.
First, simply running bundle install
from this repo doesn't seem to install aead
, since when I run the tests or pull open a pry/irb console and try to require 'aead'
it says file not found. I had to check out that repo manually, do a gem build
and install it from there globally.
Once that's done, I'm getting a ArgumentError: ciphertext failed authentication step
error, which is also happening in my application when the decrypt
operation is attempted. See below:
~/c/gala ❯❯❯ rake test master ✱ ◼
~/Code/gala/lib/gala/payment_token.rb:59: warning: assigned but unused variable - certificate
Loaded suite ~/.rbenv/versions/2.3.7/lib/ruby/gems/2.3.0/gems/rake-12.3.1/lib/rake/rake_test_loader
Started
E
================================================================================================================================================================================================================================================================================
Error: test_decrypt(Gala::PaymentTokenTest): ArgumentError: ciphertext failed authentication step
~/.rbenv/versions/2.3.7/lib/ruby/gems/2.3.0/gems/aead-1.8.2/lib/aead/cipher/aes_gcm.rb:49:in `rescue in _decrypt'
~/.rbenv/versions/2.3.7/lib/ruby/gems/2.3.0/gems/aead-1.8.2/lib/aead/cipher/aes_gcm.rb:38:in `_decrypt'
~/.rbenv/versions/2.3.7/lib/ruby/gems/2.3.0/gems/aead-1.8.2/lib/aead/cipher.rb:133:in `decrypt'
~/Code/gala/lib/gala/payment_token.rb:118:in `decrypt'
~/Code/gala/lib/gala/payment_token.rb:40:in `decrypt'
~/Code/gala/test/payment_token_test.rb:43:in `test_decrypt'
40: end
41:
42: def test_decrypt
=> 43: payment_data = JSON.parse(@payment_token.decrypt(@certificate, @private_key))
44: assert_equal "4109370251004320", payment_data["applicationPrimaryAccountNumber"]
45: assert_equal "200731", payment_data["applicationExpirationDate"]
46: assert_equal "840", payment_data["currencyCode"]
================================================================================================================================================================================================================================================================================
.....
Finished in 0.019383 seconds.
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
6 tests, 11 assertions, 0 failures, 1 errors, 0 pendings, 0 omissions, 0 notifications
83.3333% passed
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
309.55 tests/s, 567.51 assertions/s
rake aborted!
Command failed with status (1)
Tasks: TOP => test
(See full trace by running task with --trace)
~/c/gala ❯❯❯
My Ruby and System OpenSSL install are using the same version:
ruby -ropenssl -e 'puts OpenSSL::OPENSSL_VERSION'
OpenSSL 1.0.2o 27 Mar 2018
openssl version
OpenSSL 1.0.2o 27 Mar 2018
I've tried commenting out the rescue
from ~/.rbenv/versions/2.3.7/lib/ruby/gems/2.3.0/gems/aead-1.8.2/lib/aead/cipher/aes_gcm.rb:49
and then get a slightly different error of OpenSSL::Cipher::CipherError: CTRL_NOT_IMPLEMENTED
:
~/Code/gala/lib/gala/payment_token.rb:59: warning: assigned but unused variable - certificate
Loaded suite ~/.rbenv/versions/2.3.7/lib/ruby/gems/2.3.0/gems/rake-12.3.1/lib/rake/rake_test_loader
Started
E
================================================================================================================================================================================================================================================================================
Error: test_decrypt(Gala::PaymentTokenTest): OpenSSL::Cipher::CipherError: CTRL_NOT_IMPLEMENTED
~/.rbenv/versions/2.3.7/lib/ruby/gems/2.3.0/gems/aead-1.8.2/lib/aead/cipher/aes_gcm.rb:40:in `gcm_iv_len='
~/.rbenv/versions/2.3.7/lib/ruby/gems/2.3.0/gems/aead-1.8.2/lib/aead/cipher/aes_gcm.rb:40:in `block in _decrypt'
~/.rbenv/versions/2.3.7/lib/ruby/gems/2.3.0/gems/aead-1.8.2/lib/aead/cipher.rb:175:in `cipher'
~/.rbenv/versions/2.3.7/lib/ruby/gems/2.3.0/gems/aead-1.8.2/lib/aead/cipher/aes_gcm.rb:39:in `_decrypt'
~/.rbenv/versions/2.3.7/lib/ruby/gems/2.3.0/gems/aead-1.8.2/lib/aead/cipher.rb:133:in `decrypt'
~/Code/gala/lib/gala/payment_token.rb:118:in `decrypt'
~/Code/gala/lib/gala/payment_token.rb:40:in `decrypt'
~/Code/gala/test/payment_token_test.rb:43:in `test_decrypt'
40: end
41:
42: def test_decrypt
=> 43: payment_data = JSON.parse(@payment_token.decrypt(@certificate, @private_key))
44: assert_equal "4109370251004320", payment_data["applicationPrimaryAccountNumber"]
45: assert_equal "200731", payment_data["applicationExpirationDate"]
46: assert_equal "840", payment_data["currencyCode"]
================================================================================================================================================================================================================================================================================
.....
Finished in 0.019248 seconds.
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
6 tests, 11 assertions, 0 failures, 1 errors, 0 pendings, 0 omissions, 0 notifications
83.3333% passed
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
311.72 tests/s, 571.49 assertions/s
rake aborted!
Command failed with status (1)
Tasks: TOP => test
(See full trace by running task with --trace)
Any ideas?
Thank you so much for writing and maintaing the Gala gem!
Tests were passing in May 2018 (last commit) but if you run them today you'll get this error.
$ rake test
Run options: --seed 59087
# Running:
...EF.
Finished in 0.041877s, 143.2767 runs/s, 262.6740 assertions/s.
1) Error:
Gala::PaymentTokenTest#test_decrypt:
Gala::PaymentToken::InvalidSignatureError: Unable to verify a valid chain of trust from signature to root certificate.
/Users/Carreno/prj/gala/lib/gala/payment_token.rb:61:in `validate_signature'
/Users/Carreno/prj/gala/lib/gala/payment_token.rb:30:in `decrypt'
/Users/Carreno/prj/gala/test/payment_token_test.rb:43:in `test_decrypt'
The exception is raised because the call to OpenSSL::X509::Store#verify
is returning false
https://github.com/spreedly/gala/blob/master/lib/gala/payment_token.rb#L78
My guess the problem is in the certificate, which expired in 2016. You can check via:
$ openssl x509 -in test/fixtures/certificate.pem -text -noout | grep -A 2 Validity
Validity
Not Before: Oct 26 12:10:10 2014 GMT
Not After : Nov 24 12:10:10 2016 GMT
I was curious to know what this gem was licensed under? I searched through all the code and found nothing. Do you mind adding a license file so that I know how I can use this code?
I'm attempting to use rake test with my certificate and paymentData. But I'm unsure what should go in @merchant_id in setup.
Same for @shared_secret and @symmetric_key, where do I get these from?
gala/lib/gala/payment_token.rb
Line 81 in 797316f
What is the purpose of removing the first 2 bytes here?
There's a hash of applicationData
contained in the token. We should expose it if it exists.
Hash of the applicationData property of the original PKPaymentRequest object. If the value of that property is nil, this key is omitted.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.