mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-01-09 17:38:00 +00:00
Utility function ssh_key_clone().
This makes a second independent copy of an existing ssh_key, for situations where one piece of code is going to want to keep it after its current owner frees it. In order to have it work on an arbitrary ssh_key, whether public-only or a full public+private key pair, I've had to add an ssh_key query method to ask whether a private key is known. I'm surprised I haven't found a need for that before! But I suppose in most situations in an SSH client you statically know which kind of key you're dealing with.
This commit is contained in:
parent
180d1b78de
commit
c2f1a563a5
@ -317,6 +317,12 @@ static void dsa_openssh_blob(ssh_key *key, BinarySink *bs)
|
|||||||
put_mp_ssh2(bs, dsa->x);
|
put_mp_ssh2(bs, dsa->x);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool dsa_has_private(ssh_key *key)
|
||||||
|
{
|
||||||
|
struct dsa_key *dsa = container_of(key, struct dsa_key, sshk);
|
||||||
|
return dsa->x != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static int dsa_pubkey_bits(const ssh_keyalg *self, ptrlen pub)
|
static int dsa_pubkey_bits(const ssh_keyalg *self, ptrlen pub)
|
||||||
{
|
{
|
||||||
ssh_key *sshk;
|
ssh_key *sshk;
|
||||||
@ -495,6 +501,7 @@ const ssh_keyalg ssh_dsa = {
|
|||||||
.public_blob = dsa_public_blob,
|
.public_blob = dsa_public_blob,
|
||||||
.private_blob = dsa_private_blob,
|
.private_blob = dsa_private_blob,
|
||||||
.openssh_blob = dsa_openssh_blob,
|
.openssh_blob = dsa_openssh_blob,
|
||||||
|
.has_private = dsa_has_private,
|
||||||
.cache_str = dsa_cache_str,
|
.cache_str = dsa_cache_str,
|
||||||
.components = dsa_components,
|
.components = dsa_components,
|
||||||
.pubkey_bits = dsa_pubkey_bits,
|
.pubkey_bits = dsa_pubkey_bits,
|
||||||
|
@ -787,6 +787,12 @@ static void ecdsa_private_blob(ssh_key *key, BinarySink *bs)
|
|||||||
put_mp_ssh2(bs, ek->privateKey);
|
put_mp_ssh2(bs, ek->privateKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool ecdsa_has_private(ssh_key *key)
|
||||||
|
{
|
||||||
|
struct ecdsa_key *ek = container_of(key, struct ecdsa_key, sshk);
|
||||||
|
return ek->privateKey != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static void eddsa_private_blob(ssh_key *key, BinarySink *bs)
|
static void eddsa_private_blob(ssh_key *key, BinarySink *bs)
|
||||||
{
|
{
|
||||||
struct eddsa_key *ek = container_of(key, struct eddsa_key, sshk);
|
struct eddsa_key *ek = container_of(key, struct eddsa_key, sshk);
|
||||||
@ -796,6 +802,12 @@ static void eddsa_private_blob(ssh_key *key, BinarySink *bs)
|
|||||||
put_mp_le_fixedlen(bs, ek->privateKey, ek->curve->fieldBytes);
|
put_mp_le_fixedlen(bs, ek->privateKey, ek->curve->fieldBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool eddsa_has_private(ssh_key *key)
|
||||||
|
{
|
||||||
|
struct eddsa_key *ek = container_of(key, struct eddsa_key, sshk);
|
||||||
|
return ek->privateKey != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static ssh_key *ecdsa_new_priv(const ssh_keyalg *alg, ptrlen pub, ptrlen priv)
|
static ssh_key *ecdsa_new_priv(const ssh_keyalg *alg, ptrlen pub, ptrlen priv)
|
||||||
{
|
{
|
||||||
ssh_key *sshk = ecdsa_new_pub(alg, pub);
|
ssh_key *sshk = ecdsa_new_pub(alg, pub);
|
||||||
@ -1254,6 +1266,7 @@ const ssh_keyalg ssh_ecdsa_ed25519 = {
|
|||||||
.public_blob = eddsa_public_blob,
|
.public_blob = eddsa_public_blob,
|
||||||
.private_blob = eddsa_private_blob,
|
.private_blob = eddsa_private_blob,
|
||||||
.openssh_blob = eddsa_openssh_blob,
|
.openssh_blob = eddsa_openssh_blob,
|
||||||
|
.has_private = eddsa_has_private,
|
||||||
.cache_str = eddsa_cache_str,
|
.cache_str = eddsa_cache_str,
|
||||||
.components = eddsa_components,
|
.components = eddsa_components,
|
||||||
.pubkey_bits = ec_shared_pubkey_bits,
|
.pubkey_bits = ec_shared_pubkey_bits,
|
||||||
@ -1279,6 +1292,7 @@ const ssh_keyalg ssh_ecdsa_ed448 = {
|
|||||||
.public_blob = eddsa_public_blob,
|
.public_blob = eddsa_public_blob,
|
||||||
.private_blob = eddsa_private_blob,
|
.private_blob = eddsa_private_blob,
|
||||||
.openssh_blob = eddsa_openssh_blob,
|
.openssh_blob = eddsa_openssh_blob,
|
||||||
|
.has_private = eddsa_has_private,
|
||||||
.cache_str = eddsa_cache_str,
|
.cache_str = eddsa_cache_str,
|
||||||
.components = eddsa_components,
|
.components = eddsa_components,
|
||||||
.pubkey_bits = ec_shared_pubkey_bits,
|
.pubkey_bits = ec_shared_pubkey_bits,
|
||||||
@ -1308,6 +1322,7 @@ const ssh_keyalg ssh_ecdsa_nistp256 = {
|
|||||||
.public_blob = ecdsa_public_blob,
|
.public_blob = ecdsa_public_blob,
|
||||||
.private_blob = ecdsa_private_blob,
|
.private_blob = ecdsa_private_blob,
|
||||||
.openssh_blob = ecdsa_openssh_blob,
|
.openssh_blob = ecdsa_openssh_blob,
|
||||||
|
.has_private = ecdsa_has_private,
|
||||||
.cache_str = ecdsa_cache_str,
|
.cache_str = ecdsa_cache_str,
|
||||||
.components = ecdsa_components,
|
.components = ecdsa_components,
|
||||||
.pubkey_bits = ec_shared_pubkey_bits,
|
.pubkey_bits = ec_shared_pubkey_bits,
|
||||||
@ -1337,6 +1352,7 @@ const ssh_keyalg ssh_ecdsa_nistp384 = {
|
|||||||
.public_blob = ecdsa_public_blob,
|
.public_blob = ecdsa_public_blob,
|
||||||
.private_blob = ecdsa_private_blob,
|
.private_blob = ecdsa_private_blob,
|
||||||
.openssh_blob = ecdsa_openssh_blob,
|
.openssh_blob = ecdsa_openssh_blob,
|
||||||
|
.has_private = ecdsa_has_private,
|
||||||
.cache_str = ecdsa_cache_str,
|
.cache_str = ecdsa_cache_str,
|
||||||
.components = ecdsa_components,
|
.components = ecdsa_components,
|
||||||
.pubkey_bits = ec_shared_pubkey_bits,
|
.pubkey_bits = ec_shared_pubkey_bits,
|
||||||
@ -1366,6 +1382,7 @@ const ssh_keyalg ssh_ecdsa_nistp521 = {
|
|||||||
.public_blob = ecdsa_public_blob,
|
.public_blob = ecdsa_public_blob,
|
||||||
.private_blob = ecdsa_private_blob,
|
.private_blob = ecdsa_private_blob,
|
||||||
.openssh_blob = ecdsa_openssh_blob,
|
.openssh_blob = ecdsa_openssh_blob,
|
||||||
|
.has_private = ecdsa_has_private,
|
||||||
.cache_str = ecdsa_cache_str,
|
.cache_str = ecdsa_cache_str,
|
||||||
.components = ecdsa_components,
|
.components = ecdsa_components,
|
||||||
.pubkey_bits = ec_shared_pubkey_bits,
|
.pubkey_bits = ec_shared_pubkey_bits,
|
||||||
|
@ -522,6 +522,12 @@ static key_components *rsa2_components(ssh_key *key)
|
|||||||
return rsa_components(rsa);
|
return rsa_components(rsa);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool rsa2_has_private(ssh_key *key)
|
||||||
|
{
|
||||||
|
RSAKey *rsa = container_of(key, RSAKey, sshk);
|
||||||
|
return rsa->private_exponent != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static void rsa2_public_blob(ssh_key *key, BinarySink *bs)
|
static void rsa2_public_blob(ssh_key *key, BinarySink *bs)
|
||||||
{
|
{
|
||||||
RSAKey *rsa = container_of(key, RSAKey, sshk);
|
RSAKey *rsa = container_of(key, RSAKey, sshk);
|
||||||
@ -869,6 +875,7 @@ static const struct ssh2_rsa_extra
|
|||||||
.public_blob = rsa2_public_blob, \
|
.public_blob = rsa2_public_blob, \
|
||||||
.private_blob = rsa2_private_blob, \
|
.private_blob = rsa2_private_blob, \
|
||||||
.openssh_blob = rsa2_openssh_blob, \
|
.openssh_blob = rsa2_openssh_blob, \
|
||||||
|
.has_private = rsa2_has_private, \
|
||||||
.cache_str = rsa2_cache_str, \
|
.cache_str = rsa2_cache_str, \
|
||||||
.components = rsa2_components, \
|
.components = rsa2_components, \
|
||||||
.pubkey_bits = rsa2_pubkey_bits, \
|
.pubkey_bits = rsa2_pubkey_bits, \
|
||||||
|
6
ssh.h
6
ssh.h
@ -841,6 +841,7 @@ struct ssh_keyalg {
|
|||||||
void (*public_blob)(ssh_key *key, BinarySink *);
|
void (*public_blob)(ssh_key *key, BinarySink *);
|
||||||
void (*private_blob)(ssh_key *key, BinarySink *);
|
void (*private_blob)(ssh_key *key, BinarySink *);
|
||||||
void (*openssh_blob) (ssh_key *key, BinarySink *);
|
void (*openssh_blob) (ssh_key *key, BinarySink *);
|
||||||
|
bool (*has_private) (ssh_key *key);
|
||||||
char *(*cache_str) (ssh_key *key);
|
char *(*cache_str) (ssh_key *key);
|
||||||
key_components *(*components) (ssh_key *key);
|
key_components *(*components) (ssh_key *key);
|
||||||
|
|
||||||
@ -878,6 +879,8 @@ static inline void ssh_key_private_blob(ssh_key *key, BinarySink *bs)
|
|||||||
{ key->vt->private_blob(key, bs); }
|
{ key->vt->private_blob(key, bs); }
|
||||||
static inline void ssh_key_openssh_blob(ssh_key *key, BinarySink *bs)
|
static inline void ssh_key_openssh_blob(ssh_key *key, BinarySink *bs)
|
||||||
{ key->vt->openssh_blob(key, bs); }
|
{ key->vt->openssh_blob(key, bs); }
|
||||||
|
static inline bool ssh_key_has_private(ssh_key *key)
|
||||||
|
{ return key->vt->has_private(key); }
|
||||||
static inline char *ssh_key_cache_str(ssh_key *key)
|
static inline char *ssh_key_cache_str(ssh_key *key)
|
||||||
{ return key->vt->cache_str(key); }
|
{ return key->vt->cache_str(key); }
|
||||||
static inline key_components *ssh_key_components(ssh_key *key)
|
static inline key_components *ssh_key_components(ssh_key *key)
|
||||||
@ -902,6 +905,9 @@ static inline const char *ssh_keyalg_alternate_ssh_id(
|
|||||||
unsigned nullkey_supported_flags(const ssh_keyalg *self);
|
unsigned nullkey_supported_flags(const ssh_keyalg *self);
|
||||||
const char *nullkey_alternate_ssh_id(const ssh_keyalg *self, unsigned flags);
|
const char *nullkey_alternate_ssh_id(const ssh_keyalg *self, unsigned flags);
|
||||||
|
|
||||||
|
/* Utility functions implemented centrally */
|
||||||
|
ssh_key *ssh_key_clone(ssh_key *key);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SSH2 ECDH key exchange vtable
|
* SSH2 ECDH key exchange vtable
|
||||||
*/
|
*/
|
||||||
|
@ -49,6 +49,7 @@ add_sources_from_current_dir(utils
|
|||||||
smemclr.c
|
smemclr.c
|
||||||
smemeq.c
|
smemeq.c
|
||||||
spr_get_error_message.c
|
spr_get_error_message.c
|
||||||
|
ssh_key_clone.c
|
||||||
ssh2_pick_fingerprint.c
|
ssh2_pick_fingerprint.c
|
||||||
sshutils.c
|
sshutils.c
|
||||||
strbuf.c
|
strbuf.c
|
||||||
|
32
utils/ssh_key_clone.c
Normal file
32
utils/ssh_key_clone.c
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* Make a copy of an existing ssh_key object, e.g. to survive after
|
||||||
|
* the original is freed.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "misc.h"
|
||||||
|
#include "ssh.h"
|
||||||
|
|
||||||
|
ssh_key *ssh_key_clone(ssh_key *key)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* To avoid having to add a special method in the vtable API, we
|
||||||
|
* clone by round-tripping through public and private blobs.
|
||||||
|
*/
|
||||||
|
strbuf *pub = strbuf_new_nm();
|
||||||
|
ssh_key_public_blob(key, BinarySink_UPCAST(pub));
|
||||||
|
|
||||||
|
ssh_key *copy;
|
||||||
|
|
||||||
|
if (ssh_key_has_private(key)) {
|
||||||
|
strbuf *priv = strbuf_new_nm();
|
||||||
|
ssh_key_private_blob(key, BinarySink_UPCAST(priv));
|
||||||
|
copy = ssh_key_new_priv(ssh_key_alg(key), ptrlen_from_strbuf(pub),
|
||||||
|
ptrlen_from_strbuf(priv));
|
||||||
|
strbuf_free(priv);
|
||||||
|
} else {
|
||||||
|
copy = ssh_key_new_pub(ssh_key_alg(key), ptrlen_from_strbuf(pub));
|
||||||
|
}
|
||||||
|
|
||||||
|
strbuf_free(pub);
|
||||||
|
return copy;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user