17

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.

Vitalie Maldur
  • 553
  • 3
  • 19

2 Answers2

10

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

stovfl
  • 14,998
  • 7
  • 24
  • 51
0

According to OpenSSL.crypto.X509Store documentation,

An X.509 store, being only a description, cannot be used by itself to verify a certificate. To carry out the actual verification process, see X509StoreContext.

So you need at least to include in your store a set of certificates to trust first, then initialise you storecontext and after that you can do the verification job.

You can see more information here to get the actual path (on which set of certificate to trust are stored.)

A. STEFANI
  • 6,707
  • 1
  • 23
  • 48