" -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"
+ "(force new file format)\n"
" private-sshcom export ssh.com private key\n"
" public standard / ssh.com public key\n"
" public-openssh OpenSSH public key\n"
Filename *infilename = NULL, *outfilename = NULL;
enum { NOKEYGEN, RSA1, RSA2, DSA, ECDSA, ED25519 } keytype = NOKEYGEN;
char *outfile = NULL, *outfiletmp = NULL;
- enum { PRIVATE, PUBLIC, PUBLICO, FP, OPENSSH_PEM,
+ enum { PRIVATE, PUBLIC, PUBLICO, FP, OPENSSH_AUTO,
OPENSSH_NEW, SSHCOM } outtype = PRIVATE;
int bits = -1;
char *comment = NULL, *origcomment = NULL;
outtype = PRIVATE;
else if (!strcmp(p, "fingerprint"))
outtype = FP;
- else if (!strcmp(p, "private-openssh") ||
- !strcmp(p, "private-openssh-pem"))
- outtype = OPENSSH_PEM, sshver = 2;
+ else if (!strcmp(p, "private-openssh"))
+ outtype = OPENSSH_AUTO, sshver = 2;
else if (!strcmp(p, "private-openssh-new"))
outtype = OPENSSH_NEW, sshver = 2;
else if (!strcmp(p, "private-sshcom"))
* We must save the private part when generating a new key.
*/
if (keytype != NOKEYGEN &&
- (outtype != PRIVATE && outtype != OPENSSH_PEM &&
+ (outtype != PRIVATE && outtype != OPENSSH_AUTO &&
outtype != OPENSSH_NEW && outtype != SSHCOM)) {
fprintf(stderr, "puttygen: this would generate a new key but "
"discard the private part\n");
}
sshver = 2;
break;
+
+ case SSH_KEYTYPE_OPENSSH_AUTO:
+ default:
+ assert(0 && "Should never see these types on an input file");
}
}
*/
if ((intype == SSH_KEYTYPE_SSH1 && outtype == PRIVATE) ||
(intype == SSH_KEYTYPE_SSH2 && outtype == PRIVATE) ||
- (intype == SSH_KEYTYPE_OPENSSH_PEM && outtype == OPENSSH_PEM) ||
+ (intype == SSH_KEYTYPE_OPENSSH_PEM && outtype == OPENSSH_AUTO) ||
(intype == SSH_KEYTYPE_OPENSSH_NEW && outtype == OPENSSH_NEW) ||
(intype == SSH_KEYTYPE_SSHCOM && outtype == SSHCOM)) {
if (!outfile) {
* Bomb out rather than automatically choosing to write
* a private key file to stdout.
*/
- if (outtype == PRIVATE || outtype == OPENSSH_PEM ||
+ if (outtype == PRIVATE || outtype == OPENSSH_AUTO ||
outtype == OPENSSH_NEW || outtype == SSHCOM) {
fprintf(stderr, "puttygen: need to specify an output file\n");
return 1;
* out a private key format, or (b) the entire input key file
* is encrypted.
*/
- if (outtype == PRIVATE || outtype == OPENSSH_PEM ||
+ if (outtype == PRIVATE || outtype == OPENSSH_AUTO ||
outtype == OPENSSH_NEW || outtype == SSHCOM ||
intype == SSH_KEYTYPE_OPENSSH_PEM ||
intype == SSH_KEYTYPE_OPENSSH_NEW ||
}
break;
- case OPENSSH_PEM:
+ case OPENSSH_AUTO:
case OPENSSH_NEW:
case SSHCOM:
assert(sshver == 2);
random_ref(); /* both foreign key types require randomness,
* for IV or padding */
switch (outtype) {
- case OPENSSH_PEM:
- real_outtype = SSH_KEYTYPE_OPENSSH_PEM;
+ case OPENSSH_AUTO:
+ real_outtype = SSH_KEYTYPE_OPENSSH_AUTO;
break;
case OPENSSH_NEW:
real_outtype = SSH_KEYTYPE_OPENSSH_NEW;
struct ssh2_userkey *openssh_new_read(const Filename *filename,
char *passphrase,
const char **errmsg_p);
+int openssh_auto_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,
int export_ssh2(const Filename *filename, int type,
struct ssh2_userkey *key, char *passphrase)
{
- if (type == SSH_KEYTYPE_OPENSSH_PEM)
- return openssh_pem_write(filename, key, passphrase);
+ if (type == SSH_KEYTYPE_OPENSSH_AUTO)
+ return openssh_auto_write(filename, key, passphrase);
if (type == SSH_KEYTYPE_OPENSSH_NEW)
return openssh_new_write(filename, key, passphrase);
if (type == SSH_KEYTYPE_SSHCOM)
return ret;
}
+/* ----------------------------------------------------------------------
+ * The switch function openssh_auto_write(), which chooses one of the
+ * concrete OpenSSH output formats based on the key type.
+ */
+int openssh_auto_write(const Filename *filename, struct ssh2_userkey *key,
+ char *passphrase)
+{
+ /*
+ * The old OpenSSH format supports a fixed list of key types. We
+ * assume that anything not in that fixed list is newer, and hence
+ * will use the new format.
+ */
+ if (key->alg == &ssh_dss ||
+ key->alg == &ssh_rsa ||
+ key->alg == &ssh_ecdsa_nistp256 ||
+ key->alg == &ssh_ecdsa_nistp384 ||
+ key->alg == &ssh_ecdsa_nistp521)
+ return openssh_pem_write(filename, key, passphrase);
+ else
+ return openssh_new_write(filename, key, passphrase);
+}
+
/* ----------------------------------------------------------------------
* Code to read ssh.com private keys.
*/
SSH_KEYTYPE_UNOPENABLE,
SSH_KEYTYPE_UNKNOWN,
SSH_KEYTYPE_SSH1, SSH_KEYTYPE_SSH2,
+ /*
+ * The OpenSSH key types deserve a little explanation. OpenSSH has
+ * two physical formats for private key storage: an old PEM-based
+ * one largely dictated by their use of OpenSSL and full of ASN.1,
+ * and a new one using the same private key formats used over the
+ * wire for talking to ssh-agent. The old format can only support
+ * a subset of the key types, because it needs redesign for each
+ * key type, and after a while they decided to move to the new
+ * format so as not to have to do that.
+ *
+ * On input, key files are identified as either
+ * SSH_KEYTYPE_OPENSSH_PEM or SSH_KEYTYPE_OPENSSH_NEW, describing
+ * accurately which actual format the keys are stored in.
+ *
+ * On output, however, we default to following OpenSSH's own
+ * policy of writing out PEM-style keys for maximum backwards
+ * compatibility if the key type supports it, and otherwise
+ * switching to the new format. So the formats you can select for
+ * output are SSH_KEYTYPE_OPENSSH_NEW (forcing the new format for
+ * any key type), and SSH_KEYTYPE_OPENSSH_AUTO to use the oldest
+ * format supported by whatever key type you're writing out.
+ *
+ * So we have three type codes, but only two of them usable in any
+ * given circumstance. An input key file will never be identified
+ * as AUTO, only PEM or NEW; key export UIs should not be able to
+ * select PEM, only AUTO or NEW.
+ */
+ SSH_KEYTYPE_OPENSSH_AUTO,
SSH_KEYTYPE_OPENSSH_PEM,
SSH_KEYTYPE_OPENSSH_NEW,
SSH_KEYTYPE_SSHCOM
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;
+ /*
+ * This function is called with a key type derived from
+ * looking at an actual key file, so the output-only type
+ * OPENSSH_AUTO should never get here, and is much an INTERNAL
+ * ERROR as a code we don't even understand.
+ */
+ case SSH_KEYTYPE_OPENSSH_AUTO: return "INTERNAL ERROR (OPENSSH_AUTO)"; break;
default: return "INTERNAL ERROR"; break;
}
}
IDC_ABOUT,
IDC_GIVEHELP,
IDC_IMPORT,
- IDC_EXPORT_OPENSSH_PEM, IDC_EXPORT_OPENSSH_NEW,
+ IDC_EXPORT_OPENSSH_AUTO, IDC_EXPORT_OPENSSH_NEW,
IDC_EXPORT_SSHCOM
};
EnableMenuItem(state->keymenu, IDC_KEYSSH2ED25519,
MF_ENABLED|MF_BYCOMMAND);
EnableMenuItem(state->cvtmenu, IDC_IMPORT, MF_ENABLED|MF_BYCOMMAND);
- EnableMenuItem(state->cvtmenu, IDC_EXPORT_OPENSSH_PEM,
+ EnableMenuItem(state->cvtmenu, IDC_EXPORT_OPENSSH_AUTO,
MF_GRAYED|MF_BYCOMMAND);
EnableMenuItem(state->cvtmenu, IDC_EXPORT_OPENSSH_NEW,
MF_GRAYED|MF_BYCOMMAND);
EnableMenuItem(state->keymenu, IDC_KEYSSH2ED25519,
MF_GRAYED|MF_BYCOMMAND);
EnableMenuItem(state->cvtmenu, IDC_IMPORT, MF_GRAYED|MF_BYCOMMAND);
- EnableMenuItem(state->cvtmenu, IDC_EXPORT_OPENSSH_PEM,
+ EnableMenuItem(state->cvtmenu, IDC_EXPORT_OPENSSH_AUTO,
MF_GRAYED|MF_BYCOMMAND);
EnableMenuItem(state->cvtmenu, IDC_EXPORT_OPENSSH_NEW,
MF_GRAYED|MF_BYCOMMAND);
#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_PEM, SSH_KEYTYPE_OPENSSH_PEM);
+ do_export_menuitem(IDC_EXPORT_OPENSSH_AUTO, SSH_KEYTYPE_OPENSSH_AUTO);
do_export_menuitem(IDC_EXPORT_OPENSSH_NEW, SSH_KEYTYPE_OPENSSH_NEW);
do_export_menuitem(IDC_EXPORT_SSHCOM, SSH_KEYTYPE_SSHCOM);
#undef do_export_menuitem
menu1 = CreateMenu();
AppendMenu(menu1, MF_ENABLED, IDC_IMPORT, "&Import key");
AppendMenu(menu1, MF_SEPARATOR, 0, 0);
- AppendMenu(menu1, MF_ENABLED, IDC_EXPORT_OPENSSH_PEM,
- "Export &OpenSSH key (old PEM format)");
+ AppendMenu(menu1, MF_ENABLED, IDC_EXPORT_OPENSSH_AUTO,
+ "Export &OpenSSH key");
AppendMenu(menu1, MF_ENABLED, IDC_EXPORT_OPENSSH_NEW,
- "Export &OpenSSH key (new format)");
+ "Export &OpenSSH key (force new file format)");
AppendMenu(menu1, MF_ENABLED, IDC_EXPORT_SSHCOM,
"Export &ssh.com key");
AppendMenu(menu, MF_POPUP | MF_ENABLED, (UINT) menu1,
}
break;
case IDC_SAVE:
- case IDC_EXPORT_OPENSSH_PEM:
+ case IDC_EXPORT_OPENSSH_AUTO:
case IDC_EXPORT_OPENSSH_NEW:
case IDC_EXPORT_SSHCOM:
if (HIWORD(wParam) != BN_CLICKED)
else
realtype = SSH_KEYTYPE_SSH1;
- if (LOWORD(wParam) == IDC_EXPORT_OPENSSH_PEM)
- type = SSH_KEYTYPE_OPENSSH_PEM;
+ if (LOWORD(wParam) == IDC_EXPORT_OPENSSH_AUTO)
+ type = SSH_KEYTYPE_OPENSSH_AUTO;
else if (LOWORD(wParam) == IDC_EXPORT_OPENSSH_NEW)
type = SSH_KEYTYPE_OPENSSH_NEW;
else if (LOWORD(wParam) == IDC_EXPORT_SSHCOM)
case IDC_BITS:
topic = WINHELP_CTX_puttygen_bits; break;
case IDC_IMPORT:
- case IDC_EXPORT_OPENSSH_PEM:
+ case IDC_EXPORT_OPENSSH_AUTO:
case IDC_EXPORT_OPENSSH_NEW:
case IDC_EXPORT_SSHCOM:
topic = WINHELP_CTX_puttygen_conversions; break;