question

Anthony M. avatar image
Anthony M. asked

Any Examples of Validating SSL Certificate for Ruby

I've been trying for a few days now to validate the SSL certificate using the signature and PEM file as required for app submission. Does anyone have an example in Ruby that accomplishes this? This what I'm currently at, but i'm not sure exactly how to validate my request. The info I end up with in the logs looks like garbled text so I'm at a lost because i've never done this before. Any help is appreciated. url = request.headers["SignatureCertChainUrl"] Rails.logger.info request.headers["Signature"] Rails.logger.info Base64.decode64(request.headers["Signature"]) sig = request.headers["Signature"] x = URI.parse(url) puts x.host raw = open(x).read # DER- or PEM-encoded #p raw certificate = OpenSSL::X509::Certificate.new raw Rails.logger.info certificate.public_key.public_decrypt(Base64.decode64(sig)) -Anthony
alexa skills kitdebugging
10 |5000

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

Anthony M. avatar image
Anthony M. answered
Finally able to figure it out after loads of googling and i was waaaayy off. But I figured it out and below is the solution in case others have similar issues. x = URI.parse(url) raw = open(x).read # DER- or PEM-encoded certificate = OpenSSL::X509::Certificate.new raw signature = request.headers["Signature"] digest = Digest::SHA1.hexdigest request.body.read digest = OpenSSL::Digest.new('sha1', request.body.read) digest = OpenSSL::Digest::SHA1.new Rails.logger.info digest Rails.logger.info request.body.read if certificate.public_key.verify digest,Base64.decode64(signature).to_s,request.body.read Rails.logger.info 'Valid' else begin raise 'A test exception.' rescue Exception => e response.status = 400 render :text => ({:error=>"Certificate Isn't Valid - Didn't Pass signature match"}).to_json.html_safe, :status => 400 end end
10 |5000

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

Damian Finol avatar image
Damian Finol answered
Hey Anthony A lot of that work Is available in the Rubykit gem: https://github.com/damianFC/alexa-rubykit
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
Anthony, Thanks for this. I've found it very helpful trying to puzzle through the validation process. The one thing I'm stuck on -- and I'm sure I'm (stupidly) overlooking in your example -- is this step: "Use the public key extracted from the signing certificate to decrypt the encrypted signature to produce the asserted hash value." I've gotten the public key from the certificate, and have the Base64 decoded encrypted signature. But I can't figure out how to use the public key to decrypt the signature. Any guidance would be appreciated! Steve p.s. I don't have any Rails methods available in my code.
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
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. Any help would be appreciated! Thanks, 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.

Nick Gardner avatar image
Nick Gardner answered
So I'm not really an expert in Ruby, and the research I did wasn't able to get me an answer to this. Were you able to figure something else out in the meantime, or has anyone else thought of a solution in the meantime? -Nick
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
Nick, Yes, I did get it figured out with help from freebusy here: https://forums.developer.amazon.com/forums/thread.jspa?messageID=17877䗕 Thanks so much for following up! 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.

Neil Harris avatar image
Neil Harris answered

Anthony's solution worked for me. In summary, I used this:

signature = Base64.decode64(request.headers["Signature"]).to_s

digest = OpenSSL::Digest.new('sha1', request.body.read)

if certificate.public_key.verify digest, signature, request.body.read

  Rails.logger.info "Alexa :: valid"

else

  Rails.logger.info "Alexa :: invalid"

end
10 |5000

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