我想在echo客户端/服务器程序中进行相互身份验证。我在
上使用IContainer container = IContainer.make();
ssl`模块
python 2.7.12 and the
我使用Distributor ID: Ubuntu
Description: Ubuntu 14.04.5 LTS
Release: 14.04
Codename: trusty
命令生成了客户端和服务器的证书和密钥:
openssl
我希望客户端对服务器进行身份验证,我希望服务器对客户端进行身份验证。但是,下面的代码显示了服务器端的一些错误:
openssl req -new -x509 -days 365 -nodes -out client.pem -keyout client.key
openssl req -new -x509 -days 365 -nodes -out server.pem -keyout server.key
在客户方:
Traceback (most recent call last):
File "ssl_server.py", line 18, in <module>
secure_sock = ssl.wrap_socket(client, server_side=True, certfile="server.pem", keyfile="server.key")
File "/usr/lib/python2.7/ssl.py", line 933, in wrap_socket
ciphers=ciphers)
File "/usr/lib/python2.7/ssl.py", line 601, in __init__
self.do_handshake()
File "/usr/lib/python2.7/ssl.py", line 830, in do_handshake
self._sslobj.do_handshake()
ssl.SSLEOFError: EOF occurred in violation of protocol (_ssl.c:590)
服务器代码:
Traceback (most recent call last):
File "ssl_client.py", line 18, in <module>
secure_sock = context.wrap_socket(sock, server_hostname=HOST, server_side=False, certfile="client.pem", keyfile="client.key")
TypeError: wrap_socket() got an unexpected keyword argument 'certfile'
客户代码:
#!/bin/usr/env python
import socket
import ssl
import pprint
#server
if __name__ == '__main__':
HOST = '127.0.0.1'
PORT = 1234
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server_socket.bind((HOST, PORT))
server_socket.listen(10)
client, fromaddr = server_socket.accept()
secure_sock = ssl.wrap_socket(client, server_side=True, certfile="server.pem", keyfile="server.key")
print repr(secure_sock.getpeername())
print secure_sock.cipher()
print pprint.pformat(secure_sock.getpeercert())
cert = secure_sock.getpeercert()
print cert
# verify client
if not cert or ('commonName', 'test') not in cert['subject'][4]: raise Exception("ERROR")
try:
data = secure_sock.read(1024)
secure_sock.write(data)
finally:
secure_sock.close()
server_socket.close()
谢谢。
答案 0 :(得分:8)
基本上服务器需要与客户端共享他的证书,反之亦然(查看ca_certs
参数)。您的代码的主要问题是握手从未执行过。此外,Common Name
字符串位置取决于证书中指定的字段数。我一直很懒,所以我的subject
只有4个fiels,Common Name
是最后一个。
现在它有效(请随时询问更多细节)。
#!/bin/usr/env python
import socket
import ssl
import pprint
#server
if __name__ == '__main__':
HOST = '127.0.0.1'
PORT = 1234
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server_socket.bind((HOST, PORT))
server_socket.listen(10)
client, fromaddr = server_socket.accept()
secure_sock = ssl.wrap_socket(client, server_side=True, ca_certs = "client.pem", certfile="server.pem", keyfile="server.key", cert_reqs=ssl.CERT_REQUIRED,
ssl_version=ssl.PROTOCOL_TLSv1_2)
print repr(secure_sock.getpeername())
print secure_sock.cipher()
print pprint.pformat(secure_sock.getpeercert())
cert = secure_sock.getpeercert()
print cert
# verify client
if not cert or ('commonName', 'test') not in cert['subject'][3]: raise Exception("ERROR")
try:
data = secure_sock.read(1024)
secure_sock.write(data)
finally:
secure_sock.close()
server_socket.close()
import socket
import ssl
# client
if __name__ == '__main__':
HOST = '127.0.0.1'
PORT = 1234
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setblocking(1);
sock.connect((HOST, PORT))
context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2)
context.verify_mode = ssl.CERT_REQUIRED
context.load_verify_locations('server.pem')
context.load_cert_chain(certfile="client.pem", keyfile="client.key")
if ssl.HAS_SNI:
secure_sock = context.wrap_socket(sock, server_side=False, server_hostname=HOST)
else:
secure_sock = context.wrap_socket(sock, server_side=False)
cert = secure_sock.getpeercert()
print cert
# verify server
if not cert or ('commonName', 'test') not in cert['subject'][3]: raise Exception("ERROR")
secure_sock.write('hello')
print secure_sock.read(1024)
secure_sock.close()
sock.close()
看看:
Ps:我让客户打印服务器响应。
在客户方面,您从未使用我创建的上下文变量。这是否意味着它不必要?
文档说:
对于更复杂的应用程序,
ssl.SSLContext
类有助于管理设置和证书,然后可以通过SSLContext.wrap_socket()
方法创建的SSL套接字继承这些设置和证书。
我已更新代码以向您显示差异:服务器使用ssl.wrap_socket()
,客户端ssl.SSLContext.wrap_socket()
。
第二,在if和else中,套接字创建看起来是否相同时检查ssl.HAS_SNI的重点是什么?使用您的方法,我无法在套接字换行方法中使用server_hostname = HOST。
你是对的,在我使用server_hostname=HOST
的更新代码中。
另一件事:你在我创建的上下文中使用ca_certs而不是使用load_verify_locations。为什么?这两种方法是否相同?
我的错,我使用ca_cert
作为ssl.wrap_socket()
的参数,所以我根本没有使用context
。现在我用它。
还有一件事:你真的需要自己打电话给
secure_sock.do_handshake()
吗?
不,我忘了删除它:)
输出完全相同。
答案 1 :(得分:0)
ilario-pierbattista回答,但在python 3中:
def start_client_side(config):
HOST = config['host']
PORT = config['port']
pemServer = config['serverpem']
keyClient = config['clientkey']
pemClient = config['clientpem']
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setblocking(1);
sock.connect((HOST, PORT))
context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2)
context.verify_mode = ssl.CERT_REQUIRED
context.load_verify_locations(pemServer)
context.load_cert_chain(certfile=pemClient, keyfile=keyClient)
if ssl.HAS_SNI:
secure_sock = context.wrap_socket(sock, server_side=False, server_hostname=HOST)
else:
secure_sock = context.wrap_socket(sock, server_side=False)
cert = secure_sock.getpeercert()
print(pprint.pformat(cert))
# verify server
if not cert or ('commonName', 'server.utester.local') not in itertools.chain(*cert['subject']): raise Exception("ERROR")
secure_sock.write(b'hello')
print(secure_sock.read(1024))
secure_sock.close()
sock.close()
def start_server_side(config):
HOST = config['host']
PORT = config['port']
pemServer = config['serverpem']
keyServer = config['serverkey']
pemClient = config['clientpem']
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server_socket.bind((HOST, PORT))
server_socket.listen(10)
client, fromaddr = server_socket.accept()
secure_sock = ssl.wrap_socket(client, server_side=True, ca_certs=pemClient, certfile=pemServer,
keyfile=keyServer, cert_reqs=ssl.CERT_REQUIRED,
ssl_version=ssl.PROTOCOL_TLSv1_2)
print(repr(secure_sock.getpeername()))
print(secure_sock.cipher())
cert = secure_sock.getpeercert()
print(pprint.pformat(cert))
# verify client
if not cert or ('commonName', 'client.utester.local') not in itertools.chain(*cert['subject']): raise Exception("ERROR")
try:
data = secure_sock.read(1024)
secure_sock.write(data)
finally:
secure_sock.close()
server_socket.close()