【发布时间】:2018-11-12 03:24:36
【问题描述】:
我目前正在尝试在客户端和服务器之间实现双向 TLS 身份验证。我遇到了 SSL 错误,它的描述性不是很强。 StackOverflow 也没有太多与它相关的问题,因为大多数时候它是互联网上的单向 TLS。 但是,据我所知,出现此错误是因为客户端证书有问题,所以下面我附上了与此相关的信息。 如果不是这种情况,请告诉我。
生成客户证书
我客户的 cnf(foo.config) 看起来像(替换所有敏感信息):
[ req ]
default_bits = 2048
default_md = sha256
prompt = no
req_extensions = req_ext
distinguished_name = dn
encrypt_key = no
[ dn ]
O=Bar
OU=User
CN=myuser@foo.com
[ req_ext ]
subjectAltName = email:myuser@foo.com
nsCertType = client, email, objsign
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
我使用 openssl 传入这个配置文件来创建一个 csr:
openssl req -new -sha256 -key foo.key -out foo.csr -config foo.config
然后我将它发送到内部的基础架构管理 API 以签署 x509 证书。我将客户端证书保存为foo.cert(它包含到 CA 的信任链)。
我的客户如何发送证书
当我向我的服务器发送一个 urllib 打开请求时,我使用我的HTTPSConnection 发送 ssl 上下文:
... # Inside some handler code
context = ssl.create_default_context(purpose=ssl.Purpose.SERVER_AUTH,
cafile=ROOT_CA)
context.load_cert_chain(certfile=CERT_DEST, keyfile=KEY_DEST)
context.verify_mode = ssl.CERT_REQUIRED
context.check_hostname = True
return http.client.HTTPSConnection(host, context=context)
我的烧瓶服务器如何设置
当我的测试烧瓶服务器像这样接收 ssl 上下文时:
executor = Flask(__name__)
context = ssl.create_default_context(purpose=ssl.Purpose.CLIENT_AUTH, cafile=TEST_CA_CERT)
context.load_cert_chain(certfile=TEST_CERT, keyfile=TEST_KEY)
context.verify_mode = ssl.CERT_REQUIRED
context.check_hostname = False
executor.run(host=host, port=port, ssl_context=context)
它设置自己的证书和密钥文件。它还设置客户端身份验证请求。
完整的错误回溯
在运行时,在通话期间,我得到这个回溯(替换所有敏感信息):
Traceback (most recent call last):
File "/auto/foo/python3-rhel6/lib/python3.6/urllib/request.py", line 1318, in do_open
encode_chunked=req.has_header('Transfer-encoding'))
File "/auto/foo/python3-rhel6/lib/python3.6/http/client.py", line 1239, in request
self._send_request(method, url, body, headers, encode_chunked)
File "/auto/foo/python3-rhel6/lib/python3.6/http/client.py", line 1285, in _send_request
self.endheaders(body, encode_chunked=encode_chunked)
File "/auto/foo/python3-rhel6/lib/python3.6/http/client.py", line 1234, in endheaders
self._send_output(message_body, encode_chunked=encode_chunked)
File "/auto/foo/python3-rhel6/lib/python3.6/http/client.py", line 1026, in _send_output
self.send(msg)
File "/auto/foo/python3-rhel6/lib/python3.6/http/client.py", line 964, in send
self.connect()
File "/auto/foo/python3-rhel6/lib/python3.6/http/client.py", line 1400, in connect
server_hostname=server_hostname)
File "/auto/foo/python3-rhel6/lib/python3.6/ssl.py", line 407, in wrap_socket
_context=self, _session=session)
File "/auto/foo/python3-rhel6/lib/python3.6/ssl.py", line 814, in __init__
self.do_handshake()
File "/auto/foo/python3-rhel6/lib/python3.6/ssl.py", line 1068, in do_handshake
self._sslobj.do_handshake()
File "/auto/foo/python3-rhel6/lib/python3.6/ssl.py", line 689, in do_handshake
self._sslobj.do_handshake()
ssl.SSLError: [SSL: SSLV3_ALERT_UNSUPPORTED_CERTIFICATE] sslv3 alert unsupported certificate (_ssl.c:833)
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "./bar.py", line 375, in <module>
start(args, overrides, threadlock)
File "./bar.py", line 332, in start
approved, alloc_message = Executor.approve(flow.the_portal.inst)
File "/home/myuser/dev/bar/Executor.py", line 638, in approve
with opener.open(request, json_request) as response:
File "/auto/foo/python3-rhel6/lib/python3.6/urllib/request.py", line 526, in open
response = self._open(req, data)
File "/auto/foo/python3-rhel6/lib/python3.6/urllib/request.py", line 544, in _open
'_open', req)
File "/auto/foo/python3-rhel6/lib/python3.6/urllib/request.py", line 504, in _call_chain
result = func(*args)
File "/home/myuser/dev/bar/Auth.py", line 77, in https_open
return self.do_open(self.getConnection, req)
File "/auto/foo/python3-rhel6/lib/python3.6/urllib/request.py", line 1320, in do_open
raise URLError(err)
urllib.error.URLError: <urlopen error [SSL: SSLV3_ALERT_UNSUPPORTED_CERTIFICATE] sslv3 alert unsupported certificate (_ssl.c:833)>
如果需要更多信息,请随时告诉我。任何帮助将不胜感激。
编辑: 这是证书(经过编辑的形式):
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
...
Signature Algorithm: sha256WithRSAEncryption
Issuer: DC=com, DC=foo, CN=Foo Issuing CA - XXX
Validity
Not Before: ... 2018 GMT
Not After : ... GMT
Subject: O=Bar, OU=User, CN=myuser@foo.com
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
...
X509v3 extensions:
X509v3 Key Usage:
Key Encipherment, Data Encipherment
X509v3 Subject Alternative Name:
email:myuser@foo.com
X509v3 Subject Key Identifier:
...
X509v3 Authority Key Identifier:
...
X509v3 CRL Distribution Points:
Full Name:
...
Authority Information Access:
CA Issuers - ...
CA Issuers - ...
X509v3 Extended Key Usage:
TLS Web Server Authentication, TLS Web Client Authentication
用我的证书包验证这个文件说:
openssl verify -CAfile /.../certification_bundle.pem foo.cert
foo.cert: OK
我正在使用 OpenSSL v.1.0.1e-fips。这应该支持 TLSv1.2。
【问题讨论】:
-
CSR 与实际证书的相关性较低,因为 CA 不需要使证书看起来像您请求的那样。您能否在问题中包含您的实际证书(即来自
openssl x509 -text -in foo.cert的输出,可能会编辑一些细节)? -
@SteffenUllrich 稍后我将使用证书详细信息更新帖子(部分已编辑)。待机。
-
@SteffenUllrich 我已经附上了经过编辑的证书。
标签: python ssl flask openssl tls1.2