Skip Menu |

This queue is for tickets about the IO-Socket-SSL CPAN distribution.

Report information
The Basics
Id: 77691
Status: rejected
Priority: 0/
Queue: IO-Socket-SSL

People
Owner: Nobody in particular
Requestors: MARSCHAP [...] cpan.org
Cc:
AdminCc:

Bug Information
Severity: (no value)
Broken in: (no value)
Fixed in: (no value)



Subject: Allow access to localhost with SSL_verify_mode => 3
Hi, accessing the localhost with SSL_verify_mode => 3 fails if the host's certificate does not contain localhost as subjectaltName, which is _VERY_MUCH_ frowned upon. A similar issue applies if one ties to access a server securely via IP address, or the local machione via a UNIX socket. Do you have an idea how this could be made work without having to specify the real host name in PeerAddr? I am asking because of Bug #77921 (https://rt.cpan.org/Ticket/Display.html?id=77291) against perl-ldap. Best PEter
Am Do 07. Jun 2012, 17:05:29, marschap schrieb: Show quoted text
> Hi, > > accessing the localhost with SSL_verify_mode => 3 fails if the host's > certificate does not contain localhost as subjectaltName, which is > _VERY_MUCH_ frowned upon. > > A similar issue applies if one ties to access a server securely via IP > address, > or the local machione via a UNIX socket. > > Do you have an idea how this could be made work without having to > specify the real host name in PeerAddr? > > I am asking because of Bug #77921 > (https://rt.cpan.org/Ticket/Display.html?id=77291) against perl-ldap.
Hi Peter, from reading the openssl documentation to SSL_CTX_set_verify it looks for me, that SSL_verify_mode => 3 should be the same as SSL_verify_mode of 1, e.g 3 is SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT, but the SSL_VERIFY_FAIL_IF_NO_PEER_CERT gets ignored inside a client. So in a client only 0 (no verification) and 1 (verify) make sense. But SSL_verify_mode only determines the verification of the certificate and chain, it does not control verification of the names in the certificate, because this is outside of the SSL specification. Verification of hostnames is specified in various RFCs and is different for HTTP, LDAP,... : ( To control the verification you need to set the SSL_verifycn_scheme. From looking at the code of Net::LDAP the verification of the hostname is tightly bound to the verification of the chain, e.g. in _SSL_context_init_args the verification scheme gets set to ldap if any kind of verification is wanted. So either you have to change Net::LDAP to make it possible to verify the chain, but not the certificate contents or you need to explicitly provide the hostname, which is expected inside the certificate. This doesn't need to be in PeerAddr, from the code it looks like that you should be able to use a -sslserver argument in start_tls to provide the name to check against. BTW, the default ssl version is set to 'tlsv1' from what I see. That means, the SSLv3 will not work and also no initial SSLv2 handshake and then upgrade to SSLv1. I would recommend to net set the SSL_version and just use the default from IO::Socket::SSL Hope I could help, Regards, Steffen
Hi Steffen, thanks for your answer. On Friday, 8. June 2012, Steffen Ullrich via RT wrote: Show quoted text
> from reading the openssl documentation to SSL_CTX_set_verify it looks > for me, that SSL_verify_mode => 3 should be the same as
SSL_verify_mode Show quoted text
> of 1, e.g 3 is
SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT, but Show quoted text
> the SSL_VERIFY_FAIL_IF_NO_PEER_CERT gets ignored inside a
client. Show quoted text
> > So in a client only 0 (no verification) and 1 (verify) make sense.
OK, but then problem persists for 1 (verify), doesn't it ;-) Show quoted text
> [...] > Verification of hostnames is specified in various RFCs and is different > for HTTP, LDAP,... : ( > To control the verification you need to set the SSL_verifycn_scheme.
Which Net::LDAP does, and it sets SSL_verifycn_scheme => 'ldap'. Show quoted text
> From looking at the code of Net::LDAP the verification of the hostname > is tightly bound to the verification of the chain, e.g. in > _SSL_context_init_args the verification scheme gets set to ldap if > any kind of verification is wanted.
Which - to me - sounds the right way to do for Net::LDAP that only deals with LDAP[IS] ;-) Show quoted text
> So either you have to change Net::LDAP to make it possible to verify > the chain, but not the certificate contents or you need to explicitly > provide the hostname, which is expected inside the certificate. > This doesn't need to be in PeerAddr, from the code it looks like that > you should be able to use a -sslserver argument in start_tls to provide > the name to check against.
Net::LDAP->start_tls()' sslerver parameter gets mapped to SSL_verifycn_name before calling IO::Socket::SSL->start_TLS, which internally uses PeerAddr and PeerHost as fallback if SSL_verifycn_name is not set. So it does not really matter which one is set exactly ;-) If I understand you correctly, your recommendation is to special case Net::LDAP->start_tls() calls to localhost by determining & setting the real host name. This is something I'd rather avoid, as it is special casing in only one of the libraries using IO::Socket::SSL. I was much more hoping for an additional verification scheme in IO::Socket::SSL, e.g. named 'ldap+localhost', that would do the the name checks, but accept localhost too ;-) Maybe it even can try to find the FQDNs & IPs of the local host and match them against the certificate. Show quoted text
> BTW, the default ssl version is set to 'tlsv1' from what I see. That means, > the SSLv3 will not work and also no initial SSLv2 handshake and then > upgrade to SSLv1. I would recommend to net set the SSL_version and
just Show quoted text
> use the default from IO::Socket::SSL
This setting has been in place since 1.10.2001, and we have never had any complaints/issues with respect to that specific setting. I'd rather not change it (never change a running system ;-). Best Peter
Subject: Re: [rt.cpan.org #77691] Allow access to localhost with SSL_verify_mode => 3
Date: Fri, 8 Jun 2012 16:35:28 +0200
To: Peter Marschall via RT <bug-IO-Socket-SSL [...] rt.cpan.org>
From: Steffen Ullrich <Steffen_Ullrich [...] genua.de>
Show quoted text
> > So in a client only 0 (no verification) and 1 (verify) make sense.
> OK, but then problem persists for 1 (verify), doesn't it ;-)
Sure, this was only a hint that the setting of 'verify' setting in Net::LDAP probably behaves not like documented. I guess 'optional' and 'required' will behave the same and both will fail if the server does not send a certificate or if the certificate or certificate chain is wrong. Show quoted text
> > From looking at the code of Net::LDAP the verification of the hostname > > is tightly bound to the verification of the chain, e.g. in > > _SSL_context_init_args the verification scheme gets set to ldap if > > any kind of verification is wanted.
> Which - to me - sounds the right way to do for Net::LDAP that only deals > with LDAP[IS] ;-)
Yes, IMHO it is the right way. But then Net::LDAP must also know the name of the server, otherwise it cannot verify it. Show quoted text
> ... > Net::LDAP->start_tls()' sslerver parameter gets mapped to > SSL_verifycn_name > before calling IO::Socket::SSL->start_TLS, which internally uses PeerAddr > and > PeerHost as fallback if SSL_verifycn_name is not set. > So it does not really matter which one is set exactly ;-)
No, it does matter. PeerAddr is the name it connects to, which can be the name in the certificate, but don't need to be. If the user wants to connect to the ldap server using 'localhost' or an IP address, but none of these are valid names in the certificate the verification will fail - unless the user explicitly provided a different server name using 'sslserver'. But from the error message I think that problem in RT#77291 is before the name verification. The name verification is done in IO::Socket::SSL, but this is a message from OpenSSL, so there must be something other be wrong with the certificate, before the name verification event starts. Do you have some way to reproduce the problem? Show quoted text
> If I understand you correctly, your recommendation is to special case > Net::LDAP->start_tls() calls to localhost by determining & setting the real > host name.
No, it's not only localhost, although this is probably a common case. It's just the the user connects to a host and the host provides a certificate not matching the name/IP from PeerAddr. And my recommandation is not to add a special case in your code. IMHO there is nothing you should do here except: - document, that the name in the certificate will be verified - document, how one can overwrite the name used for verification (e.g. the sslserver setting) - and maybe cleanup the documentation/behavior of the 'verify' option If the user wants verification it should provide the necessary data, otherwise we cannot claim to have the certificate verified. Show quoted text
> I was much more hoping for an additional verification scheme in > IO::Socket::SSL, e.g. named 'ldap+localhost', that would do the the name > checks, but accept localhost too ;-)
No, like I said - if the user wants verification he should get it. What you propose its something magical "verify hostname unless the name is localhost or an IP address or a known bad server or whatever...", eg intransparently switch off verification in some circumstances even if the user required verification. Show quoted text
> Maybe it even can try to find the FQDNs & IPs of the local host and match > them against the certificate.
I doubt that you will be able to do it. I often do ssh forwarding to some port at localhost - you probably will not be able to figure out which real server is behind this localhost connection. Regards, Steffen -- GeNUA Gesellschaft für Netzwerk - und Unix-Administration mbH Domagkstr. 7, D-85551 Kirchheim. http://www.genua.de Tel: (089) 99 19 50-0, Fax: (089) 99 10 50 - 999 Geschäftsführer: Dr. Magnus Harlander, Dr. Michaela Harlander, Bernhard Schneck. Amtsgericht München HRB 98238
Hi, On Friday, 8. June 2012, Steffen Ullrich via RT wrote: Show quoted text
> Sure, this was only a hint that the setting of 'verify' setting in > Net::LDAP probably behaves not like documented. > I guess 'optional' and 'required' will behave the same and both will fail > if the server does not send a certificate or if the certificate > or certificate chain is wrong.
Did the implementation of IO::Socket::SSL or Net::SSLeay or openssl change recently w.r.t to this behaviour ? I may be mistaken, but I am pretty sure it worked with 'optional', but failed with 'require' in the (not so recent) past. Show quoted text
> [...] > But from the error message I think that problem in RT#77291 is before
the Show quoted text
> name verification. The name verification is done in IO::Socket::SSL, > but this is a message from OpenSSL, so there must be something other > be wrong with the certificate, before the name verification event > starts. > Do you have some way to reproduce the problem?
Sure: perl -MNet::LDAP -MData::Dumper -e \ 'my $ldap = Net::LDAP->new("ldapi://"); my $mesg = $ldap->start_tls(verify => "require"); print Dumper($mesg);' which will print: $VAR1 = bless( { 'parent' => bless( { 'net_ldap_version' => 3, 'net_ldap_scheme' => 'ldapi', 'net_ldap_debug' => 0, 'net_ldap_peer' => '/var/run/ldapi', 'net_ldap_socket' => bless( \*Symbol::GEN0, 'IO::Socket::UNIX' ), 'net_ldap_host' => 'localhost', 'net_ldap_uri' => 'ldapi://', 'net_ldap_resp' => {}, 'net_ldap_mesg' => {}, 'net_ldap_async' => 0, 'net_ldap_refcnt' => 1 }, 'Net::LDAP' ), 'errorMessage' => 'Invalid certificate authority locations error:00000000:lib(0):func(0):reason(0)', 'ctrl_hash' => undef, 'resultCode' => 1, 'callback' => undef, 'mesgid' => 1, 'matchedDN' => '', 'controls' => undef, 'raw' => undef }, 'Net::LDAP::Extension' ); Note the 'errorMessage' hash key. Show quoted text
> No, like I said - if the user wants verification he should get it. > What you propose its something magical "verify hostname unless the
name Show quoted text
> is localhost or an IP address or a known bad server or whatever...", > eg intransparently switch off verification in some circumstances even if > the user required verification.
Too bad: it was worth a try ;-) BTW: I had a look at the OpenLDAP code to which the bug reporter refers: when hostname is 'localhost', then OpenLDAP calculates the FQDN and uses that as the name to check for in the certificate verification. Best Peter
Subject: Re: [rt.cpan.org #77691] Allow access to localhost with SSL_verify_mode => 3
Date: Fri, 8 Jun 2012 19:14:49 +0200
To: Peter Marschall via RT <bug-IO-Socket-SSL [...] rt.cpan.org>
From: Steffen Ullrich <Steffen_Ullrich [...] genua.de>
On Fri, Jun 08, 2012 at 12:13:41PM -0400, Peter Marschall via RT <bug-IO-Socket-SSL@rt.cpan.org> wrote: Show quoted text
> Queue: IO-Socket-SSL > Ticket <URL: https://rt.cpan.org/Ticket/Display.html?id=77691 > > > Hi, > > On Friday, 8. June 2012, Steffen Ullrich via RT wrote:
> > Sure, this was only a hint that the setting of 'verify' setting in > > Net::LDAP probably behaves not like documented. > > I guess 'optional' and 'required' will behave the same and both will fail > > if the server does not send a certificate or if the certificate > > or certificate chain is wrong.
> Did the implementation of IO::Socket::SSL or Net::SSLeay or openssl > change recently w.r.t to this behaviour ? > I may be mistaken, but I am pretty sure it worked with 'optional', but failed > with 'require' in the (not so recent) past.
not that I'm aware of. IO::Socket::SSL gives the SSL_verify_mode parameter unchanged to Net::SSLeay, which IMHO gives it unchanged to OpenSSL. Show quoted text
> }, 'Net::LDAP' ), > 'errorMessage' => 'Invalid certificate authority locations > error:00000000:lib(0):func(0):reason(0)', > .. > Note the 'errorMessage' hash key.
the error message means, that you have given a SSL_ca_file or SSL_ca_path, which could not be used. Probably file does not exist or path does not contain any certificates. I see that you set SSL_ca_path and SSL_ca_file to '' if no capath or cafile is given - because these values are defined this will mean that it will try to use them, so you should leave them undef if you don't have a useful value for them. The relevant code for this behavior in IO::Socket::SSL is unchanged for at least 18 month (according to git blame) BTW - this error message is different from the one of RT#77291 Show quoted text
> > No, like I said - if the user wants verification he should get it. > > What you propose its something magical "verify hostname unless the
> name
> > is localhost or an IP address or a known bad server or whatever...", > > eg intransparently switch off verification in some circumstances even if > > the user required verification.
> > Too bad: it was worth a try ;-) > > BTW: > I had a look at the OpenLDAP code to which the bug reporter refers: > when hostname is 'localhost', then OpenLDAP calculates the FQDN and > uses that as the name to check for in the certificate verification.
I don't like this behavior. And like I said - there are enough cases were it will not work. But again - the error message in RT#77291 is in my opinion not related to this problem, it occurs before any host name verification. Regards, Steffen -- GeNUA Gesellschaft für Netzwerk - und Unix-Administration mbH Domagkstr. 7, D-85551 Kirchheim. http://www.genua.de Tel: (089) 99 19 50-0, Fax: (089) 99 10 50 - 999 Geschäftsführer: Dr. Magnus Harlander, Dr. Michaela Harlander, Bernhard Schneck. Amtsgericht München HRB 98238
Hi, On Friday, 8. June 2012, you wrote: Show quoted text
> BTW - this error message is different from the one of RT#77291
Sorry, my bad. A a slight addition produces the "wanted" error message: perl -MNet::LDAP -MData::Dumper -e \ 'my $ldap = Net::LDAP->new("ldapi://"); my $mesg = $ldap->start_tls(verify => "require", cafile => "/etc/ssl/certs/ADPM-cacert.pem"); print Dumper($mesg);' The file pointed to by the 'cafile' option exists, is readable, contains the CA's certificate in PEM format, and works with connections to the machine's host name. To reproduce the error, simply replace it with your CA's cert ;-) Show quoted text
> But again - the error message in RT#77291 is in my opinion not related > to this problem, it occurs before any host name verification.
See test case above. Best PEter PS: Thanks for the interesting & enlightening discussion.
Subject: Re: [rt.cpan.org #77691] Allow access to localhost with SSL_verify_mode => 3
Date: Sat, 9 Jun 2012 15:36:00 +0200
To: bug-IO-Socket-SSL [...] rt.cpan.org
From: Peter Marschall <peter [...] adpm.de>
Hi, On Friday, 8. June 2012, you wrote: Show quoted text
> BTW - this error message is different from the one of RT#77291
Sorry, my bad. A a slight addition produces the "wanted" error message: perl -MNet::LDAP -MData::Dumper -e 'my $ldap = Net::LDAP->new("ldapi://"); my $mesg = $ldap->start_tls(verify => "require", cafile => "/etc/ssl/certs/ADPM-cacert.pem"); print Dumper($mesg);' The file pointed to by the 'cafile' option exists, is readable, contains the CA's certificate in PEM format, and works with connections to the machine's host name. To reproduce the error, simply replace it with your CA's cert. Show quoted text
> But again - the error message in RT#77291 is in my opinion not related > to this problem, it occurs before any host name verification.
See test case above. Best PEter PS: Thanks for the interesting & enlightening discussion.
Subject: Re: [rt.cpan.org #77691] Allow access to localhost with SSL_verify_mode => 3
Date: Sat, 9 Jun 2012 23:04:38 +0200
To: "peter [...] adpm.de via RT" <bug-IO-Socket-SSL [...] rt.cpan.org>
From: Steffen Ullrich <Steffen_Ullrich [...] genua.de>
Show quoted text
> perl -MNet::LDAP -MData::Dumper -e 'my $ldap = Net::LDAP->new("ldapi://"); > my $mesg = $ldap->start_tls(verify => "require", > cafile => "/etc/ssl/certs/ADPM-cacert.pem"); > print Dumper($mesg);'
Hi Peter, after trying to setup openldap on ubuntu and trying to make it speak TLS I finally get the error message, and yes - there will be no error if you give the correct sslserver argument: $ldap->start_tls( verify => 'require', cafile => ..., sslserver => hostname_from_certificate ); BTW, the exact same ldapsearch command from RT#77291 behaves differently then in the bug report for me, e.g. fails also because of a bad certificate: | $ldapsearch -LLL -x -H ldapi:/// -ZZ -s base -b "" | ldap_start_tls: Connect error (-11) | additional info: TLS: hostname does not match CN in peer certificate I think the original bug report simply had a setting of TLS_REQCERT 'never' or 'allow' in the ldap.conf - in this case it will ignore the certificate or certificate errors. But with 'try' or the default setting 'hard' it will fail. So there is no special way for localhost done in the ldap tools, it's just they ignore any errors with the setting the bug report had. I think with this argumentation you should be able to close the bug, which in my eyes is a false report. The bug reporter probably did not know, that it had a weak certificate check in the config or that the config setting overwrites the explicit -ZZ option from the command line. I find this behavior from openldap unexpected too. Regards, Steffen -- GeNUA Gesellschaft für Netzwerk - und Unix-Administration mbH Domagkstr. 7, D-85551 Kirchheim. http://www.genua.de Tel: (089) 99 19 50-0, Fax: (089) 99 10 50 - 999 Geschäftsführer: Dr. Magnus Harlander, Dr. Michaela Harlander, Bernhard Schneck. Amtsgericht München HRB 98238