Skip Menu |

This queue is for tickets about the Net-IMAP-Client CPAN distribution.

Report information
The Basics
Id: 113815
Status: new
Priority: 0/
Queue: Net-IMAP-Client

People
Owner: Nobody in particular
Requestors: nigel.metheringham [...] gmail.com
Cc:
AdminCc:

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



Subject: STARTTLS support for Net-IMAP-Client
Hi, I needed STARTTLS support to access an IMAP server, so have reworked _get_socket() to support a plain text connection followed immediately by an upgrade using STARTTLS. No additional dependancies needed to support this. I'm attaching a patch against 0.9505 or you can grab the changes from github at https://github.com/nigelm/Net-IMAP-Client/tree/nm_starttls (the base for this is the BACKPAN git repo generated for all CPAN distributions). Cheers Nigel.
Subject: net_imap__client_starttls.patch
commit c4f54a75d6a8eb2b991312138bc5a0c631b2fedb Author: Nigel Metheringham <nigel.metheringham@redcentricplc.com> Date: Fri Apr 15 11:16:17 2016 +0100 Initial STARTTLS implementation diff --git a/lib/Net/IMAP/Client.pm b/lib/Net/IMAP/Client.pm index 9a0c5e8..2306577 100644 --- a/lib/Net/IMAP/Client.pm +++ b/lib/Net/IMAP/Client.pm @@ -25,6 +25,7 @@ my %DEFAULT_ARGS = ( pass => undef, ssl => 0, ssl_verify_peer => 1, + tls => 0, socket => undef, _cmd_id => 0, ssl_options => {}, @@ -37,12 +38,15 @@ sub new { $_ => exists $args{$_} ? $args{$_} : $DEFAULT_ARGS{$_} } keys %DEFAULT_ARGS }; + die "Cannot enable both ssl and tls" if ($self->{tls} and $self->{ssl}); + bless $self, $class; $self->{notifications} = []; eval { - $self->{greeting} = $self->_socket_getline; + $self->_get_socket; # set up the socket }; + return $@ ? undef : $self; } @@ -646,7 +650,11 @@ sub _get_ssl_config { } sub _get_socket { my ($self) = @_; - my $socket = $self->{socket} ||= ($self->{ssl} ? 'IO::Socket::SSL' : 'IO::Socket::INET')->new( + + my $socket = $self->{socket}; + return $socket if (defined($socket) and ($socket->isa('IO::Socket::SSL')or $socket->isa('IO::Socket::INET'))); + + $self->{socket} = ($self->{ssl} ? 'IO::Socket::SSL' : 'IO::Socket::INET')->new( ( ( %{$self->{ssl_options}} ) x !!$self->{ssl} ), PeerAddr => $self->_get_server, PeerPort => $self->_get_port, @@ -655,8 +663,44 @@ sub _get_socket { Blocking => 1, $self->_get_ssl_config, ) or die "failed connect or ssl handshake: $!,$IO::Socket::SSL::SSL_ERROR"; - $socket->sockopt(SO_KEEPALIVE, 1); - return $socket; + $self->{socket}->sockopt(SO_KEEPALIVE, 1); + + $self->{greeting} = $self->_socket_getline; # get the initial greeting + + $self->_starttls if ($self->{tls}); # upgrade to TLS if needed + + return $self->{socket}; +} + +sub _starttls { + my ($self) = @_; + + # ask for the capabilities directly at this level, make sure we can do STARTTLS + my $can_do_starttls = 0; + my ($ok, $lines) = $self->_tell_imap('CAPABILITY'); + if ($ok) { + my $line = $lines->[0][0]; + $can_do_starttls ||= 1 if ($line =~ /^\*\s+CAPABILITY.*\s+STARTTLS/); + } else { + die "IMAP server failed CAPABILITY query" + } + die "IMAP server does not have STARTTLS capability" unless ($can_do_starttls); + + # request STARTTLS + ($ok, $lines) = $self->_tell_imap('STARTTLS'); + if ($ok) { + my @sni_args; + push(@sni_args, SSL_hostname => $self->_get_server) if (IO::Socket::SSL->can_client_sni()); + IO::Socket::SSL->start_SSL( + $self->{socket}, + $self->_get_ssl_config, + @sni_args, + ) or die $IO::Socket::SSL::SSL_ERROR; + } else { + die "IMAP server failed STARTTLS command" + } + + return $self->{socket}; } sub _get_next_id { @@ -1199,7 +1243,16 @@ Password =item - B<ssl> (BOOL, optional, default FALSE) -Pass a true value if you want to use IO::Socket::SSL +Pass a true value if you want to use L<IO::Socket::SSL> +You may not set both C<ssl> and C<tls> at the same time. + +=item - B<tls> (BOOL, optional, default FALSE) + +Pass a true value if you want to use connect without SSL and then use +C<STARTTLS> to upgrade the connection to an encrypted session using +L<IO::Socket::SSL>. The other C<ssl_*> options also apply. + +You may not set both C<ssl> and C<tls> at the same time. =item - B<ssl_verify_peer> (BOOL, optional, default TRUE)