I have two certificates, a root.crt
that was used to sign client.crt
.
I want to verify that the client.crt
was indeed signed by root.key
.
Using openssl on terminal, it works like this:
$ openssl verify -CAfile root.crt client.crt
> client.crt: OK
However using pyOpenSSL - following the documentation and this blog post - I tried something like this:
client_cert = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, file('client.crt').read())
root_cert = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, file('root.crt').read())
store = OpenSSL.crypto.X509Store()
store.add_cert(root_cert)
ctx = OpenSSL.crypto.X509StoreContext(store, client_cert)
ctx.verify_certificate()
I get this error:
> X509StoreContextError: [2, 1, 'unable to get issuer certificate']
What am I missing?
The issue is that my root.crt
is not really root, but a chain of certificates:
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
And OpenSSL.crypto.load_certificate
just loads the first one.
The solution is to extract all certificates in the chain file and add them to the X509Store
.
The code solution looks like this:
_PEM_RE = re.compile(b'-----BEGIN CERTIFICATE-----\r?.+?\r?-----END CERTIFICATE-----\r?\n?', re.DOTALL)
def parse_chain(chain):
# returns a list of certificates
return [c.group() for c in _PEM_RE.finditer(chain)]
client_cert = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, file('server.crt').read())
store = OpenSSL.crypto.X509Store()
for cert in parse_chain(file('root.crt').read()):
store.add_cert(OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, cert))
ctx = OpenSSL.crypto.X509StoreContext(store, client_cert)
ctx.verify_certificate()
Adapted from https://github.com/hynek/pem/blob/master/src/pem/_core.py#L115
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With