在简单的ECHO客户端/服务器[Python/套接字/ssl模块],ssl.SSLEOF中进行相互ssl身份验证错误:发生EOF违反协议 [英] Mutual ssl authentication in simple ECHO client/server [Python / sockets / ssl modules], ssl.SSLEOFError: EOF occurred in violation of protocol

查看:146
本文介绍了在简单的ECHO客户端/服务器[Python/套接字/ssl模块],ssl.SSLEOF中进行相互ssl身份验证错误:发生EOF违反协议的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在回显客户端/服务器程序中进行相互身份验证.我在

I would like to have a mutual authentication in my echo client/server program. I'm using python 2.7.12 and thessl` module on

Distributor ID: Ubuntu
Description:    Ubuntu 14.04.5 LTS
Release:        14.04
Codename:       trusty

我已经使用openssl命令生成了客户端和服务器的证书和密钥:

I've generated client's and server's certificates and keys using the openssl commands:

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

我希望客户端对服务器进行身份验证,并且我希望服务器对客户端进行身份验证.但是,下面的代码在服务器端显示了一些错误:

I want the client to authenticate the server, and I want the server to authenticate the client. However, the code below shows some errors, at server's side:

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()

客户代码:

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.connect((HOST, PORT))

    context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2)
    context.verify_mode = ssl.CERT_REQUIRED
    context.load_verify_locations('server.pem')

    if ssl.HAS_SNI:
        secure_sock = context.wrap_socket(sock, server_hostname=HOST, server_side=False, certfile="client.pem", keyfile="client.key")
    else:
        secure_sock = context.wrap_socket(sock, server_side=False, certfile="client.pem", keyfile="client.key")

    cert = secure_sock.getpeercert()
    print cert

    # verify server
    if not cert or ('commonName', 'test') not in cert['subject'][4]: raise Exception("ERROR")

    secure_sock.write('hello')
    secure_sock.read(1024)

    secure_sock.close()
    sock.close()

谢谢.

推荐答案

基本上,服务器需要与客户端共享其证书,反之亦然(请查看ca_certs参数).您的代码的主要问题是握手从未执行过.另外,Common Name字符串的位置取决于证书中指定了多少个字段.我很懒,所以我的subject只有4个场,而Common Name是它们中的最后一个.

Basically the server need to share with the client his certificate and vice versa (look the ca_certs parameter). The main problem with your code is that the handshake were never executed. Also, the Common Name string position depends on how many field did specified in the certificate. I had been lazy, so my subject has only 4 fiels, and Common Name is the last of them.

现在可以使用了(随时询问更多详细信息).

Now it works (feel free to ask for further details).

#!/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:我让客户端打印服务器响应.

Ps: I made the client print the server response.

在客户端,您从未使用过我创建的上下文变量.这是否意味着在这里没有必要?

On client's side you never used the context variable I've created. Does it mean it's unnecessary here?

文档说:

对于更复杂的应用程序,ssl.SSLContext类有助于管理设置和证书,然后可以通过通过SSLContext.wrap_socket()方法创建的SSL套接字继承这些设置和证书.

For more sophisticated applications, the ssl.SSLContext class helps manage settings and certificates, which can then be inherited by SSL sockets created through the SSLContext.wrap_socket() method.

我已更新代码以向您显示差异:服务器使用ssl.wrap_socket(),客户端使用ssl.SSLContext.wrap_socket().

I've updated the code to show you the differences: the server uses ssl.wrap_socket(), the client ssl.SSLContext.wrap_socket().

第二,当在if和else中创建的套接字看起来相同时,检查ssl.HAS_SNI是否有意义?用您的方法,我不能在套接字包装方法中使用server_hostname = HOST.

Second, what's the point in checking if ssl.HAS_SNI when the socket creation looks the same in if and else? With your approach I cant use server_hostname=HOST in socket wrapping method.

是的,在我使用server_hostname=HOST的更新代码中.

You are right, in the updated code I used server_hostname=HOST.

另一件事:在我创建的上下文中,您正在使用ca_certs而不是使用load_verify_locations.为什么?这两种方法是否相同?

Another thing: you're using ca_certs instead of using load_verify_locations in context I created. Why? Are those 2 methods identical?

我的错,我使用ca_cert作为ssl.wrap_socket()的参数,所以我根本没有使用context.现在我用它.

My fault, I was using ca_cert as parameter of ssl.wrap_socket(), so I didn't used the context at all. Now I use it.

还有另一件事:您真的需要自己打电话给secure_sock.do_handshake()吗?

不是,我忘了删除它:)

Nope, I forgot to remove it :)

输出完全相同.

这篇关于在简单的ECHO客户端/服务器[Python/套接字/ssl模块],ssl.SSLEOF中进行相互ssl身份验证错误:发生EOF违反协议的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆