[NoCat] Patch: CypherSecret-02.patch

Karl Gaissmaier karl.gaissmaier at kiz.uni-ulm.de
Mon, 28 Jul 2003 23:57:57 +0200


--------------Boundary-00=_L09RU2RHXYRQ6K8AFHJU
Content-Type: text/plain;
  charset="us-ascii"
Content-Transfer-Encoding: 8bit

Name:
	CypherSecret-02.patch

Affected Files:
	authserv.conf
	cgi-bin/login
	lib/NoCat.pm

Version: Patch against 0.82 or later

Severity:
	important, but depends on the user group (we are at a University!)
	Prohibits the standard cleartext passwords in the html source

Description:
	the cgi param password is replaced with cryptpwd. The algorithm
	building the symmetric encryption is the same as in the
	radius protocol. The encryption code is nearly literally copied from
	Authen::Radius. The already exchanged and periodically altered
	token is used as a salt.

Future:
	Perhaps with the usage of CGI::Session the whole authentication 
	and renewal algorithm should be cleaned up and improved.

--
Karl Gaissmaier KIZ/Infrastructure, University of Ulm, Germany 
Email:karl.gaissmaier@kiz.uni-ulm.de Service Group Network
--------------Boundary-00=_L09RU2RHXYRQ6K8AFHJU
Content-Type: text/x-diff;
  charset="us-ascii";
  name="CypherSecret-02.patch"
Content-Transfer-Encoding: 8bit
Content-Disposition: attachment; filename="CypherSecret-02.patch"

diff -Naur NoCatAuth-nightly/authserv.conf NoCatAuth-mod/authserv.conf
--- NoCatAuth-nightly/authserv.conf	Mon Mar 17 23:46:11 2003
+++ NoCatAuth-mod/authserv.conf	Mon Jul 14 09:56:42 2003
@@ -12,6 +12,13 @@
 #
 Verbosity       10
 
+#
+# CypherSecret -- used for symmetric encryption of the
+# user password. Without a CypherSecret the cleartext password is
+# viewable in the html sources, the browser cache, the history, the ...
+#
+CypherSecret	mysecret
+
 ##
 # PGPKeyPath -- The directory in which PGP keys are stored.
 #   NoCat tries to find this in the pgp/ directory above
diff -Naur NoCatAuth-nightly/cgi-bin/login NoCatAuth-mod/cgi-bin/login
--- NoCatAuth-nightly/cgi-bin/login	Thu Aug 15 04:05:18 2002
+++ NoCatAuth-mod/cgi-bin/login	Mon Jul 14 10:30:11 2003
@@ -52,6 +52,13 @@
 $authserv->display( FatalForm => "Your gateway token is undefined.  Problem with the gateway?" )
     unless $params->{token};
 
+# did we get a crypted password, generate the cleartext for authentication
+if ($authserv->{CypherSecret} and not $params->{pass}) {
+    my $salt = $params->{token};
+    $params->{pass} = $authserv->encrypt_pwd($params->{cryptpwd}, $salt)
+	if $params->{cryptpwd};
+};
+
 # If the user skipped authentication...
 if ( $params->{user} eq ANONYMOUS or $params->{mode} =~ /^skip/io ) {
     $params->{user} = ANONYMOUS;
@@ -80,10 +87,27 @@
 # Either we're requesting the renewal popup box...
 if ( $params->{mode} =~ /^popup/io ) {
     $form = ( $params->{gateway} ? "PassiveRenewForm" : "RenewForm" );
+    # create cryptpwd with new token as salt
+    if ($authserv->{CypherSecret}) {
+	my $salt = $params->{token};
+	$params->{cryptpwd} = $authserv->encrypt_pwd($params->{pass}, $salt);
+	# be sure no cleartext password can be in the html forms or url's
+	delete $params->{pass};
+    };
+
     $params->{redirect} = $authserv->renew_url;
 
 # Or we're either logging in, or renewing, in which case, notify the gateway.
 } elsif ($gw = $authserv->notify( Permit => $params )) {
+
+    # create cryptpwd with new token as salt
+    if ($authserv->{CypherSecret} and not $gw->{Error}) {
+	my $salt = $gw->{Token} || $gw->{token};
+	$params->{cryptpwd} = $authserv->encrypt_pwd($params->{pass}, $salt);
+	# be sure no cleartext password can be in the html forms or url's
+	delete $params->{pass};
+    };
+
     if ( $gw->{Error} ) {
 	# Oddly enough, this isn't really success.
 	$form = "ExpiredForm";
diff -Naur NoCatAuth-nightly/lib/NoCat.pm NoCatAuth-mod/lib/NoCat.pm
--- NoCatAuth-nightly/lib/NoCat.pm	Sun Jul 13 12:00:04 2003
+++ NoCatAuth-mod/lib/NoCat.pm	Mon Jul 14 09:56:42 2003
@@ -14,6 +14,7 @@
 use FindBin;
 use Exporter;
 use Carp;
+use Digest::MD5 qw();
 use vars qw( @ISA @EXPORT_OK *FILE );
 use strict;
 
@@ -378,6 +379,26 @@
     return NoCat::Peer->new( Parent => $self, @_ );
 }
 
+sub encrypt_pwd {
+    # based on the algorithm used in the radius protocol
+    croak "parameter(s) missing" unless scalar @_ == 3;
+    my ($self, $pwd, $token) = @_;
+    my ($i, $ct, @pwdp, @xor);
+
+    # algorithm copied nearly literally from Authen::Radius by kg
+    # this only works for passwords <= 16 chars
+    $pwd .= "\0" x (16 - length($pwd) % 16);
+    @pwdp = unpack('C16', pack('a16', $pwd));
+    $ct = Digest::MD5->new;
+    $ct->add ($self->{CypherSecret}, $token);
+    @xor = unpack('C16', $ct->digest());
+    for $i (0..15) {
+	    $pwdp[$i] ^= $xor[$i];
+    }
+
+    pack('C' . length($pwd), @pwdp);
+}
+
 1;
 
 __END__
@@ -477,6 +498,8 @@
 
 =item template() Pass a template, and optional hashref, and it returns the filled template. 
 
+=item encrypt_pwd() Symmetrically encrypts a string. Algorithm copied from Authen::Radius()
+
 =item gateway() Returns a NoCat::Gateway object
 
 =item firewall() Returns a NoCat::Firewall object

--------------Boundary-00=_L09RU2RHXYRQ6K8AFHJU--