I noticed that Net::LDAP doesn't seem to correctly verify the SSL certificate presented by a remote LDAP server, even if verify => 'require' is given when creating a connection, as in:
my $ldap = new Net::LDAP( "ldaps://some.ldap.server", version => 3, verify => "require", capath => "/etc/ssl/certs", );
Specifically, Net::LDAP doesn't seem to attempt to verify the server's identity -- as long as the server presents a certificate signed by a CA that the client trusts, the client allows the connection to proceed. This violates section 3.1.3 of RFC 4513, which describes how LDAP clients should validate SSL certificates, and, IIUC, effectively allows anyone with an SSL certificate for any site signed by a widely-trusted CA to successfully impersonate, from the perspective of Net::LDAP clients, any LDAP server, even if those clients are configured to strictly validate server certificates.
This behavior seems to be a result of IO::Socket::SSL's default behavior regarding identity verification, which is to not validate identities:
SSL_verifycn_scheme
Set the scheme used to automatically verify the hostname of the peer. See the information about the verification schemes in verify_hostname. The default is undef, e.g. to not automatically verify the hostname.
We can easily address this by changing the options we pass to IO::Socket::SSL's new and start_SSL functions. I'm attaching a patch that does this, setting SSL_verifycn_name to 'ldap'. This behaves correctly in my tests: LDAPS connections to a server only succeed if the server presents a certificate (signed by a CA trusted by the client) that correctly identifies the name that the client connected to.
Any thoughts? Does this seem appropriate for inclusion in a future release of the perl-ldap software?
Thanks, -- Kevan Carstensen <kacarsten...@csupomona.edu> Operating Systems Analyst, I&IT Systems, Cal Poly Pomona
> We can easily address this by changing the options we pass to > IO::Socket::SSL's new and start_SSL functions. I'm attaching a patch > that does this, setting SSL_verifycn_name to 'ldap'. This behaves > correctly in my tests: LDAPS connections to a server only succeed if the > server presents a certificate (signed by a CA trusted by the client) > that correctly identifies the name that the client connected to.
> Any thoughts? Does this seem appropriate for inclusion in a future > release of the perl-ldap software?
The patch looks good to me, I think it should go in. Does it force a new minimum version of IO::Socket::SSL?
Excerpts from Chris Ridd's message of 2011-08-03 11:27:03 -0700:
> The patch looks good to me, I think it should go in. Does it force a > new minimum version of IO::Socket::SSL?
It looks like perl-ldap currently depends on IO::Socket::SSL version 0.93 or greater. The feature my patch uses appears to have been introduced in version 1.14 of IO::Socket::SSL:
v1.14 - added support for verification of hostname from certificate including subjectAltNames, support for IDN etc based on patch and input from christopher[AT]odenbachs[DOT]de and achim[AT]grolmsnet[DOT]de. It is also possible to get more information from peer_certificate based on this patch. See documentation for peer_certificate and verify_hostname - automatic verification of hostnames with SSL_verifycn_scheme and SSL_verifycn_name
though there's a security bugfix in v1.2.6 that would be nice to have if we want to advertise more complete certificate validation.
v1.26 2009.07.03 - SECURITY BUGFIX! fix Bug in verify_hostname_of_cert where it matched only the prefix for the hostname when no wildcard was given, e.g. www.example.org matched against a certificate with name www.exam in it Thanks to MLEHMANN for reporting
Specifying v1.26 as the new minimum version of IO::Socket::SSL is one way to handle that issue. In a quick test I did just now, it seems that IO::Socket::SSL is content to ignore options that it doesn't understand in the options hash that my patch modifies, so the patch wouldn't necessarily cause perl-ldap to break against older versions of IO::Socket::SSL; it'd just fail to validate the certificate, as it does now. I'd prefer to require a more recent version of IO::Socket::SSL, since that seems like a more complete fix, but I guess that's up to the maintainers and not me. :-)
I suppose that this change will also break installations running with broken certificates and verify => 'optional' or verify => 'require'. I don't think that's a reason to avoid the change, but it should probably be featured prominently in the changelog so it doesn't surprise anyone.
Thanks, -- Kevan Carstensen <kacarsten...@csupomona.edu> Operating Systems Analyst, I&IT Systems, Cal Poly Pomona