snk authentication

Larry D'Anna ldanna at tislabs.com
Thu Jun 7 09:35:21 EST 2001


Here is a little patch against 2.9p1 that performs the SNK (also known
as TIS authserv) challenge-response automaticly instead of asking the
user.  hope you find it useful.

	--larry 
-------------- next part --------------
diff -NuBw openssh-2.9p1/Makefile.in openssh/Makefile.in
--- openssh-2.9p1/Makefile.in	Thu Apr 26 20:31:08 2001
+++ openssh/Makefile.in	Wed Jun  6 16:15:56 2001
@@ -43,9 +43,9 @@
 
 @NO_SFTP at SFTP_PROGS=sftp-server$(EXEEXT) sftp$(EXEEXT)
 
-TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keyscan${EXEEXT} ssh-agent$(EXEEXT) scp$(EXEEXT) $(SFTP_PROGS)
+TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keyscan${EXEEXT} ssh-agent$(EXEEXT) scp$(EXEEXT)  snk$(EXEEXT) $(SFTP_PROGS)
 
-LIBSSH_OBJS=atomicio.o authfd.o authfile.o bufaux.o buffer.o canohost.o channels.o cipher.o cli.o compat.o compress.o crc32.o deattack.o dh.o dispatch.o mac.o hostfile.o key.o kex.o kexdh.o kexgex.o log.o match.o misc.o mpaux.o nchan.o packet.o radix.o rijndael.o entropy.o readpass.o rsa.o ssh-dss.o ssh-rsa.o tildexpand.o ttymodes.o uidswap.o uuencode.o xmalloc.o 
+LIBSSH_OBJS=atomicio.o authfd.o authfile.o bufaux.o buffer.o canohost.o channels.o cipher.o cli.o compat.o compress.o crc32.o deattack.o dh.o dispatch.o mac.o hostfile.o key.o kex.o kexdh.o kexgex.o log.o match.o misc.o mpaux.o nchan.o packet.o radix.o rijndael.o entropy.o readpass.o rsa.o ssh-dss.o ssh-rsa.o tildexpand.o ttymodes.o uidswap.o uuencode.o xmalloc.o snk.o
 
 SSHOBJS= ssh.o sshconnect.o sshconnect1.o sshconnect2.o sshtty.o readconf.o clientloop.o
 
@@ -118,6 +118,9 @@
 
 sftp$(EXEEXT): $(LIBCOMPAT) libssh.a sftp.o sftp-client.o sftp-int.o sftp-common.o sftp-glob.o scp-common.o
 	$(LD) -o $@ sftp.o sftp-client.o sftp-common.o sftp-int.o sftp-glob.o scp-common.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
+
+snk$(EXEEXT): $(LIBCOMPAT) snkmain.o snk.o
+	$(LD) -o $@ snkmain.o snk.o  -lcrypto 
 
 # test driver for the loginrec code - not built by default
 logintest: logintest.o $(LIBCOMPAT) libssh.a loginrec.o
Common subdirectories: openssh-2.9p1/contrib and openssh/contrib
Common subdirectories: openssh-2.9p1/openbsd-compat and openssh/openbsd-compat
diff -NuBw openssh-2.9p1/readconf.c openssh/readconf.c
--- openssh-2.9p1/readconf.c	Tue Apr 17 14:11:37 2001
+++ openssh/readconf.c	Wed Jun  6 14:38:23 2001
@@ -111,7 +111,7 @@
 	oGlobalKnownHostsFile2, oUserKnownHostsFile2, oPubkeyAuthentication,
 	oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias,
 	oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication,
-	oHostKeyAlgorithms
+	oHostKeyAlgorithms, oSNKFile
 } OpCodes;
 
 /* Textual representations of the tokens. */
@@ -177,6 +177,7 @@
 	{ "dynamicforward", oDynamicForward },
 	{ "preferredauthentications", oPreferredAuthentications },
 	{ "hostkeyalgorithms", oHostKeyAlgorithms },
+	{ "SNKFile", oSNKFile },
 	{ NULL, 0 }
 };
 
@@ -435,6 +436,10 @@
 		charptr = &options->system_hostfile;
 		goto parse_string;
 
+	case oSNKFile: 
+	  charptr = &options->snk_keyfile;
+	  goto parse_string;
+
 	case oUserKnownHostsFile:
 		charptr = &options->user_hostfile;
 		goto parse_string;
@@ -761,6 +766,7 @@
 	options->num_remote_forwards = 0;
 	options->log_level = (LogLevel) - 1;
 	options->preferred_authentications = NULL;
+	options->snk_keyfile = NULL;
 }
 
 /*
diff -NuBw openssh-2.9p1/readconf.h openssh/readconf.h
--- openssh-2.9p1/readconf.h	Tue Apr 17 14:11:37 2001
+++ openssh/readconf.h	Wed Jun  6 15:07:34 2001
@@ -97,6 +97,8 @@
 	/* Remote TCP/IP forward requests. */
 	int     num_remote_forwards;
 	Forward remote_forwards[SSH_MAX_FORWARDS_PER_DIRECTION];
+
+  char *snk_keyfile; /* Path to a file with an encrypted snk key */ 
 }       Options;
 
 
diff -NuBw openssh-2.9p1/snk.c openssh/snk.c
--- openssh-2.9p1/snk.c	Wed Dec 31 19:00:00 1969
+++ openssh/snk.c	Wed Jun  6 19:25:27 2001
@@ -0,0 +1,176 @@
+
+
+
+/* by Brian Wellington and / or Jeff Cook */ 
+
+#include	<ctype.h>
+#include	<string.h>
+
+#include	<openssl/des.h>
+#include	<openssl/md5.h>
+
+static int
+make_key_sched(char *s, des_cblock k) {
+	int	k0, k1, k2, k3, k4, k5, k6, k7;
+	int	x;
+
+	x = sscanf(s, "%o %o %o %o %o %o %o %o",
+		&k0, &k1, &k2, &k3, &k4, &k5, &k6, &k7);
+	if(x != 8)
+		return(1);
+	k[0] = k0;
+	k[1] = k1;
+	k[2] = k2;
+	k[3] = k3;
+	k[4] = k4;
+	k[5] = k5;
+	k[6] = k6;
+	k[7] = k7;
+	return(0);
+}
+
+
+
+int do_snk(char *chal, char *pass, char *rbuf) {
+	des_key_schedule	keysched;
+	des_cblock		kblock;
+	char			buf[12];
+	char			cbuf[12];
+	int			i;
+	int			j;
+	unsigned long		kval = 0;
+	
+	/* set up a key from the shared secret */
+	if(make_key_sched(pass,kblock)) {
+		strcpy(rbuf,"Cannot decode user secret key");
+		return(1);
+	}
+	for(i=0; i < 64; i++)pass[i]=0;
+	
+	des_set_key((des_cblock *)kblock,keysched);
+
+	/* zeroize the entire buffer */
+	for(i = 0; i < 9; i++)
+		buf[i] = '\0';
+	strncpy(buf,chal,8);
+
+	/* push it through the rotating knives */
+	des_ecb_encrypt((des_cblock *)buf, (des_cblock *)cbuf, keysched,
+			DES_ENCRYPT);
+
+	/* pull some bits out of the ciphertext into a long */
+	for(i=0; i<4; i++)
+		for(j = 0; j < 8; j++)
+			kval = (kval << 1) | ((cbuf[i] >> (7 - j)) & 1);
+
+	/* crunch it into a hex string */
+	sprintf(buf,"%08lx",kval);
+
+	/* crunch hex to decimal and try that */
+	for(i=0; buf[i]; i++)
+		if(buf[i] == 'a' || buf[i] == 'b' || buf[i] == 'c')
+			buf[i] = '2';
+		else
+			if(buf[i] == 'd' || buf[i] == 'e' || buf[i] == 'f')
+				buf[i] = '3';
+	strcpy(rbuf, buf);
+	return(0);
+}
+
+/* Get the DES key from the specified data. */
+
+int get_snk_pass(char *pass, char *res, int reslen, char *data) {
+	des_cblock		kblock;
+	des_key_schedule	keysched;
+	char		kbuf[16];
+	des_cblock		iv;
+	int i, j;
+	char *p;
+	MD5_CTX ctx;
+	unsigned char digest[16];
+	    
+	if(data[0] ){
+		des_string_to_key(pass, &kblock); 
+		des_set_key((des_cblock *)kblock, keysched);
+		p = (char *)&iv;
+		for(i=0; i < 8; i++)*p++ = 130-i;
+		
+		des_cbc_encrypt((des_cblock *)data, (des_cblock *)kbuf, 16l,
+				keysched, &iv, DES_DECRYPT);			
+		j = (kbuf[8]&0xff) + (kbuf[9]&0xff) * 256;
+		if( j < 0 || j >=reslen){
+			return 1;
+		}
+		MD5_Init(&ctx);
+		MD5_Update(&ctx, (unsigned char *)&kbuf[8], 2);
+		MD5_Update(&ctx, (unsigned char *)&kbuf[10], (j<=6) ? j : 6);
+
+		strncpy(res, &kbuf[10], 6);
+		res[6] = '\0';
+		j -= 6;
+		if( j > 0){
+			i = (j+7)& 0xf8;
+			des_cbc_encrypt((des_cblock *)&data[16],
+					(des_cblock *)&res[6], i*1l,
+					keysched, &iv, DES_DECRYPT);
+			MD5_Update(&ctx, (unsigned char *)&res[6], j);
+		}
+		res[6+j] = '\0';
+
+		MD5_Final(digest, &ctx);
+		for(i=0; i < 8; i++){
+			if( digest[i] != (kbuf[i]&0xff))
+				return 1;
+		}
+	}else{
+		strncpy(res, pass, reslen);
+	}
+	return 0;
+}
+
+
+
+int put_snk_pass(char *pass, char *res, int reslen, char *data) {
+	des_cblock		kblock;
+	des_key_schedule	keysched;
+	char		kbuf[16];
+	des_cblock		iv;
+	int i, j;
+	char *p;
+	MD5_CTX ctx;
+	unsigned char digest[16];
+    
+	des_string_to_key(pass, &kblock); 
+	des_set_key((des_cblock *)kblock, keysched);
+	p = (char *)&iv;
+	for(i=0; i < 8; i++)*p++ = 130-i;
+	
+	kbuf[8] = reslen&0xff;
+	kbuf[9] = (reslen >> 8)&0xff;
+	for(i=0; i < 6 && i < reslen; i++)
+		kbuf[10+i] = res[i];
+	MD5_Init(&ctx);
+	MD5_Update(&ctx, (unsigned char *)&kbuf[8], 2);
+	MD5_Update(&ctx, res, reslen);
+	MD5_Final(digest, &ctx);
+	for(i=0; i < 8; i++)
+		kbuf[i] = digest[i];
+
+	des_cbc_encrypt((des_cblock *)kbuf, (des_cblock *)data, 16l,
+			keysched, &iv, DES_ENCRYPT);			
+	j = reslen - 6;
+	if( j > 0){
+		i = (j+7)& 0xf8;
+		des_cbc_encrypt((des_cblock *)&res[6], (des_cblock *)&data[16],
+				i*1l, keysched, &iv, DES_ENCRYPT);
+	}
+	return 0;
+}
+
+
+int valid_secret_p (char *s) {
+  int x, y;
+  x = sscanf(s, "%o %o %o %o %o %o %o %o",
+	     &y, &y, &y, &y, &y, &y, &y, &y);
+  return x == 8;
+}
diff -NuBw openssh-2.9p1/snk.h openssh/snk.h
--- openssh-2.9p1/snk.h	Wed Dec 31 19:00:00 1969
+++ openssh/snk.h	Wed Jun  6 15:56:23 2001
@@ -0,0 +1,9 @@
+
+
+extern int do_snk(char *, char *, char *);
+extern int get_snk_pass(char *pass, char *res, int reslen, char *data);
+extern int put_snk_pass(char *pass, char *res, int reslen, char *data);
+extern int valid_secret_p (char *s); 
+
+
+
diff -NuBw openssh-2.9p1/snkmain.c openssh/snkmain.c
--- openssh-2.9p1/snkmain.c	Wed Dec 31 19:00:00 1969
+++ openssh/snkmain.c	Wed Jun  6 19:24:58 2001
@@ -0,0 +1,256 @@
+#include <ctype.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pwd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+
+#include "snk.h"
+
+
+/* 
+ * originaly written by Brian Wellington and / or Jeff Cook 
+ * modified by Larry D'Anna 
+ */ 
+
+
+#define hexvalue(c) ((tolower(c) < 'a') ? (tolower(c) - '0') : (tolower(c) - 'a' + 10))
+
+char *keyfile, *outfile = NULL;
+
+static void
+usage() {
+	fprintf (stderr, "Usage:\n");
+	fprintf (stderr, "snk [-f keyfile] [challenge]        Compute response\n");
+	fprintf (stderr, "snk -w [-f keyfile]                 Save Key\n");
+	fprintf (stderr, "snk -p [-f keyfile] [-o outfile]    Change Passphrase\n");
+}
+
+void save_snk() {
+	FILE *fp;
+	char secret[256];
+	char password[256];
+	int i,x1,x2,x3,x4,x5,x6,x7,x8;
+	int   y1,y2,y3,y4,y5,y6,y7,y8;
+	unsigned char data[48];
+
+ get_key:
+	strncpy(secret, getpass("Enter SNK secret key: "), sizeof(secret));
+	if (sscanf(secret, "%d %d %d %d %d %d %d %d", &x1, &x2, &x3, &x4, &x5, &x6, &x7, &x8) != 8) {
+	  fprintf (stderr, "Error: Invalid secret key\n");
+	  goto get_key;
+	}
+	if (sscanf(getpass("Repeat: "), "%d %d %d %d %d %d %d %d", 
+		   &y1, &y2, &y3, &y4, &y5, &y6, &y7, &y8) != 8 || 
+	    x1 != y1 ||	    x2 != y2 ||	    x3 != y3 ||	    x4 != y4 ||	    
+	    x5 != y5 ||	    x6 != y6 ||     x7 != y7 ||	    x8 != y8 ) {
+	  fprintf (stderr, "Keys do not match\n");
+	  goto get_key;
+	}
+ get_password:
+	strncpy(password, getpass("Enter SNK passphrase: "), sizeof(password));
+	if ( strcmp(password, getpass("Repeat: ")) != 0  ) {
+	  fprintf (stderr, "Passphrases do not match\n");
+	  goto get_password;
+	}
+	memset(data, 0, sizeof(data));
+	put_snk_pass(password, secret, strlen(secret) + 1, data);
+	fp = fopen (outfile, "w");
+	if (fp == NULL) {
+	  fprintf (stderr, "Error: Cannot create %s\n", keyfile);
+	  exit(1);
+	}
+	if ( chmod(keyfile, S_IRUSR|S_IWUSR) == -1 ) 
+	  fprintf (stderr, "Error: cannot set permissions on %s\n", keyfile);
+	for (i=0; i<sizeof(data); i++)
+		fprintf (fp, "%02x", data[i]);
+	fprintf (fp, "\n");
+	fclose(fp);
+}
+
+
+void compute_snk(char *maybe_challenge) {
+	FILE *fp;
+	char *password;
+	char secret[256];
+	char response[256];
+	char challenge[256];
+	int len;
+	unsigned char data[48];
+
+	fp = fopen (keyfile, "r");
+	if (fp == NULL) {
+	  fprintf (stderr, "Error: Cannot open %s: %s\n", keyfile, strerror(errno));
+	  exit(1);
+	}
+	len = 0;
+	memset(data, 0, sizeof(data));
+	while (len < sizeof(data)) {
+		int c1 = fgetc(fp);
+		int c2 = fgetc(fp);
+		if (c1 == '\n' || c1 == EOF || c2 == '\n' || c2 == EOF)
+			break;
+		data[len++] = (hexvalue(c1) << 4 ) + hexvalue(c2);
+	}
+	fclose(fp);
+	get_snk_pass("", secret, sizeof(secret), data);
+	if (! valid_secret_p(secret) ) {
+	get_password:
+	  password = getpass("Enter SNK password: ");
+	  get_snk_pass(password, secret, sizeof(secret), data);
+	  if (! valid_secret_p(secret) ) {
+	    fprintf(stderr, "Cannot decode secret key\n");
+	    goto get_password;
+	  }	  
+	}
+	if (maybe_challenge)
+		strncpy(challenge, maybe_challenge, sizeof(challenge));
+	else {
+		printf ("Enter SNK challenge: ");
+		fgets (challenge, sizeof(challenge), stdin);
+		if (challenge[strlen(challenge)-1] == '\n')
+			challenge[strlen(challenge)-1] = 0;
+	}
+	do_snk(challenge, secret, response);
+	printf ("SNK response = %s\n", response);
+}
+
+void passwd() {
+  FILE *fp; 
+  unsigned char data[48];
+  char secret[256];
+  char password[256];
+  int i, len;
+
+  fp = fopen (keyfile, "r");
+  if (fp == NULL) {
+    fprintf (stderr, "Error: Cannot open %s: %s\n", keyfile, strerror(errno));
+    exit(1);
+  }
+  len = 0;
+  memset(data, 0, sizeof(data));
+  while (len < sizeof(data)) {
+    int c1 = fgetc(fp);
+    int c2 = fgetc(fp);
+    if (c1 == '\n' || c1 == EOF || c2 == '\n' || c2 == EOF)
+      break;
+    data[len++] = (hexvalue(c1) << 4 ) + hexvalue(c2);
+  }
+  fclose(fp);
+  get_snk_pass("", secret, sizeof(secret), data);
+  if (! valid_secret_p(secret) ) {
+  get_password:
+    strncpy(password, getpass("Enter SNK passphrase: "), sizeof(password));
+    get_snk_pass(password, secret, sizeof(secret), data);
+    if (! valid_secret_p(secret) ) {
+      fprintf(stderr, "Cannot decode secret key\n");
+      goto get_password;
+    }	  
+  }
+
+  printf ("\n");
+
+ get_password2:
+  strncpy(password, getpass("Enter new passphrase: "), sizeof(password));
+  if ( strcmp(password, getpass("Repeat: ")) != 0  ) {
+    fprintf (stderr, "Passphrases do not match\n");
+    goto get_password2;
+  }
+  
+  memset(data, 0, sizeof(data));
+  put_snk_pass(password, secret, strlen(secret) + 1, data);
+  fp = fopen (outfile, "w");
+  if (fp == NULL) {
+    fprintf (stderr, "Error: Cannot create %s\n", keyfile);
+    exit(1);
+  }
+  if ( chmod(keyfile, S_IRUSR|S_IWUSR) == -1 ) 
+    fprintf (stderr, "Error: cannot set permissions on %s\n", keyfile);
+  for (i=0; i<sizeof(data); i++)
+    fprintf (fp, "%02x", data[i]);
+  fprintf (fp, "\n");
+  fclose(fp);
+  
+}
+  
+  
+	
+int main(int argc, char **argv) {
+  char ch;
+  enum { mWrite, mPasswd, mDefault } mode = mDefault;
+  
+  struct passwd *pwd;
+  pwd = getpwuid(getuid());
+  if (pwd == NULL) {
+    fprintf (stderr, "Error: No valid password entry\n");
+    exit(1);
+  }
+  keyfile = (char *) malloc (strlen(pwd->pw_dir) + 10);
+  snprintf (keyfile, strlen(pwd->pw_dir)+10, "%s/.snk", pwd->pw_dir);
+  outfile = keyfile;
+  
+  while ((ch = getopt(argc, argv, "hwpf:o:")) != -1) {
+    switch (ch) {
+    case 'w': 
+      if (mode != mDefault) {
+	fprintf (stderr, "Error: -w and -p may only be used once.\n");
+	return 1;
+      }
+      mode = mWrite;
+      break;
+    case 'p':
+      if (mode != mDefault) {
+	fprintf (stderr, "Error: -w and -p may only be used once.\n");
+	return 1;
+      }
+      mode = mPasswd;
+      break;      
+    case 'f':
+      keyfile = optarg;
+      break;
+    case 'o':
+      outfile = optarg;
+      break;
+    case '?':
+    case 'h':
+    default:
+      usage();
+      return 1;
+    }
+  }
+  argc -= optind;
+  argv += optind;
+
+  switch (mode) {
+  case mWrite:
+    if (argc != 0) {
+      usage();
+      return 1;
+    }
+    save_snk();
+    break;
+  case mPasswd:
+    if (argc != 0) {
+      usage();
+      return 1;
+    }
+    passwd();
+    break;
+  case mDefault:
+    if (argc == 0) 
+      compute_snk (NULL);
+    else if ( argc == 1 ) 
+      compute_snk (argv[0]);
+    else {
+      usage();
+      return 1;
+    }
+    break;
+  }      
+
+  return 0;
+
+}
diff -NuBw openssh-2.9p1/sshconnect1.c openssh/sshconnect1.c
--- openssh-2.9p1/sshconnect1.c	Tue Apr 17 14:08:16 2001
+++ openssh/sshconnect1.c	Wed Jun  6 17:57:41 2001
@@ -43,6 +43,8 @@
 #include "readpass.h"
 #include "cipher.h"
 #include "canohost.h"
+#include "snk.h" 
+
 
 /* Session id for the current session. */
 u_char session_id[16];
@@ -611,6 +613,8 @@
 
 #endif /* AFS */
 
+#define hexvalue(c) ((tolower(c) < 'a') ? (tolower(c) - '0') : (tolower(c) - 'a' + 10))
+
 /*
  * Tries to authenticate with any string-based challenge/response system.
  * Note that the client code is not tied to s/key or TIS.
@@ -624,6 +628,9 @@
 	char prompt[1024];
 	char *challenge, *response;
 
+	char *octchal, *p, *q;
+
+
 	debug("Doing challenge reponse authentication.");
 
 	for (i = 0; i < options.number_of_password_prompts; i++) {
@@ -644,6 +651,51 @@
 		}
 		challenge = packet_get_string(&clen);
 		packet_integrity_check(payload_len, (4 + clen), type);
+
+		if (options.snk_keyfile != NULL) {
+		  FILE *fp; 
+		  int len;
+		  unsigned char data[48];
+		  char secret[256];
+		  char *password;
+
+		  octchal = (char *) xmalloc (clen);
+		  memset (octchal, 0, clen);
+		  for (p = challenge, q = octchal; *p; p++)
+		    if ('0' <= *p && *p <= '9')
+		      *q++ = *p;
+		  debug  ("SNK challenge is %s", octchal); 
+
+		  fp = fopen (options.snk_keyfile, "r");
+		  if (fp == NULL) {
+		    debug ("Cannot open SNK keyfile: %s", options.snk_keyfile);
+		    return 0;
+		  }
+		  len = 0;
+		  memset(data, 0, sizeof(data));
+		  while (len < sizeof(data)) {
+		    int c1 = fgetc(fp);
+		    int c2 = fgetc(fp);
+		    if (c1 == '\n' || c1 == EOF || c2 == '\n' || c2 == EOF)
+		      break;
+		    data[len++] = (hexvalue(c1) << 4 ) + hexvalue(c2);
+		  }
+		  fclose(fp);
+
+		  get_snk_pass("", secret, sizeof(secret), data);
+		  if (! valid_secret_p(secret) ) {
+		    password = read_passphrase("Enter passphrase for SNK secret:", 0);
+		    get_snk_pass(password, secret, sizeof(secret), data);
+		    xfree (password);
+		    if (! valid_secret_p(secret) ) {
+		      error("Cannot decode user SNK secret");
+		      return 0;
+		    }	  
+		  }
+		  response = (char *) xmalloc (256);
+		  do_snk(octchal, secret, response);
+		  debug ("SNK response is %s", response);
+		} else {
 		snprintf(prompt, sizeof prompt, "%s%s", challenge,
 		     strchr(challenge, '\n') ? "" : "\nResponse: ");
 		xfree(challenge);
@@ -657,6 +709,7 @@
 			xfree(response);
 			break;
 		}
+		}
 		packet_start(SSH_CMSG_AUTH_TIS_RESPONSE);
 		ssh_put_password(response);
 		memset(response, 0, strlen(response));


More information about the openssh-unix-dev mailing list