简体   繁体   中英

Determine if SSL certificate is self signed using Python

I am trying to determine if an SSL certificate is self signed or not. Currently I have the following code which compares the issuer CN and the subject CN and if they are the same, marks the result as self signed.

with open(cert_file, "r") as f: 
    x509 = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, f.read())

result = {
    'subject': dict(x509.get_subject().get_components()),
    'issuer': dict(x509.get_issuer().get_components()),
    'serialNumber': x509.get_serial_number(),
    'version': x509.get_version(),
    'notBefore': datetime.strptime(x509.get_notBefore(), '%Y%m%d%H%M%SZ'),
    'notAfter': datetime.strptime(x509.get_notAfter(), '%Y%m%d%H%M%SZ'),
}

extensions = (x509.get_extension(i) for i in range(x509.get_extension_count()))
extension_data = {e.get_short_name(): str(e) for e in extensions}
result.update(extension_data)

if result['issuer']['CN'] == result['subject']['CN']:
    result.update({'self-signed': True})
else:
    result.update({'self-signed': False})

This comparison is very simplistic, but works in a lot of cases. I'm not trying to verify SSL certs or reimplement OpenSSL. How can I make this better and be roughly 95% sure if a certificate is self signed or not?

My one requirement is that I would like to do this in Python and not call other processes or use shell commands.

The OpenSSL definition of self-signed is:

The subject and issuer names match and extension values imply it is self signed.

The code that determines whether a cert is self-signed is:

/* Return 1 is a certificate is self signed */
static int cert_self_signed(X509 *x)
{
    X509_check_purpose(x, -1, 0);
    if (x->ex_flags & EXFLAG_SS)
        return 1;
    else
        return 0;
}

And the code that sets EXFLAG_SS :

/* Does subject name match issuer ? */
if (!X509_NAME_cmp(X509_get_subject_name(x), X509_get_issuer_name(x))) {
    x->ex_flags |= EXFLAG_SI;
    /* If SKID matches AKID also indicate self signed */
    if (X509_check_akid(x, x->akid) == X509_V_OK &&
        !ku_reject(x, KU_KEY_CERT_SIGN))
        x->ex_flags |= EXFLAG_SS;
}

So basically three things to check:

  • The subject name and the issuer name must match
  • The subject key identifier and the authority key identifier must match
  • The cert must contain a key usage extension with the KU_KEY_CERT_SIGN bit set

You are already comparing the subject name and the issuer name. The next important thing to do would be to compare the SKID and the AKID. After a cursory glance at pyopenssl it doesn't look like it provides a way to check this, so if you want a pure Python solution you might have to extend the library. However even the code you have would probably cover you in 95% of cases you said you wanted it to cover.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM