将证书传递到请求库

时间:2019-06-05 14:36:05

标签: python-3.x https openssl

我有使用Python编写的https服务器,该服务器使用自我认证:

"-x, --donot_pickle"

生成证书的步骤:

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)

我也有https客户端:

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

这可行,但是我想将不同的请求发送到某个路径,例如#!/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/fillrequests lib。

我正在尝试将证书传递给此库

urllib3

但是客户端同时挂起了两个库:

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 )中一样工作。

1 个答案:

答案 0 :(得分:0)

我使用证书的方式不正确。 因此,用于生成证书的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)