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