From 511d967d256f37cab8c7bd71e04f36c947bde551 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Mon, 11 May 2015 18:34:45 +0100 Subject: [PATCH] Unix Pageant: first draft of -l key list option. It doesn't look very pretty at the moment, but it lists the keys and gets the fingerprints right. --- pageant.c | 137 ++++++++++++++++++++++++++++++++++++++++++++++++++ pageant.h | 5 ++ unix/uxpgnt.c | 15 +++++- 3 files changed, 156 insertions(+), 1 deletion(-) diff --git a/pageant.c b/pageant.c index 51baab02..8f0747cb 100644 --- a/pageant.c +++ b/pageant.c @@ -1582,3 +1582,140 @@ int pageant_add_keyfile(Filename *filename, const char *passphrase, } return PAGEANT_ACTION_OK; } + +int pageant_enum_keys(pageant_key_enum_fn_t callback, void *callback_ctx, + char **retstr) +{ + unsigned char *keylist, *p; + int i, nkeys, keylistlen; + char *comment; + + keylist = pageant_get_keylist1(&keylistlen); + if (keylistlen < 4) { + *retstr = dupstr("Received broken SSH-1 key list from agent"); + sfree(keylist); + return PAGEANT_ACTION_FAILURE; + } + nkeys = toint(GET_32BIT(keylist)); + if (nkeys < 0) { + *retstr = dupstr("Received broken SSH-1 key list from agent"); + sfree(keylist); + return PAGEANT_ACTION_FAILURE; + } + p = keylist + 4; + keylistlen -= 4; + + for (i = 0; i < nkeys; i++) { + struct RSAKey rkey; + char fingerprint[128]; + int n; + + /* public blob and fingerprint */ + memset(&rkey, 0, sizeof(rkey)); + n = makekey(p, keylistlen, &rkey, NULL, 0); + if (n < 0 || n > keylistlen) { + freersakey(&rkey); + *retstr = dupstr("Received broken SSH-1 key list from agent"); + sfree(keylist); + return PAGEANT_ACTION_FAILURE; + } + p += n, keylistlen -= n; + rsa_fingerprint(fingerprint, sizeof(fingerprint), &rkey); + + /* comment */ + if (keylistlen < 4) { + *retstr = dupstr("Received broken SSH-1 key list from agent"); + freersakey(&rkey); + sfree(keylist); + return PAGEANT_ACTION_FAILURE; + } + n = toint(GET_32BIT(p)); + p += 4, keylistlen -= 4; + if (n < 0 || keylistlen < n) { + *retstr = dupstr("Received broken SSH-1 key list from agent"); + freersakey(&rkey); + sfree(keylist); + return PAGEANT_ACTION_FAILURE; + } + comment = dupprintf("%.*s", (int)n, (const char *)p); + p += n, keylistlen -= n; + + callback(callback_ctx, fingerprint, comment); + freersakey(&rkey); + sfree(comment); + } + + sfree(keylist); + + if (keylistlen != 0) { + *retstr = dupstr("Received broken SSH-1 key list from agent"); + return PAGEANT_ACTION_FAILURE; + } + + keylist = pageant_get_keylist2(&keylistlen); + if (keylistlen < 4) { + *retstr = dupstr("Received broken SSH-2 key list from agent"); + sfree(keylist); + return PAGEANT_ACTION_FAILURE; + } + nkeys = toint(GET_32BIT(keylist)); + if (nkeys < 0) { + *retstr = dupstr("Received broken SSH-2 key list from agent"); + sfree(keylist); + return PAGEANT_ACTION_FAILURE; + } + p = keylist + 4; + keylistlen -= 4; + + for (i = 0; i < nkeys; i++) { + char *fingerprint; + int n; + + /* public blob */ + if (keylistlen < 4) { + *retstr = dupstr("Received broken SSH-2 key list from agent"); + sfree(keylist); + return PAGEANT_ACTION_FAILURE; + } + n = toint(GET_32BIT(p)); + p += 4, keylistlen -= 4; + if (n < 0 || keylistlen < n) { + *retstr = dupstr("Received broken SSH-2 key list from agent"); + sfree(keylist); + return PAGEANT_ACTION_FAILURE; + } + fingerprint = fingerprint_ssh2_blob(p, n); + p += n, keylistlen -= n; + + /* comment */ + if (keylistlen < 4) { + *retstr = dupstr("Received broken SSH-2 key list from agent"); + sfree(fingerprint); + sfree(keylist); + return PAGEANT_ACTION_FAILURE; + } + n = toint(GET_32BIT(p)); + p += 4, keylistlen -= 4; + if (n < 0 || keylistlen < n) { + *retstr = dupstr("Received broken SSH-2 key list from agent"); + sfree(fingerprint); + sfree(keylist); + return PAGEANT_ACTION_FAILURE; + } + comment = dupprintf("%.*s", (int)n, (const char *)p); + p += n, keylistlen -= n; + + callback(callback_ctx, fingerprint, comment); + sfree(fingerprint); + sfree(comment); + } + + sfree(keylist); + + if (keylistlen != 0) { + *retstr = dupstr("Received broken SSH-1 key list from agent"); + return PAGEANT_ACTION_FAILURE; + } + + return PAGEANT_ACTION_OK; +} diff --git a/pageant.h b/pageant.h index c1bc854e..ec94a50c 100644 --- a/pageant.h +++ b/pageant.h @@ -120,3 +120,8 @@ enum { int pageant_add_keyfile(Filename *filename, const char *passphrase, char **retstr); void pageant_forget_passphrases(void); +typedef void (*pageant_key_enum_fn_t)(void *ctx, + const char *fingerprint, + const char *comment); +int pageant_enum_keys(pageant_key_enum_fn_t callback, void *callback_ctx, + char **retstr); diff --git a/unix/uxpgnt.c b/unix/uxpgnt.c index 61517097..4d2aa08e 100644 --- a/unix/uxpgnt.c +++ b/unix/uxpgnt.c @@ -354,10 +354,16 @@ static int unix_add_keyfile(const char *filename_str) return ret; } +void key_list_callback(void *ctx, const char *fingerprint, const char *comment) +{ + printf("%s %s\n", fingerprint, comment); +} + void run_client(void) { const struct cmdline_key_action *act; int errors = FALSE; + char *retstr; if (!agent_exists()) { fprintf(stderr, "pageant: no agent running to talk to\n"); @@ -370,9 +376,16 @@ void run_client(void) if (!unix_add_keyfile(act->filename)) errors = TRUE; break; + case KEYACT_CLIENT_LIST: + if (pageant_enum_keys(key_list_callback, NULL, &retstr) == + PAGEANT_ACTION_FAILURE) { + fprintf(stderr, "pageant: listing keys: %s\n", retstr); + sfree(retstr); + errors = TRUE; + } + break; case KEYACT_CLIENT_DEL: case KEYACT_CLIENT_DEL_ALL: - case KEYACT_CLIENT_LIST: case KEYACT_CLIENT_LIST_FULL: fprintf(stderr, "NYI\n"); errors = TRUE;