Передача сертификатов в запросы lib - PullRequest
0 голосов
/ 05 июня 2019

У меня есть сервер https, написанный на Python, который использует самостоятельные сертификаты:

server_cert = 'certs/server/server.crt'
server_key = 'certs/server/server.key'
client_certs = 'certs/client/client.crt'

context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
context.verify_mode = ssl.CERT_REQUIRED
context.load_cert_chain(certfile=server_cert, keyfile=server_key)
context.load_verify_locations(cafile=client_certs)

Шаги к сертификатам генерируют:

openssl req -new -newkey rsa:2048 -days 365 -nodes -x509 -subj "/C=US/ST=Denial/L=Springfield/O=Dis/CN=localhost/UID=testnotifier" -keyout ${certs}/server/server.key -out ${certs}/server/server.crt
openssl req -new -newkey rsa:2048 -days 365 -nodes -x509 -subj "/C=US/ST=Denial/L=Springfield/O=Dis/CN=localhost/UID=testnotifier" -keyout ${certs}/client/client.key -out ${certs}/client/client.crt

Также у меня есть клиент https:

#!/usr/bin/python3

import socket
import ssl

host_addr = '127.0.0.1'
host_port = 8082
server_sni_hostname = 'localhost'
server_cert = 'certs/server/server.crt'
client_cert = 'certs/client/client.crt'
client_key = 'certs/client/client.key'

context = ssl.create_default_context(ssl.Purpose.SERVER_AUTH, cafile=server_cert)
context.load_cert_chain(certfile=client_cert, keyfile=client_key)

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
conn = context.wrap_socket(s, server_side=False, server_hostname=server_sni_hostname)
conn.connect((host_addr, host_port))
conn.send(b"Hello, world!")
conn.close()

Это работает, но я хочу отправлять разные запросы по какому-либо пути, например /rest/v1/fill.Итак, я решил использовать requests или urllib3 lib.

Я пытаюсь передать сертификаты этим библиотекам

https = urllib3.PoolManager(cert_file=client_cert, cert_reqs='CERT_REQUIRED', ca_certs=server_cert, key_file=client_key)
https.request('GET', 'https://localhost:8082/rest/v1/fill')

, но клиент зависает с обеими библиотеками:

/home/marat/.local/lib/python3.6/site-packages/urllib3/connection.py:362: SubjectAltNameWarning: Certificate for localhost has no `subjectAltName`, falling back to check for a `commonName` for now. This feature is being removed by major browsers and deprecated by RFC 2818. (See https://github.com/shazow/urllib3/issues/497 for details.)
  SubjectAltNameWarning
^CTraceback (most recent call last):
  File "/home/marat/.local/lib/python3.6/site-packages/urllib3/connectionpool.py", line 377, in _make_request
    httplib_response = conn.getresponse(buffering=True)
TypeError: getresponse() got an unexpected keyword argument 'buffering'

вывод сервера:

Client connected: 127.0.0.1:40026
SSL established. Peer: {'subject': ((('countryName', 'US'),), (('stateOrProvinceName', 'Denial'),), (('localityName', 'Springfield'),), (('organizationName', 'Dis'),), (('commonName', 'localhost'),), (('userId', 'testnotifier'),)), 'issuer': ((('countryName', 'US'),), (('stateOrProvinceName', 'Denial'),), (('localityName', 'Springfield'),), (('organizationName', 'Dis'),), (('commonName', 'localhost'),), (('userId', 'testnotifier'),)), 'version': 3, 'serialNumber': '88F15B15B2D1ABE7', 'notBefore': 'Jun  5 11:35:38 2019 GMT', 'notAfter': 'Jun  4 11:35:38 2020 GMT'}
Received: b'GET / HTTP/1.1\r\nHost: localhost:8082\r\nAccept-Encoding: identity\r\n\r\n'
Closing connection

Я хотел бы знать, как передавать сертификаты, чтобы клиент работал как в первой версии (с socket/ssl).

1 Ответ

0 голосов
/ 06 июня 2019

Я некорректно работал с сертификатами. Итак, скрипт bash для генерации сертификатов:

generate_test_certs() {
  echo "Generate test certs"
  mkdir -p ${SCRIPT_PATH}/test/certs/{server,client,root}
  local certs=${SCRIPT_PATH}/test/certs
  local CN=localhost # common name
  cat <<EOF > ${certs}/openssl.cnf
authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
subjectAltName = @alt_names
[alt_names]
DNS.1 = ${CN}
EOF

  # Create root key
  openssl genrsa -out ${certs}/root/rootCA.key 2048
  openssl req -new -x509 -days 3650 -key ${certs}/root/rootCA.key -out ${certs}/root/rootCA.crt \
        -subj "/C=US/ST=Denial/L=Springfield/O=Qwerty Inc./OU=Qwerty Operations/CN=Qwerty Root"

  # Generate sign request
  openssl req -new -newkey rsa:2048 -subj "/C=US/ST=Denial/L=Springfield/O=Dis/CN=${CN}/UID=testnotifier" \
        -keyout ${certs}/server/server.key -nodes -out ${certs}/server/server.csr
  # Sign CSR by ROOT CA certificate
  openssl x509 -req -days 3650 -in ${certs}/server/server.csr -CA ${certs}/root/rootCA.crt \
        -CAkey ${certs}/root/rootCA.key -set_serial 01 -out ${certs}/server/server.crt \
        -extfile ${certs}/openssl.cnf

  # Generate client certificate
  openssl req -new -newkey rsa:2048 -nodes -subj "/C=US/ST=Denial/L=Springfield/O=Dis/CN=${CN}/UID=testnotifier" \
        -keyout ${certs}/client/client.key -out ${certs}/client/client.csr
  openssl x509 -req -days 3650 -in ${certs}/client/client.csr -CA ${certs}/root/rootCA.crt -CAkey ${certs}/root/rootCA.key \
        -set_serial 01 -out ${certs}/client/client.crt
}

Конфигурация Nginx, например:

server {
    listen          451 ssl;
    server_name     tester;

    ssl_certificate         ../../../test/certs/server/server.crt;
    ssl_certificate_key     ../../../test/certs/server/server.key;
    ssl_client_certificate  ../../../test/certs/root/rootCA.crt;
    ssl_verify_client       optional;
    ssl_verify_depth        3;

    include ../../../conf/tester.rules.conf;
}

И, наконец, клиент Python

#!/usr/bin/python3

import requests

root_ca = 'certs/root/rootCA.crt'
client_cert = 'certs/client/client.crt'
client_key = 'certs/client/client.key'

resp = requests.get('https://localhost:451/qwe/rty',
                    cert=(client_cert, client_key), verify=root_ca)
print(resp.status_code)
print(resp.content)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...