首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用pyOpenSSL - Python处理SNI

用pyOpenSSL - Python处理SNI
EN

Stack Overflow用户
提问于 2016-03-06 04:31:41
回答 1查看 3.2K关注 0票数 3

我最近在使用pyOpenSSL,但是我遇到了一些使用SNI为同一IP地址提供多个证书的urls。下面是我的代码:

代码语言:javascript
复制
from OpenSSL import SSL
from socket import socket
from sys import argv, stdout
import re
from urlparse import urlparse

def callback(conn, cert, errno, depth, result):
    if depth == 0 and (errno == 9 or errno == 10):
        return False # or raise Exception("Certificate not yet valid or expired")
    return True

def main():
    if len(argv) < 2:
            print 'Usage: %s <hostname>' % (argv[0],)
            return 1

    o = urlparse(argv[1])
    host_name = o.netloc
    context = SSL.Context(SSL.TLSv1_METHOD) # Use TLS Method
    context.set_options(SSL.OP_NO_SSLv2) # Don't accept SSLv2
    context.set_verify(SSL.VERIFY_PEER | SSL.VERIFY_FAIL_IF_NO_PEER_CERT,
                       callback)
    # context.load_verify_locations(ca_file, ca_path)

    sock = socket()
    ssl_sock = SSL.Connection(context, sock)
    ssl_sock.connect((host_name, 443))
    ssl_sock.do_handshake()

    cert = ssl_sock.get_peer_certificate()
    common_name = cert.get_subject().commonName.decode()
    print "Common Name: ", common_name
    print "Cert number: ", cert.get_serial_number()
    regex = common_name.replace('.', r'\.').replace('*',r'.*') + '$'
    if re.match(regex, host_name):
        print "matches"
    else:
        print "invalid"

if __name__ == "__main__":
    main()

例如,假设我有以下url:

代码语言:javascript
复制
https://example.com

当我得到以下输出时:

代码语言:javascript
复制
python sni.py https://example.com/
Common Name:  *.example.com
Cert number:  63694395280496902491340707875731768741
invalid

哪个证书与https://another.example.com的证书相同

代码语言:javascript
复制
python sni.py https://another.example.com/
Common Name:  *.example.com
Cert number:  63694395280496902491340707875731768741
matches

但是,假设https://another.example.com的证书已过期,连接无论如何都会被接受,因为它使用的是有效的*.example.com证书。但是,我希望能够使用https://another.example.com/,如果它无效,则直接拒绝连接。我如何才能做到这一点?

EN

回答 1

Stack Overflow用户

发布于 2016-03-06 04:43:29

您需要使用set_tlsext_host_name。来自the documentation

代码语言:javascript
复制
Connection.set_tlsext_host_name(name)
  Specify the byte string to send as the server name in the client hello message.
  New in version 0.13.

除此之外,您的主机名验证是错误的,因为它只与CN而不是主题替代名称进行比较。此外,它允许在任何地方使用通配符,这违反了通配符应该只允许在最左边的标签中使用的规则:*.example.com很好,而www.*.com甚至*.*.*是不允许的,但您的代码可以接受。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/35819525

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档