diff --git a/cmdgen.c b/cmdgen.c index e5a43c1f..ea60c25f 100644 --- a/cmdgen.c +++ b/cmdgen.c @@ -160,6 +160,10 @@ void help(void) " -O specify output type:\n" " private output PuTTY private key format\n" " private-openssh export OpenSSH private key\n" + " private-openssh-pem export OpenSSH private key " + "(force old PEM format)\n" + " private-openssh-new export OpenSSH private key " + "(force new format)\n" " private-sshcom export ssh.com private key\n" " public standard / ssh.com public key\n" " public-openssh OpenSSH public key\n" @@ -267,7 +271,8 @@ int main(int argc, char **argv) Filename *infilename = NULL, *outfilename = NULL; enum { NOKEYGEN, RSA1, RSA2, DSA, ECDSA } keytype = NOKEYGEN; char *outfile = NULL, *outfiletmp = NULL; - enum { PRIVATE, PUBLIC, PUBLICO, FP, OPENSSH, SSHCOM } outtype = PRIVATE; + enum { PRIVATE, PUBLIC, PUBLICO, FP, OPENSSH_PEM, + OPENSSH_NEW, SSHCOM } outtype = PRIVATE; int bits = 2048; char *comment = NULL, *origcomment = NULL; int change_passphrase = FALSE; @@ -460,8 +465,11 @@ int main(int argc, char **argv) outtype = PRIVATE; else if (!strcmp(p, "fingerprint")) outtype = FP; - else if (!strcmp(p, "private-openssh")) - outtype = OPENSSH, sshver = 2; + else if (!strcmp(p, "private-openssh") || + !strcmp(p, "private-openssh-pem")) + outtype = OPENSSH_PEM, sshver = 2; + else if (!strcmp(p, "private-openssh-new")) + outtype = OPENSSH_NEW, sshver = 2; else if (!strcmp(p, "private-sshcom")) outtype = SSHCOM, sshver = 2; else { @@ -536,7 +544,8 @@ int main(int argc, char **argv) * We must save the private part when generating a new key. */ if (keytype != NOKEYGEN && - (outtype != PRIVATE && outtype != OPENSSH && outtype != SSHCOM)) { + (outtype != PRIVATE && outtype != OPENSSH_PEM && + outtype != OPENSSH_NEW && outtype != SSHCOM)) { fprintf(stderr, "puttygen: this would generate a new key but " "discard the private part\n"); return 1; @@ -590,7 +599,8 @@ int main(int argc, char **argv) break; case SSH_KEYTYPE_SSH2: - case SSH_KEYTYPE_OPENSSH: + case SSH_KEYTYPE_OPENSSH_PEM: + case SSH_KEYTYPE_OPENSSH_NEW: case SSH_KEYTYPE_SSHCOM: if (sshver == 1) { fprintf(stderr, "puttygen: conversion from SSH-2 to SSH-1 keys" @@ -614,7 +624,8 @@ int main(int argc, char **argv) */ if ((intype == SSH_KEYTYPE_SSH1 && outtype == PRIVATE) || (intype == SSH_KEYTYPE_SSH2 && outtype == PRIVATE) || - (intype == SSH_KEYTYPE_OPENSSH && outtype == OPENSSH) || + (intype == SSH_KEYTYPE_OPENSSH_PEM && outtype == OPENSSH_PEM) || + (intype == SSH_KEYTYPE_OPENSSH_NEW && outtype == OPENSSH_NEW) || (intype == SSH_KEYTYPE_SSHCOM && outtype == SSHCOM)) { if (!outfile) { outfile = infile; @@ -632,7 +643,8 @@ int main(int argc, char **argv) * Bomb out rather than automatically choosing to write * a private key file to stdout. */ - if (outtype==PRIVATE || outtype==OPENSSH || outtype==SSHCOM) { + if (outtype == PRIVATE || outtype == OPENSSH_PEM || + outtype == OPENSSH_NEW || outtype == SSHCOM) { fprintf(stderr, "puttygen: need to specify an output file\n"); return 1; } @@ -645,8 +657,11 @@ int main(int argc, char **argv) * out a private key format, or (b) the entire input key file * is encrypted. */ - if (outtype == PRIVATE || outtype == OPENSSH || outtype == SSHCOM || - intype == SSH_KEYTYPE_OPENSSH || intype == SSH_KEYTYPE_SSHCOM) + if (outtype == PRIVATE || outtype == OPENSSH_PEM || + outtype == OPENSSH_NEW || outtype == SSHCOM || + intype == SSH_KEYTYPE_OPENSSH_PEM || + intype == SSH_KEYTYPE_OPENSSH_NEW || + intype == SSH_KEYTYPE_SSHCOM) load_encrypted = TRUE; else load_encrypted = FALSE; @@ -831,7 +846,8 @@ int main(int argc, char **argv) } break; - case SSH_KEYTYPE_OPENSSH: + case SSH_KEYTYPE_OPENSSH_PEM: + case SSH_KEYTYPE_OPENSSH_NEW: case SSH_KEYTYPE_SSHCOM: ssh2key = import_ssh2(infilename, intype, passphrase, &error); if (ssh2key) { @@ -1052,19 +1068,25 @@ int main(int argc, char **argv) } break; - case OPENSSH: + case OPENSSH_PEM: + case OPENSSH_NEW: case SSHCOM: assert(sshver == 2); assert(ssh2key); random_ref(); /* both foreign key types require randomness, * for IV or padding */ switch (outtype) { - case OPENSSH: - real_outtype = SSH_KEYTYPE_OPENSSH; + case OPENSSH_PEM: + real_outtype = SSH_KEYTYPE_OPENSSH_PEM; + break; + case OPENSSH_NEW: + real_outtype = SSH_KEYTYPE_OPENSSH_NEW; break; case SSHCOM: real_outtype = SSH_KEYTYPE_SSHCOM; break; + default: + assert(0 && "control flow goof"); } ret = export_ssh2(outfilename, real_outtype, ssh2key, passphrase); if (!ret) { diff --git a/import.c b/import.c index 2c0157d5..ce3887df 100644 --- a/import.c +++ b/import.c @@ -15,8 +15,10 @@ int openssh_encrypted(const Filename *filename); struct ssh2_userkey *openssh_read(const Filename *filename, char *passphrase, const char **errmsg_p); -int openssh_write(const Filename *filename, struct ssh2_userkey *key, - char *passphrase); +int openssh_pem_write(const Filename *filename, struct ssh2_userkey *key, + char *passphrase); +int openssh_new_write(const Filename *filename, struct ssh2_userkey *key, + char *passphrase); int sshcom_encrypted(const Filename *filename, char **comment); struct ssh2_userkey *sshcom_read(const Filename *filename, char *passphrase, @@ -29,7 +31,9 @@ int sshcom_write(const Filename *filename, struct ssh2_userkey *key, */ int import_possible(int type) { - if (type == SSH_KEYTYPE_OPENSSH) + if (type == SSH_KEYTYPE_OPENSSH_PEM) + return 1; + if (type == SSH_KEYTYPE_OPENSSH_NEW) return 1; if (type == SSH_KEYTYPE_SSHCOM) return 1; @@ -54,7 +58,7 @@ int import_target_type(int type) */ int import_encrypted(const Filename *filename, int type, char **comment) { - if (type == SSH_KEYTYPE_OPENSSH) { + if (type == SSH_KEYTYPE_OPENSSH_PEM || type == SSH_KEYTYPE_OPENSSH_NEW) { /* OpenSSH doesn't do key comments */ *comment = dupstr(filename_to_str(filename)); return openssh_encrypted(filename); @@ -80,7 +84,7 @@ int import_ssh1(const Filename *filename, int type, struct ssh2_userkey *import_ssh2(const Filename *filename, int type, char *passphrase, const char **errmsg_p) { - if (type == SSH_KEYTYPE_OPENSSH) + if (type == SSH_KEYTYPE_OPENSSH_PEM || type == SSH_KEYTYPE_OPENSSH_NEW) return openssh_read(filename, passphrase, errmsg_p); if (type == SSH_KEYTYPE_SSHCOM) return sshcom_read(filename, passphrase, errmsg_p); @@ -102,8 +106,10 @@ int export_ssh1(const Filename *filename, int type, struct RSAKey *key, int export_ssh2(const Filename *filename, int type, struct ssh2_userkey *key, char *passphrase) { - if (type == SSH_KEYTYPE_OPENSSH) - return openssh_write(filename, key, passphrase); + if (type == SSH_KEYTYPE_OPENSSH_PEM) + return openssh_pem_write(filename, key, passphrase); + if (type == SSH_KEYTYPE_OPENSSH_NEW) + return openssh_new_write(filename, key, passphrase); if (type == SSH_KEYTYPE_SSHCOM) return sshcom_write(filename, key, passphrase); return 0; @@ -305,6 +311,11 @@ static int ssh2_read_mpint(void *data, int len, struct mpint_pos *ret) /* ---------------------------------------------------------------------- * Code to read and write OpenSSH private keys. + * + * These come in two more or less entirely different formats, except + * that the base64 wrapper is similar enough to handle with the same + * code. Accordingly, there's just one function to load OpenSSH keys + * in both formats, but separate functions to write the two formats. */ typedef enum { @@ -1263,8 +1274,8 @@ struct ssh2_userkey *openssh_read(const Filename *filename, char *passphrase, return retval; } -int openssh_write(const Filename *filename, struct ssh2_userkey *key, - char *passphrase) +int openssh_pem_write(const Filename *filename, struct ssh2_userkey *key, + char *passphrase) { unsigned char *pubblob, *privblob, *spareblob; int publen, privlen, sparelen = 0; @@ -1626,6 +1637,12 @@ int openssh_write(const Filename *filename, struct ssh2_userkey *key, return ret; } +int openssh_new_write(const Filename *filename, struct ssh2_userkey *key, + char *passphrase) +{ + return FALSE; +} + /* ---------------------------------------------------------------------- * Code to read ssh.com private keys. */ diff --git a/ssh.h b/ssh.h index c958ddd1..f81d95c5 100644 --- a/ssh.h +++ b/ssh.h @@ -630,7 +630,9 @@ enum { SSH_KEYTYPE_UNOPENABLE, SSH_KEYTYPE_UNKNOWN, SSH_KEYTYPE_SSH1, SSH_KEYTYPE_SSH2, - SSH_KEYTYPE_OPENSSH, SSH_KEYTYPE_SSHCOM + SSH_KEYTYPE_OPENSSH_PEM, + SSH_KEYTYPE_OPENSSH_NEW, + SSH_KEYTYPE_SSHCOM }; int key_type(const Filename *filename); char *key_type_to_str(int type); diff --git a/sshpubk.c b/sshpubk.c index 8b80f389..6af08c75 100644 --- a/sshpubk.c +++ b/sshpubk.c @@ -1157,6 +1157,7 @@ int key_type(const Filename *filename) char buf[32]; const char putty2_sig[] = "PuTTY-User-Key-File-"; const char sshcom_sig[] = "---- BEGIN SSH2 ENCRYPTED PRIVAT"; + const char openssh_new_sig[] = "-----BEGIN OPENSSH PRIVATE KEY"; const char openssh_sig[] = "-----BEGIN "; int i; @@ -1173,8 +1174,10 @@ int key_type(const Filename *filename) return SSH_KEYTYPE_SSH1; if (!memcmp(buf, putty2_sig, sizeof(putty2_sig)-1)) return SSH_KEYTYPE_SSH2; + if (!memcmp(buf, openssh_new_sig, sizeof(openssh_new_sig)-1)) + return SSH_KEYTYPE_OPENSSH_NEW; if (!memcmp(buf, openssh_sig, sizeof(openssh_sig)-1)) - return SSH_KEYTYPE_OPENSSH; + return SSH_KEYTYPE_OPENSSH_PEM; if (!memcmp(buf, sshcom_sig, sizeof(sshcom_sig)-1)) return SSH_KEYTYPE_SSHCOM; return SSH_KEYTYPE_UNKNOWN; /* unrecognised or EOF */ @@ -1191,7 +1194,8 @@ char *key_type_to_str(int type) case SSH_KEYTYPE_UNKNOWN: return "not a private key"; break; case SSH_KEYTYPE_SSH1: return "SSH-1 private key"; break; case SSH_KEYTYPE_SSH2: return "PuTTY SSH-2 private key"; break; - case SSH_KEYTYPE_OPENSSH: return "OpenSSH SSH-2 private key"; break; + case SSH_KEYTYPE_OPENSSH_PEM: return "OpenSSH SSH-2 private key (old PEM format)"; break; + case SSH_KEYTYPE_OPENSSH_NEW: return "OpenSSH SSH-2 private key (new format)"; break; case SSH_KEYTYPE_SSHCOM: return "ssh.com SSH-2 private key"; break; default: return "INTERNAL ERROR"; break; } diff --git a/windows/winpgen.c b/windows/winpgen.c index 8f263efc..e7f240a5 100644 --- a/windows/winpgen.c +++ b/windows/winpgen.c @@ -534,7 +534,9 @@ enum { IDC_BITSSTATIC, IDC_BITS, IDC_ABOUT, IDC_GIVEHELP, - IDC_IMPORT, IDC_EXPORT_OPENSSH, IDC_EXPORT_SSHCOM + IDC_IMPORT, + IDC_EXPORT_OPENSSH_PEM, IDC_EXPORT_OPENSSH_NEW, + IDC_EXPORT_SSHCOM }; static const int nokey_ids[] = { IDC_NOKEY, 0 }; @@ -579,7 +581,9 @@ void ui_set_state(HWND hwnd, struct MainDlgState *state, int status) EnableMenuItem(state->keymenu, IDC_KEYSSH2ECDSA, MF_ENABLED|MF_BYCOMMAND); EnableMenuItem(state->cvtmenu, IDC_IMPORT, MF_ENABLED|MF_BYCOMMAND); - EnableMenuItem(state->cvtmenu, IDC_EXPORT_OPENSSH, + EnableMenuItem(state->cvtmenu, IDC_EXPORT_OPENSSH_PEM, + MF_GRAYED|MF_BYCOMMAND); + EnableMenuItem(state->cvtmenu, IDC_EXPORT_OPENSSH_NEW, MF_GRAYED|MF_BYCOMMAND); EnableMenuItem(state->cvtmenu, IDC_EXPORT_SSHCOM, MF_GRAYED|MF_BYCOMMAND); @@ -607,7 +611,9 @@ void ui_set_state(HWND hwnd, struct MainDlgState *state, int status) EnableMenuItem(state->keymenu, IDC_KEYSSH2ECDSA, MF_GRAYED|MF_BYCOMMAND); EnableMenuItem(state->cvtmenu, IDC_IMPORT, MF_GRAYED|MF_BYCOMMAND); - EnableMenuItem(state->cvtmenu, IDC_EXPORT_OPENSSH, + EnableMenuItem(state->cvtmenu, IDC_EXPORT_OPENSSH_PEM, + MF_GRAYED|MF_BYCOMMAND); + EnableMenuItem(state->cvtmenu, IDC_EXPORT_OPENSSH_NEW, MF_GRAYED|MF_BYCOMMAND); EnableMenuItem(state->cvtmenu, IDC_EXPORT_SSHCOM, MF_GRAYED|MF_BYCOMMAND); @@ -643,7 +649,8 @@ void ui_set_state(HWND hwnd, struct MainDlgState *state, int status) #define do_export_menuitem(x,y) \ EnableMenuItem(state->cvtmenu, x, MF_BYCOMMAND | \ (import_target_type(y)==type?MF_ENABLED:MF_GRAYED)) - do_export_menuitem(IDC_EXPORT_OPENSSH, SSH_KEYTYPE_OPENSSH); + do_export_menuitem(IDC_EXPORT_OPENSSH_PEM, SSH_KEYTYPE_OPENSSH_PEM); + do_export_menuitem(IDC_EXPORT_OPENSSH_NEW, SSH_KEYTYPE_OPENSSH_NEW); do_export_menuitem(IDC_EXPORT_SSHCOM, SSH_KEYTYPE_SSHCOM); #undef do_export_menuitem break; @@ -883,8 +890,10 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg, menu1 = CreateMenu(); AppendMenu(menu1, MF_ENABLED, IDC_IMPORT, "&Import key"); AppendMenu(menu1, MF_SEPARATOR, 0, 0); - AppendMenu(menu1, MF_ENABLED, IDC_EXPORT_OPENSSH, - "Export &OpenSSH key"); + AppendMenu(menu1, MF_ENABLED, IDC_EXPORT_OPENSSH_PEM, + "Export &OpenSSH key (old PEM format)"); + AppendMenu(menu1, MF_ENABLED, IDC_EXPORT_OPENSSH_NEW, + "Export &OpenSSH key (new format)"); AppendMenu(menu1, MF_ENABLED, IDC_EXPORT_SSHCOM, "Export &ssh.com key"); AppendMenu(menu, MF_POPUP | MF_ENABLED, (UINT) menu1, @@ -1161,7 +1170,8 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg, } break; case IDC_SAVE: - case IDC_EXPORT_OPENSSH: + case IDC_EXPORT_OPENSSH_PEM: + case IDC_EXPORT_OPENSSH_NEW: case IDC_EXPORT_SSHCOM: if (HIWORD(wParam) != BN_CLICKED) break; @@ -1177,8 +1187,10 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg, else realtype = SSH_KEYTYPE_SSH1; - if (LOWORD(wParam) == IDC_EXPORT_OPENSSH) - type = SSH_KEYTYPE_OPENSSH; + if (LOWORD(wParam) == IDC_EXPORT_OPENSSH_PEM) + type = SSH_KEYTYPE_OPENSSH_PEM; + else if (LOWORD(wParam) == IDC_EXPORT_OPENSSH_NEW) + type = SSH_KEYTYPE_OPENSSH_NEW; else if (LOWORD(wParam) == IDC_EXPORT_SSHCOM) type = SSH_KEYTYPE_SSHCOM; else @@ -1453,7 +1465,8 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg, case IDC_BITS: topic = WINHELP_CTX_puttygen_bits; break; case IDC_IMPORT: - case IDC_EXPORT_OPENSSH: + case IDC_EXPORT_OPENSSH_PEM: + case IDC_EXPORT_OPENSSH_NEW: case IDC_EXPORT_SSHCOM: topic = WINHELP_CTX_puttygen_conversions; break; }