1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-01-09 17:38:00 +00:00

Clean up the crufty old SSH-1 RSA API.

Lots of functions had really generic names (like 'makekey'), or names
that missed out an important concept (like 'rsakey_pubblob', which
loads a public blob from a _file_ and doesn't generate it from an
in-memory representation at all). Also, the opaque 'int order' that
distinguishes the two formats of public key blob is now a mnemonic
enumeration, and while I'm at it, rsa_ssh1_public_blob takes one of
those as an extra argument.
This commit is contained in:
Simon Tatham 2018-05-24 08:22:44 +01:00
parent 1a02274272
commit 7e8ae41a3f
8 changed files with 109 additions and 89 deletions

View File

@ -769,7 +769,7 @@ int main(int argc, char **argv)
* Find out whether the input key is encrypted.
*/
if (intype == SSH_KEYTYPE_SSH1)
encrypted = rsakey_encrypted(infilename, &origcomment);
encrypted = rsa_ssh1_encrypted(infilename, &origcomment);
else if (intype == SSH_KEYTYPE_SSH2)
encrypted = ssh2_userkey_encrypted(infilename, &origcomment);
else
@ -811,8 +811,8 @@ int main(int argc, char **argv)
unsigned char *blob;
int n, l, bloblen;
ret = rsakey_pubblob(infilename, &vblob, &bloblen,
&origcomment, &error);
ret = rsa_ssh1_loadpub(infilename, &vblob, &bloblen,
&origcomment, &error);
blob = (unsigned char *)vblob;
n = 4; /* skip modulus bits */
@ -836,7 +836,8 @@ int main(int argc, char **argv)
ssh1key->q = NULL;
ssh1key->iqmp = NULL;
} else {
ret = loadrsakey(infilename, ssh1key, old_passphrase, &error);
ret = rsa_ssh1_loadkey(
infilename, ssh1key, old_passphrase, &error);
}
if (ret > 0)
error = NULL;
@ -972,7 +973,7 @@ int main(int argc, char **argv)
case PRIVATE:
if (sshver == 1) {
assert(ssh1key);
ret = saversakey(outfilename, ssh1key, new_passphrase);
ret = rsa_ssh1_savekey(outfilename, ssh1key, new_passphrase);
if (!ret) {
fprintf(stderr, "puttygen: unable to save SSH-1 private key\n");
return 1;

View File

@ -11,8 +11,8 @@
#include "pageant.h"
/*
* We need this to link with the RSA code, because rsaencrypt()
* pads its data with random bytes. Since we only use rsadecrypt()
* We need this to link with the RSA code, because rsa_ssh1_encrypt()
* pads its data with random bytes. Since we only use rsa_ssh1_decrypt()
* and the signing functions, which are deterministic, this should
* never be called.
*
@ -182,7 +182,7 @@ void *pageant_make_keylist1(int *length)
nkeys = 0;
for (i = 0; NULL != (key = index234(rsakeys, i)); i++) {
nkeys++;
blob = rsa_public_blob(key, &bloblen);
blob = rsa_ssh1_public_blob(key, &bloblen, RSA_SSH1_EXPONENT_FIRST);
len += bloblen;
sfree(blob);
len += 4 + strlen(key->comment);
@ -195,7 +195,7 @@ void *pageant_make_keylist1(int *length)
PUT_32BIT(p, nkeys);
p += 4;
for (i = 0; NULL != (key = index234(rsakeys, i)); i++) {
blob = rsa_public_blob(key, &bloblen);
blob = rsa_ssh1_public_blob(key, &bloblen, RSA_SSH1_EXPONENT_FIRST);
memcpy(p, blob, bloblen);
p += bloblen;
sfree(blob);
@ -447,7 +447,7 @@ void *pageant_handle_msg(const void *msg, int msglen, int *outlen,
fail_reason = "key not found";
goto failure;
}
response = rsadecrypt(challenge, key);
response = rsa_ssh1_decrypt(challenge, key);
for (i = 0; i < 32; i++)
response_source[i] = bignum_byte(response, 31 - i);
@ -547,7 +547,8 @@ void *pageant_handle_msg(const void *msg, int msglen, int *outlen,
key = snew(struct RSAKey);
memset(key, 0, sizeof(struct RSAKey));
n = makekey(p, msgend - p, key, NULL, 1);
n = rsa_ssh1_readpub(p, msgend - p, key, NULL,
RSA_SSH1_MODULUS_FIRST);
if (n < 0) {
freersakey(key);
sfree(key);
@ -556,7 +557,7 @@ void *pageant_handle_msg(const void *msg, int msglen, int *outlen,
}
p += n;
n = makeprivate(p, msgend - p, key);
n = rsa_ssh1_readpriv(p, msgend - p, key);
if (n < 0) {
freersakey(key);
sfree(key);
@ -745,7 +746,8 @@ void *pageant_handle_msg(const void *msg, int msglen, int *outlen,
plog(logctx, logfn, "request: SSH1_AGENTC_REMOVE_RSA_IDENTITY");
n = makekey(p, msgend - p, &reqkey, NULL, 0);
n = rsa_ssh1_readpub(p, msgend - p, &reqkey, NULL,
RSA_SSH1_EXPONENT_FIRST);
if (n < 0) {
fail_reason = "request truncated before public key";
goto failure;
@ -1286,7 +1288,7 @@ int pageant_add_keyfile(Filename *filename, const char *passphrase,
int i, nkeys, bloblen, keylistlen;
if (type == SSH_KEYTYPE_SSH1) {
if (!rsakey_pubblob(filename, &blob, &bloblen, NULL, &error)) {
if (!rsa_ssh1_loadpub(filename, &blob, &bloblen, NULL, &error)) {
*retstr = dupprintf("Couldn't load private key (%s)", error);
return PAGEANT_ACTION_FAILURE;
}
@ -1396,7 +1398,7 @@ int pageant_add_keyfile(Filename *filename, const char *passphrase,
error = NULL;
if (type == SSH_KEYTYPE_SSH1)
needs_pass = rsakey_encrypted(filename, &comment);
needs_pass = rsa_ssh1_encrypted(filename, &comment);
else
needs_pass = ssh2_userkey_encrypted(filename, &comment);
attempts = 0;
@ -1434,7 +1436,7 @@ int pageant_add_keyfile(Filename *filename, const char *passphrase,
this_passphrase = "";
if (type == SSH_KEYTYPE_SSH1)
ret = loadrsakey(filename, rkey, this_passphrase, &error);
ret = rsa_ssh1_loadkey(filename, rkey, this_passphrase, &error);
else {
skey = ssh2_load_userkey(filename, this_passphrase, &error);
if (skey == SSH2_WRONG_PASSPHRASE)
@ -1629,7 +1631,8 @@ int pageant_enum_keys(pageant_key_enum_fn_t callback, void *callback_ctx,
/* public blob and fingerprint */
memset(&rkey, 0, sizeof(rkey));
n = makekey(p, keylistlen, &rkey, NULL, 0);
n = rsa_ssh1_readpub(p, keylistlen, &rkey, NULL,
RSA_SSH1_EXPONENT_FIRST);
if (n < 0 || n > keylistlen) {
freersakey(&rkey);
*retstr = dupstr("Received broken SSH-1 key list from agent");
@ -1657,7 +1660,8 @@ int pageant_enum_keys(pageant_key_enum_fn_t callback, void *callback_ctx,
comment = dupprintf("%.*s", (int)n, (const char *)p);
p += n, keylistlen -= n;
cbkey.blob = rsa_public_blob(&rkey, &cbkey.bloblen);
cbkey.blob = rsa_ssh1_public_blob(&rkey, &cbkey.bloblen,
RSA_SSH1_EXPONENT_FIRST);
cbkey.comment = comment;
cbkey.ssh_version = 1;
callback(callback_ctx, fingerprint, comment, &cbkey);

31
ssh.c
View File

@ -2871,9 +2871,9 @@ static int ssh1_pkt_getrsakey(struct Packet *pkt, struct RSAKey *key,
{
int j;
j = makekey(pkt->body + pkt->savedpos,
pkt->length - pkt->savedpos,
key, keystr, 0);
j = rsa_ssh1_readpub(pkt->body + pkt->savedpos,
pkt->length - pkt->savedpos,
key, keystr, RSA_SSH1_EXPONENT_FIRST);
if (j < 0)
return FALSE;
@ -4424,13 +4424,13 @@ static void do_ssh1_login(void *vctx)
}
if (s->hostkey.bytes > s->servkey.bytes) {
ret = rsaencrypt(s->rsabuf, 32, &s->servkey);
ret = rsa_ssh1_encrypt(s->rsabuf, 32, &s->servkey);
if (ret)
ret = rsaencrypt(s->rsabuf, s->servkey.bytes, &s->hostkey);
ret = rsa_ssh1_encrypt(s->rsabuf, s->servkey.bytes, &s->hostkey);
} else {
ret = rsaencrypt(s->rsabuf, 32, &s->hostkey);
ret = rsa_ssh1_encrypt(s->rsabuf, 32, &s->hostkey);
if (ret)
ret = rsaencrypt(s->rsabuf, s->hostkey.bytes, &s->servkey);
ret = rsa_ssh1_encrypt(s->rsabuf, s->hostkey.bytes, &s->servkey);
}
if (!ret) {
bombout(("SSH-1 public key encryptions failed due to bad formatting"));
@ -4617,14 +4617,13 @@ static void do_ssh1_login(void *vctx)
if (keytype == SSH_KEYTYPE_SSH1 ||
keytype == SSH_KEYTYPE_SSH1_PUBLIC) {
const char *error;
if (rsakey_pubblob(s->keyfile,
&s->publickey_blob, &s->publickey_bloblen,
&s->publickey_comment, &error)) {
if (rsa_ssh1_loadpub(s->keyfile,
&s->publickey_blob, &s->publickey_bloblen,
&s->publickey_comment, &error)) {
s->privatekey_available = (keytype == SSH_KEYTYPE_SSH1);
if (!s->privatekey_available)
logeventf(ssh, "Key file contains public key only");
s->privatekey_encrypted = rsakey_encrypted(s->keyfile,
NULL);
s->privatekey_encrypted = rsa_ssh1_encrypted(s->keyfile, NULL);
} else {
char *msgbuf;
logeventf(ssh, "Unable to load key (%s)", error);
@ -4888,8 +4887,8 @@ static void do_ssh1_login(void *vctx)
* Try decrypting key with passphrase.
*/
s->keyfile = conf_get_filename(ssh->conf, CONF_keyfile);
ret = loadrsakey(s->keyfile, &s->key, passphrase,
&error);
ret = rsa_ssh1_loadkey(
s->keyfile, &s->key, passphrase, &error);
if (passphrase) {
smemclr(passphrase, strlen(passphrase));
sfree(passphrase);
@ -4910,7 +4909,7 @@ static void do_ssh1_login(void *vctx)
got_passphrase = FALSE;
/* and try again */
} else {
assert(0 && "unexpected return from loadrsakey()");
assert(0 && "unexpected return from rsa_ssh1_loadkey()");
got_passphrase = FALSE; /* placate optimisers */
}
}
@ -4943,7 +4942,7 @@ static void do_ssh1_login(void *vctx)
bombout(("Server's RSA challenge was badly formatted"));
crStopV;
}
response = rsadecrypt(challenge, &s->key);
response = rsa_ssh1_decrypt(challenge, &s->key);
freebn(s->key.private_exponent);/* burn the evidence */
for (i = 0; i < 32; i++) {

39
ssh.h
View File

@ -173,18 +173,29 @@ struct ec_key {
struct ec_point *ec_public(const Bignum privateKey, const struct ec_curve *curve);
int makekey(const unsigned char *data, int len, struct RSAKey *result,
const unsigned char **keystr, int order);
int makeprivate(const unsigned char *data, int len, struct RSAKey *result);
int rsaencrypt(unsigned char *data, int length, struct RSAKey *key);
Bignum rsadecrypt(Bignum input, struct RSAKey *key);
void rsasign(unsigned char *data, int length, struct RSAKey *key);
/*
* SSH-1 never quite decided which order to store the two components
* of an RSA key. During connection setup, the server sends its host
* and server keys with the exponent first; private key files store
* the modulus first. The agent protocol is even more confusing,
* because the client specifies a key to the server in one order and
* the server lists the keys it knows about in the other order!
*/
typedef enum { RSA_SSH1_EXPONENT_FIRST, RSA_SSH1_MODULUS_FIRST } RsaSsh1Order;
int rsa_ssh1_readpub(const unsigned char *data, int len, struct RSAKey *result,
const unsigned char **keystr, RsaSsh1Order order);
int rsa_ssh1_readpriv(const unsigned char *data, int len,
struct RSAKey *result);
int rsa_ssh1_encrypt(unsigned char *data, int length, struct RSAKey *key);
Bignum rsa_ssh1_decrypt(Bignum input, struct RSAKey *key);
void rsasanitise(struct RSAKey *key);
int rsastr_len(struct RSAKey *key);
void rsastr_fmt(char *str, struct RSAKey *key);
void rsa_fingerprint(char *str, int len, struct RSAKey *key);
int rsa_verify(struct RSAKey *key);
unsigned char *rsa_public_blob(struct RSAKey *key, int *len);
unsigned char *rsa_ssh1_public_blob(struct RSAKey *key, int *len,
RsaSsh1Order order);
int rsa_public_blob_len(void *data, int maxlen);
void freersakey(struct RSAKey *key);
@ -711,13 +722,13 @@ Bignum dh_create_e(void *, int nbits);
const char *dh_validate_f(void *handle, Bignum f);
Bignum dh_find_K(void *, Bignum f);
int loadrsakey(const Filename *filename, struct RSAKey *key,
const char *passphrase, const char **errorstr);
int rsakey_encrypted(const Filename *filename, char **comment);
int rsakey_pubblob(const Filename *filename, void **blob, int *bloblen,
char **commentptr, const char **errorstr);
int saversakey(const Filename *filename, struct RSAKey *key, char *passphrase);
int rsa_ssh1_encrypted(const Filename *filename, char **comment);
int rsa_ssh1_loadpub(const Filename *filename, void **blob, int *bloblen,
char **commentptr, const char **errorstr);
int rsa_ssh1_loadkey(const Filename *filename, struct RSAKey *key,
const char *passphrase, const char **errorstr);
int rsa_ssh1_savekey(const Filename *filename, struct RSAKey *key,
char *passphrase);
extern int base64_decode_atom(const char *atom, unsigned char *out);
extern int base64_lines(int datalen);

View File

@ -23,9 +23,9 @@
static int key_type_fp(FILE *fp);
static int loadrsakey_main(FILE * fp, struct RSAKey *key, int pub_only,
char **commentptr, const char *passphrase,
const char **error)
static int rsa_ssh1_load_main(FILE * fp, struct RSAKey *key, int pub_only,
char **commentptr, const char *passphrase,
const char **error)
{
unsigned char buf[16384];
unsigned char keybuf[16];
@ -69,7 +69,7 @@ static int loadrsakey_main(FILE * fp, struct RSAKey *key, int pub_only,
i += 4;
/* Now the serious stuff. An ordinary SSH-1 public key. */
j = makekey(buf + i, len - i, key, NULL, 1);
j = rsa_ssh1_readpub(buf + i, len - i, key, NULL, RSA_SSH1_MODULUS_FIRST);
if (j < 0)
goto end; /* overran */
i += j;
@ -132,7 +132,7 @@ static int loadrsakey_main(FILE * fp, struct RSAKey *key, int pub_only,
* decryption exponent, and then the three auxiliary values
* (iqmp, q, p).
*/
j = makeprivate(buf + i, len - i, key);
j = rsa_ssh1_readpriv(buf + i, len - i, key);
if (j < 0) goto end;
i += j;
j = ssh1_read_bignum(buf + i, len - i, &key->iqmp);
@ -157,8 +157,8 @@ static int loadrsakey_main(FILE * fp, struct RSAKey *key, int pub_only,
return ret;
}
int loadrsakey(const Filename *filename, struct RSAKey *key,
const char *passphrase, const char **errorstr)
int rsa_ssh1_loadkey(const Filename *filename, struct RSAKey *key,
const char *passphrase, const char **errorstr)
{
FILE *fp;
char buf[64];
@ -179,7 +179,7 @@ int loadrsakey(const Filename *filename, struct RSAKey *key,
/*
* This routine will take care of calling fclose() for us.
*/
ret = loadrsakey_main(fp, key, FALSE, NULL, passphrase, &error);
ret = rsa_ssh1_load_main(fp, key, FALSE, NULL, passphrase, &error);
fp = NULL;
goto end;
}
@ -201,7 +201,7 @@ int loadrsakey(const Filename *filename, struct RSAKey *key,
* See whether an RSA key is encrypted. Return its comment field as
* well.
*/
int rsakey_encrypted(const Filename *filename, char **comment)
int rsa_ssh1_encrypted(const Filename *filename, char **comment)
{
FILE *fp;
char buf[64];
@ -219,7 +219,7 @@ int rsakey_encrypted(const Filename *filename, char **comment)
/*
* This routine will take care of calling fclose() for us.
*/
return loadrsakey_main(fp, NULL, FALSE, comment, NULL, &dummy);
return rsa_ssh1_load_main(fp, NULL, FALSE, comment, NULL, &dummy);
}
fclose(fp);
return 0; /* wasn't the right kind of file */
@ -230,8 +230,8 @@ int rsakey_encrypted(const Filename *filename, char **comment)
* 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)
int rsa_ssh1_loadpub(const Filename *filename, void **blob, int *bloblen,
char **commentptr, const char **errorstr)
{
FILE *fp;
char buf[64];
@ -256,12 +256,13 @@ int rsakey_pubblob(const Filename *filename, void **blob, int *bloblen,
*/
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);
if (rsa_ssh1_load_main(fp, &key, TRUE, commentptr, NULL, &error)) {
*blob = rsa_ssh1_public_blob(&key, bloblen,
RSA_SSH1_EXPONENT_FIRST);
freersakey(&key);
ret = 1;
}
fp = NULL; /* loadrsakey_main unconditionally closes fp */
fp = NULL; /* rsa_ssh1_load_main unconditionally closes fp */
} else {
/*
* Try interpreting the file as an SSH-1 public key.
@ -307,7 +308,7 @@ int rsakey_pubblob(const Filename *filename, void **blob, int *bloblen,
}
if (commentptr)
*commentptr = commentp ? dupstr(commentp) : NULL;
*blob = rsa_public_blob(&key, bloblen);
*blob = rsa_ssh1_public_blob(&key, bloblen, RSA_SSH1_EXPONENT_FIRST);
freersakey(&key);
sfree(line);
fclose(fp);
@ -329,7 +330,8 @@ int rsakey_pubblob(const Filename *filename, void **blob, int *bloblen,
/*
* Save an RSA key file. Return nonzero on success.
*/
int saversakey(const Filename *filename, struct RSAKey *key, char *passphrase)
int rsa_ssh1_savekey(const Filename *filename, struct RSAKey *key,
char *passphrase)
{
unsigned char buf[16384];
unsigned char keybuf[16];

View File

@ -10,8 +10,8 @@
#include "ssh.h"
#include "misc.h"
int makekey(const unsigned char *data, int len, struct RSAKey *result,
const unsigned char **keystr, int order)
int rsa_ssh1_readpub(const unsigned char *data, int len, struct RSAKey *result,
const unsigned char **keystr, RsaSsh1Order order)
{
const unsigned char *p = data;
int i, n;
@ -28,13 +28,7 @@ int makekey(const unsigned char *data, int len, struct RSAKey *result,
len -= 4;
/*
* order=0 means exponent then modulus (the keys sent by the
* server). order=1 means modulus then exponent (the keys
* stored in a keyfile).
*/
if (order == 0) {
if (order == RSA_SSH1_EXPONENT_FIRST) {
n = ssh1_read_bignum(p, len, result ? &result->exponent : NULL);
if (n < 0) return -1;
p += n;
@ -50,7 +44,7 @@ int makekey(const unsigned char *data, int len, struct RSAKey *result,
p += n;
len -= n;
if (order == 1) {
if (order == RSA_SSH1_MODULUS_FIRST) {
n = ssh1_read_bignum(p, len, result ? &result->exponent : NULL);
if (n < 0) return -1;
p += n;
@ -59,12 +53,13 @@ int makekey(const unsigned char *data, int len, struct RSAKey *result,
return p - data;
}
int makeprivate(const unsigned char *data, int len, struct RSAKey *result)
int rsa_ssh1_readpriv(const unsigned char *data, int len,
struct RSAKey *result)
{
return ssh1_read_bignum(data, len, &result->private_exponent);
}
int rsaencrypt(unsigned char *data, int length, struct RSAKey *key)
int rsa_ssh1_encrypt(unsigned char *data, int length, struct RSAKey *key)
{
Bignum b1, b2;
int i;
@ -318,7 +313,7 @@ static Bignum rsa_privkey_op(Bignum input, struct RSAKey *key)
return ret;
}
Bignum rsadecrypt(Bignum input, struct RSAKey *key)
Bignum rsa_ssh1_decrypt(Bignum input, struct RSAKey *key)
{
return rsa_privkey_op(input, key);
}
@ -468,8 +463,8 @@ int rsa_verify(struct RSAKey *key)
return 1;
}
/* Public key blob as used by Pageant: exponent before modulus. */
unsigned char *rsa_public_blob(struct RSAKey *key, int *len)
unsigned char *rsa_ssh1_public_blob(struct RSAKey *key, int *len,
RsaSsh1Order order)
{
int length, pos;
unsigned char *ret;
@ -480,8 +475,13 @@ unsigned char *rsa_public_blob(struct RSAKey *key, int *len)
PUT_32BIT(ret, bignum_bitcount(key->modulus));
pos = 4;
pos += ssh1_write_bignum(ret + pos, key->exponent);
pos += ssh1_write_bignum(ret + pos, key->modulus);
if (order == RSA_SSH1_EXPONENT_FIRST) {
pos += ssh1_write_bignum(ret + pos, key->exponent);
pos += ssh1_write_bignum(ret + pos, key->modulus);
} else {
pos += ssh1_write_bignum(ret + pos, key->modulus);
pos += ssh1_write_bignum(ret + pos, key->exponent);
}
*len = length;
return ret;

View File

@ -556,8 +556,8 @@ struct pageant_pubkey *find_key(const char *string, char **retstr)
keytype == SSH_KEYTYPE_SSH1_PUBLIC) {
const char *error;
if (!rsakey_pubblob(fn, &key_in.blob, &key_in.bloblen,
NULL, &error)) {
if (!rsa_ssh1_loadpub(fn, &key_in.blob, &key_in.bloblen,
NULL, &error)) {
if (file_errors) {
*retstr = dupprintf("unable to load file '%s': %s",
string, error);
@ -696,7 +696,8 @@ void run_client(void)
struct RSAKey rkey;
memset(&rkey, 0, sizeof(rkey));
rkey.comment = dupstr(key->comment);
makekey(key->blob, key->bloblen, &rkey, NULL, 0);
rsa_ssh1_readpub(key->blob, key->bloblen, &rkey, NULL,
RSA_SSH1_EXPONENT_FIRST);
ssh1_write_pubkey(fp, &rkey);
freersakey(&rkey);
} else {

View File

@ -671,7 +671,7 @@ void load_key_file(HWND hwnd, struct MainDlgState *state,
comment = NULL;
passphrase = NULL;
if (realtype == SSH_KEYTYPE_SSH1)
needs_pass = rsakey_encrypted(filename, &comment);
needs_pass = rsa_ssh1_encrypted(filename, &comment);
else if (realtype == SSH_KEYTYPE_SSH2)
needs_pass = ssh2_userkey_encrypted(filename, &comment);
else
@ -698,7 +698,8 @@ void load_key_file(HWND hwnd, struct MainDlgState *state,
passphrase = dupstr("");
if (type == SSH_KEYTYPE_SSH1) {
if (realtype == type)
ret = loadrsakey(filename, &newkey1, passphrase, &errmsg);
ret = rsa_ssh1_loadkey(
filename, &newkey1, passphrase, &errmsg);
else
ret = import_ssh1(filename, realtype, &newkey1,
passphrase, &errmsg);
@ -1279,8 +1280,9 @@ static INT_PTR CALLBACK MainDlgProc(HWND hwnd, UINT msg,
ret = export_ssh1(fn, type, &state->key,
*passphrase ? passphrase : NULL);
else
ret = saversakey(fn, &state->key,
*passphrase ? passphrase : NULL);
ret = rsa_ssh1_savekey(
fn, &state->key,
*passphrase ? passphrase : NULL);
filename_free(fn);
}
if (ret <= 0) {