mirror of git://anongit.mindrot.org/openssh.git
upstream: factor out public key serialization
feedback/ok markus@ OpenBSD-Commit-ID: a3570c4b97290c5662890aea7328d87f55939033
This commit is contained in:
parent
1e78844ae2
commit
591fed94e6
27
ssh-dss.c
27
ssh-dss.c
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: ssh-dss.c,v 1.41 2022/10/28 00:36:31 djm Exp $ */
|
||||
/* $OpenBSD: ssh-dss.c,v 1.42 2022/10/28 00:37:24 djm Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2000 Markus Friedl. All rights reserved.
|
||||
*
|
||||
|
@ -102,6 +102,30 @@ ssh_dss_equal(const struct sshkey *a, const struct sshkey *b)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
ssh_dss_serialize_public(const struct sshkey *key, struct sshbuf *b,
|
||||
const char *typename, enum sshkey_serialize_rep opts)
|
||||
{
|
||||
int r;
|
||||
const BIGNUM *dsa_p, *dsa_q, *dsa_g, *dsa_pub_key;
|
||||
|
||||
if (key->dsa == NULL)
|
||||
return SSH_ERR_INVALID_ARGUMENT;
|
||||
DSA_get0_pqg(key->dsa, &dsa_p, &dsa_q, &dsa_g);
|
||||
DSA_get0_key(key->dsa, &dsa_pub_key, NULL);
|
||||
if (dsa_p == NULL || dsa_q == NULL ||
|
||||
dsa_g == NULL || dsa_pub_key == NULL)
|
||||
return SSH_ERR_INTERNAL_ERROR;
|
||||
if ((r = sshbuf_put_cstring(b, typename)) != 0 ||
|
||||
(r = sshbuf_put_bignum2(b, dsa_p)) != 0 ||
|
||||
(r = sshbuf_put_bignum2(b, dsa_q)) != 0 ||
|
||||
(r = sshbuf_put_bignum2(b, dsa_g)) != 0 ||
|
||||
(r = sshbuf_put_bignum2(b, dsa_pub_key)) != 0)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
ssh_dss_sign(const struct sshkey *key, u_char **sigp, size_t *lenp,
|
||||
const u_char *data, size_t datalen, u_int compat)
|
||||
|
@ -264,6 +288,7 @@ static const struct sshkey_impl_funcs sshkey_dss_funcs = {
|
|||
/* .alloc = */ ssh_dss_alloc,
|
||||
/* .cleanup = */ ssh_dss_cleanup,
|
||||
/* .equal = */ ssh_dss_equal,
|
||||
/* .ssh_serialize_public = */ ssh_dss_serialize_public,
|
||||
};
|
||||
|
||||
const struct sshkey_impl sshkey_dss_impl = {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: ssh-ecdsa-sk.c,v 1.10 2022/10/28 00:36:31 djm Exp $ */
|
||||
/* $OpenBSD: ssh-ecdsa-sk.c,v 1.11 2022/10/28 00:37:24 djm Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2000 Markus Friedl. All rights reserved.
|
||||
* Copyright (c) 2010 Damien Miller. All rights reserved.
|
||||
|
@ -81,6 +81,21 @@ ssh_ecdsa_sk_equal(const struct sshkey *a, const struct sshkey *b)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
ssh_ecdsa_sk_serialize_public(const struct sshkey *key, struct sshbuf *b,
|
||||
const char *typename, enum sshkey_serialize_rep opts)
|
||||
{
|
||||
int r;
|
||||
|
||||
if ((r = sshkey_ecdsa_funcs.serialize_public(key, b,
|
||||
typename, opts)) != 0)
|
||||
return r;
|
||||
if ((r = sshkey_serialize_sk(key, b)) != 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.
|
||||
|
@ -346,6 +361,7 @@ static const struct sshkey_impl_funcs sshkey_ecdsa_sk_funcs = {
|
|||
/* .alloc = */ NULL,
|
||||
/* .cleanup = */ ssh_ecdsa_sk_cleanup,
|
||||
/* .equal = */ ssh_ecdsa_sk_equal,
|
||||
/* .ssh_serialize_public = */ ssh_ecdsa_sk_serialize_public,
|
||||
};
|
||||
|
||||
const struct sshkey_impl sshkey_ecdsa_sk_impl = {
|
||||
|
|
21
ssh-ecdsa.c
21
ssh-ecdsa.c
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: ssh-ecdsa.c,v 1.18 2022/10/28 00:36:31 djm Exp $ */
|
||||
/* $OpenBSD: ssh-ecdsa.c,v 1.19 2022/10/28 00:37:24 djm Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2000 Markus Friedl. All rights reserved.
|
||||
* Copyright (c) 2010 Damien Miller. All rights reserved.
|
||||
|
@ -87,9 +87,27 @@ ssh_ecdsa_equal(const struct sshkey *a, const struct sshkey *b)
|
|||
return 0;
|
||||
if (EC_POINT_cmp(grp_a, pub_a, pub_b, NULL) != 0)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
ssh_ecdsa_serialize_public(const struct sshkey *key, struct sshbuf *b,
|
||||
const char *typename, enum sshkey_serialize_rep opts)
|
||||
{
|
||||
int r;
|
||||
|
||||
if (key->ecdsa == NULL)
|
||||
return SSH_ERR_INVALID_ARGUMENT;
|
||||
if ((r = sshbuf_put_cstring(b, typename)) != 0 ||
|
||||
(r = sshbuf_put_cstring(b,
|
||||
sshkey_curve_nid_to_name(key->ecdsa_nid))) != 0 ||
|
||||
(r = sshbuf_put_eckey(b, key->ecdsa)) != 0)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
int
|
||||
ssh_ecdsa_sign(const struct sshkey *key, u_char **sigp, size_t *lenp,
|
||||
|
@ -248,6 +266,7 @@ const struct sshkey_impl_funcs sshkey_ecdsa_funcs = {
|
|||
/* .alloc = */ NULL,
|
||||
/* .cleanup = */ ssh_ecdsa_cleanup,
|
||||
/* .equal = */ ssh_ecdsa_equal,
|
||||
/* .ssh_serialize_public = */ ssh_ecdsa_serialize_public,
|
||||
};
|
||||
|
||||
const struct sshkey_impl sshkey_ecdsa_nistp256_impl = {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: ssh-ed25519-sk.c,v 1.8 2022/10/28 00:36:31 djm Exp $ */
|
||||
/* $OpenBSD: ssh-ed25519-sk.c,v 1.9 2022/10/28 00:37:24 djm Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2019 Markus Friedl. All rights reserved.
|
||||
*
|
||||
|
@ -55,6 +55,21 @@ ssh_ed25519_sk_equal(const struct sshkey *a, const struct sshkey *b)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
ssh_ed25519_sk_serialize_public(const struct sshkey *key, struct sshbuf *b,
|
||||
const char *typename, enum sshkey_serialize_rep opts)
|
||||
{
|
||||
int r;
|
||||
|
||||
if ((r = sshkey_ed25519_funcs.serialize_public(key, b,
|
||||
typename, opts)) != 0)
|
||||
return r;
|
||||
if ((r = sshkey_serialize_sk(key, b)) != 0)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
ssh_ed25519_sk_verify(const struct sshkey *key,
|
||||
const u_char *signature, size_t signaturelen,
|
||||
|
@ -187,6 +202,7 @@ static const struct sshkey_impl_funcs sshkey_ed25519_sk_funcs = {
|
|||
/* .alloc = */ NULL,
|
||||
/* .cleanup = */ ssh_ed25519_sk_cleanup,
|
||||
/* .equal = */ ssh_ed25519_sk_equal,
|
||||
/* .ssh_serialize_public = */ ssh_ed25519_sk_serialize_public,
|
||||
};
|
||||
|
||||
const struct sshkey_impl sshkey_ed25519_sk_impl = {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: ssh-ed25519.c,v 1.12 2022/10/28 00:36:31 djm Exp $ */
|
||||
/* $OpenBSD: ssh-ed25519.c,v 1.13 2022/10/28 00:37:24 djm Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2013 Markus Friedl <markus@openbsd.org>
|
||||
*
|
||||
|
@ -51,6 +51,21 @@ ssh_ed25519_equal(const struct sshkey *a, const struct sshkey *b)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
ssh_ed25519_serialize_public(const struct sshkey *key, struct sshbuf *b,
|
||||
const char *typename, enum sshkey_serialize_rep opts)
|
||||
{
|
||||
int r;
|
||||
|
||||
if (key->ed25519_pk == NULL)
|
||||
return SSH_ERR_INVALID_ARGUMENT;
|
||||
if ((r = sshbuf_put_cstring(b, typename)) != 0 ||
|
||||
(r = sshbuf_put_string(b, key->ed25519_pk, ED25519_PK_SZ)) != 0)
|
||||
return r;
|
||||
|
||||
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)
|
||||
|
@ -184,6 +199,7 @@ const struct sshkey_impl_funcs sshkey_ed25519_funcs = {
|
|||
/* .alloc = */ NULL,
|
||||
/* .cleanup = */ ssh_ed25519_cleanup,
|
||||
/* .equal = */ ssh_ed25519_equal,
|
||||
/* .ssh_serialize_public = */ ssh_ed25519_serialize_public,
|
||||
};
|
||||
|
||||
const struct sshkey_impl sshkey_ed25519_impl = {
|
||||
|
|
21
ssh-rsa.c
21
ssh-rsa.c
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: ssh-rsa.c,v 1.70 2022/10/28 00:36:31 djm Exp $ */
|
||||
/* $OpenBSD: ssh-rsa.c,v 1.71 2022/10/28 00:37:24 djm Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2000, 2003 Markus Friedl <markus@openbsd.org>
|
||||
*
|
||||
|
@ -86,6 +86,24 @@ ssh_rsa_equal(const struct sshkey *a, const struct sshkey *b)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
ssh_rsa_serialize_public(const struct sshkey *key, struct sshbuf *b,
|
||||
const char *typename, enum sshkey_serialize_rep opts)
|
||||
{
|
||||
int r;
|
||||
const BIGNUM *rsa_n, *rsa_e;
|
||||
|
||||
if (key->rsa == NULL)
|
||||
return SSH_ERR_INVALID_ARGUMENT;
|
||||
RSA_get0_key(key->rsa, &rsa_n, &rsa_e, NULL);
|
||||
if ((r = sshbuf_put_cstring(b, typename)) != 0 ||
|
||||
(r = sshbuf_put_bignum2(b, rsa_e)) != 0 ||
|
||||
(r = sshbuf_put_bignum2(b, rsa_n)) != 0)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char *
|
||||
rsa_hash_alg_ident(int hash_alg)
|
||||
{
|
||||
|
@ -499,6 +517,7 @@ static const struct sshkey_impl_funcs sshkey_rsa_funcs = {
|
|||
/* .alloc = */ ssh_rsa_alloc,
|
||||
/* .cleanup = */ ssh_rsa_cleanup,
|
||||
/* .equal = */ ssh_rsa_equal,
|
||||
/* .ssh_serialize_public = */ ssh_rsa_serialize_public,
|
||||
};
|
||||
|
||||
const struct sshkey_impl sshkey_rsa_impl = {
|
||||
|
|
22
ssh-xmss.c
22
ssh-xmss.c
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: ssh-xmss.c,v 1.7 2022/10/28 00:36:31 djm Exp $*/
|
||||
/* $OpenBSD: ssh-xmss.c,v 1.8 2022/10/28 00:37:24 djm Exp $*/
|
||||
/*
|
||||
* Copyright (c) 2017 Stefan-Lukas Gazdag.
|
||||
* Copyright (c) 2017 Markus Friedl.
|
||||
|
@ -63,6 +63,25 @@ ssh_xmss_equal(const struct sshkey *a, const struct sshkey *b)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
ssh_xmss_serialize_public(const struct sshkey *key, struct sshbuf *b,
|
||||
const char *typename, enum sshkey_serialize_rep opts)
|
||||
{
|
||||
int r;
|
||||
|
||||
if (key->xmss_name == NULL || key->xmss_pk == NULL ||
|
||||
sshkey_xmss_pklen(key) == 0)
|
||||
return SSH_ERR_INVALID_ARGUMENT;
|
||||
if ((r = sshbuf_put_cstring(b, typename)) != 0 ||
|
||||
(r = sshbuf_put_cstring(b, key->xmss_name)) != 0 ||
|
||||
(r = sshbuf_put_string(b, key->xmss_pk,
|
||||
sshkey_xmss_pklen(key))) != 0 ||
|
||||
(r = sshkey_xmss_serialize_pk_info(key, b, opts)) != 0)
|
||||
return r;
|
||||
|
||||
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)
|
||||
|
@ -216,6 +235,7 @@ static const struct sshkey_impl_funcs sshkey_xmss_funcs = {
|
|||
/* .alloc = */ NULL,
|
||||
/* .cleanup = */ ssh_xmss_cleanup,
|
||||
/* .equal = */ ssh_xmss_equal,
|
||||
/* .ssh_serialize_public = */ ssh_xmss_serialize_public,
|
||||
};
|
||||
|
||||
const struct sshkey_impl sshkey_xmss_impl = {
|
||||
|
|
117
sshkey.c
117
sshkey.c
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: sshkey.c,v 1.124 2022/10/28 00:36:31 djm Exp $ */
|
||||
/* $OpenBSD: sshkey.c,v 1.125 2022/10/28 00:37:24 djm Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
|
||||
* Copyright (c) 2008 Alexander von Gernler. All rights reserved.
|
||||
|
@ -679,116 +679,47 @@ sshkey_equal(const struct sshkey *a, const struct sshkey *b)
|
|||
return sshkey_equal_public(a, b);
|
||||
}
|
||||
|
||||
|
||||
/* Serialise common FIDO key parts */
|
||||
int
|
||||
sshkey_serialize_sk(const struct sshkey *key, struct sshbuf *b)
|
||||
{
|
||||
int r;
|
||||
|
||||
if ((r = sshbuf_put_cstring(b, key->sk_application)) != 0)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
to_blob_buf(const struct sshkey *key, struct sshbuf *b, int force_plain,
|
||||
enum sshkey_serialize_rep opts)
|
||||
{
|
||||
int type, ret = SSH_ERR_INTERNAL_ERROR;
|
||||
const char *typename;
|
||||
#ifdef WITH_OPENSSL
|
||||
const BIGNUM *rsa_n, *rsa_e, *dsa_p, *dsa_q, *dsa_g, *dsa_pub_key;
|
||||
#endif /* WITH_OPENSSL */
|
||||
const struct sshkey_impl *impl;
|
||||
|
||||
if (key == NULL)
|
||||
return SSH_ERR_INVALID_ARGUMENT;
|
||||
|
||||
if (sshkey_is_cert(key)) {
|
||||
type = force_plain ? sshkey_type_plain(key->type) : key->type;
|
||||
|
||||
if (sshkey_type_is_cert(type)) {
|
||||
if (key->cert == NULL)
|
||||
return SSH_ERR_EXPECTED_CERT;
|
||||
if (sshbuf_len(key->cert->certblob) == 0)
|
||||
return SSH_ERR_KEY_LACKS_CERTBLOB;
|
||||
}
|
||||
type = force_plain ? sshkey_type_plain(key->type) : key->type;
|
||||
typename = sshkey_ssh_name_from_type_nid(type, key->ecdsa_nid);
|
||||
|
||||
switch (type) {
|
||||
#ifdef WITH_OPENSSL
|
||||
case KEY_DSA_CERT:
|
||||
case KEY_ECDSA_CERT:
|
||||
case KEY_ECDSA_SK_CERT:
|
||||
case KEY_RSA_CERT:
|
||||
#endif /* WITH_OPENSSL */
|
||||
case KEY_ED25519_CERT:
|
||||
case KEY_ED25519_SK_CERT:
|
||||
#ifdef WITH_XMSS
|
||||
case KEY_XMSS_CERT:
|
||||
#endif /* WITH_XMSS */
|
||||
/* Use the existing blob */
|
||||
/* XXX modified flag? */
|
||||
if ((ret = sshbuf_putb(b, key->cert->certblob)) != 0)
|
||||
return ret;
|
||||
break;
|
||||
#ifdef WITH_OPENSSL
|
||||
case KEY_DSA:
|
||||
if (key->dsa == NULL)
|
||||
return SSH_ERR_INVALID_ARGUMENT;
|
||||
DSA_get0_pqg(key->dsa, &dsa_p, &dsa_q, &dsa_g);
|
||||
DSA_get0_key(key->dsa, &dsa_pub_key, NULL);
|
||||
if ((ret = sshbuf_put_cstring(b, typename)) != 0 ||
|
||||
(ret = sshbuf_put_bignum2(b, dsa_p)) != 0 ||
|
||||
(ret = sshbuf_put_bignum2(b, dsa_q)) != 0 ||
|
||||
(ret = sshbuf_put_bignum2(b, dsa_g)) != 0 ||
|
||||
(ret = sshbuf_put_bignum2(b, dsa_pub_key)) != 0)
|
||||
return ret;
|
||||
break;
|
||||
# ifdef OPENSSL_HAS_ECC
|
||||
case KEY_ECDSA:
|
||||
case KEY_ECDSA_SK:
|
||||
if (key->ecdsa == NULL)
|
||||
return SSH_ERR_INVALID_ARGUMENT;
|
||||
if ((ret = sshbuf_put_cstring(b, typename)) != 0 ||
|
||||
(ret = sshbuf_put_cstring(b,
|
||||
sshkey_curve_nid_to_name(key->ecdsa_nid))) != 0 ||
|
||||
(ret = sshbuf_put_eckey(b, key->ecdsa)) != 0)
|
||||
return ret;
|
||||
if (type == KEY_ECDSA_SK) {
|
||||
if ((ret = sshbuf_put_cstring(b,
|
||||
key->sk_application)) != 0)
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
# endif
|
||||
case KEY_RSA:
|
||||
if (key->rsa == NULL)
|
||||
return SSH_ERR_INVALID_ARGUMENT;
|
||||
RSA_get0_key(key->rsa, &rsa_n, &rsa_e, NULL);
|
||||
if ((ret = sshbuf_put_cstring(b, typename)) != 0 ||
|
||||
(ret = sshbuf_put_bignum2(b, rsa_e)) != 0 ||
|
||||
(ret = sshbuf_put_bignum2(b, rsa_n)) != 0)
|
||||
return ret;
|
||||
break;
|
||||
#endif /* WITH_OPENSSL */
|
||||
case KEY_ED25519:
|
||||
case KEY_ED25519_SK:
|
||||
if (key->ed25519_pk == NULL)
|
||||
return SSH_ERR_INVALID_ARGUMENT;
|
||||
if ((ret = sshbuf_put_cstring(b, typename)) != 0 ||
|
||||
(ret = sshbuf_put_string(b,
|
||||
key->ed25519_pk, ED25519_PK_SZ)) != 0)
|
||||
return ret;
|
||||
if (type == KEY_ED25519_SK) {
|
||||
if ((ret = sshbuf_put_cstring(b,
|
||||
key->sk_application)) != 0)
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
#ifdef WITH_XMSS
|
||||
case KEY_XMSS:
|
||||
if (key->xmss_name == NULL || key->xmss_pk == NULL ||
|
||||
sshkey_xmss_pklen(key) == 0)
|
||||
return SSH_ERR_INVALID_ARGUMENT;
|
||||
if ((ret = sshbuf_put_cstring(b, typename)) != 0 ||
|
||||
(ret = sshbuf_put_cstring(b, key->xmss_name)) != 0 ||
|
||||
(ret = sshbuf_put_string(b,
|
||||
key->xmss_pk, sshkey_xmss_pklen(key))) != 0 ||
|
||||
(ret = sshkey_xmss_serialize_pk_info(key, b, opts)) != 0)
|
||||
return ret;
|
||||
break;
|
||||
#endif /* WITH_XMSS */
|
||||
default:
|
||||
return SSH_ERR_KEY_TYPE_UNKNOWN;
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
if ((impl = sshkey_impl_from_type(type)) == NULL)
|
||||
return SSH_ERR_KEY_TYPE_UNKNOWN;
|
||||
|
||||
typename = sshkey_ssh_name_from_type_nid(type, key->ecdsa_nid);
|
||||
return impl->funcs->serialize_public(key, b, typename, opts);
|
||||
}
|
||||
|
||||
int
|
||||
|
|
5
sshkey.h
5
sshkey.h
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: sshkey.h,v 1.54 2022/10/28 00:36:31 djm Exp $ */
|
||||
/* $OpenBSD: sshkey.h,v 1.55 2022/10/28 00:37:24 djm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
|
||||
|
@ -169,6 +169,8 @@ struct sshkey_impl_funcs {
|
|||
int (*alloc)(struct sshkey *); /* optional */
|
||||
void (*cleanup)(struct sshkey *); /* optional */
|
||||
int (*equal)(const struct sshkey *, const struct sshkey *);
|
||||
int (*serialize_public)(const struct sshkey *, struct sshbuf *,
|
||||
const char *, enum sshkey_serialize_rep);
|
||||
};
|
||||
|
||||
struct sshkey_impl {
|
||||
|
@ -309,6 +311,7 @@ void sshkey_sig_details_free(struct sshkey_sig_details *);
|
|||
#ifdef SSHKEY_INTERNAL
|
||||
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 ssh_rsa_sign(const struct sshkey *key,
|
||||
u_char **sigp, size_t *lenp, const u_char *data, size_t datalen,
|
||||
|
|
Loading…
Reference in New Issue