[python3-ldap] Trouble with STARTTLS

python3ldap python3ldap at gmail.com
Tue Apr 29 22:24:32 CEST 2014


Hi Mark, thanks for your great job in debugging this issue. I refactored
the start_tls code in version 0.9.1 and must have messed up the code base.
There should be no redundant checking for site names and name checking
cannot obviuosly performed before handshake. I will fix this bug as soon as
I can.

In the meanwhile I apologize for wasting your time while trying to
understand what was wrong.

Bye,
gc

Il martedì 29 aprile 2014, Mark E. Haase <mehaase at gmail.com> ha scritto:

> 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<javascript:_e(%7B%7D,'cvml','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<javascript:_e(%7B%7D,'cvml','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
>>
>>
>

-- 
Have fun,
gc
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python3-ldap/attachments/20140429/2878f42f/attachment-0001.html>


More information about the python3-ldap mailing list