简体   繁体   English

如何在python 2.7中为TLS套接字进行证书固定?

[英]How can I do certificate pinning for TLS sockets in python 2.7?

I have a python TLS server using a self signed certificate. 我有一个使用自签名证书的python TLS服务器。 That works. 这样可行。 The code looks like this for now: 现在的代码如下所示:

#!/usr/bin/python

import socket, ssl

context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
context.load_cert_chain(certfile="server.crt", keyfile="server.key")

bindsocket = socket.socket()
bindsocket.bind(('127.0.0.1', 8888))
bindsocket.listen(5)

while True:
    newsocket, fromaddr = bindsocket.accept()
    connstream = context.wrap_socket(newsocket, server_side=True)
    try:
        print("Got connection!")
    finally:
        connstream.shutdown(socket.SHUT_RDWR)
        connstream.close()

I am now trying to make a client in python that connects to this server. 我现在正在尝试在python中建立连接到该服务器的客户端。 On the first connection attempt, I'd like to retrieve either the public key, or a hash of the public key, and then verify this on all future connections. 第一次尝试连接时,我想检索公共密钥或公共密钥的哈希,然后在以后的所有连接中进行验证。 How can I do with with python and the ssl package? 如何使用python和ssl包?

This is the code I'm playing with: 这是我正在使用的代码:

#!/usr/bin/python

import ssl, socket, pprint

context = ssl.SSLContext(ssl.PROTOCOL_TLS)
context.verify_mode = ssl.CERT_REQUIRED
context.check_hostname = False


cnx = context.wrap_socket(socket.socket(socket.AF_INET), certfile="server.crt")
cnx.connect(('127.0.0.1', 8888))
pprint.pprint(cnx.getpeercert())

As it stands right now, it fails because there is no certificate chain to verify the cert. 就目前而言,它失败了,因为没有证书链可以验证证书。 I don't care about that, though. 不过,我不在乎。 All I care about is that the server I'm talking to has the private key that matches the public key. 我只关心与之交谈的服务器具有与公钥匹配的私钥。 What do I do? 我该怎么办?

So I've made this work, though it's not exactly what I hoped for. 所以我做了这项工作,尽管这并不是我所希望的。 My biggest complaint is that it requires storing the entire server certificate in a file on disk, whereas really all I care about is the public key. 我最大的抱怨是,它需要将整个服务器证书存储在磁盘上的文件中,而我真正关心的只是公共密钥。 However, here's what I have working: 但是,这是我的工作:

#!/usr/bin/python

import ssl, socket, pprint, os, sys

# If we haven't retrieved the certificate previously...
if not os.path.isfile('server_cert.pem'):

    # Grab the cert
    cert = ssl.get_server_certificate(('127.0.0.1', 8888))

    # If it worked...
    if cert:

        # Write it to a file
        with open('server_cert.pem', 'w') as f:
            f.write(cert)
    else:
        sys.exit()

# Prepare context, including reference to the server's certificate
context = ssl.SSLContext(ssl.PROTOCOL_TLS)
context.verify_mode = ssl.CERT_REQUIRED
context.check_hostname = False
context.load_verify_locations(cafile='server_cert.pem')
cnx = context.wrap_socket(socket.socket(socket.AF_INET))

# Connect and evaluate
cnx.connect(('127.0.0.1', 8888))

I'll wait a bit to mark this answer accepted to see if someone can find a cleaner way of doing this. 我将稍等一下以将此答案标记为已接受,以查看是否有人可以找到一种更干净的方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM