Skip Menu |

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

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

People
Owner: Nobody in particular
Requestors: klara.mall [...] kit.edu
Cc:
AdminCc:

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



Subject: SSL fails after plain text + STARTTLS
Date: Sun, 17 Nov 2013 17:35:22 +0100
To: <bug-IO-Socket-SSL [...] rt.cpan.org>
From: Klara Mall <klara.mall [...] kit.edu>
Hi, I use the Perl software radiator (RADIUS server) where I authenticate users with LDAP. With some LDAP servers I use an SSL connection and with some plain text and STARTTLS. With this configuration radiator told me from time to time that it could not open the LDAP connection. I analyzed this and noticed that the first SSL connection after using plaintext + STARTTLS fails. Rather the verification of the certificate fails providing that you use two different servers in the plain text / STARTTLS and the SSL connection. I could reproduce this with a litte Perl program: ----------------------------------------------------------------- #!/usr/bin/perl -w use IO::Socket::SSL qw(debug3); my $tls_host = "kit-dc-04.kit.edu"; my $ssl_host = "kit-ad.scc.kit.edu"; require Net::LDAP; my $ldap_tls = Net::LDAP->new( $tls_host, port => 389, timeout => 3); $ldap_tls-> start_tls( verify => 'require', cafile => 'ca.pem'); require Net::LDAPS; my $ldap_ssl = Net::LDAPS->new( $ssl_host, port => 636, timeout => 3, verify => 'require', cafile => 'ca.pem'); ----------------------------------------------------------------- Result: ----------------------------------------------------------------- DEBUG: .../IO/Socket/SSL.pm:1653: new ctx 22392624 DEBUG: .../IO/Socket/SSL.pm:1061: start handshake DEBUG: .../IO/Socket/SSL.pm:383: ssl handshake not started DEBUG: .../IO/Socket/SSL.pm:433: set socket to non-blocking to enforce timeout=3 DEBUG: .../IO/Socket/SSL.pm:446: Net::SSLeay::connect -> -1 DEBUG: .../IO/Socket/SSL.pm:456: ssl handshake in progress DEBUG: .../IO/Socket/SSL.pm:466: waiting for fd to become ready: SSL wants a read first DEBUG: .../IO/Socket/SSL.pm:486: socket ready, retrying connect DEBUG: .../IO/Socket/SSL.pm:446: Net::SSLeay::connect -> -1 DEBUG: .../IO/Socket/SSL.pm:456: ssl handshake in progress DEBUG: .../IO/Socket/SSL.pm:466: waiting for fd to become ready: SSL wants a read first DEBUG: .../IO/Socket/SSL.pm:486: socket ready, retrying connect DEBUG: .../IO/Socket/SSL.pm:1641: ok=1 cert=22397184 DEBUG: .../IO/Socket/SSL.pm:1641: ok=1 cert=22521520 DEBUG: .../IO/Socket/SSL.pm:1641: ok=1 cert=22513408 DEBUG: .../IO/Socket/SSL.pm:1641: ok=1 cert=22421632 DEBUG: .../IO/Socket/SSL.pm:1201: scheme=ldap cert=22421632 DEBUG: .../IO/Socket/SSL.pm:1210: identity=kit-dc-04.kit.edu cn=kit-dc-04.kit.edu alt=2 kit-dc-04.kit.edu 2 kit-dc.kit.edu DEBUG: .../IO/Socket/SSL.pm:446: Net::SSLeay::connect -> -1 DEBUG: .../IO/Socket/SSL.pm:456: ssl handshake in progress DEBUG: .../IO/Socket/SSL.pm:466: waiting for fd to become ready: SSL wants a read first DEBUG: .../IO/Socket/SSL.pm:486: socket ready, retrying connect DEBUG: .../IO/Socket/SSL.pm:446: Net::SSLeay::connect -> 1 DEBUG: .../IO/Socket/SSL.pm:501: ssl handshake done DEBUG: .../IO/Socket/SSL.pm:1653: new ctx 22444320 DEBUG: .../IO/Socket/SSL.pm:363: socket not yet connected DEBUG: .../IO/Socket/SSL.pm:365: socket connected DEBUG: .../IO/Socket/SSL.pm:383: ssl handshake not started DEBUG: .../IO/Socket/SSL.pm:433: set socket to non-blocking to enforce timeout=3 DEBUG: .../IO/Socket/SSL.pm:446: Net::SSLeay::connect -> -1 DEBUG: .../IO/Socket/SSL.pm:456: ssl handshake in progress DEBUG: .../IO/Socket/SSL.pm:466: waiting for fd to become ready: SSL wants a read first DEBUG: .../IO/Socket/SSL.pm:486: socket ready, retrying connect DEBUG: .../IO/Socket/SSL.pm:1641: ok=1 cert=22556704 DEBUG: .../IO/Socket/SSL.pm:1641: ok=1 cert=22677424 DEBUG: .../IO/Socket/SSL.pm:1641: ok=1 cert=22669216 DEBUG: .../IO/Socket/SSL.pm:1641: ok=1 cert=22570864 DEBUG: .../IO/Socket/SSL.pm:1201: scheme=ldap cert=22570864 DEBUG: .../IO/Socket/SSL.pm:1210: identity=kit-dc-04.kit.edu cn=kit-ad.scc.kit.edu alt=1 f5@scc.kit.edu DEBUG: .../IO/Socket/SSL.pm:446: Net::SSLeay::connect -> -1 DEBUG: .../IO/Socket/SSL.pm:1328: SSL connect attempt failed with unknown error error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed DEBUG: .../IO/Socket/SSL.pm:452: fatal SSL error: SSL connect attempt failed with unknown error error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed DEBUG: .../IO/Socket/SSL.pm:1328: IO::Socket::IP configuration failed error:00000000:lib(0):func(0):reason(0) DEBUG: .../IO/Socket/SSL.pm:1690: free ctx 22444320 open=22444320 22392624 DEBUG: .../IO/Socket/SSL.pm:1695: free ctx 22444320 callback DEBUG: .../IO/Socket/SSL.pm:1698: OK free ctx 22444320 DEBUG: .../IO/Socket/SSL.pm:1690: free ctx 22392624 open=22392624 DEBUG: .../IO/Socket/SSL.pm:1695: free ctx 22392624 callback DEBUG: .../IO/Socket/SSL.pm:1698: OK free ctx 22392624 ----------------------------------------------------------------- To understand the problem I had a look at SSL.pm from IO::Socket:SSL. As far as I understand SSL variables which are not set are overriden with global variables. So I moved this code block somewhat down which fixes it. (Although I'm wondering if the identity should be overriden with a global variable at all.) I'm using IO::Socket:SSL 1.74 from Debian wheezy, but I also installed the recent version 1.959. It's the same problem although the code is a bit different. Fix for version 1.74 (Debian wheezy): ----------------------------------------------------------- --- SSL.pm.orig 2013-11-13 02:11:46.752935483 +0100 +++ SSL.pm 2013-11-13 02:12:44.413920483 +0100 @@ -291,9 +291,6 @@ } } - #Replace nonexistent entries with defaults - %$arg_hash = ( %default_args, %$GLOBAL_CONTEXT_ARGS, %$arg_hash ); - #Avoid passing undef arguments to Net::SSLeay defined($arg_hash->{$_}) or delete($arg_hash->{$_}) foreach (keys %$arg_hash); @@ -327,6 +324,9 @@ return $rv; }; } + + #Replace nonexistent entries with defaults + %$arg_hash = ( %default_args, %$GLOBAL_CONTEXT_ARGS, %$arg_hash ); ${*$self}{'_SSL_arguments'} = $arg_hash; ${*$self}{'_SSL_ctx'} = IO::Socket::SSL::SSL_Context->new($arg_hash) || return; ----------------------------------------------------------- Fix for recent version 1.959: ----------------------------------------------------------- --- SSL.pm.orig 2013-11-13 02:05:17.658251025 +0100 +++ SSL.pm 2013-11-13 02:04:55.129862855 +0100 @@ -300,13 +300,6 @@ $is_server = $arg_hash->{SSL_server} = $arg_hash->{Listen} || 0; } - # add user defined defaults - %$arg_hash = ( - %$GLOBAL_SSL_ARGS, - $is_server ? %$GLOBAL_SSL_SERVER_ARGS : %$GLOBAL_SSL_CLIENT_ARGS, - %$arg_hash - ); - my $ctx = $arg_hash->{'SSL_reuse_ctx'}; if ($ctx) { if ($ctx->isa('IO::Socket::SSL::SSL_Context') and @@ -320,6 +313,13 @@ # create context # this will fill in defaults in $arg_hash $ctx ||= IO::Socket::SSL::SSL_Context->new($arg_hash); + + # add user defined defaults + %$arg_hash = ( + %$GLOBAL_SSL_ARGS, + $is_server ? %$GLOBAL_SSL_SERVER_ARGS : %$GLOBAL_SSL_CLIENT_ARGS, + %$arg_hash + ); ${*$self}{'_SSL_arguments'} = $arg_hash; ${*$self}{'_SSL_ctx'} = $ctx; ----------------------------------------------------------- Don't know if these fixes are ok, but I think they show where the problem resides. BTW: For testing I installed libnet-ldap-perl from Debian squeeze and it works. As it seems the reason is that the part of the IO::Socket::SSL code with the identity is not used (no DEBUG output for this). Is this a bug in IO::Socket::SSL? It would be nice if you check what's the problem here. Thanks in advance Klara -- Karlsruher Institut für Technologie (KIT) Steinbuch Centre for Computing (SCC) Klara Mall Netze und Telekommunikation (NET) Hermann-von-Helmholtz-Platz 1 76344 Eggenstein-Leopoldshafen Telefon: +49 721 608-28630 Telefon: +49 721 608-48946 E-Mail: klara.mall@kit.edu Web: http://www.scc.kit.edu KIT - Universität des Landes Baden-Württemberg und nationales Forschungszentrum in der Helmholtz-Gemeinschaft
Subject: SSL fails after plain text + STARTTLS (certificate does not match hostname)
Show quoted text
> my $tls_host = "kit-dc-04.kit.edu"; > my $ssl_host = "kit-ad.scc.kit.edu"; > ... > DEBUG: .../IO/Socket/SSL.pm:1210: identity=kit-dc-04.kit.edu cn=kit- > ad.scc.kit.edu alt=1 f5@scc.kit.edu > DEBUG: .../IO/Socket/SSL.pm:446: Net::SSLeay::connect -> -1 > DEBUG: .../IO/Socket/SSL.pm:1328: SSL connect attempt failed with > unknown error error:14090086:SSL > routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed
Hi, you can see in the debug output: ...identity=kit-dc-04.kit.edu cn=kit-ad.scc.kit.edu alt=1 f5@scc.kit.edu This means, that you access the server as "kit-dc-04.kit.edu", but the certificate in the server has a commonName of "kit-ad.scc.kit.edu", which is different from the name you use to access the server. Furthermore an alternative name is provided in the certificate, but this is not a DNS name but an email 'f5@scc.kit.edu' (general name type 1: GEN_EMAIL). But, the verification scheme for ldap requires the hostname to match either the commonName or the subjectAltName. If none of these match the verification fails. So the problem is not with IO::Socket::SSL, it's with either the hostname you use or the certificate provided by the hostname. You get the same kind of problem in your webbrowser: for example accessing https://comdirect.de currently gives you an error, because it returns a certificate, which matches only "www.comdirect.de", but not "comdirect.de". Regards, Steffen
CC: "behroozi [...] www.pls.uni.edu" <behroozi [...] www.pls.uni.edu>
Subject: Re: [rt.cpan.org #90453] SSL fails after plain text + STARTTLS (certificate does not match hostname)
Date: Sun, 17 Nov 2013 19:57:56 +0100
To: Steffen Ullrich via RT <bug-IO-Socket-SSL [...] rt.cpan.org>
From: Klara Mall <klara.mall [...] kit.edu>
Hi Steffen, On Sun, Nov 17, 2013 at 07:29:48PM +0100, Steffen Ullrich via RT wrote: Show quoted text
> <URL: https://rt.cpan.org/Ticket/Display.html?id=90453 > > > >
> > my $tls_host = "kit-dc-04.kit.edu"; > > my $ssl_host = "kit-ad.scc.kit.edu"; > > ... > > DEBUG: .../IO/Socket/SSL.pm:1210: identity=kit-dc-04.kit.edu cn=kit- > > ad.scc.kit.edu alt=1 f5@scc.kit.edu > > DEBUG: .../IO/Socket/SSL.pm:446: Net::SSLeay::connect -> -1 > > DEBUG: .../IO/Socket/SSL.pm:1328: SSL connect attempt failed with > > unknown error error:14090086:SSL > > routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed
> > Hi, > > you can see in the debug output: > ...identity=kit-dc-04.kit.edu cn=kit-ad.scc.kit.edu alt=1 f5@scc.kit.edu > > This means, that you access the server as "kit-dc-04.kit.edu", but the certificate in the server has a commonName of "kit-ad.scc.kit.edu", which is different from the name you use to access the server. Furthermore an alternative name is provided in the certificate, but this is not a DNS name but an email 'f5@scc.kit.edu' (general name type 1: GEN_EMAIL).
No, that's not the problem. Please reread my code. I connect to kit-ad.scc.kit.edu. That are two different servers: kit-dc-04.kit.edu has "kit-dc-04.kit.edu" as common name and kit-ad.scc.kit.edu has "kit-ad.scc.kit.edu" as common name in its certificate. First I connect to kit-dc-04.kit.edu with plain text / STARTTLS (success) and then to kit-ad.scc.kit.edu with SSL (failure) because identity is set to kit-dc-04.kit.edu (if I connect to kit-dc-05.kit.edu first, then identity is set to kit-dc-05.kit.edu). If I only connect with SSL to kit-ad.scc.kit.edu (without connecting to a different server before with plain text + STARTTLS - in this case kit-dc-04.kit.edu) there is no problem. Please try to reproduce this. It is reproducible for me with arbitrary servers. Kind Regards Klara
Show quoted text
> No, that's not the problem. Please reread my code. I connect to > kit-ad.scc.kit.edu. That are two different servers: > kit-dc-04.kit.edu has "kit-dc-04.kit.edu" as common name and > kit-ad.scc.kit.edu has "kit-ad.scc.kit.edu" as common name in its > certificate.
Now I understand your problem. From my understanding it is a bug in Net::LDAP. In Net::LDAP::start_tls it applies the ssl specific settings, including SSL_verifycn_name, not only to the socket, but globally: 1053 sub start_tls { ... 1085 IO::Socket::SSL::context_init( { _SSL_context_init_args($arg) } ); 1086 my $sock_class = ref($sock); 1087 1088 return $mesg 1089 if IO::Socket::SSL->start_SSL($sock, {_SSL_context_init_args($arg)}); The line 1085 is what causes the problem. Additionally SSL_verifycn_name is only set if _SSL_context_init_args is called from within start_tls, not from connect_ldaps (e.g. Net::LDAPS->new). So the latter call to Net::LDAPS->new will reuse the hostname for verification from the earlier start_tls call. Because in line 1089 the SSL upgrade of the socket is done with all SSL specific settings (which only apply to the socket) there should be no need for the global settings at all, so line 1085 should simply be removed. The code in IO::Socket::SSL is at least in this regard correct: because the default and global ssl settings need to be applied when creating the socket (e.g. ciphers...) they must be mixed into the user supplied args before creating the socket. So please try to remove line 1085 from Net::LDAP and see if it fixes the problem. Then file the bug against Net::LDAP :) Regards, Steffen
CC: "behroozi [...] www.pls.uni.edu" <behroozi [...] www.pls.uni.edu>
Subject: Re: [rt.cpan.org #90453] SSL fails after plain text + STARTTLS
Date: Sun, 17 Nov 2013 22:01:20 +0100
To: Steffen Ullrich via RT <bug-IO-Socket-SSL [...] rt.cpan.org>
From: Klara Mall <klara.mall [...] kit.edu>
Hi Steffen, On Sun, Nov 17, 2013 at 08:56:24PM +0100, Steffen Ullrich via RT wrote: Show quoted text
> <URL: https://rt.cpan.org/Ticket/Display.html?id=90453 > > >
> > No, that's not the problem. Please reread my code. I connect to > > kit-ad.scc.kit.edu. That are two different servers: > > kit-dc-04.kit.edu has "kit-dc-04.kit.edu" as common name and > > kit-ad.scc.kit.edu has "kit-ad.scc.kit.edu" as common name in its > > certificate.
> > Now I understand your problem. > From my understanding it is a bug in Net::LDAP. In Net::LDAP::start_tls it applies the ssl specific settings, including SSL_verifycn_name, not only to the socket, but globally: > > 1053 sub start_tls { > ... > 1085 IO::Socket::SSL::context_init( { _SSL_context_init_args($arg) } ); > 1086 my $sock_class = ref($sock); > 1087 > 1088 return $mesg > 1089 if IO::Socket::SSL->start_SSL($sock, {_SSL_context_init_args($arg)}); > > The line 1085 is what causes the problem. > Additionally SSL_verifycn_name is only set if _SSL_context_init_args is called from within start_tls, not from connect_ldaps (e.g. Net::LDAPS->new). So the latter call to Net::LDAPS->new will reuse the hostname for verification from the earlier start_tls call. > > > Because in line 1089 the SSL upgrade of the socket is done with all SSL specific settings (which only apply to the socket) there should be no need for the global settings at all, so line 1085 should simply be removed. > > The code in IO::Socket::SSL is at least in this regard correct: because the default and global ssl settings need to be applied when creating the socket (e.g. ciphers...) they must be mixed into the user supplied args before creating the socket. > > So please try to remove line 1085 from Net::LDAP and see if it fixes the problem. > Then file the bug against Net::LDAP :)
Thank you very much for the detailed explanation. Removing that line fixes it. :) Filed the bug against Net::LDAP: https://rt.cpan.org/Ticket/Display.html?id=90459 Regards Klara