pyOpenSSL : verify certificates chain : works with 2 but not with more
Asked Answered
G

1

1

I build my own certificates chain and try to verify it.
When I have only 2 certificates (the root CA and the to-be-verified): it works fine.
When I have 3 (the root CA, an intermediate, and the to-be-verified): I get the message "invalid CA certificate".
Here is a minimalist code :

import OpenSSL

def create_cert_chain ( nb ):

    chain        = []
    issuer_key   = None
    issuer_name  = None
    is_root      = True
    
    for i in range( nb ):
    
        my_name = b'certificate #%d'%i # certificate #0 is the root CA
        cert    = OpenSSL.crypto.X509()
        my_key  = OpenSSL.crypto.PKey()
        my_key  . generate_key( OpenSSL.crypto.TYPE_RSA,2048 )

        if is_root :    
            cert.add_extensions( [OpenSSL.crypto.X509Extension(b"subjectKeyIdentifier", False, b"hash",subject=cert)])
            cert.add_extensions( [OpenSSL.crypto.X509Extension(b"authorityKeyIdentifier", False, b"keyid:always",issuer=cert)])
            cert.add_extensions( [OpenSSL.crypto.X509Extension(b"basicConstraints", False, b"CA:TRUE,pathlen:5")])
            cert.add_extensions( [OpenSSL.crypto.X509Extension(b"keyUsage", False, b"keyCertSign, cRLSign")])
                
        cert.get_subject().O = my_name
        cert.get_issuer().O  = my_name if is_root else issuer_name
        cert.gmtime_adj_notBefore( 0 )
        cert.gmtime_adj_notAfter( 365*24*60*60 )
        cert.set_pubkey( my_key )
        cert.sign( my_key if is_root else issuer_key,'sha256' )
        chain += [cert]

        issuer_key  = my_key
        issuer_name = my_name
        is_root     = False
    return chain

def check_chain ( nb ):
    chain = create_cert_chain( nb )
    store = OpenSSL.crypto.X509Store()
    for cert in chain[:-1] :
        print( 'store certificate%s'%cert.get_subject().O )
        store.add_cert( cert )
    print( 'check certificate%s'%chain[-1].get_subject().O )
    ctx = OpenSSL.crypto.X509StoreContext( store,chain[-1] )
    ctx.verify_certificate()
    print('ok')

check_chain( 2 ) # works fine
check_chain( 3 ) # fails with "invalid CA certificate"

What do I wrong ?
I suspect a mistake about the extensions but I can't figure out what it is...
And by the way, why does it works with only 2 certificates ?

Griseofulvin answered 20/5, 2022 at 13:19 Comment(0)
G
1

I found out my mistake : the basic contraint CA:TRUE is not only to be applied to the root certificate, but to all the intermediate ones. So, the correct test is if i < nb-1 : (instead of if is_root :).
Add if I want to be as must restrictive as possible about the path length, I have to set it to nb-i-2.
And by the way, for my need, all other extensions are optional.

Griseofulvin answered 20/5, 2022 at 14:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.