aboutsummaryrefslogtreecommitdiff
path: root/crypto/openssh/ssh-rsa.c
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/openssh/ssh-rsa.c')
-rw-r--r--crypto/openssh/ssh-rsa.c353
1 files changed, 336 insertions, 17 deletions
diff --git a/crypto/openssh/ssh-rsa.c b/crypto/openssh/ssh-rsa.c
index 9b14f9a9a715..be8f51e7576b 100644
--- a/crypto/openssh/ssh-rsa.c
+++ b/crypto/openssh/ssh-rsa.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh-rsa.c,v 1.67 2018/07/03 11:39:54 djm Exp $ */
+/* $OpenBSD: ssh-rsa.c,v 1.79 2023/03/05 05:34:09 dtucker Exp $ */
/*
* Copyright (c) 2000, 2003 Markus Friedl <markus@openbsd.org>
*
@@ -28,7 +28,6 @@
#include <string.h>
#include "sshbuf.h"
-#include "compat.h"
#include "ssherr.h"
#define SSHKEY_INTERNAL
#include "sshkey.h"
@@ -39,6 +38,234 @@
static int openssh_RSA_verify(int, u_char *, size_t, u_char *, size_t, RSA *);
+static u_int
+ssh_rsa_size(const struct sshkey *key)
+{
+ const BIGNUM *rsa_n;
+
+ if (key->rsa == NULL)
+ return 0;
+ RSA_get0_key(key->rsa, &rsa_n, NULL, NULL);
+ return BN_num_bits(rsa_n);
+}
+
+static int
+ssh_rsa_alloc(struct sshkey *k)
+{
+ if ((k->rsa = RSA_new()) == NULL)
+ return SSH_ERR_ALLOC_FAIL;
+ return 0;
+}
+
+static void
+ssh_rsa_cleanup(struct sshkey *k)
+{
+ RSA_free(k->rsa);
+ k->rsa = NULL;
+}
+
+static int
+ssh_rsa_equal(const struct sshkey *a, const struct sshkey *b)
+{
+ const BIGNUM *rsa_e_a, *rsa_n_a;
+ const BIGNUM *rsa_e_b, *rsa_n_b;
+
+ if (a->rsa == NULL || b->rsa == NULL)
+ return 0;
+ RSA_get0_key(a->rsa, &rsa_n_a, &rsa_e_a, NULL);
+ RSA_get0_key(b->rsa, &rsa_n_b, &rsa_e_b, NULL);
+ if (rsa_e_a == NULL || rsa_e_b == NULL)
+ return 0;
+ if (rsa_n_a == NULL || rsa_n_b == NULL)
+ return 0;
+ if (BN_cmp(rsa_e_a, rsa_e_b) != 0)
+ return 0;
+ if (BN_cmp(rsa_n_a, rsa_n_b) != 0)
+ return 0;
+ return 1;
+}
+
+static int
+ssh_rsa_serialize_public(const struct sshkey *key, struct sshbuf *b,
+ 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_bignum2(b, rsa_e)) != 0 ||
+ (r = sshbuf_put_bignum2(b, rsa_n)) != 0)
+ return r;
+
+ return 0;
+}
+
+static int
+ssh_rsa_serialize_private(const struct sshkey *key, struct sshbuf *b,
+ enum sshkey_serialize_rep opts)
+{
+ int r;
+ const BIGNUM *rsa_n, *rsa_e, *rsa_d, *rsa_iqmp, *rsa_p, *rsa_q;
+
+ RSA_get0_key(key->rsa, &rsa_n, &rsa_e, &rsa_d);
+ RSA_get0_factors(key->rsa, &rsa_p, &rsa_q);
+ RSA_get0_crt_params(key->rsa, NULL, NULL, &rsa_iqmp);
+
+ if (!sshkey_is_cert(key)) {
+ /* Note: can't reuse ssh_rsa_serialize_public: e, n vs. n, e */
+ if ((r = sshbuf_put_bignum2(b, rsa_n)) != 0 ||
+ (r = sshbuf_put_bignum2(b, rsa_e)) != 0)
+ return r;
+ }
+ if ((r = sshbuf_put_bignum2(b, rsa_d)) != 0 ||
+ (r = sshbuf_put_bignum2(b, rsa_iqmp)) != 0 ||
+ (r = sshbuf_put_bignum2(b, rsa_p)) != 0 ||
+ (r = sshbuf_put_bignum2(b, rsa_q)) != 0)
+ return r;
+
+ return 0;
+}
+
+static int
+ssh_rsa_generate(struct sshkey *k, int bits)
+{
+ RSA *private = NULL;
+ BIGNUM *f4 = NULL;
+ int ret = SSH_ERR_INTERNAL_ERROR;
+
+ if (bits < SSH_RSA_MINIMUM_MODULUS_SIZE ||
+ bits > SSHBUF_MAX_BIGNUM * 8)
+ return SSH_ERR_KEY_LENGTH;
+ if ((private = RSA_new()) == NULL || (f4 = BN_new()) == NULL) {
+ ret = SSH_ERR_ALLOC_FAIL;
+ goto out;
+ }
+ if (!BN_set_word(f4, RSA_F4) ||
+ !RSA_generate_key_ex(private, bits, f4, NULL)) {
+ ret = SSH_ERR_LIBCRYPTO_ERROR;
+ goto out;
+ }
+ k->rsa = private;
+ private = NULL;
+ ret = 0;
+ out:
+ RSA_free(private);
+ BN_free(f4);
+ 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 int
+ssh_rsa_deserialize_public(const char *ktype, struct sshbuf *b,
+ struct sshkey *key)
+{
+ int ret = SSH_ERR_INTERNAL_ERROR;
+ BIGNUM *rsa_n = NULL, *rsa_e = NULL;
+
+ if (sshbuf_get_bignum2(b, &rsa_e) != 0 ||
+ sshbuf_get_bignum2(b, &rsa_n) != 0) {
+ ret = SSH_ERR_INVALID_FORMAT;
+ goto out;
+ }
+ if (!RSA_set0_key(key->rsa, rsa_n, rsa_e, NULL)) {
+ ret = SSH_ERR_LIBCRYPTO_ERROR;
+ goto out;
+ }
+ rsa_n = rsa_e = NULL; /* transferred */
+ if ((ret = sshkey_check_rsa_length(key, 0)) != 0)
+ goto out;
+#ifdef DEBUG_PK
+ RSA_print_fp(stderr, key->rsa, 8);
+#endif
+ /* success */
+ ret = 0;
+ out:
+ BN_clear_free(rsa_n);
+ BN_clear_free(rsa_e);
+ return ret;
+}
+
+static int
+ssh_rsa_deserialize_private(const char *ktype, struct sshbuf *b,
+ struct sshkey *key)
+{
+ int r;
+ BIGNUM *rsa_n = NULL, *rsa_e = NULL, *rsa_d = NULL;
+ BIGNUM *rsa_iqmp = NULL, *rsa_p = NULL, *rsa_q = NULL;
+
+ /* Note: can't reuse ssh_rsa_deserialize_public: e, n vs. n, e */
+ if (!sshkey_is_cert(key)) {
+ if ((r = sshbuf_get_bignum2(b, &rsa_n)) != 0 ||
+ (r = sshbuf_get_bignum2(b, &rsa_e)) != 0)
+ goto out;
+ if (!RSA_set0_key(key->rsa, rsa_n, rsa_e, NULL)) {
+ r = SSH_ERR_LIBCRYPTO_ERROR;
+ goto out;
+ }
+ rsa_n = rsa_e = NULL; /* transferred */
+ }
+ if ((r = sshbuf_get_bignum2(b, &rsa_d)) != 0 ||
+ (r = sshbuf_get_bignum2(b, &rsa_iqmp)) != 0 ||
+ (r = sshbuf_get_bignum2(b, &rsa_p)) != 0 ||
+ (r = sshbuf_get_bignum2(b, &rsa_q)) != 0)
+ goto out;
+ if (!RSA_set0_key(key->rsa, NULL, NULL, rsa_d)) {
+ r = SSH_ERR_LIBCRYPTO_ERROR;
+ goto out;
+ }
+ rsa_d = NULL; /* transferred */
+ if (!RSA_set0_factors(key->rsa, rsa_p, rsa_q)) {
+ r = SSH_ERR_LIBCRYPTO_ERROR;
+ goto out;
+ }
+ rsa_p = rsa_q = NULL; /* transferred */
+ if ((r = sshkey_check_rsa_length(key, 0)) != 0)
+ goto out;
+ if ((r = ssh_rsa_complete_crt_parameters(key, rsa_iqmp)) != 0)
+ goto out;
+ if (RSA_blinding_on(key->rsa, NULL) != 1) {
+ r = SSH_ERR_LIBCRYPTO_ERROR;
+ goto out;
+ }
+ /* success */
+ r = 0;
+ out:
+ BN_clear_free(rsa_n);
+ BN_clear_free(rsa_e);
+ BN_clear_free(rsa_d);
+ BN_clear_free(rsa_p);
+ BN_clear_free(rsa_q);
+ BN_clear_free(rsa_iqmp);
+ return r;
+}
+
static const char *
rsa_hash_alg_ident(int hash_alg)
{
@@ -160,14 +387,16 @@ ssh_rsa_complete_crt_parameters(struct sshkey *key, const BIGNUM *iqmp)
}
/* RSASSA-PKCS1-v1_5 (PKCS #1 v2.0 signature) with SHA1 */
-int
-ssh_rsa_sign(const struct sshkey *key, u_char **sigp, size_t *lenp,
- const u_char *data, size_t datalen, const char *alg_ident)
+static int
+ssh_rsa_sign(struct sshkey *key,
+ u_char **sigp, size_t *lenp,
+ const u_char *data, size_t datalen,
+ const char *alg, const char *sk_provider, const char *sk_pin, u_int compat)
{
const BIGNUM *rsa_n;
u_char digest[SSH_DIGEST_MAX_LENGTH], *sig = NULL;
size_t slen = 0;
- u_int dlen, len;
+ u_int hlen, len;
int nid, hash_alg, ret = SSH_ERR_INTERNAL_ERROR;
struct sshbuf *b = NULL;
@@ -176,10 +405,10 @@ ssh_rsa_sign(const struct sshkey *key, u_char **sigp, size_t *lenp,
if (sigp != NULL)
*sigp = NULL;
- if (alg_ident == NULL || strlen(alg_ident) == 0)
+ if (alg == NULL || strlen(alg) == 0)
hash_alg = SSH_DIGEST_SHA1;
else
- hash_alg = rsa_hash_id_from_keyname(alg_ident);
+ hash_alg = rsa_hash_id_from_keyname(alg);
if (key == NULL || key->rsa == NULL || hash_alg == -1 ||
sshkey_type_plain(key->type) != KEY_RSA)
return SSH_ERR_INVALID_ARGUMENT;
@@ -192,7 +421,7 @@ ssh_rsa_sign(const struct sshkey *key, u_char **sigp, size_t *lenp,
/* hash the data */
nid = rsa_hash_alg_nid(hash_alg);
- if ((dlen = ssh_digest_bytes(hash_alg)) == 0)
+ if ((hlen = ssh_digest_bytes(hash_alg)) == 0)
return SSH_ERR_INTERNAL_ERROR;
if ((ret = ssh_digest_memory(hash_alg, data, datalen,
digest, sizeof(digest))) != 0)
@@ -203,7 +432,7 @@ ssh_rsa_sign(const struct sshkey *key, u_char **sigp, size_t *lenp,
goto out;
}
- if (RSA_sign(nid, digest, dlen, sig, &len, key->rsa) != 1) {
+ if (RSA_sign(nid, digest, hlen, sig, &len, key->rsa) != 1) {
ret = SSH_ERR_LIBCRYPTO_ERROR;
goto out;
}
@@ -241,15 +470,16 @@ ssh_rsa_sign(const struct sshkey *key, u_char **sigp, size_t *lenp,
return ret;
}
-int
+static int
ssh_rsa_verify(const struct sshkey *key,
- const u_char *sig, size_t siglen, const u_char *data, size_t datalen,
- const char *alg)
+ const u_char *sig, size_t siglen,
+ const u_char *data, size_t dlen, const char *alg, u_int compat,
+ struct sshkey_sig_details **detailsp)
{
const BIGNUM *rsa_n;
char *sigtype = NULL;
int hash_alg, want_alg, ret = SSH_ERR_INTERNAL_ERROR;
- size_t len = 0, diff, modlen, dlen;
+ size_t len = 0, diff, modlen, hlen;
struct sshbuf *b = NULL;
u_char digest[SSH_DIGEST_MAX_LENGTH], *osigblob, *sigblob = NULL;
@@ -310,15 +540,15 @@ ssh_rsa_verify(const struct sshkey *key,
explicit_bzero(sigblob, diff);
len = modlen;
}
- if ((dlen = ssh_digest_bytes(hash_alg)) == 0) {
+ if ((hlen = ssh_digest_bytes(hash_alg)) == 0) {
ret = SSH_ERR_INTERNAL_ERROR;
goto out;
}
- if ((ret = ssh_digest_memory(hash_alg, data, datalen,
+ if ((ret = ssh_digest_memory(hash_alg, data, dlen,
digest, sizeof(digest))) != 0)
goto out;
- ret = openssh_RSA_verify(hash_alg, digest, dlen, sigblob, len,
+ ret = openssh_RSA_verify(hash_alg, digest, hlen, sigblob, len,
key->rsa);
out:
freezero(sigblob, len);
@@ -446,4 +676,93 @@ done:
freezero(decrypted, rsasize);
return ret;
}
+
+static const struct sshkey_impl_funcs sshkey_rsa_funcs = {
+ /* .size = */ ssh_rsa_size,
+ /* .alloc = */ ssh_rsa_alloc,
+ /* .cleanup = */ ssh_rsa_cleanup,
+ /* .equal = */ ssh_rsa_equal,
+ /* .ssh_serialize_public = */ ssh_rsa_serialize_public,
+ /* .ssh_deserialize_public = */ ssh_rsa_deserialize_public,
+ /* .ssh_serialize_private = */ ssh_rsa_serialize_private,
+ /* .ssh_deserialize_private = */ ssh_rsa_deserialize_private,
+ /* .generate = */ ssh_rsa_generate,
+ /* .copy_public = */ ssh_rsa_copy_public,
+ /* .sign = */ ssh_rsa_sign,
+ /* .verify = */ ssh_rsa_verify,
+};
+
+const struct sshkey_impl sshkey_rsa_impl = {
+ /* .name = */ "ssh-rsa",
+ /* .shortname = */ "RSA",
+ /* .sigalg = */ NULL,
+ /* .type = */ KEY_RSA,
+ /* .nid = */ 0,
+ /* .cert = */ 0,
+ /* .sigonly = */ 0,
+ /* .keybits = */ 0,
+ /* .funcs = */ &sshkey_rsa_funcs,
+};
+
+const struct sshkey_impl sshkey_rsa_cert_impl = {
+ /* .name = */ "ssh-rsa-cert-v01@openssh.com",
+ /* .shortname = */ "RSA-CERT",
+ /* .sigalg = */ NULL,
+ /* .type = */ KEY_RSA_CERT,
+ /* .nid = */ 0,
+ /* .cert = */ 1,
+ /* .sigonly = */ 0,
+ /* .keybits = */ 0,
+ /* .funcs = */ &sshkey_rsa_funcs,
+};
+
+/* SHA2 signature algorithms */
+
+const struct sshkey_impl sshkey_rsa_sha256_impl = {
+ /* .name = */ "rsa-sha2-256",
+ /* .shortname = */ "RSA",
+ /* .sigalg = */ NULL,
+ /* .type = */ KEY_RSA,
+ /* .nid = */ 0,
+ /* .cert = */ 0,
+ /* .sigonly = */ 1,
+ /* .keybits = */ 0,
+ /* .funcs = */ &sshkey_rsa_funcs,
+};
+
+const struct sshkey_impl sshkey_rsa_sha512_impl = {
+ /* .name = */ "rsa-sha2-512",
+ /* .shortname = */ "RSA",
+ /* .sigalg = */ NULL,
+ /* .type = */ KEY_RSA,
+ /* .nid = */ 0,
+ /* .cert = */ 0,
+ /* .sigonly = */ 1,
+ /* .keybits = */ 0,
+ /* .funcs = */ &sshkey_rsa_funcs,
+};
+
+const struct sshkey_impl sshkey_rsa_sha256_cert_impl = {
+ /* .name = */ "rsa-sha2-256-cert-v01@openssh.com",
+ /* .shortname = */ "RSA-CERT",
+ /* .sigalg = */ "rsa-sha2-256",
+ /* .type = */ KEY_RSA_CERT,
+ /* .nid = */ 0,
+ /* .cert = */ 1,
+ /* .sigonly = */ 1,
+ /* .keybits = */ 0,
+ /* .funcs = */ &sshkey_rsa_funcs,
+};
+
+const struct sshkey_impl sshkey_rsa_sha512_cert_impl = {
+ /* .name = */ "rsa-sha2-512-cert-v01@openssh.com",
+ /* .shortname = */ "RSA-CERT",
+ /* .sigalg = */ "rsa-sha2-512",
+ /* .type = */ KEY_RSA_CERT,
+ /* .nid = */ 0,
+ /* .cert = */ 1,
+ /* .sigonly = */ 1,
+ /* .keybits = */ 0,
+ /* .funcs = */ &sshkey_rsa_funcs,
+};
#endif /* WITH_OPENSSL */