Определите, является ли сертификат SSL самозаверяющим с использованием Python - PullRequest
10 голосов
/ 26 июня 2019

Я пытаюсь определить, является ли сертификат SSL самоподписанным или нет. В настоящее время у меня есть следующий код, который сравнивает CN издателя и CN субъекта и, если они совпадают, помечает результат как самоподписанный.

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})

Это сравнение очень упрощенное, но работает во многих случаях. Я не пытаюсь проверить SSL-сертификаты или переопределить OpenSSL. Как я могу сделать это лучше и быть примерно на 95% уверенным, если сертификат самоподписан или нет?

Мое единственное требование - я хотел бы сделать это в Python, а не вызывать другие процессы или использовать команды оболочки.

1 Ответ

3 голосов
/ 04 июля 2019

OpenSSL определение самоподписанного :

Имена субъектов и издателей совпадают и значения расширений подразумевают, что он самоподписан.

Код , который определяет, является ли сертификат самоподписанным :

/* 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;
}

И код , который устанавливает 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;
}

Итак, в основном нужно проверить три вещи:

  • Имя субъекта и имя эмитента должны совпадать
  • Идентификатор ключа субъекта и идентификатор ключа доступа должны совпадать
  • Сертификат должен содержать расширение использования ключа с установленным битом KU_KEY_CERT_SIGN

Вы уже сравниваете имя субъекта и имя эмитента. Следующее, что нужно сделать, это сравнить SKID и AKID. После беглого взгляда на pyopenssl это не похоже на способ проверить это, поэтому, если вам нужно чистое решение Python, вам, возможно, придется расширить библиотеку. Однако даже код, который у вас есть, вероятно, охватит вас в 95% случаев, когда вы сказали, что хотите, чтобы он покрывал.

...