summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--usr.bin/ssh/ssh-dss.c40
-rw-r--r--usr.bin/ssh/ssh-ecdsa-sk.c15
-rw-r--r--usr.bin/ssh/ssh-ecdsa.c15
-rw-r--r--usr.bin/ssh/ssh-ed25519-sk.c15
-rw-r--r--usr.bin/ssh/ssh-ed25519.c14
-rw-r--r--usr.bin/ssh/ssh-rsa.c29
-rw-r--r--usr.bin/ssh/ssh-xmss.c28
-rw-r--r--usr.bin/ssh/sshkey.c137
-rw-r--r--usr.bin/ssh/sshkey.h4
9 files changed, 166 insertions, 131 deletions
diff --git a/usr.bin/ssh/ssh-dss.c b/usr.bin/ssh/ssh-dss.c
index 6b2c48750c8..2dba1ed1d2c 100644
--- a/usr.bin/ssh/ssh-dss.c
+++ b/usr.bin/ssh/ssh-dss.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh-dss.c,v 1.43 2022/10/28 00:39:29 djm Exp $ */
+/* $OpenBSD: ssh-dss.c,v 1.44 2022/10/28 00:41:17 djm Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
*
@@ -136,6 +136,43 @@ ssh_dss_generate(struct sshkey *k, int bits)
return 0;
}
+static int
+ssh_dss_copy_public(const struct sshkey *from, struct sshkey *to)
+{
+ const BIGNUM *dsa_p, *dsa_q, *dsa_g, *dsa_pub_key;
+ BIGNUM *dsa_p_dup = NULL, *dsa_q_dup = NULL, *dsa_g_dup = NULL;
+ BIGNUM *dsa_pub_key_dup = NULL;
+ int r = SSH_ERR_INTERNAL_ERROR;
+
+ DSA_get0_pqg(from->dsa, &dsa_p, &dsa_q, &dsa_g);
+ DSA_get0_key(from->dsa, &dsa_pub_key, NULL);
+ if ((dsa_p_dup = BN_dup(dsa_p)) == NULL ||
+ (dsa_q_dup = BN_dup(dsa_q)) == NULL ||
+ (dsa_g_dup = BN_dup(dsa_g)) == NULL ||
+ (dsa_pub_key_dup = BN_dup(dsa_pub_key)) == NULL) {
+ r = SSH_ERR_ALLOC_FAIL;
+ goto out;
+ }
+ if (!DSA_set0_pqg(to->dsa, dsa_p_dup, dsa_q_dup, dsa_g_dup)) {
+ r = SSH_ERR_LIBCRYPTO_ERROR;
+ goto out;
+ }
+ dsa_p_dup = dsa_q_dup = dsa_g_dup = NULL; /* transferred */
+ if (!DSA_set0_key(to->dsa, dsa_pub_key_dup, NULL)) {
+ r = SSH_ERR_LIBCRYPTO_ERROR;
+ goto out;
+ }
+ dsa_pub_key_dup = NULL; /* transferred */
+ /* success */
+ r = 0;
+ out:
+ BN_clear_free(dsa_p_dup);
+ BN_clear_free(dsa_q_dup);
+ BN_clear_free(dsa_g_dup);
+ BN_clear_free(dsa_pub_key_dup);
+ return r;
+}
+
int
ssh_dss_sign(const struct sshkey *key, u_char **sigp, size_t *lenp,
const u_char *data, size_t datalen, u_int compat)
@@ -300,6 +337,7 @@ static const struct sshkey_impl_funcs sshkey_dss_funcs = {
/* .equal = */ ssh_dss_equal,
/* .ssh_serialize_public = */ ssh_dss_serialize_public,
/* .generate = */ ssh_dss_generate,
+ /* .copy_public = */ ssh_dss_copy_public,
};
const struct sshkey_impl sshkey_dss_impl = {
diff --git a/usr.bin/ssh/ssh-ecdsa-sk.c b/usr.bin/ssh/ssh-ecdsa-sk.c
index 5c844d8baac..f3692b0b7fb 100644
--- a/usr.bin/ssh/ssh-ecdsa-sk.c
+++ b/usr.bin/ssh/ssh-ecdsa-sk.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh-ecdsa-sk.c,v 1.12 2022/10/28 00:39:29 djm Exp $ */
+/* $OpenBSD: ssh-ecdsa-sk.c,v 1.13 2022/10/28 00:41:17 djm Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
* Copyright (c) 2010 Damien Miller. All rights reserved.
@@ -78,6 +78,18 @@ ssh_ecdsa_sk_serialize_public(const struct sshkey *key, struct sshbuf *b,
return 0;
}
+static int
+ssh_ecdsa_sk_copy_public(const struct sshkey *from, struct sshkey *to)
+{
+ int r;
+
+ if ((r = sshkey_ecdsa_funcs.copy_public(from, to)) != 0)
+ return r;
+ if ((r = sshkey_copy_public_sk(from, to)) != 0)
+ return r;
+ return 0;
+}
+
/*
* Check FIDO/W3C webauthn signatures clientData field against the expected
* format and prepare a hash of it for use in signature verification.
@@ -345,6 +357,7 @@ static const struct sshkey_impl_funcs sshkey_ecdsa_sk_funcs = {
/* .equal = */ ssh_ecdsa_sk_equal,
/* .ssh_serialize_public = */ ssh_ecdsa_sk_serialize_public,
/* .generate = */ NULL,
+ /* .copy_public = */ ssh_ecdsa_sk_copy_public,
};
const struct sshkey_impl sshkey_ecdsa_sk_impl = {
diff --git a/usr.bin/ssh/ssh-ecdsa.c b/usr.bin/ssh/ssh-ecdsa.c
index 9e576648354..b2b03205d13 100644
--- a/usr.bin/ssh/ssh-ecdsa.c
+++ b/usr.bin/ssh/ssh-ecdsa.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh-ecdsa.c,v 1.20 2022/10/28 00:39:29 djm Exp $ */
+/* $OpenBSD: ssh-ecdsa.c,v 1.21 2022/10/28 00:41:17 djm Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
* Copyright (c) 2010 Damien Miller. All rights reserved.
@@ -118,6 +118,18 @@ ssh_ecdsa_generate(struct sshkey *k, int bits)
return 0;
}
+static int
+ssh_ecdsa_copy_public(const struct sshkey *from, struct sshkey *to)
+{
+ to->ecdsa_nid = from->ecdsa_nid;
+ if ((to->ecdsa = EC_KEY_new_by_curve_name(from->ecdsa_nid)) == NULL)
+ return SSH_ERR_ALLOC_FAIL;
+ if (EC_KEY_set_public_key(to->ecdsa,
+ EC_KEY_get0_public_key(from->ecdsa)) != 1)
+ return SSH_ERR_LIBCRYPTO_ERROR; /* caller will free k->ecdsa */
+ return 0;
+}
+
/* ARGSUSED */
int
ssh_ecdsa_sign(const struct sshkey *key, u_char **sigp, size_t *lenp,
@@ -278,6 +290,7 @@ const struct sshkey_impl_funcs sshkey_ecdsa_funcs = {
/* .equal = */ ssh_ecdsa_equal,
/* .ssh_serialize_public = */ ssh_ecdsa_serialize_public,
/* .generate = */ ssh_ecdsa_generate,
+ /* .copy_public = */ ssh_ecdsa_copy_public,
};
const struct sshkey_impl sshkey_ecdsa_nistp256_impl = {
diff --git a/usr.bin/ssh/ssh-ed25519-sk.c b/usr.bin/ssh/ssh-ed25519-sk.c
index 7131363f4a2..99676d96a84 100644
--- a/usr.bin/ssh/ssh-ed25519-sk.c
+++ b/usr.bin/ssh/ssh-ed25519-sk.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh-ed25519-sk.c,v 1.10 2022/10/28 00:39:29 djm Exp $ */
+/* $OpenBSD: ssh-ed25519-sk.c,v 1.11 2022/10/28 00:41:17 djm Exp $ */
/*
* Copyright (c) 2019 Markus Friedl. All rights reserved.
*
@@ -68,6 +68,18 @@ ssh_ed25519_sk_serialize_public(const struct sshkey *key, struct sshbuf *b,
return 0;
}
+static int
+ssh_ed25519_sk_copy_public(const struct sshkey *from, struct sshkey *to)
+{
+ int r;
+
+ if ((r = sshkey_ed25519_funcs.copy_public(from, to)) != 0)
+ return r;
+ if ((r = sshkey_copy_public_sk(from, to)) != 0)
+ return r;
+ return 0;
+}
+
int
ssh_ed25519_sk_verify(const struct sshkey *key,
const u_char *signature, size_t signaturelen,
@@ -202,6 +214,7 @@ static const struct sshkey_impl_funcs sshkey_ed25519_sk_funcs = {
/* .equal = */ ssh_ed25519_sk_equal,
/* .ssh_serialize_public = */ ssh_ed25519_sk_serialize_public,
/* .generate = */ NULL,
+ /* .copy_public = */ ssh_ed25519_sk_copy_public,
};
const struct sshkey_impl sshkey_ed25519_sk_impl = {
diff --git a/usr.bin/ssh/ssh-ed25519.c b/usr.bin/ssh/ssh-ed25519.c
index bbf164c8c42..db1dc96f379 100644
--- a/usr.bin/ssh/ssh-ed25519.c
+++ b/usr.bin/ssh/ssh-ed25519.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh-ed25519.c,v 1.14 2022/10/28 00:39:29 djm Exp $ */
+/* $OpenBSD: ssh-ed25519.c,v 1.15 2022/10/28 00:41:17 djm Exp $ */
/*
* Copyright (c) 2013 Markus Friedl <markus@openbsd.org>
*
@@ -73,6 +73,17 @@ ssh_ed25519_generate(struct sshkey *k, int bits)
return 0;
}
+static int
+ssh_ed25519_copy_public(const struct sshkey *from, struct sshkey *to)
+{
+ if (from->ed25519_pk == NULL)
+ return 0; /* XXX SSH_ERR_INTERNAL_ERROR ? */
+ if ((to->ed25519_pk = malloc(ED25519_PK_SZ)) == NULL)
+ return SSH_ERR_ALLOC_FAIL;
+ memcpy(to->ed25519_pk, from->ed25519_pk, ED25519_PK_SZ);
+ return 0;
+}
+
int
ssh_ed25519_sign(const struct sshkey *key, u_char **sigp, size_t *lenp,
const u_char *data, size_t datalen, u_int compat)
@@ -208,6 +219,7 @@ const struct sshkey_impl_funcs sshkey_ed25519_funcs = {
/* .equal = */ ssh_ed25519_equal,
/* .ssh_serialize_public = */ ssh_ed25519_serialize_public,
/* .generate = */ ssh_ed25519_generate,
+ /* .copy_public = */ ssh_ed25519_copy_public,
};
const struct sshkey_impl sshkey_ed25519_impl = {
diff --git a/usr.bin/ssh/ssh-rsa.c b/usr.bin/ssh/ssh-rsa.c
index f6aa4bfef63..f13a082555b 100644
--- a/usr.bin/ssh/ssh-rsa.c
+++ b/usr.bin/ssh/ssh-rsa.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh-rsa.c,v 1.72 2022/10/28 00:39:29 djm Exp $ */
+/* $OpenBSD: ssh-rsa.c,v 1.73 2022/10/28 00:41:17 djm Exp $ */
/*
* Copyright (c) 2000, 2003 Markus Friedl <markus@openbsd.org>
*
@@ -125,6 +125,32 @@ ssh_rsa_generate(struct sshkey *k, int bits)
return ret;
}
+static int
+ssh_rsa_copy_public(const struct sshkey *from, struct sshkey *to)
+{
+ const BIGNUM *rsa_n, *rsa_e;
+ BIGNUM *rsa_n_dup = NULL, *rsa_e_dup = NULL;
+ int r = SSH_ERR_INTERNAL_ERROR;
+
+ RSA_get0_key(from->rsa, &rsa_n, &rsa_e, NULL);
+ if ((rsa_n_dup = BN_dup(rsa_n)) == NULL ||
+ (rsa_e_dup = BN_dup(rsa_e)) == NULL) {
+ r = SSH_ERR_ALLOC_FAIL;
+ goto out;
+ }
+ if (!RSA_set0_key(to->rsa, rsa_n_dup, rsa_e_dup, NULL)) {
+ r = SSH_ERR_LIBCRYPTO_ERROR;
+ goto out;
+ }
+ rsa_n_dup = rsa_e_dup = NULL; /* transferred */
+ /* success */
+ r = 0;
+ out:
+ BN_clear_free(rsa_n_dup);
+ BN_clear_free(rsa_e_dup);
+ return r;
+}
+
static const char *
rsa_hash_alg_ident(int hash_alg)
{
@@ -540,6 +566,7 @@ static const struct sshkey_impl_funcs sshkey_rsa_funcs = {
/* .equal = */ ssh_rsa_equal,
/* .ssh_serialize_public = */ ssh_rsa_serialize_public,
/* .generate = */ ssh_rsa_generate,
+ /* .copy_public = */ ssh_rsa_copy_public,
};
const struct sshkey_impl sshkey_rsa_impl = {
diff --git a/usr.bin/ssh/ssh-xmss.c b/usr.bin/ssh/ssh-xmss.c
index 30cd89c7f1b..7a3bec7c7f0 100644
--- a/usr.bin/ssh/ssh-xmss.c
+++ b/usr.bin/ssh/ssh-xmss.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh-xmss.c,v 1.9 2022/10/28 00:39:29 djm Exp $*/
+/* $OpenBSD: ssh-xmss.c,v 1.10 2022/10/28 00:41:17 djm Exp $*/
/*
* Copyright (c) 2017 Stefan-Lukas Gazdag.
* Copyright (c) 2017 Markus Friedl.
@@ -79,6 +79,31 @@ ssh_xmss_serialize_public(const struct sshkey *key, struct sshbuf *b,
return 0;
}
+static int
+ssh_xmss_copy_public(const struct sshkey *from, struct sshkey *to)
+{
+ int r = SSH_ERR_INTERNAL_ERROR;
+ u_int32_t left;
+ size_t pklen;
+
+ if ((r = sshkey_xmss_init(to, from->xmss_name)) != 0)
+ return r;
+ if (from->xmss_pk == NULL)
+ return 0; /* XXX SSH_ERR_INTERNAL_ERROR ? */
+
+ if ((pklen = sshkey_xmss_pklen(from)) == 0 ||
+ sshkey_xmss_pklen(to) != pklen)
+ return SSH_ERR_INTERNAL_ERROR;
+ if ((to->xmss_pk = malloc(pklen)) == NULL)
+ return SSH_ERR_ALLOC_FAIL;
+ memcpy(to->xmss_pk, from->xmss_pk, pklen);
+ /* simulate number of signatures left on pubkey */
+ left = sshkey_xmss_signatures_left(from);
+ if (left)
+ sshkey_xmss_enable_maxsign(to, left);
+ return 0;
+}
+
int
ssh_xmss_sign(const struct sshkey *key, u_char **sigp, size_t *lenp,
const u_char *data, size_t datalen, u_int compat)
@@ -234,6 +259,7 @@ static const struct sshkey_impl_funcs sshkey_xmss_funcs = {
/* .equal = */ ssh_xmss_equal,
/* .ssh_serialize_public = */ ssh_xmss_serialize_public,
/* .generate = */ sshkey_xmss_generate_private_key,
+ /* .copy_public = */ ssh_xmss_copy_public,
};
const struct sshkey_impl sshkey_xmss_impl = {
diff --git a/usr.bin/ssh/sshkey.c b/usr.bin/ssh/sshkey.c
index 74ee6b4409a..7a6daeb8a6d 100644
--- a/usr.bin/ssh/sshkey.c
+++ b/usr.bin/ssh/sshkey.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sshkey.c,v 1.127 2022/10/28 00:39:29 djm Exp $ */
+/* $OpenBSD: sshkey.c,v 1.128 2022/10/28 00:41:17 djm Exp $ */
/*
* Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
* Copyright (c) 2008 Alexander von Gernler. All rights reserved.
@@ -1406,130 +1406,30 @@ sshkey_cert_copy(const struct sshkey *from_key, struct sshkey *to_key)
}
int
+sshkey_copy_public_sk(const struct sshkey *from, struct sshkey *to)
+{
+ /* Append security-key application string */
+ if ((to->sk_application = strdup(from->sk_application)) == NULL)
+ return SSH_ERR_ALLOC_FAIL;
+ return 0;
+}
+
+int
sshkey_from_private(const struct sshkey *k, struct sshkey **pkp)
{
struct sshkey *n = NULL;
int r = SSH_ERR_INTERNAL_ERROR;
-#ifdef WITH_OPENSSL
- const BIGNUM *rsa_n, *rsa_e;
- BIGNUM *rsa_n_dup = NULL, *rsa_e_dup = NULL;
- const BIGNUM *dsa_p, *dsa_q, *dsa_g, *dsa_pub_key;
- BIGNUM *dsa_p_dup = NULL, *dsa_q_dup = NULL, *dsa_g_dup = NULL;
- BIGNUM *dsa_pub_key_dup = NULL;
-#endif /* WITH_OPENSSL */
+ const struct sshkey_impl *impl;
*pkp = NULL;
+ if ((impl = sshkey_impl_from_key(k)) == NULL)
+ return SSH_ERR_KEY_TYPE_UNKNOWN;
if ((n = sshkey_new(k->type)) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
- switch (k->type) {
-#ifdef WITH_OPENSSL
- case KEY_DSA:
- case KEY_DSA_CERT:
- DSA_get0_pqg(k->dsa, &dsa_p, &dsa_q, &dsa_g);
- DSA_get0_key(k->dsa, &dsa_pub_key, NULL);
- if ((dsa_p_dup = BN_dup(dsa_p)) == NULL ||
- (dsa_q_dup = BN_dup(dsa_q)) == NULL ||
- (dsa_g_dup = BN_dup(dsa_g)) == NULL ||
- (dsa_pub_key_dup = BN_dup(dsa_pub_key)) == NULL) {
- r = SSH_ERR_ALLOC_FAIL;
- goto out;
- }
- if (!DSA_set0_pqg(n->dsa, dsa_p_dup, dsa_q_dup, dsa_g_dup)) {
- r = SSH_ERR_LIBCRYPTO_ERROR;
- goto out;
- }
- dsa_p_dup = dsa_q_dup = dsa_g_dup = NULL; /* transferred */
- if (!DSA_set0_key(n->dsa, dsa_pub_key_dup, NULL)) {
- r = SSH_ERR_LIBCRYPTO_ERROR;
- goto out;
- }
- dsa_pub_key_dup = NULL; /* transferred */
-
- break;
- case KEY_ECDSA:
- case KEY_ECDSA_CERT:
- case KEY_ECDSA_SK:
- case KEY_ECDSA_SK_CERT:
- n->ecdsa_nid = k->ecdsa_nid;
- n->ecdsa = EC_KEY_new_by_curve_name(k->ecdsa_nid);
- if (n->ecdsa == NULL) {
- r = SSH_ERR_ALLOC_FAIL;
- goto out;
- }
- if (EC_KEY_set_public_key(n->ecdsa,
- EC_KEY_get0_public_key(k->ecdsa)) != 1) {
- r = SSH_ERR_LIBCRYPTO_ERROR;
- goto out;
- }
- if (k->type != KEY_ECDSA_SK && k->type != KEY_ECDSA_SK_CERT)
- break;
- /* Append security-key application string */
- if ((n->sk_application = strdup(k->sk_application)) == NULL)
- goto out;
- break;
- case KEY_RSA:
- case KEY_RSA_CERT:
- RSA_get0_key(k->rsa, &rsa_n, &rsa_e, NULL);
- if ((rsa_n_dup = BN_dup(rsa_n)) == NULL ||
- (rsa_e_dup = BN_dup(rsa_e)) == NULL) {
- r = SSH_ERR_ALLOC_FAIL;
- goto out;
- }
- if (!RSA_set0_key(n->rsa, rsa_n_dup, rsa_e_dup, NULL)) {
- r = SSH_ERR_LIBCRYPTO_ERROR;
- goto out;
- }
- rsa_n_dup = rsa_e_dup = NULL; /* transferred */
- break;
-#endif /* WITH_OPENSSL */
- case KEY_ED25519:
- case KEY_ED25519_CERT:
- case KEY_ED25519_SK:
- case KEY_ED25519_SK_CERT:
- if (k->ed25519_pk != NULL) {
- if ((n->ed25519_pk = malloc(ED25519_PK_SZ)) == NULL) {
- r = SSH_ERR_ALLOC_FAIL;
- goto out;
- }
- memcpy(n->ed25519_pk, k->ed25519_pk, ED25519_PK_SZ);
- }
- if (k->type != KEY_ED25519_SK &&
- k->type != KEY_ED25519_SK_CERT)
- break;
- /* Append security-key application string */
- if ((n->sk_application = strdup(k->sk_application)) == NULL)
- goto out;
- break;
-#ifdef WITH_XMSS
- case KEY_XMSS:
- case KEY_XMSS_CERT:
- if ((r = sshkey_xmss_init(n, k->xmss_name)) != 0)
- goto out;
- if (k->xmss_pk != NULL) {
- u_int32_t left;
- size_t pklen = sshkey_xmss_pklen(k);
- if (pklen == 0 || sshkey_xmss_pklen(n) != pklen) {
- r = SSH_ERR_INTERNAL_ERROR;
- goto out;
- }
- if ((n->xmss_pk = malloc(pklen)) == NULL) {
- r = SSH_ERR_ALLOC_FAIL;
- goto out;
- }
- memcpy(n->xmss_pk, k->xmss_pk, pklen);
- /* simulate number of signatures left on pubkey */
- left = sshkey_xmss_signatures_left(k);
- if (left)
- sshkey_xmss_enable_maxsign(n, left);
- }
- break;
-#endif /* WITH_XMSS */
- default:
- r = SSH_ERR_KEY_TYPE_UNKNOWN;
+ if ((r = impl->funcs->copy_public(k, n)) != 0)
goto out;
- }
if (sshkey_is_cert(k) && (r = sshkey_cert_copy(k, n)) != 0)
goto out;
/* success */
@@ -1538,15 +1438,6 @@ sshkey_from_private(const struct sshkey *k, struct sshkey **pkp)
r = 0;
out:
sshkey_free(n);
-#ifdef WITH_OPENSSL
- BN_clear_free(rsa_n_dup);
- BN_clear_free(rsa_e_dup);
- BN_clear_free(dsa_p_dup);
- BN_clear_free(dsa_q_dup);
- BN_clear_free(dsa_g_dup);
- BN_clear_free(dsa_pub_key_dup);
-#endif /* WITH_OPENSSL */
-
return r;
}
diff --git a/usr.bin/ssh/sshkey.h b/usr.bin/ssh/sshkey.h
index c90724ac575..899614dbe30 100644
--- a/usr.bin/ssh/sshkey.h
+++ b/usr.bin/ssh/sshkey.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: sshkey.h,v 1.56 2022/10/28 00:39:29 djm Exp $ */
+/* $OpenBSD: sshkey.h,v 1.57 2022/10/28 00:41:17 djm Exp $ */
/*
* Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
@@ -166,6 +166,7 @@ struct sshkey_impl_funcs {
int (*serialize_public)(const struct sshkey *, struct sshbuf *,
const char *, enum sshkey_serialize_rep);
int (*generate)(struct sshkey *, int); /* optional */
+ int (*copy_public)(const struct sshkey *, struct sshkey *);
};
struct sshkey_impl {
@@ -307,6 +308,7 @@ void sshkey_sig_details_free(struct sshkey_sig_details *);
int sshkey_sk_fields_equal(const struct sshkey *a, const struct sshkey *b);
void sshkey_sk_cleanup(struct sshkey *k);
int sshkey_serialize_sk(const struct sshkey *key, struct sshbuf *b);
+int sshkey_copy_public_sk(const struct sshkey *from, struct sshkey *to);
int ssh_rsa_sign(const struct sshkey *key,
u_char **sigp, size_t *lenp, const u_char *data, size_t datalen,