From 2007a49ed948d6501b67985f88296d470933ed2e Mon Sep 17 00:00:00 2001 From: owen Date: Sun, 6 Feb 2005 15:00:36 +0000 Subject: [PATCH] First stab at a host key cache on the Mac. git-svn-id: svn://svn.tartarus.org/sgt/putty@5260 cda61777-01e9-0310-a592-d414129be87e --- mac/mac.c | 36 +++++++++++++----- mac/mac.h | 3 ++ mac/macstore.c | 118 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 147 insertions(+), 10 deletions(-) diff --git a/mac/mac.c b/mac/mac.c index a2e89f91..d621b914 100644 --- a/mac/mac.c +++ b/mac/mac.c @@ -696,6 +696,7 @@ void verify_ssh_host_key(void *frontend, char *host, int port, char *keytype, { Str255 stuff; Session *s = frontend; + int ret; /* * This function is horribly wrong. For one thing, the alert @@ -703,23 +704,40 @@ void verify_ssh_host_key(void *frontend, char *host, int port, char *keytype, * Aqua. Also, PuTTY might be in the background, in which case we * should use the Notification Manager to wake up the user. In * any case, we shouldn't hold up processing of other connections' - * data just because this one's waiting for the user. It should - * also handle a host key cache, of course, and see the note below - * about closing the connection. All in all, a bit of a mess - * really. + * data just because this one's waiting for the user. Also see the + * note below about closing the connection. All in all, a bit of + * a mess really. */ - stuff[0] = sprintf((char *)(&stuff[1]), - "The server's key fingerprint is: %s\n" - "Continue connecting?", fingerprint); - ParamText(stuff, NULL, NULL, NULL); + /* Verify the key against the cache */ + + ret = verify_host_key(host, port, keytype, keystr); + + if (ret == 0) /* success - key matched OK */ + return; + if (ret == 2) { /* key was different */ + stuff[0] = sprintf((char *)(&stuff[1]), + "WARNING - POTENTIAL SECURITY BREACH\n", + "The key fingerprint is: %s\n" + "Continue connecting?", fingerprint); + ParamText(stuff, NULL, NULL, NULL); + } + if (ret == 1) { /* key was absent */ + stuff[0] = sprintf((char *)(&stuff[1]), + "The server's key fingerprint is: %s\n" + "Continue connecting?", fingerprint); + ParamText(stuff, NULL, NULL, NULL); + } + if (CautionAlert(wQuestion, NULL) == 2) { /* * User chose "Cancel". Unfortunately, if I tear the * connection down here, Bad Things happen when I return. I * think this function should actually return something * telling the SSH code to abandon the connection. - */ + */ + } else { + store_host_key(host, port, keytype, keystr); } } diff --git a/mac/mac.h b/mac/mac.h index ec4835f9..8a0c7f13 100644 --- a/mac/mac.h +++ b/mac/mac.h @@ -21,6 +21,7 @@ #define INTERNAL_CREATOR FOUR_CHAR_CODE('pTTI') #define SESS_TYPE FOUR_CHAR_CODE('Sess') #define SEED_TYPE FOUR_CHAR_CODE('Seed') +#define HKYS_TYPE FOUR_CHAR_CODE('Hkys') struct mac_gestalts { long sysvers; @@ -167,6 +168,8 @@ extern OSErr get_putty_dir(Boolean makeit, short *pVRefNum, long *pDirID); extern OSErr get_session_dir(Boolean makeit, short *pVRefNum, long *pDirID); extern void *open_settings_r_fsp(FSSpec *); extern void *open_settings_w_fsp(FSSpec *); +extern int verify_host_key(const char *, int, const char *, const char*); +extern void store_host_key(const char *, int, const char *, const char*); /* from macucs.c */ extern void init_ucs(Session *); /* from macnet.c */ diff --git a/mac/macstore.c b/mac/macstore.c index 548b7ac2..7643c548 100644 --- a/mac/macstore.c +++ b/mac/macstore.c @@ -1,4 +1,4 @@ -/* $Id: macstore.c,v 1.19 2003/04/01 18:10:25 simon Exp $ */ +/* $Id$ */ /* * macstore.c: Macintosh-specific impementation of the interface @@ -602,6 +602,122 @@ void write_random_seed(void *data, int len) return; } +int verify_host_key(const char *hostname, int port, + const char *keytype, const char *key) +{ + short puttyVRefNum; + long puttyDirID; + OSErr error; + FSSpec keyfile; + short refnum; + char *resname; + Str255 presname; + char *resvalue; + Handle reshandle; + int len, compare; + + if (get_putty_dir(kCreateFolder, &puttyVRefNum, &puttyDirID) != noErr) + return 1; + + error = FSMakeFSSpec(puttyVRefNum, puttyDirID, "\pSSH Host Keys", + &keyfile); + if (error == fnfErr) { + /* Keys file doesn't exist yet, so we can't match the key */ + return 1; + } + + refnum = FSpOpenResFile(&keyfile, fsRdPerm); + + if (refnum == -1) { + /* We couldn't open the resource fork, so we can't match the key */ + return 1; + } + + UseResFile(refnum); + + resname = dupprintf("%s@%d:%s", keytype, port, hostname); + c2pstrcpy(presname, resname); + reshandle = Get1NamedResource(FOUR_CHAR_CODE('TEXT'), presname); + if (ResError() != noErr) { + /* Couldn't open the specific resource */ + return 1; + } + + len = GetHandleSize(reshandle); + resvalue = snewn(len+1, char); + memcpy(resvalue, *reshandle, len); + resvalue[len]='\0'; + ReleaseResource(reshandle); + CloseResFile(refnum); + + compare = strncmp(resvalue, key, strlen(resvalue)); + sfree(resname); + sfree(resvalue); + + if (compare) { + /* Key different */ + return 2; + } else { + /* Key matched */ + return 0; + } +} + +void store_host_key(const char *hostname, int port, + const char *keytype, const char *key) +{ + short puttyVRefNum; + long puttyDirID; + OSErr error; + FSSpec keyfile; + short keyrefnum; + char *resname; + Str255 presname; + Handle resvalue; + int id; + + /* Open the host key file */ + + if (get_putty_dir(~kCreateFolder, &puttyVRefNum, &puttyDirID) != noErr) + goto out; + + error = FSMakeFSSpec(puttyVRefNum, puttyDirID, "\pSSH Host Keys", + &keyfile); + if (error == fnfErr) { + /* It doesn't exist, so create it */ + FSpCreateResFile(&keyfile, INTERNAL_CREATOR, HKYS_TYPE, smRoman); + keyrefnum = FSpOpenResFile(&keyfile, fsWrPerm); + if (ResError() == noErr) { + copy_resource('STR', -16397); /* XXX: wtf is this? */ + CloseResFile(keyrefnum); + } + } else if (error != noErr) goto out; + + keyrefnum = FSpOpenResFile(&keyfile, fsWrPerm); + if (keyrefnum == -1) goto out; + + UseResFile(keyrefnum); + resname = dupprintf("%s@%d:%s", keytype, port, hostname); + c2pstrcpy(presname, resname); + + error = PtrToHand(key, &resvalue, strlen(key)); + if (error != noErr) goto out; + + id = Unique1ID(FOUR_CHAR_CODE('TEXT')); + if (ResError() != noErr) goto out; + AddResource(resvalue, FOUR_CHAR_CODE('TEXT'), id, presname); + if (ResError() != noErr) goto out; + + CloseResFile(keyrefnum); + return; + + out: + fatalbox("Writing host key failed (%d)", error); + sfree(resname); +} + + + /* * Emacs magic: * Local Variables: -- 2.11.0