Какова правильная цель сертификата для клиента SSL в python? - PullRequest
4 голосов
/ 15 марта 2020

Я устанавливаю подтверждение клиента SSL в моем приложении python. На данный момент мой проверочный код не работает только после установления безопасного соединения.

Похоже, что сгенерированные мной сертификаты либо используют сертификат без необходимых разрешений ( более вероятно, IMO ) или у них есть разрешения, которые сервер не может понять или принять ( немного менее вероятно, IMO ).

Это должно быть относительно тривиально, но я не могу найти нужную документацию .

Я сгенерировал сертификат сервера и клиента через OpenSSL. Я делал это в прошлом для других приложений без проблем. Но я гораздо менее знаком с созданием клиентских сертификатов. OpenSSL сообщает, что используемый мной клиентский сертификат имеет расширения:

X509v3 extensions:
    X509v3 Subject Key Identifier: 
        AF:AB:9D:AA:88:96:F4:0C:F5:56:9A:2C:DB:B6:BA:D9:DD:11:69:45
    X509v3 Subject Alternative Name: 
        email:a@example.com
    X509v3 Basic Constraints: 
        CA:FALSE
    Netscape Cert Type: 
        SSL Client
    X509v3 Authority Key Identifier: 
        keyid:E1:35:7C:39:7F:39:A4:43:D2:F8:00:59:38:91:71:AF:B9:38:AD:3F

    X509v3 Key Usage: 
        Digital Signature, Key Encipherment
    X509v3 Extended Key Usage: 
        TLS Web Client Authentication

Тривиальный тестовый код сервера:

import ssl
import socket
import logging

_log = logging.getLogger(__name__)


def main():
    context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
    context.load_cert_chain("1B.pem", "key2.pem")
    context.verify_mode = ssl.CERT_REQUIRED
    context.load_verify_locations("my_ca.crt")

    raw_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
    try:
        # domain replaced for SO question
        raw_server_socket.bind(('neptune.example.com', 8812))
        raw_server_socket.listen(5)
        server_socket = context.wrap_socket(raw_server_socket, server_side=True)
    except Exception:
        raw_server_socket.close()
        raise

    with server_socket:
        while True:
            try:
                connection_to_client, address = server_socket.accept()
                with connection_to_client:
                    connection_to_client.write(b'Hello')
            except Exception as ex:
                print(ex)


if __name__ == "__main__":
    main()

Это выдает ошибку:

[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unsupported certificate purpose (_ssl.c:1076)

... Когда клиент с этим связан:

import socket
import ssl

context = ssl.create_default_context(ssl.Purpose.SERVER_AUTH)
context.load_cert_chain("1C.pem", "key.pem")

raw_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Domain changed for SO question
conn = context.wrap_socket(raw_socket, server_side=False, server_hostname="neptune.example.com")
conn.connect(("neptune.example.com", 8812))
conn.close()

1 Ответ

0 голосов
/ 17 марта 2020

Как намекнул Штеффен Уллрих, похоже, проблема не в самом сертификате, а в сертификате CA, который я использовал для его подписи.

Сертификаты CA ограничены в правах, которые они могут авторизовать. Они представлены в тех же расширениях, что и сертификаты, которые они подписывают. Поэтому для ЦС для подписи сертификата в качестве клиентского SSL-сертификата и клиентский сертификат и сертификат ЦС должны иметь:

  • Использование ключа с «цифровой подписью».
  • расширение 1.3.6.1.5.5.7.3.2 AKA TLS Web Client Authentication

То есть openssl должен сообщить следующее для и сертификата CA и подписанного сертификата клиента:

X509v3 Key Usage: 
    Digital Signature
X509v3 Extended Key Usage: 
    TLS Web Client Authentication

В моем случае у CA не было расширенного использования 1.3.6.1.5.5.7.3.2. Это было нормально для серверных сертификатов, но не могло подписывать клиентские сертификаты.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...