question

Steve A avatar image
Steve A asked

Trouble Verifying Certificate

I'm stuck trying to get my app (skill) to verify the Echo request. I cannot get the derived and asserted hashes to match, so I must be doing something wrong! I've successfully downloaded the certificate and extracted the public key. I'm pretty sure I've got a hold of the Signature header, assuming it looks like this: K5/htfI8fc1YFX3d6MMs5rfwqTk/8rAV5M663N5uwRJqT9JbVilFRa7jlOiW5ALM1e5MVwf/GHJ8XSuPF8iukHGzvHA4HrXN66nqqXiP9p6SqElsg7sjqrGFj45Zh9Vwg8LDrPKdTlh4b8ODwPL0fLLmNuBBmbZykO2AlobhqUxqEYomEuYoe780PCunmDshDD51x9O5qDnLetOcgaFwt2DUhWe9CBIq5vPfjw5W0FDEfY44YhBxOcrcBoEyWoGL/Q9WrVKUfZ7aHwTHXDRKPCJEAkCvifstMnbX+ycNGIy+6+7SFUb20+WGE7AjrkQHNk1zl2WELjNvWOgwGsyeXg== I then Base64 decode that signature ( in Ruby: Base64.decode64(signature) ) I'm guessing I'm having trouble generating the derived hash from the request body. The documentation says to "Generate a SHA-1 hash value from the full HTTPS request body" This (for example) is the body I'm computing the hash on. '{:version=>\"1.0\", :session=>{:new=>true, :sessionId=>\"amzn1.echo-api.session.91044d80-4e18-4c93-85e2-3595eb020004\", :application=>{:applicationId=>\"amzn1.echo-sdk-ams.app.414bc21e-8a3f-4295-8ab6-17ed845d8ca3\"}, :user=>{:userId=>\"amzn1.account.AFFFF24637WVI3RVMW2JSZA5TTTT\"}}, :request=>{:type=>\"LaunchRequest\", :requestId=>\"amzn1.echo-api.request.a180250b-2ae9-4b8b-b7ec-896380faa32c\", :timestamp=>\"2015-07-01T04:14:16Z\"}}' ( in Ruby: digest = OpenSSL::Digest.new('sha1', body_given_above) ) However the following comparison between the derived and asserted hash always yields "false:" certificate.public_key.verify(digest, base64_decoded_signature, body_given_above) I'm sort of stuck about where to go from here. I realize this might be a bit of a Ruby-centric question, but maybe I'm missing some step?? Any help would be appreciated! Thanks, Steve
alexa skills kitsubmission testing certification
10 |5000

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Stefan Negritoiu avatar image
Stefan Negritoiu answered
Hi Steven, make sure you're taking the hash of the raw body bytes not some string-encoded interpretation of the raw bytes. I'm not a Ruby dev so I can't tell whether the API you're using is giving you back the raw data, but if it's not, go lower in the stack to get to the bytes. HTH, Stefan
10 |5000

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Steve A avatar image
Steve A answered
Yes! Thanks!!!
10 |5000

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

sai94 avatar image
sai94 answered
Hi steven, I'm a ruby developer...i didn't get what freebusy mentioned...i'm stuck with the same problem as you are....It is always returning me false....Please help me
10 |5000

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Steve A avatar image
Steve A answered
It would be helpful to know exactly where you were stuck, or see some code. But this works for me. Assuming you've fetched or cached the certificate already: # This allows you to read the certificate attributes certificate = OpenSSL::X509::Certificate.new (certificate_received_from_amazon) # You need to grab the signature header and the full request body to generate a hash value on. # I'm using a Sinatra server, so ymmv for getting the header and body digest = OpenSSL::Digest::SHA1.new sig_header = request.env["HTTP_SIGNATURE"] signature = Base64.decode64(sig_header) body = request.body.read # Finally, compare the derived and asserted hash values. # If all goes well, this should return true. certificate.public_key.verify(digest, signature, body) Hope that helps! Steve
10 |5000

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

sai94 avatar image
sai94 answered
Hi Steve, Actually my issue was with Google inapp purchases.I had to write a server side code to verify the receipt sent by google. base64_encoded_public_key = PUBLIC_KEY_GOOGLE data1 = response_google['purchaseData'] sig = Base64.decode64(response_google['dataSignature']) key = OpenSSL::PKey::RSA.new(Base64.decode64(base64_encoded_public_key)) check = key.verify( OpenSSL::Digest::SHA1.new, Base64.decode64(sig), data1.to_s ) This is always yielding me check= false return value. {\"status\":0,\"dataSignature\":\"YMQ52M7LGRIX2lkZc7eXn54aYRwQQSsq\\/Hdk3Zp\\/FlwGOkEVj+h2dv4pVY9vrr01k3G***********************************************************CIYLGJPzhGVZaX9neFj8p+HIErgnnIGj6q4db0BQqcO0MygPPnbLGSRV6RetfgJDUq\\/ER8P7Q2vzuDOx5aKwGptp1CvdmYGVgnK5plvZTLhH86ABOqC97KaaLbbemrTANEpyUZPWDsNzlwcG+YKslDjpkEVlnWT\\/G7\\/2cFg7HQ==\",\"purchaseData\":{\"purchaseToken\":\"pDx*******fmD7e7kZ3iFhs3wP7k-1ChZFGHw63v-Bpw3AGqRMYc7GMNNVDitOmLGawZPy6tLf-sHxDzsou9GPrVpqKNNk1o2hudxBLW04CvnDKTk75Y\",\"developerPayload\":\"3d64143d45687c2db2cc352916319e43\",\"packageName\":\"com.example\",\"purchaseState\":0,\"orderId\":\"G**.1**0-2**8-1**9-1**9\",\"purchaseTime\":14439555,\"productId\":\"com.example.s\"}}"
10 |5000

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

sai94 avatar image
sai94 answered
The last body i mentioned is a data1 string and i will take the dataSignature from the string and use it encode and decode the signature
10 |5000

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

sai94 avatar image
sai94 answered
I have also tried. check = key.verify( OpenSSL::Digest::SHA1.new, sig , data1.to_s ) check = key.verify( OpenSSL::Digest::SHA1.new, sig , data1['purchaseData'].to_s ) But none of them worked. I donot understand where i'm going wrong. Am I using the receipt (data1.to_s) and signature(dataSignature from the receipt string) correctly? What does freebusy mean by 'hash of raw data rather than encoded string (of what)'?? Please Help...Thanks in advance Thanks Sai
10 |5000

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Steve A avatar image
Steve A answered
Sorry, I'm not familiar with that in particular. A couple of questions for you: Have you tried *not* double Base64 decoding the signature? Have you tried *not* string encoding the response (data1.to_s)? Wish I could be of more help.... Steve
10 |5000

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

sai94 avatar image
sai94 answered
10 |5000

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Steve A avatar image
Steve A answered
> What does freebusy mean by 'hash of raw data rather > than encoded string (of what)'?? > You are string encoding the body (data1.to_s). Have you tried verifying against the non-string encoded data? Or even: data1 = JSON.parse(data1) Or, my best advice of all: Have you checked on StackOverflow? 'Cause there you might get people who actually know about this problem in particular. See: https://stackoverflow.com/questions/5971031/how-do-i-verify-android-in-app-billing-with-a-server-with-ruby Steve
10 |5000

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.