/* * Return a malloc'ed chunk of memory containing the public blob of * an RSA key, as given in the agent protocol (modulus bits, * exponent, modulus). */ int rsakey_pubblob(const Filename *filename, void **blob, int *bloblen, char **commentptr, const char **errorstr) { FILE *fp; char buf[64]; struct RSAKey key; int ret; const char *error = NULL; /* Default return if we fail. */ *blob = NULL; *bloblen = 0; ret = 0; fp = f_open(filename, "rb", FALSE); if (!fp) { error = "can't open file"; goto end; } /* * Read the first line of the file and see if it's a v1 private * key file. */ if (fgets(buf, sizeof(buf), fp) && !strcmp(buf, rsa_signature)) { memset(&key, 0, sizeof(key)); if (loadrsakey_main(fp, &key, TRUE, commentptr, NULL, &error)) { *blob = rsa_public_blob(&key, bloblen); freersakey(&key); ret = 1; } fp = NULL; /* loadrsakey_main unconditionally closes fp */ } else { error = "not an SSH-1 RSA file"; } end: if (fp) fclose(fp); if ((ret != 1) && errorstr) *errorstr = error; return ret; }
static int loadrsakey_main(FILE * fp, struct RSAKey *key, int pub_only, char **commentptr, char *passphrase, const char **error) { unsigned char buf[16384]; unsigned char keybuf[16]; int len; int i, j, ciphertype; int ret = 0; struct MD5Context md5c; char *comment; *error = NULL; /* Slurp the whole file (minus the header) into a buffer. */ len = fread(buf, 1, sizeof(buf), fp); fclose(fp); if (len < 0 || len == sizeof(buf)) { *error = "error reading file"; goto end; /* file too big or not read */ } i = 0; *error = "file format error"; /* * A zero byte. (The signature includes a terminating NUL.) */ if (len - i < 1 || buf[i] != 0) goto end; i++; /* One byte giving encryption type, and one reserved uint32. */ if (len - i < 1) goto end; ciphertype = buf[i]; if (ciphertype != 0 && ciphertype != SSH_CIPHER_3DES) goto end; i++; if (len - i < 4) goto end; /* reserved field not present */ if (buf[i] != 0 || buf[i + 1] != 0 || buf[i + 2] != 0 || buf[i + 3] != 0) goto end; /* reserved field nonzero, panic! */ i += 4; /* Now the serious stuff. An ordinary SSH-1 public key. */ j = makekey(buf + i, len - i, key, NULL, 1); if (j < 0) goto end; /* overran */ i += j; /* Next, the comment field. */ j = toint(GET_32BIT(buf + i)); i += 4; if (j < 0 || len - i < j) goto end; comment = snewn(j + 1, char); if (comment) { memcpy(comment, buf + i, j); comment[j] = '\0'; } i += j; if (commentptr) *commentptr = dupstr(comment); if (key) key->comment = comment; else sfree(comment); if (pub_only) { ret = 1; goto end; } if (!key) { ret = ciphertype != 0; *error = NULL; goto end; } /* * Decrypt remainder of buffer. */ if (ciphertype) { MD5Init(&md5c); MD5Update(&md5c, (unsigned char *)passphrase, strlen(passphrase)); MD5Final(keybuf, &md5c); des3_decrypt_pubkey(keybuf, buf + i, (len - i + 7) & ~7); smemclr(keybuf, sizeof(keybuf)); /* burn the evidence */ } /* * We are now in the secret part of the key. The first four * bytes should be of the form a, b, a, b. */ if (len - i < 4) goto end; if (buf[i] != buf[i + 2] || buf[i + 1] != buf[i + 3]) { *error = "wrong passphrase"; ret = -1; goto end; } i += 4; /* * After that, we have one further bignum which is our * decryption exponent, and then the three auxiliary values * (iqmp, q, p). */ j = makeprivate(buf + i, len - i, key); if (j < 0) goto end; i += j; j = ssh1_read_bignum(buf + i, len - i, &key->iqmp); if (j < 0) goto end; i += j; j = ssh1_read_bignum(buf + i, len - i, &key->q); if (j < 0) goto end; i += j; j = ssh1_read_bignum(buf + i, len - i, &key->p); if (j < 0) goto end; i += j; if (!rsa_verify(key)) { *error = "rsa_verify failed"; freersakey(key); ret = 0; } else ret = 1; end: smemclr(buf, sizeof(buf)); /* burn the evidence */ return ret; }
static void rsa2_freekey(void *key) { struct RSAKey *rsa = (struct RSAKey *) key; freersakey(rsa); sfree(rsa); }
/* * Return a malloc'ed chunk of memory containing the public blob of * an RSA key, as given in the agent protocol (modulus bits, * exponent, modulus). */ int rsakey_pubblob(const Filename *filename, void **blob, int *bloblen, char **commentptr, const char **errorstr) { FILE *fp; char buf[64]; struct RSAKey key; int ret; const char *error = NULL; /* Default return if we fail. */ *blob = NULL; *bloblen = 0; ret = 0; fp = f_open(filename, "rb", FALSE); if (!fp) { error = "can't open file"; goto end; } /* * Read the first line of the file and see if it's a v1 private * key file. */ if (fgets(buf, sizeof(buf), fp) && !strcmp(buf, rsa_signature)) { memset(&key, 0, sizeof(key)); if (loadrsakey_main(fp, &key, TRUE, commentptr, NULL, &error)) { *blob = rsa_public_blob(&key, bloblen); freersakey(&key); ret = 1; } fp = NULL; /* loadrsakey_main unconditionally closes fp */ } else { /* * Try interpreting the file as an SSH-1 public key. */ char *line, *p, *bitsp, *expp, *modp, *commentp; rewind(fp); line = chomp(fgetline(fp)); p = line; bitsp = p; p += strspn(p, "0123456789"); if (*p != ' ') goto not_public_either; *p++ = '\0'; expp = p; p += strspn(p, "0123456789"); if (*p != ' ') goto not_public_either; *p++ = '\0'; modp = p; p += strspn(p, "0123456789"); if (*p) { if (*p != ' ') goto not_public_either; *p++ = '\0'; commentp = p; } else { commentp = NULL; } memset(&key, 0, sizeof(key)); key.exponent = bignum_from_decimal(expp); key.modulus = bignum_from_decimal(modp); if (atoi(bitsp) != bignum_bitcount(key.modulus)) { freebn(key.exponent); freebn(key.modulus); sfree(line); error = "key bit count does not match in SSH-1 public key file"; goto end; } if (commentptr) *commentptr = commentp ? dupstr(commentp) : NULL; *blob = rsa_public_blob(&key, bloblen); freersakey(&key); return 1; not_public_either: sfree(line); error = "not an SSH-1 RSA file"; } end: if (fp) fclose(fp); if ((ret != 1) && errorstr) *errorstr = error; return ret; }
int main(int argc, char **argv) { Filename *infilename = NULL, *outfilename = NULL; int intype = SSH_KEYTYPE_UNOPENABLE; int encrypted = 0; char* origcomment = 0; char* line = 0; char* passphrase = 0; struct ssh2_userkey *ssh2key = NULL; struct RSAKey *ssh1key = NULL; printf("fzputtygen\n"); printf("Copyright (C) 2008-2015 Tim Kosse\n"); printf("Based on PuTTY's puttygen\n"); printf("Copyright (C) 1997-2015 Simon Tatham and the PuTTY team\n"); printf("Converts private SSH keys into PuTTY's format.\n"); printf("This program is used by FileZilla and not intended to be used directly.\n"); printf("Use the puttygen tool from PuTTY for a human-usable tool.\n"); printf("\n"); fflush(stdout); while (1) { if (line) sfree(line); line = fgetline(stdin); if (!line || !*line || *line == '\n') break; line[strlen(line) - 1] = 0; char* cmd = line, *args = line; while (*args) { if (*args == ' ') { *(args++) = 0; break; } args++; } if (!*args) args = 0; if (!strcmp(cmd, "file")) { if (ssh1key) { freersakey(ssh1key); ssh1key = 0; } if (ssh2key) { ssh2key->alg->freekey(ssh2key->data); sfree(ssh2key); ssh2key = 0; } if (passphrase) { sfree(passphrase); passphrase = 0; } if (!args) { fzprintf(sftpError, "No argument given"); continue; } infilename = filename_from_str(args); intype = key_type(infilename); switch (intype) { case SSH_KEYTYPE_SSH1: case SSH_KEYTYPE_SSH2: fzprintf(sftpReply, "0"); break; case SSH_KEYTYPE_UNKNOWN: case SSH_KEYTYPE_UNOPENABLE: default: fzprintf(sftpReply, "2"); intype = SSH_KEYTYPE_UNOPENABLE; break; case SSH_KEYTYPE_OPENSSH: case SSH_KEYTYPE_SSHCOM: fzprintf(sftpReply, "1"); break; } } else if (!strcmp(cmd, "encrypted")) { if (intype == SSH_KEYTYPE_UNOPENABLE) { fzprintf(sftpError, "No keyfile opened"); continue; } if (intype == SSH_KEYTYPE_SSH1) encrypted = rsakey_encrypted(infilename, &origcomment); else if (intype == SSH_KEYTYPE_SSH2) encrypted = ssh2_userkey_encrypted(infilename, &origcomment); else encrypted = import_encrypted(infilename, intype, &origcomment); fzprintf(sftpReply, "%d", encrypted ? 1 : 0); } else if (!strcmp(cmd, "comment")) { if (intype == SSH_KEYTYPE_UNOPENABLE) { fzprintf(sftpError, "No keyfile opened"); continue; } if (origcomment) fzprintf(sftpReply, "%s", origcomment); else fzprintf(sftpReply, ""); } else if (!strcmp(cmd, "password")) { if (!args) { fzprintf(sftpError, "No argument given"); continue; } if (intype == SSH_KEYTYPE_UNOPENABLE) { fzprintf(sftpError, "No keyfile opened"); continue; } if (passphrase) sfree(passphrase); passphrase = strdup(args); fzprintf(sftpReply, ""); } else if (!strcmp(cmd, "load")) { const char* error = 0; if (ssh1key) { freersakey(ssh1key); ssh1key = 0; } if (ssh2key) { ssh2key->alg->freekey(ssh2key->data); sfree(ssh2key); ssh2key = 0; } if (intype == SSH_KEYTYPE_UNOPENABLE) { fzprintf(sftpError, "No keyfile opened"); continue; } if (encrypted && !passphrase) { fzprintf(sftpError, "No password given"); continue; } switch (intype) { int ret; case SSH_KEYTYPE_SSH1: ssh1key = snew(struct RSAKey); ret = loadrsakey(infilename, ssh1key, passphrase, &error); if (ret > 0) error = NULL; else if (!error) error = "unknown error"; break; case SSH_KEYTYPE_SSH2: ssh2key = ssh2_load_userkey(infilename, passphrase, &error); if (ssh2key == SSH2_WRONG_PASSPHRASE) { error = "wrong passphrase"; ssh2key = 0; } else if (ssh2key) error = NULL; else if (!error) error = "unknown error"; break; case SSH_KEYTYPE_OPENSSH: case SSH_KEYTYPE_SSHCOM: ssh2key = import_ssh2(infilename, intype, passphrase, &error); if (ssh2key) { if (ssh2key != SSH2_WRONG_PASSPHRASE) error = NULL; else { ssh2key = NULL; error = "wrong passphrase"; } } else if (!error) error = "unknown error"; break; default: assert(0); } if (error) fzprintf(sftpError, "Error loading file: %s", error); else fzprintf(sftpReply, ""); } else if (!strcmp(cmd, "data")) { if (!ssh1key && !ssh2key) { fzprintf(sftpError, "No key loaded"); continue; } if (ssh1key) { char data[512]; char* p; strcpy(data, "ssh1 "); p = data + strlen(data); rsa_fingerprint(p, sizeof(data) - (p - data), ssh1key); fzprintf(sftpReply, "%s", data); continue; } if (ssh2key) { char* fingerprint = ssh2key->alg->fingerprint(ssh2key->data); if (fingerprint) { fzprintf(sftpReply, "%s", fingerprint); continue; } } fzprintf(sftpReply, ""); } else if (!strcmp(cmd, "write")) { int ret; if (!args) { fzprintf(sftpError, "No argument given"); continue; } if (!ssh1key && !ssh2key) { fzprintf(sftpError, "No key loaded"); continue; } outfilename = filename_from_str(args); if (ssh1key) { ret = saversakey(outfilename, ssh1key, 0); if (!ret) { fzprintf(sftpError, "Unable to save SSH-1 private key"); continue; } } else if (ssh2key) { ret = ssh2_save_userkey(outfilename, ssh2key, 0); if (!ret) { fzprintf(sftpError, "Unable to save SSH-2 private key"); continue; } } fzprintf(sftpReply, ""); } else fzprintf(sftpError, "Unknown command"); }
/* * Dialog-box function for the key list box. */ static INT_PTR CALLBACK KeyListProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { struct RSAKey *rkey; struct ssh2_userkey *skey; switch (msg) { case WM_INITDIALOG: /* * Centre the window. */ { /* centre the window */ RECT rs, rd; HWND hw; hw = GetDesktopWindow(); if (GetWindowRect(hw, &rs) && GetWindowRect(hwnd, &rd)) MoveWindow(hwnd, (rs.right + rs.left + rd.left - rd.right) / 2, (rs.bottom + rs.top + rd.top - rd.bottom) / 2, rd.right - rd.left, rd.bottom - rd.top, TRUE); } if (has_help()) SetWindowLongPtr(hwnd, GWL_EXSTYLE, GetWindowLongPtr(hwnd, GWL_EXSTYLE) | WS_EX_CONTEXTHELP); else { HWND item = GetDlgItem(hwnd, 103); /* the Help button */ if (item) DestroyWindow(item); } keylist = hwnd; { static int tabs[] = {35, 75, 250}; SendDlgItemMessage(hwnd, 100, LB_SETTABSTOPS, sizeof(tabs) / sizeof(*tabs), (LPARAM)tabs); } keylist_update(); return 0; case WM_COMMAND: switch (LOWORD(wParam)) { case IDOK: case IDCANCEL: keylist = NULL; DestroyWindow(hwnd); return 0; case 101: /* add key */ if (HIWORD(wParam) == BN_CLICKED || HIWORD(wParam) == BN_DOUBLECLICKED) { if (passphrase_box) { MessageBeep(MB_ICONERROR); SetForegroundWindow(passphrase_box); break; } prompt_add_keyfile(); } return 0; case 102: /* remove key */ if (HIWORD(wParam) == BN_CLICKED || HIWORD(wParam) == BN_DOUBLECLICKED) { int i; int rCount, sCount; int *selectedArray; /* our counter within the array of selected items */ int itemNum; /* get the number of items selected in the list */ int numSelected = SendDlgItemMessage(hwnd, 100, LB_GETSELCOUNT, 0, 0); /* none selected? that was silly */ if (numSelected == 0) { MessageBeep(0); break; } /* get item indices in an array */ selectedArray = snewn(numSelected, int); SendDlgItemMessage( hwnd, 100, LB_GETSELITEMS, numSelected, (WPARAM)selectedArray); itemNum = numSelected - 1; rCount = pageant_count_ssh1_keys(); sCount = pageant_count_ssh2_keys(); /* go through the non-rsakeys until we've covered them all, * and/or we're out of selected items to check. note that * we go *backwards*, to avoid complications from deleting * things hence altering the offset of subsequent items */ for (i = sCount - 1; (itemNum >= 0) && (i >= 0); i--) { skey = pageant_nth_ssh2_key(i); if (selectedArray[itemNum] == rCount + i) { pageant_delete_ssh2_key(skey); skey->alg->freekey(skey->data); sfree(skey); itemNum--; } } /* do the same for the rsa keys */ for (i = rCount - 1; (itemNum >= 0) && (i >= 0); i--) { rkey = pageant_nth_ssh1_key(i); if (selectedArray[itemNum] == i) { pageant_delete_ssh1_key(rkey); freersakey(rkey); sfree(rkey); itemNum--; } } sfree(selectedArray); keylist_update(); } return 0; case 103: /* help */ if (HIWORD(wParam) == BN_CLICKED || HIWORD(wParam) == BN_DOUBLECLICKED) { launch_help(hwnd, WINHELP_CTX_pageant_general); } return 0; } return 0; case WM_HELP: { int id = ((LPHELPINFO)lParam)->iCtrlId; const char *topic = NULL; switch (id) { case 100: topic = WINHELP_CTX_pageant_keylist; break; case 101: topic = WINHELP_CTX_pageant_addkey; break; case 102: topic = WINHELP_CTX_pageant_remkey; break; } if (topic) { launch_help(hwnd, topic); } else { MessageBeep(0); } } break; case WM_CLOSE: keylist = NULL; DestroyWindow(hwnd); return 0; }
static void rsa2_freekey(ssh_key *key) { RSAKey *rsa = container_of(key, RSAKey, sshk); freersakey(rsa); sfree(rsa); }