Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Verify signature from iOS transactionReceipt

I'm attempting to verify the deprecated iOS transactionReceipt; and I'm stuck on the verifying the signature.

I've base64 decoded the receipt and parsed the initial plist, resulting with:

payload = {
  "signature"=>"AnTJSzQAjehWYmnqlofOYVqrXJ51UNZr9//2HXq3MB9i2aPjVilv38ixmZoO/9YfPlRHYDusXT2IpYbDs4pFZNw/mQL1TzkIIetYea4OyjuV5KluEB4LKVol7nmHfd27HI6PM6jBDZKLmpktmNVCmfnheT+jlMjLx7eZKjHSFhlRAAADVzCCA1MwggI7oAMCAQICCBup4+PAhm/LMA0GCSqGSIb3DQEBBQUAMH8xCzAJBgNVBAYTAlVTMRMwEQYDVQQKDApBcHBsZSBJbmMuMSYwJAYDVQQLDB1BcHBsZSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEzMDEGA1UEAwwqQXBwbGUgaVR1bmVzIFN0b3JlIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTE0MDYwNzAwMDIyMVoXDTE2MDUxODE4MzEzMFowZDEjMCEGA1UEAwwaUHVyY2hhc2VSZWNlaXB0Q2VydGlmaWNhdGUxGzAZBgNVBAsMEkFwcGxlIGlUdW5lcyBTdG9yZTETMBEGA1UECgwKQXBwbGUgSW5jLjELMAkGA1UEBhMCVVMwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMmTEuLgjimLwRJxy1oEf0esUNDVEIe6wDsnnal14hNBt1v195X6n93YO7gi3orPSux9D554SkMp+Sayg84lTc362UtmYLpWnb34nqyGx9KBVTy5OGV4ljE1OwC+oTnRM+QLRCmeNxMbPZhS47T+eZtDEhVB9usk3+JM2Cogfwo7AgMBAAGjcjBwMB0GA1UdDgQWBBSJaEeNuq9Df6ZfN68Fe+I2u22ssDAMBgNVHRMBAf8EAjAAMB8GA1UdIwQYMBaAFDYd6OKdgtIBGLUyaw7XQwuRWEM6MA4GA1UdDwEB/wQEAwIHgDAQBgoqhkiG92NkBgUBBAIFADANBgkqhkiG9w0BAQUFAAOCAQEAeaJV2U51rxfcqAAe5C2/fEW8KUl4iO4lMuta7N6XzP1pZIz1NkkCtIIweyNj5URYHK+HjRKSU9RLguNl0nkfxqObiMckwRudKSq69NInrZyCD66R4K77nb9lMTABSSYlsKt8oNtlhgR/1kjSSRQcHktsDcSiQGKMdkSlp4AyXf7vnHPBe4yCwYV2PpSN04kboiJ3pBlxsGwV/ZlL26M2ueYHKYCuXhdqFwxVgm52h3oeJOOt/vY4EcQq7eqHm6m03Z9b7PRzYM2KGXHDmOMk7vDpeMVlLDPSGYz1+U3sDxJzebSpbaJmT7imzUKfggEY7xxf4czfH0yj5wNzSGTOvQ==",
  "purchase-info"=>"ewoJIm9yaWdpbmFsLXB1cmNoYXNlLWRhdGUtcHN0IiA9ICIyMDE1LTExLTE3IDA4OjM0OjQxIEFtZXJpY2EvTG9zX0FuZ2VsZXMiOwoJInB1cmNoYXNlLWRhdGUtbXMiID0gIjE0NDc4MjEyODEwMDAiOwoJInVuaXF1ZS1pZGVudGlmaWVyIiA9ICJkZDBlMzNlYmY1NmJiMWYzYWQ0YzJkYmFhN2EwYjMzYWM2OGIwZTg1IjsKCSJvcmlnaW5hbC10cmFuc2FjdGlvbi1pZCIgPSAiMTAwMDAwMDE4MDYzNjIyNiI7CgkiZXhwaXJlcy1kYXRlIiA9ICIxNDQ4MzQ2ODgxMDAwIjsKCSJ0cmFuc2FjdGlvbi1pZCIgPSAiMTAwMDAwMDE4MTI5ODczNCI7Cgkib3JpZ2luYWwtcHVyY2hhc2UtZGF0ZS1tcyIgPSAiMTQ0Nzc3ODA4MTAwMCI7Cgkid2ViLW9yZGVyLWxpbmUtaXRlbS1pZCIgPSAiMTAwMDAwMDAzMDkzODcxMyI7CgkiYnZycyIgPSAiMSI7CgkidW5pcXVlLXZlbmRvci1pZGVudGlmaWVyIiA9ICI0RTVFMUEzQi1GMDFBLTQ4NTUtODIwRi1GMzQ5RjEyNDIxNDgiOwoJImV4cGlyZXMtZGF0ZS1mb3JtYXR0ZWQtcHN0IiA9ICIyMDE1LTExLTIzIDIyOjM0OjQxIEFtZXJpY2EvTG9zX0FuZ2VsZXMiOwoJIml0ZW0taWQiID0gIjEwMjg5NTA3OTciOwoJImV4cGlyZXMtZGF0ZS1mb3JtYXR0ZWQiID0gIjIwMTUtMTEtMjQgMDY6MzQ6NDEgRXRjL0dNVCI7CgkicHJvZHVjdC1pZCIgPSAieWVhcmx5IjsKCSJwdXJjaGFzZS1kYXRlIiA9ICIyMDE1LTExLTE4IDA0OjM0OjQxIEV0Yy9HTVQiOwoJIm9yaWdpbmFsLXB1cmNoYXNlLWRhdGUiID0gIjIwMTUtMTEtMTcgMTY6MzQ6NDEgRXRjL0dNVCI7CgkiYmlkIiA9ICJjb20ubWJhYXN5Lmlvcy5kZW1vIjsKCSJwdXJjaGFzZS1kYXRlLXBzdCIgPSAiMjAxNS0xMS0xNyAyMDozNDo0MSBBbWVyaWNhL0xvc19BbmdlbGVzIjsKCSJxdWFudGl0eSIgPSAiMSI7Cn0=",
  "environment"=>"Sandbox",
  "pod"=>"100",
  "signing-status"=>"0"
}

So now I want to verify the signature, here is what I have so far:

version, sig, cert_length, cert = payload.fetch('signature')
                                  .unpack('m').first
                                  .unpack('c a128 N a*')
return false unless
  version == 2 &&
  sig.size == 128 &&
  cert.size == cert_length

cert = OpenSSL::X509::Certificate.new cert

digest = OpenSSL::Digest::SHA1.new
digest << version.to_s
digest << payload.fetch('purchase-info').unpack('m').first

cert.public_key.verify OpenSSL::Digest::SHA1.new, sig, digest.digest

The result from cert.public_key.verify is always false which is not what I want since I'm working from a real receipt.

I'm using this Quora post as a guide which has given me insight into how to unpack the signature, and I have successfully extracted all the parts from the blob.

Perhaps encoding is an issue? sig and data are both ASCII-8BIT and version is an integer.

I appreciate your help on this.

like image 872
Marc Greenstock Avatar asked Dec 14 '15 11:12

Marc Greenstock


People also ask

How do I decode an Apple receipt?

Validate the receipt Locate and load the app receipt from the app's bundle. The class Bundle provides the location of the receipt with the property appStoreReceiptURL . Decode the app receipt as a PKCS #7 container and verify that the chain of trust for the container's signature matches the Apple root certificate.

What is Apple StoreKit?

StoreKit provides a simple and secure way to purchase digital goods or services in your apps across all Apple platforms, so people can start playing, gaming, reading, and more, right away.

How do you use SKReceiptRefreshRequest?

To request the receipt using the SKReceiptRefreshRequest object, you initialize it, attach a delegate , and then call the request's start() method. The receipt refresh request displays a system prompt that asks users to authenticate with their App Store credentials.


1 Answers

Hereby the answer according to https://gist.github.com/lxcid/4441003

message = [version, payload.fetch('purchase-info').unpack('m').first].pack('CA*') 

cert.public_key.verify OpenSSL::Digest::SHA1.new, sig, message
like image 92
Laurens Avatar answered Oct 17 '22 02:10

Laurens