]> git.g-eek.se Git - interimap.git/commitdiff
Move SSL fingerprint verification to the the verify callback.
authorGuilhem Moulin <guilhem@fripost.org>
Wed, 16 Sep 2015 16:28:10 +0000 (18:28 +0200)
committerGuilhem Moulin <guilhem@fripost.org>
Wed, 16 Sep 2015 16:28:10 +0000 (18:28 +0200)
interimap.1
lib/Net/IMAP/InterIMAP.pm

index d0c547493c05ad7b36c558d55f1cf73cfe5895cf..60493f39b05b38303ec9615d3d8d215bbe4673b3 100644 (file)
@@ -317,8 +317,8 @@ Fingerprint of the server certificate (or its public key) in the form
 \fIALGO\fR$\fIDIGEST_HEX\fR, where \fIALGO\fR is the used algorithm
 (default \(lqsha256\(rq).
 Attempting to connect to a server with a non-matching certificate
-fingerprint causes \fBInterIMAP\fR to abort the connection immediately
-after the SSL/TLS handshake.
+fingerprint causes \fBInterIMAP\fR to abort the connection during the
+SSL/TLS handshake.
 
 .TP
 .I SSL_verify
index f54f239077c2b45b2568feb895ed6fe4cf822b1a..bf3329477c8284bfb7f66b9f389b6c1305c5de4b 100644 (file)
@@ -1380,7 +1380,8 @@ sub _ssl_verify($$$) {
         $self->log('  Subject Name: ', Net::SSLeay::X509_NAME_oneline(Net::SSLeay::X509_get_subject_name($cert)));
     }
 
-    if ($depth == 0) {
+    $ok = 1 unless $self->{SSL_verify} // 1;
+    if ($depth == 0 and !exists $self->{_SSL_PEER_VERIFIED}) {
         if ($self->{debug}) {
             my $algo = 'sha256';
             my $type = Net::SSLeay::EVP_get_digestbyname($algo)
@@ -1388,6 +1389,21 @@ sub _ssl_verify($$$) {
             $self->log('Peer certificate fingerprint: '
                       .$algo.'$'.unpack('H*', Net::SSLeay::X509_digest($cert, $type)));
         }
+
+        if (defined (my $fpr = $self->{SSL_fingerprint})) {
+            (my $algo, $fpr) = $fpr =~ /^([^\$]+)\$(.*)/ ? ($1, $2) : ('sha256', $fpr);
+            my $digest = pack 'H*', ($fpr =~ tr/://rd);
+
+            my $type = Net::SSLeay::EVP_get_digestbyname($algo)
+                or $self->_ssl_error("Can't find MD value for name '$algo'");
+
+            if (Net::SSLeay::X509_digest($cert, $type) ne $digest and
+                Net::SSLeay::X509_pubkey_digest($cert, $type) ne $digest) {
+                $self->warn("Fingerprint doesn't match!  MiTM in action?");
+                $ok = 0;
+            }
+        }
+        $self->{_SSL_PEER_VERIFIED} = $ok;
     }
     return $ok; # 1=accept cert, 0=reject
 }
@@ -1426,17 +1442,18 @@ sub _start_ssl($$) {
             Net::SSLeay::CTX_load_verify_locations($ctx, $file, $path)
                 or $self->_ssl_error("Can't load verify locations");
         }
-        Net::SSLeay::CTX_set_verify($ctx, Net::SSLeay::VERIFY_PEER(), sub($$) {$self->_ssl_verify(@_)});
-        Net::SSLeay::CTX_set_purpose($ctx, Net::SSLeay::X509_PURPOSE_SSL_SERVER())
-                or $self->_ssl_error("Can't set purpose");
     }
     else {
-        Net::SSLeay::CTX_set_verify($ctx, Net::SSLeay::VERIFY_NONE());
+        Net::SSLeay::CTX_set_verify_depth($ctx, 0);
     }
+    Net::SSLeay::CTX_set_purpose($ctx, Net::SSLeay::X509_PURPOSE_SSL_SERVER())
+        or $self->_ssl_error("Can't set purpose");
+    Net::SSLeay::CTX_set_verify($ctx, Net::SSLeay::VERIFY_PEER(), sub($$) {$self->_ssl_verify(@_)});
 
     my $ssl = Net::SSLeay::new($ctx) or $self->fail("Can't create new SSL structure");
     Net::SSLeay::set_fd($ssl, fileno $socket) or $self->fail("SSL filehandle association failed");
     $self->_ssl_error("Can't initiate TLS/SSL handshake") unless Net::SSLeay::connect($ssl) == 1;
+    $self->panic("Couldn't verify") unless $self->{_SSL_PEER_VERIFIED}; # sanity check
 
     if ($self->{debug}) {
         my $v = Net::SSLeay::version($ssl);
@@ -1452,22 +1469,6 @@ sub _start_ssl($$) {
                           , Net::SSLeay::get_cipher_bits($ssl)));
     }
 
-    if (defined (my $fpr = $self->{SSL_fingerprint})) {
-        # ensure we're talking to the right server
-        (my $algo, $fpr) = $fpr =~ /^([^\$]+)\$(.*)/ ? ($1, $2) : ('sha256', $fpr);
-        my $digest = pack 'H*', ($fpr =~ tr/://rd);
-
-        my $type = Net::SSLeay::EVP_get_digestbyname($algo)
-            or $self->_ssl_error("Can't find MD value for name '$algo'");
-
-        my $cert = Net::SSLeay::get_peer_certificate($ssl)
-            or $self->_ssl_error("Can't get peer certificate");
-
-        $self->fail("Fingerprint doesn't match!  MiTM in action?")
-            if Net::SSLeay::X509_digest($cert, $type) ne $digest and
-               Net::SSLeay::X509_pubkey_digest($cert, $type) ne $digest;
-    }
-
     @$self{qw/_SSL _SSL_CTX/} = ($ssl, $ctx);
 }