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

Closed
kaie opened this issue Oct 9, 2018 · 5 comments
Closed

No hostname check #795

kaie opened this issue Oct 9, 2018 · 5 comments

Comments

@kaie
Copy link

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
Copy link
Author

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
Copy link
Author

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
Copy link

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

@tiran
Copy link

tiran commented Dec 14, 2019

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

@reaperhulk
Copy link
Member

We expose the ability to do this properly in pyopenssl now.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Nov 13, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Development

No branches or pull requests

4 participants