[python3-ldap] Trouble with STARTTLS

Mark E. Haase mehaase at gmail.com
Tue Apr 29 20:47:27 CEST 2014


Thanks for the reply, gc. I tried with Python 3 with different but still
unsuccessful results:

Here is one machine I tried on:

$ python3 --version
Python 3.2.3
$ python3 test.py
Traceback (most recent call last):
  File "test.py", line 15, in <module>
    ldap_handle.start_tls()
  File "/usr/local/lib/python3.2/dist-packages/ldap3/core/connection.py",
line 535, in start_tls
    if self.server.tls.start_tls(self):
  File "/usr/local/lib/python3.2/dist-packages/ldap3/core/tls.py", line
118, in start_tls
    return self._start_tls(connection)
  File "/usr/local/lib/python3.2/dist-packages/ldap3/core/tls.py", line
121, in _start_tls
    connection.socket = self.wrap_socket(connection, False)
  File "/usr/local/lib/python3.2/dist-packages/ldap3/core/tls.py", line 91,
in wrap_socket
    check_hostname(wrapped_socket, connection.server.host, self.valid_names)
  File "/usr/local/lib/python3.2/dist-packages/ldap3/core/tls.py", line
203, in check_hostname
    ssl.match_hostname(server_certificate, host_name)  # raise
CertificateError if certificate doesn't match server name
  File "/usr/lib/python3.2/ssl.py", line 141, in match_hostname
    raise ValueError("empty or no certificate")
ValueError: empty or no certificate

Here's another:

$ python3 --version
Python 3.4.0
$ python3 test.py
Traceback (most recent call last):
  File "test.py", line 15, in <module>
    ldap_handle.start_tls()
  File "/usr/local/lib/python3.4/dist-packages/ldap3/core/connection.py",
line 535, in start_tls
    if self.server.tls.start_tls(self):
  File "/usr/local/lib/python3.4/dist-packages/ldap3/core/tls.py", line
118, in start_tls
    return self._start_tls(connection)
  File "/usr/local/lib/python3.4/dist-packages/ldap3/core/tls.py", line
121, in _start_tls
    connection.socket = self.wrap_socket(connection, False)
  File "/usr/local/lib/python3.4/dist-packages/ldap3/core/tls.py", line 91,
in wrap_socket
    check_hostname(wrapped_socket, connection.server.host, self.valid_names)
  File "/usr/local/lib/python3.4/dist-packages/ldap3/core/tls.py", line
196, in check_hostname
    server_certificate = sock.getpeercert()
  File "/usr/lib/python3.4/ssl.py", line 648, in getpeercert
    return self._sslobj.peer_certificate(binary_form)
ValueError: handshake not done yet

This is apparently a new error in Python 3.4, according to the python docs.

I took a closer look at core/tls.py, and I see in wrap_socket(), lines
90-91 perform a hostname check, but these lines are redundant with lines
128-129 in _start_tls(). Furthermore, these lines execute *before* the
handshake at line 123. I tried making the following change and my test
script doesn't throw any exceptions. I haven't tested it any deeper yet
because I wanted to get your feedback.

core/tls.py:
84     def wrap_socket(self, connection, do_handshake=False):
85         """
86         Adds TLS to a plain socket and returns the SSL socket
87         """
88         wrapped_socket = ssl.wrap_socket(connection.socket,
keyfile=self.private_key_file, certfile=self.certificate_file, server
 _side=False, cert_reqs=self.validate, ssl_version=self.version,
ca_certs=self.ca_certs_file, do_handshake_on_connect=do_handshake    )
89
90         if do_handshake and self.validate == ssl.CERT_REQUIRED or
self.validate == ssl.CERT_OPTIONAL:
91             check_hostname(wrapped_socket, connection.server.host,
self.valid_names)
92
93         return wrapped_socket

At line 90 I added the "do_handshake and" condition. I believe this would
fix the starttls operation without breaking any existing callers to
wrap_socket.

What do you think?



On Tue, Apr 29, 2014 at 2:23 AM, python3ldap <python3ldap at gmail.com> wrote:

>
> Hello Mark, could you try the same operation with python 3? Python 2 is
> (with no apparent reason) missing a fundamental check in ssl handshake
> (match hostname in certificate with a valid list of names), so I backported
> it from 3 to 2 (the match_hostname_backport function). If your code works
> with python 3 maybe there is a problem in the backport function. Or you can
> try to disable the whole match_hostname passing a valid_names='*' parameter
> in the Tls() creation.
>
> Bye,
> gc
>
>
> Il martedì 29 aprile 2014, Mark E. Haase <mehaase at gmail.com> ha scritto:
>
> I really like python3-ldap. Much cleaner than building on top of OpenLDAP
>> :)
>>
>> I can get TLS working on port 636, but I can't figure out how to get
>> Start TLS on port 389. Here's what I have so far (Python 2.7):
>>
>> 01 import ldap3
>> 02 import os
>> 03 import ssl
>> 04
>> 05 host = "ldap.*************.net"
>> 06 port = 389
>> 07 username = "cn=admin,dc=*************,dc=net"
>> 08 password = "*************"
>> 09 base_path = os.path.dirname(os.path.realpath(__file__))
>> 10
>> 11 tls = ldap3.Tls(validate=ssl.CERT_REQUIRED,
>> ca_certs_file=os.path.join(base_path, "goodca"))
>> 12 ldap_server = ldap3.Server(host, port=port, use_ssl=False, tls=tls)
>> 13 ldap_handle = ldap3.Connection(ldap_server, user=username,
>> password=password)
>> 14 ldap_handle.open()
>> 15 ldap_handle.start_tls()
>> 16 ldap_handle.bind()
>>
>> I'm ~100% sure that "goodca" is not the problem, because I've validated
>> it with openssl s_client, gnutls-cli, ldapsearch, and python-ldap. It's PEM
>> encoded. When I run this example, I get this exception:
>>
>> mhaase at luci:~/luci/bin$ python test.py
>> Traceback (most recent call last):
>>   File "test.py", line 15, in <module>
>>     ldap_handle.start_tls()
>>   File "/usr/local/lib/python2.7/dist-packages/ldap3/core/connection.py",
>> line 535, in start_tls
>>     if self.server.tls.start_tls(self):
>>   File "/usr/local/lib/python2.7/dist-packages/ldap3/core/tls.py", line
>> 118, in start_tls
>>     return self._start_tls(connection)
>>   File "/usr/local/lib/python2.7/dist-packages/ldap3/core/tls.py", line
>> 121, in _start_tls
>>     connection.socket = self.wrap_socket(connection, False)
>>   File "/usr/local/lib/python2.7/dist-packages/ldap3/core/tls.py", line
>> 91, in wrap_socket
>>     check_hostname(wrapped_socket, connection.server.host,
>> self.valid_names)
>>   File "/usr/local/lib/python2.7/dist-packages/ldap3/core/tls.py", line
>> 206, in check_hostname
>>     match_hostname_backport(server_certificate, host_name)
>>   File "/usr/local/lib/python2.7/dist-packages/ldap3/core/tls.py", line
>> 168, in match_hostname_backport
>>     raise ValueError("empty or no certificate")
>> ValueError: empty or no certificate
>>
>> Any ideas what I'm doing wrong? Any help would be greatly appreciated...
>> I've been struggling with openldap/python-ldap/python3-for 12 hours today!!
>>
>
>
> --
> Have fun,
> gc
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python3-ldap/attachments/20140429/3c1642fb/attachment.html>


More information about the python3-ldap mailing list