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));