[LON-CAPA-cvs] cvs: loncom / lonssl.pm

foxr lon-capa-cvs@mail.lon-capa.org
Thu, 17 Jun 2004 09:27:38 -0000


foxr		Thu Jun 17 05:27:38 2004 EDT

  Modified files:              
    /loncom	lonssl.pm 
  Log:
  Debug ssl based key exchange support
  
  
Index: loncom/lonssl.pm
diff -u loncom/lonssl.pm:1.7 loncom/lonssl.pm:1.8
--- loncom/lonssl.pm:1.7	Tue Jun  1 05:53:44 2004
+++ loncom/lonssl.pm	Thu Jun 17 05:27:38 2004
@@ -1,5 +1,5 @@
 #
-# $Id: lonssl.pm,v 1.7 2004/06/01 09:53:44 foxr Exp $
+# $Id: lonssl.pm,v 1.8 2004/06/17 09:27:38 foxr Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -38,6 +38,9 @@
 use IO::Socket::INET;
 use IO::Socket::SSL;
 
+use Fcntl;
+use POSIX;
+
 #  Loncapa modules:
 
 use LONCAPA::Configuration;
@@ -55,6 +58,39 @@
 $perlvar = LONCAPA::Configuration::read_conf('loncapa.conf');
 
 
+my $lasterror="";
+
+
+sub LastError {
+    return $lasterror;
+}
+
+#-------------------------------------------------------------------------
+# Name SetFdBlocking - 
+#      Turn blocking mode on on the file handle.  This is required for
+#      SSL key negotiation.
+#
+# Parameters:
+#      Handle   - Reference to the handle to modify.
+# Returns:
+#      prior flag settings.
+#
+sub SetFdBlocking {
+    print STDERR "SetFdBlocking called \n";
+    my $Handle = shift;
+
+
+
+    my $flags  = fcntl($Handle, F_GETFL, 0);
+    if(!$flags) {
+	print STDERR "SetBLocking fcntl get faild $!\n";
+    }
+    my $newflags  = $flags & (~ O_NONBLOCK); # Turn off O_NONBLOCK...
+    if(!fcntl($Handle, F_SETFL, $newflags)) {
+	print STDERR "Can't set non block mode  $!\n";
+    }
+    return $flags;
+}
 
 #--------------------------------------------------------------------------
 #
@@ -73,6 +109,8 @@
 #	-	Reference to an SSL socket on success
 #       -	undef on failure.  Reason for failure can be interrogated from 
 #               IO::Socket::SSL
+# Side effects:  socket is left in blocking mode!!
+#
 
 sub PromoteClientSocket {
     my ($PlaintextSocket,
@@ -81,18 +119,29 @@
 	$KeyFile)          = @_;
     
     
+    print STDERR "Client promotion using key: $KeyFile, Cert: $MyCert, CA: $CACert\n";
+
     # To create the ssl socket we need to duplicate the existing
     # socket.  Otherwise closing the ssl socket will close the plaintext socket
-    # too:
-    
-    open (DUPLICATE, "+>$PlaintextSocket");
+    # too.  We also must flip into blocking mode for the duration of the
+    # ssl negotiation phase.. the caller will have to flip to non block if
+    # that's what they want
+
+    my $oldflags = SetFdBlocking($PlaintextSocket);
+    my $dupfno   = fcntl($PlaintextSocket, F_DUPFD, 0);
+    print STDERR "Client promotion got dup = $dupfno\n";
+
     
-    my $client = IO::Socket::SSL->new_from_fd(fileno(DUPLICATE),
+    my $client = IO::Socket::SSL->new_from_fd($dupfno,
 					      SSL_user_cert => 1,
 					      SSL_key_file  => $KeyFile,
 					      SSL_cert_file => $MyCert,
-					      SSL_ca_fie    => $$CACert);
+					      SSL_ca_fie    => $CACert);
     
+    if(!$client) {
+	$lasterror = IO::Socket::SSL::errstr();
+	return undef;
+    }
     return $client;		# Undef if the client negotiation fails.
 }
 
@@ -112,6 +161,9 @@
 #	-	Reference to an SSL socket on success
 #       -	undef on failure.  Reason for failure can be interrogated from 
 #               IO::Socket::SSL
+# Side Effects:
+#       Socket is left in blocking mode!!!
+#
 sub PromoteServerSocket {
     my ($PlaintextSocket,
 	$CACert,
@@ -124,14 +176,24 @@
     # socket.  Otherwise closing the ssl socket will close the plaintext socket
     # too:
 
-    open (DUPLICATE, "+>$PlaintextSocket");
-
-    my $client = IO::Socket::SSL->new_from_fd(fileno(DUPLICATE),
+    print STDERR "Server promotion: Key = $KeyFile, Cert $MyCert CA $CACert\n";
+ 
+    my $oldflags = SetFdBlocking($PlaintextSocket);
+    my $dupfno   = fcntl($PlaintextSocket, F_DUPFD, 0);
+    if (!$dupfno) {
+	print STDERR "dup failed: $!\n";
+    }
+    print STDERR " Fileno = $dupfno\n";
+    my $client = IO::Socket::SSL->new_from_fd($dupfno,
 					      SSL_server    => 1, # Server role.
 					      SSL_user_cert => 1,
 					      SSL_key_file  => $KeyFile,
 					      SSL_cert_file => $MyCert,
-					      SSL_ca_fie    => $$CACert);
+					      SSL_ca_fie    => $CACert);
+    if(!$client) {
+	$lasterror = IO::Socket::SSL::errstr();
+	return undef;
+    }
     return $client;
 }
 
@@ -170,7 +232,7 @@
     my $CertOwner = $SSLSocket->peer_certificate("owner");
     my $CertCA    = $SSLSocket->peer_certificate("authority");
     
-    return \($CertCA, $CertOwner);
+    return ($CertCA, $CertOwner);
 }
 #----------------------------------------------------------------------------
 #
@@ -193,6 +255,8 @@
     #  Ensure the existence of these variables:
     
     if((!$CertificateDir)  || (!$CaFilename) || (!$CertFilename)) {
+	$lasterror = "Missing info: dir: $CertificateDir CA: $CaFilename "
+	            ."Cert: $CertFilename";
 	return undef;
     }
     
@@ -203,12 +267,14 @@
     my $CertFilename = $CertificateDir.$pathsep.$CertFilename;
     
     if((! -r $CaFilename) || (! -r $CertFilename)) {
+	$lasterror = "CA file $CaFilename or Cert File: $CertFilename "
+	            ."not readable";
 	return undef;
     }
     
     # Everything works fine!!
     
-    return \($CaFilename, $CertFilename);
+    return ($CaFilename, $CertFilename);
 
 }
 #------------------------------------------------------------------------
@@ -230,6 +296,8 @@
     # Ensure the variables exist:
     
     if((!$CertificateDir) || (!$KeyFilename)) {
+	$lasterror = "Missing parameter dir: $CertificateDir "
+	            ."key: $KeyFilename";
 	return undef;
     }
     
@@ -238,6 +306,7 @@
     
     my $KeyFilename    = $CertificateDir.$pathsep.$KeyFilename;
     if(! (-r $KeyFilename)) {
+	$lasterror = "Unreadable key file $KeyFilename";
 	return undef;
     }