Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

No hostname check #795

Open
kaie opened this issue Oct 9, 2018 · 4 comments
Open

No hostname check #795

kaie opened this issue Oct 9, 2018 · 4 comments

Comments

@kaie
Copy link

@kaie kaie commented Oct 9, 2018

When using pyopenssl to connect to a server, the pyopenssl client side code doesn't verify that the server's certificate is valid for the target hostname.
Usually, the application code requests which hostname the server certificate should match.
This can be done with openssl as explained on https://wiki.openssl.org/index.php/Hostname_validation
I couldn't find support in pyopenssl for requesting this check.
I'll suggest patches to add this functionality.

@kaie

This comment has been minimized.

Copy link
Author

@kaie kaie commented Oct 9, 2018

# Test code from Kai Engert based on the code below:
# Copyright (C) AB Strakt
# Copyright (C) Jean-Paul Calderone
# See LICENSE for details.

import os

from sys import stdout
from socket import socket

from OpenSSL.SSL import TLSv1_METHOD, Context, Connection
from OpenSSL import SSL, crypto

def verify_cb(conn, cert, errnum, depth, ok):
    if not ok:
        certsubject = crypto.X509Name(cert.get_subject())
        print 'certificate', certsubject, 'chain depth', depth, 'verification failed, errnum:', errnum
    return ok


def main():
    client = socket()

    hostname = "mismatch.kuix.de"

    print 'Connecting...',
    stdout.flush()
    client.connect((hostname, 443))
    print 'connected', client.getpeername()

    ctx = SSL.Context(SSL.SSLv23_METHOD)
    ctx.set_options(SSL.OP_NO_SSLv2)
    ctx.set_options(SSL.OP_NO_SSLv3)
    ctx.set_verify(SSL.VERIFY_PEER, verify_cb)  # Demand a certificate

	
    ca_bundle = '/etc/ssl/certs/ca-bundle.crt' # Fedora
    ca_dir = '/etc/ssl/certs'                  # Debian
    if not os.path.isfile(ca_bundle):
        ca_bundle = None
    else:
        ca_dir = None
    
    ctx.load_verify_locations(ca_bundle, ca_dir)

    client_ssl = Connection(ctx, client)
    client_ssl.set_connect_state()
    client_ssl.set_tlsext_host_name(hostname)
    #client_ssl.set_verify_host(hostname)
    try:
        client_ssl.do_handshake()
        print "connection succeeded"
        print 'Server subject is', client_ssl.get_peer_certificate().get_subject()
    except Exception as e:
        print str(e)
        print "connection failed"
    client_ssl.close()


if __name__ == '__main__':
    import client
    raise SystemExit(client.main())

@kaie

This comment has been minimized.

Copy link
Author

@kaie kaie commented Oct 9, 2018

The above is example code, based on the pyopenssl client.py example code, which performs a connection to server https://mismatch.kuix.de
The certificate used by that server isn't valid for that hostname, and should get rejected.
However, the above example code connects to the host without reporting a failure.
Note the commented out line "client_ssl.set_verify_host(hostname)". I'll supply patches to add this new API. With the patches and that line enabled, pyopenssl will correctly report a failure.

@bortzmeyer

This comment has been minimized.

Copy link

@bortzmeyer bortzmeyer commented Dec 14, 2019

OpenSSL, since 1.1.0, has a X509_check_host . It could be sufficient to just export it and then rely on it.

@tiran

This comment has been minimized.

Copy link

@tiran tiran commented Dec 14, 2019

Even better, the feature is already available since OpenSSL 1.0.2.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
3 participants
You can’t perform that action at this time.