class AlexaRuby::Certificates

SSL certificates validator

Public Class Methods

new(certificates_chain_url, signature, request) click to toggle source

Setup new certificates chain

@param certificates_chain_url [String] SSL certificates chain URL @param signature [String] HTTP request signature @param request [String] plain HTTP request body

# File lib/alexa_ruby/request/base_request/validator/certificates.rb, line 13
def initialize(certificates_chain_url, signature, request)
  download_certificates(certificates_chain_url)
  @signature = signature
  @request = request
end

Public Instance Methods

valid?() click to toggle source

Check if it is a valid certificates chain and request signature

@return [Boolean]

# File lib/alexa_ruby/request/base_request/validator/certificates.rb, line 22
def valid?
  active? && amazon? && verified?
end

Private Instance Methods

active?() click to toggle source

Check if it is an active certificate

@return [Boolean]

# File lib/alexa_ruby/request/base_request/validator/certificates.rb, line 40
def active?
  now = Time.now
  (@cert.not_before < now && @cert.not_after > now) ||
    raise(
      ArgumentError,
      'Amazon SSL certificate is outdated ' \
      "specified dates: #{@cert.not_before} - #{@cert.not_after}"
    )
end
amazon?() click to toggle source

Check if Subject Alternative Names includes Amazon domain name

@return [Boolean]

# File lib/alexa_ruby/request/base_request/validator/certificates.rb, line 53
def amazon?
  @cert.subject.to_a.flatten.include?('echo-api.amazon.com') ||
    raise(
      ArgumentError,
      'Certificate must be issued for "echo-api.amazon.com" ' \
      "(given certificate subject: #{@cert.subject.to_a})"
    )
end
decode_signature() click to toggle source

Decode base64-encoded signature

@return [String] decoded signature

# File lib/alexa_ruby/request/base_request/validator/certificates.rb, line 80
def decode_signature
  Base64.decode64(@signature)
end
download_certificates(certificates_chain_url) click to toggle source

Download SSL certificates chain from Amazon URL

@param certificates_chain_url [String] SSL certificates chain URL

# File lib/alexa_ruby/request/base_request/validator/certificates.rb, line 31
def download_certificates(certificates_chain_url)
  resp = HTTParty.get(certificates_chain_url)
  raise ArgumentError, 'Invalid certificates chain' unless resp.code == 200
  @cert = OpenSSL::X509::Certificate.new(resp.body)
end
hash() click to toggle source

Get hash type for comparison

@return [OpenSSL::Digest::SHA1] OpenSSL SHA1 hash

# File lib/alexa_ruby/request/base_request/validator/certificates.rb, line 94
def hash
  OpenSSL::Digest::SHA1.new
end
public_key() click to toggle source

Get public key from certificate

@return [OpenSSL::PKey::RSA] OpenSSL PKey object

# File lib/alexa_ruby/request/base_request/validator/certificates.rb, line 87
def public_key
  @cert.public_key
end
verified?() click to toggle source

Check if given signature matches given request

@return [Boolean]

# File lib/alexa_ruby/request/base_request/validator/certificates.rb, line 65
def verified?
  sign = decode_signature
  pkey = public_key
  pkey.verify(hash, sign, @request) ||
    raise(
      ArgumentError,
      'Given request signature does not match with request SHA1 hash ' \
      "(signature: #{@signature};\n" \
      "request: #{@request})"
    )
end