Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Alexa request validation in python

I work on a service that will handle Alexa voice intents. I need to verify the signature of each request and I almost succeed. The only part that is not working is the validation of certificates chain.

From the documentation I know that:

This certificate chain is composed of, in order, (1) the Amazon signing certificate and (2) one or more additional certificates that create a chain of trust to a root certificate authority (CA) certificate.

My code looks like this:

certificates = pem.parse_file("chain.pem")
store = crypto.X509Store()
for cert in certificates[:-1]:
    loaded_cert = crypto.load_certificate(crypto.FILETYPE_PEM,
                                          cert.as_bytes())
    store.add_cert(loaded_cert)

intermediate_cert = crypto.load_certificate(
    crypto.FILETYPE_PEM,
    certificates[-1].as_bytes()
)
# Create a certificate context
store_ctx = crypto.X509StoreContext(store, intermediate_cert)

# Verify the certificate
store_ctx.verify_certificate()

I receive the following error:

OpenSSL.crypto.X509StoreContextError: [20, 0, 'unable to get local issuer certificate']

I don't know what I did wrong, maybe there is someone who already implemented this and can drop a hint.

like image 874
Vitalie Maldur Avatar asked May 23 '17 12:05

Vitalie Maldur


People also ask

Can I program Alexa with Python?

The Alexa Skills Kit SDK for Python simplifies the development of the back-end cloud service for your Alexa skill. A part of the Alexa Skills Kit, the SDK reduces the amount of code you need to write to process Alexa requests and responses and to handle other common skill tasks.

Can Alexa send a HTTP request?

The Request module is one of the most popular NPM module for making HTTP requests. It supports both HTTP and HTTPS and follows redirects by default.

How do you fix there was a problem with the requested skill's response?

One simple way to debug this issue is copying the input JSON from Alexa skill simulator and paste it in the lambda's configure test events. Now run test and it'll generate all the error logs in the lambda itself, for your easy reference.


1 Answers

First and once get the CA Issuer for all Certificate in 'chain.pem':

for cert in pem.parse_file("chain.pem"):
    CA_cert = crypto.load_certificate(crypto.FILETYPE_PEM, cert.as_bytes())
    print('CA_cert:\nissuer :{}\nsubject:{}'.
        format(CA_cert.get_subject(), CA_cert.get_issuer()))

Output, for example:

CA_cert:
issuer :<X509Name object '/C=US/O=thawte, Inc./OU=Certification Services Division/OU=(c) 2006 thawte, Inc. - For authorized use only/CN=thawte Primary Root CA'>
subject:<X509Name object '/C=US/O=thawte, Inc./OU=Certification Services Division/OU=(c) 2006 thawte, Inc. - For authorized use only/CN=thawte Primary Root CA'>

This shown example Certificate is a self signed certificate.


Add all shown issuer to CA_store, then do .verify_certificate for all Certificate in 'chain.pem'.

CA_store = crypto.X509Store()
for _pem in ['issuer_1.pem', 'issuer_2.pem']:
    for cert in pem.parse_file(_pem):
        CA_store.add_cert(
            crypto.load_certificate(crypto.FILETYPE_PEM, cert.as_bytes())
        )

for cert in pem.parse_file("chain.pem"):
    try:
        crypto.X509StoreContext(CA_store,
                                crypto.load_certificate(crypto.FILETYPE_PEM, cert.as_bytes())
                                ).verify_certificate()
    except X509StoreContextError as exp:
        cert = exp.certificate
        print('X509StoreContextError:{}\ncertificate\n\tissuer :{}\n\tsubject:{}'.
            format(exp.args, cert.get_issuer(), cert.get_subject()))

Tested with Python:3.4.2 - OpenSSL:17.0.0 - cryptography:1.8.2 - cffi:1.10.0

like image 99
stovfl Avatar answered Sep 21 '22 06:09

stovfl