xref: /netbsd-src/crypto/external/bsd/openssh/dist/ssh-rsa.c (revision 9469f4f13c84743995b7d51c506f9c9849ba30de)
1*9469f4f1Schristos /*	$NetBSD: ssh-rsa.c,v 1.20 2024/09/24 21:32:19 christos Exp $	*/
2*9469f4f1Schristos /* $OpenBSD: ssh-rsa.c,v 1.80 2024/08/15 00:51:51 djm Exp $ */
3*9469f4f1Schristos 
4ca32bd8dSchristos /*
5ca32bd8dSchristos  * Copyright (c) 2000, 2003 Markus Friedl <markus@openbsd.org>
6ca32bd8dSchristos  *
7ca32bd8dSchristos  * Permission to use, copy, modify, and distribute this software for any
8ca32bd8dSchristos  * purpose with or without fee is hereby granted, provided that the above
9ca32bd8dSchristos  * copyright notice and this permission notice appear in all copies.
10ca32bd8dSchristos  *
11ca32bd8dSchristos  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12ca32bd8dSchristos  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13ca32bd8dSchristos  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14ca32bd8dSchristos  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15ca32bd8dSchristos  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16ca32bd8dSchristos  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17ca32bd8dSchristos  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18ca32bd8dSchristos  */
19ca32bd8dSchristos 
20313c6c94Schristos #include "includes.h"
21*9469f4f1Schristos __RCSID("$NetBSD: ssh-rsa.c,v 1.20 2024/09/24 21:32:19 christos Exp $");
22ca32bd8dSchristos #include <sys/types.h>
23ca32bd8dSchristos 
24ca32bd8dSchristos #include <openssl/evp.h>
25ca32bd8dSchristos #include <openssl/err.h>
26ca32bd8dSchristos 
27ca32bd8dSchristos #include <string.h>
28ca32bd8dSchristos 
298a4530f9Schristos #include "sshbuf.h"
308a4530f9Schristos #include "ssherr.h"
318a4530f9Schristos #define SSHKEY_INTERNAL
328a4530f9Schristos #include "sshkey.h"
338a4530f9Schristos #include "digest.h"
34ffae97bbSchristos #include "log.h"
35ca32bd8dSchristos 
36b1066cf3Schristos static u_int
37*9469f4f1Schristos ssh_rsa_size(const struct sshkey *k)
38b1066cf3Schristos {
39*9469f4f1Schristos 	if (k->pkey == NULL)
40b1066cf3Schristos 		return 0;
41*9469f4f1Schristos 	return EVP_PKEY_bits(k->pkey);
42b1066cf3Schristos }
43b1066cf3Schristos 
44b1066cf3Schristos static int
45b1066cf3Schristos ssh_rsa_alloc(struct sshkey *k)
46b1066cf3Schristos {
47*9469f4f1Schristos 	if ((k->pkey = EVP_PKEY_new()) == NULL)
48b1066cf3Schristos 		return SSH_ERR_ALLOC_FAIL;
49b1066cf3Schristos 	return 0;
50b1066cf3Schristos }
51b1066cf3Schristos 
52b1066cf3Schristos static void
53b1066cf3Schristos ssh_rsa_cleanup(struct sshkey *k)
54b1066cf3Schristos {
55*9469f4f1Schristos 	EVP_PKEY_free(k->pkey);
56*9469f4f1Schristos 	k->pkey = NULL;
57b1066cf3Schristos }
58b1066cf3Schristos 
59b1066cf3Schristos static int
60b1066cf3Schristos ssh_rsa_equal(const struct sshkey *a, const struct sshkey *b)
61b1066cf3Schristos {
62*9469f4f1Schristos 	if (a->pkey == NULL || b->pkey == NULL)
63b1066cf3Schristos 		return 0;
64*9469f4f1Schristos 	return EVP_PKEY_cmp(a->pkey, b->pkey) == 1;
65b1066cf3Schristos }
66b1066cf3Schristos 
67b1066cf3Schristos static int
68b1066cf3Schristos ssh_rsa_serialize_public(const struct sshkey *key, struct sshbuf *b,
69b1066cf3Schristos     enum sshkey_serialize_rep opts)
70b1066cf3Schristos {
71b1066cf3Schristos 	int r;
72b1066cf3Schristos 	const BIGNUM *rsa_n, *rsa_e;
73*9469f4f1Schristos 	const RSA *rsa;
74b1066cf3Schristos 
75*9469f4f1Schristos 	if (key->pkey == NULL)
76b1066cf3Schristos 		return SSH_ERR_INVALID_ARGUMENT;
77*9469f4f1Schristos 	if ((rsa = EVP_PKEY_get0_RSA(key->pkey)) == NULL)
78*9469f4f1Schristos 		return SSH_ERR_LIBCRYPTO_ERROR;
79*9469f4f1Schristos 
80*9469f4f1Schristos 	RSA_get0_key(rsa, &rsa_n, &rsa_e, NULL);
81b1066cf3Schristos 	if ((r = sshbuf_put_bignum2(b, rsa_e)) != 0 ||
82b1066cf3Schristos 	    (r = sshbuf_put_bignum2(b, rsa_n)) != 0)
83b1066cf3Schristos 		return r;
84b1066cf3Schristos 
85b1066cf3Schristos 	return 0;
86b1066cf3Schristos }
87b1066cf3Schristos 
88b1066cf3Schristos static int
89b1066cf3Schristos ssh_rsa_serialize_private(const struct sshkey *key, struct sshbuf *b,
90b1066cf3Schristos     enum sshkey_serialize_rep opts)
91b1066cf3Schristos {
92b1066cf3Schristos 	int r;
93b1066cf3Schristos 	const BIGNUM *rsa_n, *rsa_e, *rsa_d, *rsa_iqmp, *rsa_p, *rsa_q;
94*9469f4f1Schristos 	const RSA *rsa;
95b1066cf3Schristos 
96*9469f4f1Schristos 	if ((rsa = EVP_PKEY_get0_RSA(key->pkey)) == NULL)
97*9469f4f1Schristos 		return SSH_ERR_LIBCRYPTO_ERROR;
98*9469f4f1Schristos 	RSA_get0_key(rsa, &rsa_n, &rsa_e, &rsa_d);
99*9469f4f1Schristos 	RSA_get0_factors(rsa, &rsa_p, &rsa_q);
100*9469f4f1Schristos 	RSA_get0_crt_params(rsa, NULL, NULL, &rsa_iqmp);
101b1066cf3Schristos 
102b1066cf3Schristos 	if (!sshkey_is_cert(key)) {
103b1066cf3Schristos 		/* Note: can't reuse ssh_rsa_serialize_public: e, n vs. n, e */
104b1066cf3Schristos 		if ((r = sshbuf_put_bignum2(b, rsa_n)) != 0 ||
105b1066cf3Schristos 		    (r = sshbuf_put_bignum2(b, rsa_e)) != 0)
106b1066cf3Schristos 			return r;
107b1066cf3Schristos 	}
108b1066cf3Schristos 	if ((r = sshbuf_put_bignum2(b, rsa_d)) != 0 ||
109b1066cf3Schristos 	    (r = sshbuf_put_bignum2(b, rsa_iqmp)) != 0 ||
110b1066cf3Schristos 	    (r = sshbuf_put_bignum2(b, rsa_p)) != 0 ||
111b1066cf3Schristos 	    (r = sshbuf_put_bignum2(b, rsa_q)) != 0)
112b1066cf3Schristos 		return r;
113b1066cf3Schristos 
114b1066cf3Schristos 	return 0;
115b1066cf3Schristos }
116b1066cf3Schristos 
117b1066cf3Schristos static int
118b1066cf3Schristos ssh_rsa_generate(struct sshkey *k, int bits)
119b1066cf3Schristos {
120*9469f4f1Schristos 	EVP_PKEY_CTX *ctx = NULL;
121*9469f4f1Schristos 	EVP_PKEY *res = NULL;
122*9469f4f1Schristos 
123b1066cf3Schristos 	int ret = SSH_ERR_INTERNAL_ERROR;
124b1066cf3Schristos 
125b1066cf3Schristos 	if (bits < SSH_RSA_MINIMUM_MODULUS_SIZE ||
126b1066cf3Schristos 	    bits > SSHBUF_MAX_BIGNUM * 8)
127b1066cf3Schristos 		return SSH_ERR_KEY_LENGTH;
128*9469f4f1Schristos 
129*9469f4f1Schristos 	if ((ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL)) == NULL) {
130b1066cf3Schristos 		ret = SSH_ERR_ALLOC_FAIL;
131b1066cf3Schristos 		goto out;
132b1066cf3Schristos 	}
133*9469f4f1Schristos 	if (EVP_PKEY_keygen_init(ctx) <= 0) {
134b1066cf3Schristos 		ret = SSH_ERR_LIBCRYPTO_ERROR;
135b1066cf3Schristos 		goto out;
136b1066cf3Schristos 	}
137*9469f4f1Schristos 	if (EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, bits) <= 0) {
138*9469f4f1Schristos 		ret = SSH_ERR_KEY_LENGTH;
139*9469f4f1Schristos 		goto out;
140*9469f4f1Schristos 	}
141*9469f4f1Schristos 	if (EVP_PKEY_keygen(ctx, &res) <= 0 || res == NULL) {
142*9469f4f1Schristos 		ret = SSH_ERR_LIBCRYPTO_ERROR;
143*9469f4f1Schristos 		goto out;
144*9469f4f1Schristos 	}
145*9469f4f1Schristos 	/* success */
146*9469f4f1Schristos 	k->pkey = res;
147b1066cf3Schristos 	ret = 0;
148b1066cf3Schristos  out:
149*9469f4f1Schristos 	EVP_PKEY_CTX_free(ctx);
150b1066cf3Schristos 	return ret;
151b1066cf3Schristos }
152b1066cf3Schristos 
153b1066cf3Schristos static int
154b1066cf3Schristos ssh_rsa_copy_public(const struct sshkey *from, struct sshkey *to)
155b1066cf3Schristos {
156b1066cf3Schristos 	const BIGNUM *rsa_n, *rsa_e;
157b1066cf3Schristos 	BIGNUM *rsa_n_dup = NULL, *rsa_e_dup = NULL;
158b1066cf3Schristos 	int r = SSH_ERR_INTERNAL_ERROR;
159*9469f4f1Schristos 	const RSA *rsa_from;
160*9469f4f1Schristos 	RSA *rsa_to = NULL;
161b1066cf3Schristos 
162*9469f4f1Schristos 	if ((rsa_from = EVP_PKEY_get0_RSA(from->pkey)) == NULL ||
163*9469f4f1Schristos 	    (rsa_to = RSA_new()) == NULL)
164*9469f4f1Schristos 		return SSH_ERR_LIBCRYPTO_ERROR;
165*9469f4f1Schristos 
166*9469f4f1Schristos 	RSA_get0_key(rsa_from, &rsa_n, &rsa_e, NULL);
167b1066cf3Schristos 	if ((rsa_n_dup = BN_dup(rsa_n)) == NULL ||
168b1066cf3Schristos 	    (rsa_e_dup = BN_dup(rsa_e)) == NULL) {
169b1066cf3Schristos 		r = SSH_ERR_ALLOC_FAIL;
170b1066cf3Schristos 		goto out;
171b1066cf3Schristos 	}
172*9469f4f1Schristos 	if (!RSA_set0_key(rsa_to, rsa_n_dup, rsa_e_dup, NULL)) {
173b1066cf3Schristos 		r = SSH_ERR_LIBCRYPTO_ERROR;
174b1066cf3Schristos 		goto out;
175b1066cf3Schristos 	}
176b1066cf3Schristos 	rsa_n_dup = rsa_e_dup = NULL; /* transferred */
177*9469f4f1Schristos 
178*9469f4f1Schristos 	if (EVP_PKEY_set1_RSA(to->pkey, rsa_to) != 1) {
179*9469f4f1Schristos 		r = SSH_ERR_LIBCRYPTO_ERROR;
180*9469f4f1Schristos 		goto out;
181*9469f4f1Schristos 	}
182b1066cf3Schristos 	/* success */
183b1066cf3Schristos 	r = 0;
184b1066cf3Schristos  out:
185*9469f4f1Schristos 	RSA_free(rsa_to);
186b1066cf3Schristos 	BN_clear_free(rsa_n_dup);
187b1066cf3Schristos 	BN_clear_free(rsa_e_dup);
188b1066cf3Schristos 	return r;
189b1066cf3Schristos }
190b1066cf3Schristos 
191b1066cf3Schristos static int
192b1066cf3Schristos ssh_rsa_deserialize_public(const char *ktype, struct sshbuf *b,
193b1066cf3Schristos     struct sshkey *key)
194b1066cf3Schristos {
195b1066cf3Schristos 	int ret = SSH_ERR_INTERNAL_ERROR;
196b1066cf3Schristos 	BIGNUM *rsa_n = NULL, *rsa_e = NULL;
197*9469f4f1Schristos 	RSA *rsa = NULL;
198*9469f4f1Schristos 
199*9469f4f1Schristos 	if ((rsa = RSA_new()) == NULL)
200*9469f4f1Schristos 		return SSH_ERR_LIBCRYPTO_ERROR;
201b1066cf3Schristos 
202b1066cf3Schristos 	if (sshbuf_get_bignum2(b, &rsa_e) != 0 ||
203b1066cf3Schristos 	    sshbuf_get_bignum2(b, &rsa_n) != 0) {
204b1066cf3Schristos 		ret = SSH_ERR_INVALID_FORMAT;
205b1066cf3Schristos 		goto out;
206b1066cf3Schristos 	}
207*9469f4f1Schristos 	if (!RSA_set0_key(rsa, rsa_n, rsa_e, NULL)) {
208b1066cf3Schristos 		ret = SSH_ERR_LIBCRYPTO_ERROR;
209b1066cf3Schristos 		goto out;
210b1066cf3Schristos 	}
211b1066cf3Schristos 	rsa_n = rsa_e = NULL; /* transferred */
212*9469f4f1Schristos 	if (EVP_PKEY_set1_RSA(key->pkey, rsa) != 1) {
213*9469f4f1Schristos 		ret = SSH_ERR_LIBCRYPTO_ERROR;
214*9469f4f1Schristos 		goto out;
215*9469f4f1Schristos 	}
216b1066cf3Schristos 	if ((ret = sshkey_check_rsa_length(key, 0)) != 0)
217b1066cf3Schristos 		goto out;
218b1066cf3Schristos #ifdef DEBUG_PK
219*9469f4f1Schristos 	RSA_print_fp(stderr, rsa, 8);
220b1066cf3Schristos #endif
221b1066cf3Schristos 	/* success */
222b1066cf3Schristos 	ret = 0;
223b1066cf3Schristos  out:
224*9469f4f1Schristos 	RSA_free(rsa);
225b1066cf3Schristos 	BN_clear_free(rsa_n);
226b1066cf3Schristos 	BN_clear_free(rsa_e);
227b1066cf3Schristos 	return ret;
228b1066cf3Schristos }
229b1066cf3Schristos 
230b1066cf3Schristos static int
231b1066cf3Schristos ssh_rsa_deserialize_private(const char *ktype, struct sshbuf *b,
232b1066cf3Schristos     struct sshkey *key)
233b1066cf3Schristos {
234b1066cf3Schristos 	int r;
235b1066cf3Schristos 	BIGNUM *rsa_n = NULL, *rsa_e = NULL, *rsa_d = NULL;
236b1066cf3Schristos 	BIGNUM *rsa_iqmp = NULL, *rsa_p = NULL, *rsa_q = NULL;
237*9469f4f1Schristos 	BIGNUM *rsa_dmp1 = NULL, *rsa_dmq1 = NULL;
238*9469f4f1Schristos 	RSA *rsa = NULL;
239b1066cf3Schristos 
240*9469f4f1Schristos 	if (sshkey_is_cert(key)) {
241*9469f4f1Schristos 		/* sshkey_private_deserialize already has pubkey from cert */
242*9469f4f1Schristos 		if ((rsa = EVP_PKEY_get1_RSA(key->pkey)) == NULL) {
243*9469f4f1Schristos 			r = SSH_ERR_LIBCRYPTO_ERROR;
244*9469f4f1Schristos 			goto out;
245*9469f4f1Schristos 		}
246*9469f4f1Schristos 	} else {
247*9469f4f1Schristos 		if ((rsa = RSA_new()) == NULL) {
248*9469f4f1Schristos 			r = SSH_ERR_LIBCRYPTO_ERROR;
249*9469f4f1Schristos 			goto out;
250*9469f4f1Schristos 		}
251b1066cf3Schristos 		/* Note: can't reuse ssh_rsa_deserialize_public: e,n vs. n,e */
252b1066cf3Schristos 		if ((r = sshbuf_get_bignum2(b, &rsa_n)) != 0 ||
253b1066cf3Schristos 		    (r = sshbuf_get_bignum2(b, &rsa_e)) != 0)
254b1066cf3Schristos 			goto out;
255*9469f4f1Schristos 		if (!RSA_set0_key(rsa, rsa_n, rsa_e, NULL)) {
256b1066cf3Schristos 			r = SSH_ERR_LIBCRYPTO_ERROR;
257b1066cf3Schristos 			goto out;
258b1066cf3Schristos 		}
259b1066cf3Schristos 		rsa_n = rsa_e = NULL; /* transferred */
260b1066cf3Schristos 	}
261b1066cf3Schristos 	if ((r = sshbuf_get_bignum2(b, &rsa_d)) != 0 ||
262b1066cf3Schristos 	    (r = sshbuf_get_bignum2(b, &rsa_iqmp)) != 0 ||
263b1066cf3Schristos 	    (r = sshbuf_get_bignum2(b, &rsa_p)) != 0 ||
264b1066cf3Schristos 	    (r = sshbuf_get_bignum2(b, &rsa_q)) != 0)
265b1066cf3Schristos 		goto out;
266*9469f4f1Schristos 	if ((r = ssh_rsa_complete_crt_parameters(rsa_d, rsa_p, rsa_q,
267*9469f4f1Schristos 	    rsa_iqmp, &rsa_dmp1, &rsa_dmq1)) != 0)
268*9469f4f1Schristos 		goto out;
269*9469f4f1Schristos 	if (!RSA_set0_key(rsa, NULL, NULL, rsa_d)) {
270b1066cf3Schristos 		r = SSH_ERR_LIBCRYPTO_ERROR;
271b1066cf3Schristos 		goto out;
272b1066cf3Schristos 	}
273b1066cf3Schristos 	rsa_d = NULL; /* transferred */
274*9469f4f1Schristos 	if (!RSA_set0_factors(rsa, rsa_p, rsa_q)) {
275b1066cf3Schristos 		r = SSH_ERR_LIBCRYPTO_ERROR;
276b1066cf3Schristos 		goto out;
277b1066cf3Schristos 	}
278b1066cf3Schristos 	rsa_p = rsa_q = NULL; /* transferred */
279*9469f4f1Schristos 	if (!RSA_set0_crt_params(rsa, rsa_dmp1, rsa_dmq1, rsa_iqmp)) {
280b1066cf3Schristos 		r = SSH_ERR_LIBCRYPTO_ERROR;
281b1066cf3Schristos 		goto out;
282b1066cf3Schristos 	}
283*9469f4f1Schristos 	rsa_dmp1 = rsa_dmq1 = rsa_iqmp = NULL;
284*9469f4f1Schristos 	if (RSA_blinding_on(rsa, NULL) != 1) {
285*9469f4f1Schristos 		r = SSH_ERR_LIBCRYPTO_ERROR;
286*9469f4f1Schristos 		goto out;
287*9469f4f1Schristos 	}
288*9469f4f1Schristos 	if (EVP_PKEY_set1_RSA(key->pkey, rsa) != 1) {
289*9469f4f1Schristos 		r = SSH_ERR_LIBCRYPTO_ERROR;
290*9469f4f1Schristos 		goto out;
291*9469f4f1Schristos 	}
292*9469f4f1Schristos 	if ((r = sshkey_check_rsa_length(key, 0)) != 0)
293*9469f4f1Schristos 		goto out;
294b1066cf3Schristos 	/* success */
295b1066cf3Schristos 	r = 0;
296b1066cf3Schristos  out:
297*9469f4f1Schristos 	RSA_free(rsa);
298b1066cf3Schristos 	BN_clear_free(rsa_n);
299b1066cf3Schristos 	BN_clear_free(rsa_e);
300b1066cf3Schristos 	BN_clear_free(rsa_d);
301b1066cf3Schristos 	BN_clear_free(rsa_p);
302b1066cf3Schristos 	BN_clear_free(rsa_q);
303b1066cf3Schristos 	BN_clear_free(rsa_iqmp);
304*9469f4f1Schristos 	BN_clear_free(rsa_dmp1);
305*9469f4f1Schristos 	BN_clear_free(rsa_dmq1);
306b1066cf3Schristos 	return r;
307b1066cf3Schristos }
308b1066cf3Schristos 
30979976551Schristos static const char *
31079976551Schristos rsa_hash_alg_ident(int hash_alg)
31179976551Schristos {
31279976551Schristos 	switch (hash_alg) {
31379976551Schristos 	case SSH_DIGEST_SHA1:
31479976551Schristos 		return "ssh-rsa";
31579976551Schristos 	case SSH_DIGEST_SHA256:
31679976551Schristos 		return "rsa-sha2-256";
31779976551Schristos 	case SSH_DIGEST_SHA512:
31879976551Schristos 		return "rsa-sha2-512";
31979976551Schristos 	}
32079976551Schristos 	return NULL;
32179976551Schristos }
32279976551Schristos 
32355a4608bSchristos /*
32455a4608bSchristos  * Returns the hash algorithm ID for a given algorithm identifier as used
32555a4608bSchristos  * inside the signature blob,
32655a4608bSchristos  */
32779976551Schristos static int
32855a4608bSchristos rsa_hash_id_from_ident(const char *ident)
32979976551Schristos {
33055a4608bSchristos 	if (strcmp(ident, "ssh-rsa") == 0)
33179976551Schristos 		return SSH_DIGEST_SHA1;
33279976551Schristos 	if (strcmp(ident, "rsa-sha2-256") == 0)
33379976551Schristos 		return SSH_DIGEST_SHA256;
33479976551Schristos 	if (strcmp(ident, "rsa-sha2-512") == 0)
33579976551Schristos 		return SSH_DIGEST_SHA512;
33679976551Schristos 	return -1;
33779976551Schristos }
33879976551Schristos 
33955a4608bSchristos /*
34055a4608bSchristos  * Return the hash algorithm ID for the specified key name. This includes
34155a4608bSchristos  * all the cases of rsa_hash_id_from_ident() but also the certificate key
34255a4608bSchristos  * types.
34355a4608bSchristos  */
34455a4608bSchristos static int
34555a4608bSchristos rsa_hash_id_from_keyname(const char *alg)
34655a4608bSchristos {
34755a4608bSchristos 	int r;
34855a4608bSchristos 
34955a4608bSchristos 	if ((r = rsa_hash_id_from_ident(alg)) != -1)
35055a4608bSchristos 		return r;
35155a4608bSchristos 	if (strcmp(alg, "ssh-rsa-cert-v01@openssh.com") == 0)
35255a4608bSchristos 		return SSH_DIGEST_SHA1;
35355a4608bSchristos 	if (strcmp(alg, "rsa-sha2-256-cert-v01@openssh.com") == 0)
35455a4608bSchristos 		return SSH_DIGEST_SHA256;
35555a4608bSchristos 	if (strcmp(alg, "rsa-sha2-512-cert-v01@openssh.com") == 0)
35655a4608bSchristos 		return SSH_DIGEST_SHA512;
35755a4608bSchristos 	return -1;
35855a4608bSchristos }
35955a4608bSchristos 
3607a183406Schristos int
361*9469f4f1Schristos ssh_rsa_complete_crt_parameters(const BIGNUM *rsa_d, const BIGNUM *rsa_p,
362*9469f4f1Schristos     const BIGNUM *rsa_q, const BIGNUM *rsa_iqmp, BIGNUM **rsa_dmp1,
363*9469f4f1Schristos     BIGNUM **rsa_dmq1)
3647a183406Schristos {
365aa36fcacSchristos 	BIGNUM *aux = NULL, *d_consttime = NULL;
3667a183406Schristos 	BN_CTX *ctx = NULL;
3677a183406Schristos 	int r;
3687a183406Schristos 
369*9469f4f1Schristos 	*rsa_dmq1 = *rsa_dmp1 = NULL;
3707a183406Schristos 	if ((ctx = BN_CTX_new()) == NULL)
3717a183406Schristos 		return SSH_ERR_ALLOC_FAIL;
372aa36fcacSchristos 	if ((aux = BN_new()) == NULL ||
373*9469f4f1Schristos 	    (*rsa_dmq1 = BN_new()) == NULL ||
374*9469f4f1Schristos 	    (*rsa_dmp1 = BN_new()) == NULL)
375aa36fcacSchristos 		return SSH_ERR_ALLOC_FAIL;
376*9469f4f1Schristos 	if ((d_consttime = BN_dup(rsa_d)) == NULL) {
3777a183406Schristos 		r = SSH_ERR_ALLOC_FAIL;
3787a183406Schristos 		goto out;
3797a183406Schristos 	}
380ffae97bbSchristos 	BN_set_flags(aux, BN_FLG_CONSTTIME);
381aa36fcacSchristos 	BN_set_flags(d_consttime, BN_FLG_CONSTTIME);
3827a183406Schristos 
383aa36fcacSchristos 	if ((BN_sub(aux, rsa_q, BN_value_one()) == 0) ||
384*9469f4f1Schristos 	    (BN_mod(*rsa_dmq1, d_consttime, aux, ctx) == 0) ||
385aa36fcacSchristos 	    (BN_sub(aux, rsa_p, BN_value_one()) == 0) ||
386*9469f4f1Schristos 	    (BN_mod(*rsa_dmp1, d_consttime, aux, ctx) == 0)) {
387b400d007Schristos 		r = SSH_ERR_LIBCRYPTO_ERROR;
388b400d007Schristos 		goto out;
389b400d007Schristos 	}
390aa36fcacSchristos 	/* success */
3917a183406Schristos 	r = 0;
3927a183406Schristos  out:
3937a183406Schristos 	BN_clear_free(aux);
394aa36fcacSchristos 	BN_clear_free(d_consttime);
3957a183406Schristos 	BN_CTX_free(ctx);
3967a183406Schristos 	return r;
3977a183406Schristos }
3987a183406Schristos 
399ca32bd8dSchristos /* RSASSA-PKCS1-v1_5 (PKCS #1 v2.0 signature) with SHA1 */
400b1066cf3Schristos static int
401b1066cf3Schristos ssh_rsa_sign(struct sshkey *key,
402b1066cf3Schristos     u_char **sigp, size_t *lenp,
403b1066cf3Schristos     const u_char *data, size_t datalen,
404b1066cf3Schristos     const char *alg, const char *sk_provider, const char *sk_pin, u_int compat)
405ca32bd8dSchristos {
406*9469f4f1Schristos 	u_char *sig = NULL;
407*9469f4f1Schristos 	size_t diff, len = 0;
408*9469f4f1Schristos 	int slen = 0;
409*9469f4f1Schristos 	int hash_alg, ret = SSH_ERR_INTERNAL_ERROR;
4108a4530f9Schristos 	struct sshbuf *b = NULL;
411ca32bd8dSchristos 
4128a4530f9Schristos 	if (lenp != NULL)
4138a4530f9Schristos 		*lenp = 0;
4148a4530f9Schristos 	if (sigp != NULL)
4158a4530f9Schristos 		*sigp = NULL;
416ca32bd8dSchristos 
417b1066cf3Schristos 	if (alg == NULL || strlen(alg) == 0)
41879976551Schristos 		hash_alg = SSH_DIGEST_SHA1;
41979976551Schristos 	else
420b1066cf3Schristos 		hash_alg = rsa_hash_id_from_keyname(alg);
421*9469f4f1Schristos 
422*9469f4f1Schristos 	if (key == NULL || key->pkey == NULL || hash_alg == -1 ||
4237a183406Schristos 	    sshkey_type_plain(key->type) != KEY_RSA)
4248a4530f9Schristos 		return SSH_ERR_INVALID_ARGUMENT;
425*9469f4f1Schristos 	slen = EVP_PKEY_size(key->pkey);
426*9469f4f1Schristos 	if (slen <= 0 || slen > SSHBUF_MAX_BIGNUM)
4278a4530f9Schristos 		return SSH_ERR_INVALID_ARGUMENT;
428*9469f4f1Schristos 	if (EVP_PKEY_bits(key->pkey) < SSH_RSA_MINIMUM_MODULUS_SIZE)
429*9469f4f1Schristos 		return SSH_ERR_KEY_LENGTH;
430ca32bd8dSchristos 
431*9469f4f1Schristos 	if ((ret = sshkey_pkey_digest_sign(key->pkey, hash_alg, &sig, &len,
432*9469f4f1Schristos 	    data, datalen)) < 0)
4338a4530f9Schristos 		goto out;
434*9469f4f1Schristos 	if (len < (size_t)slen) {
435*9469f4f1Schristos 		diff = slen - len;
436ca32bd8dSchristos 		memmove(sig + diff, sig, len);
4378a4530f9Schristos 		explicit_bzero(sig, diff);
438*9469f4f1Schristos 	} else if (len > (size_t)slen) {
4398a4530f9Schristos 		ret = SSH_ERR_INTERNAL_ERROR;
4408a4530f9Schristos 		goto out;
441ca32bd8dSchristos 	}
442*9469f4f1Schristos 
443ca32bd8dSchristos 	/* encode signature */
4448a4530f9Schristos 	if ((b = sshbuf_new()) == NULL) {
4458a4530f9Schristos 		ret = SSH_ERR_ALLOC_FAIL;
4468a4530f9Schristos 		goto out;
4478a4530f9Schristos 	}
44879976551Schristos 	if ((ret = sshbuf_put_cstring(b, rsa_hash_alg_ident(hash_alg))) != 0 ||
4498a4530f9Schristos 	    (ret = sshbuf_put_string(b, sig, slen)) != 0)
4508a4530f9Schristos 		goto out;
4518a4530f9Schristos 	len = sshbuf_len(b);
4528a4530f9Schristos 	if (sigp != NULL) {
4538a4530f9Schristos 		if ((*sigp = malloc(len)) == NULL) {
4548a4530f9Schristos 			ret = SSH_ERR_ALLOC_FAIL;
4558a4530f9Schristos 			goto out;
4568a4530f9Schristos 		}
4578a4530f9Schristos 		memcpy(*sigp, sshbuf_ptr(b), len);
4588a4530f9Schristos 	}
459ca32bd8dSchristos 	if (lenp != NULL)
460ca32bd8dSchristos 		*lenp = len;
4618a4530f9Schristos 	ret = 0;
4628a4530f9Schristos  out:
463ffae97bbSchristos 	freezero(sig, slen);
4648a4530f9Schristos 	sshbuf_free(b);
4654054ffb0Schristos 	return ret;
466ca32bd8dSchristos }
467ca32bd8dSchristos 
468b1066cf3Schristos static int
4698a4530f9Schristos ssh_rsa_verify(const struct sshkey *key,
470b1066cf3Schristos     const u_char *sig, size_t siglen,
471b1066cf3Schristos     const u_char *data, size_t dlen, const char *alg, u_int compat,
472b1066cf3Schristos     struct sshkey_sig_details **detailsp)
473ca32bd8dSchristos {
474ffae97bbSchristos 	char *sigtype = NULL;
47555a4608bSchristos 	int hash_alg, want_alg, ret = SSH_ERR_INTERNAL_ERROR;
476*9469f4f1Schristos 	size_t len = 0, diff, modlen, rsasize;
4778a4530f9Schristos 	struct sshbuf *b = NULL;
4788a4530f9Schristos 	u_char digest[SSH_DIGEST_MAX_LENGTH], *osigblob, *sigblob = NULL;
479ca32bd8dSchristos 
480*9469f4f1Schristos 	if (key == NULL || key->pkey == NULL ||
4818a4530f9Schristos 	    sshkey_type_plain(key->type) != KEY_RSA ||
4825101d403Schristos 	    sig == NULL || siglen == 0)
4838a4530f9Schristos 		return SSH_ERR_INVALID_ARGUMENT;
484*9469f4f1Schristos 	if (EVP_PKEY_bits(key->pkey) < SSH_RSA_MINIMUM_MODULUS_SIZE)
4857a183406Schristos 		return SSH_ERR_KEY_LENGTH;
4868a4530f9Schristos 
48779976551Schristos 	if ((b = sshbuf_from(sig, siglen)) == NULL)
4888a4530f9Schristos 		return SSH_ERR_ALLOC_FAIL;
489ffae97bbSchristos 	if (sshbuf_get_cstring(b, &sigtype, NULL) != 0) {
4908a4530f9Schristos 		ret = SSH_ERR_INVALID_FORMAT;
4918a4530f9Schristos 		goto out;
492ca32bd8dSchristos 	}
49355a4608bSchristos 	if ((hash_alg = rsa_hash_id_from_ident(sigtype)) == -1) {
49455a4608bSchristos 		ret = SSH_ERR_KEY_TYPE_MISMATCH;
49555a4608bSchristos 		goto out;
49655a4608bSchristos 	}
49755a4608bSchristos 	/*
49855a4608bSchristos 	 * Allow ssh-rsa-cert-v01 certs to generate SHA2 signatures for
49955a4608bSchristos 	 * legacy reasons, but otherwise the signature type should match.
50055a4608bSchristos 	 */
50155a4608bSchristos 	if (alg != NULL && strcmp(alg, "ssh-rsa-cert-v01@openssh.com") != 0) {
50255a4608bSchristos 		if ((want_alg = rsa_hash_id_from_keyname(alg)) == -1) {
50355a4608bSchristos 			ret = SSH_ERR_INVALID_ARGUMENT;
50455a4608bSchristos 			goto out;
50555a4608bSchristos 		}
50655a4608bSchristos 		if (hash_alg != want_alg) {
507ffae97bbSchristos 			ret = SSH_ERR_SIGNATURE_INVALID;
508ffae97bbSchristos 			goto out;
509ffae97bbSchristos 		}
510ca32bd8dSchristos 	}
5118a4530f9Schristos 	if (sshbuf_get_string(b, &sigblob, &len) != 0) {
5128a4530f9Schristos 		ret = SSH_ERR_INVALID_FORMAT;
5138a4530f9Schristos 		goto out;
5148a4530f9Schristos 	}
5158a4530f9Schristos 	if (sshbuf_len(b) != 0) {
5168a4530f9Schristos 		ret = SSH_ERR_UNEXPECTED_TRAILING_DATA;
5178a4530f9Schristos 		goto out;
518ca32bd8dSchristos 	}
519ca32bd8dSchristos 	/* RSA_verify expects a signature of RSA_size */
520*9469f4f1Schristos 	modlen = EVP_PKEY_size(key->pkey);
521ca32bd8dSchristos 	if (len > modlen) {
5228a4530f9Schristos 		ret = SSH_ERR_KEY_BITS_MISMATCH;
5238a4530f9Schristos 		goto out;
524ca32bd8dSchristos 	} else if (len < modlen) {
5258a4530f9Schristos 		diff = modlen - len;
5268a4530f9Schristos 		osigblob = sigblob;
5278a4530f9Schristos 		if ((sigblob = realloc(sigblob, modlen)) == NULL) {
5288a4530f9Schristos 			sigblob = osigblob; /* put it back for clear/free */
5298a4530f9Schristos 			ret = SSH_ERR_ALLOC_FAIL;
5308a4530f9Schristos 			goto out;
5318a4530f9Schristos 		}
532ca32bd8dSchristos 		memmove(sigblob + diff, sigblob, len);
5338a4530f9Schristos 		explicit_bzero(sigblob, diff);
534ca32bd8dSchristos 		len = modlen;
535ca32bd8dSchristos 	}
536*9469f4f1Schristos 
537*9469f4f1Schristos 	rsasize = EVP_PKEY_size(key->pkey);
538*9469f4f1Schristos 	if (rsasize <= 0 || rsasize > SSHBUF_MAX_BIGNUM ||
539*9469f4f1Schristos 	    len == 0 || len > rsasize) {
540*9469f4f1Schristos 		ret = SSH_ERR_INVALID_ARGUMENT;
5418a4530f9Schristos 		goto out;
542ca32bd8dSchristos 	}
543*9469f4f1Schristos 	ret = sshkey_pkey_digest_verify(key->pkey, hash_alg, data, dlen,
544*9469f4f1Schristos 	    sigblob, len);
545ca32bd8dSchristos 
5468a4530f9Schristos  out:
547ffae97bbSchristos 	freezero(sigblob, len);
548ffae97bbSchristos 	free(sigtype);
5498a4530f9Schristos 	sshbuf_free(b);
5508a4530f9Schristos 	explicit_bzero(digest, sizeof(digest));
551ca32bd8dSchristos 	return ret;
552ca32bd8dSchristos }
553ca32bd8dSchristos 
554b1066cf3Schristos static const struct sshkey_impl_funcs sshkey_rsa_funcs = {
555b1066cf3Schristos 	/* .size = */		ssh_rsa_size,
556b1066cf3Schristos 	/* .alloc = */		ssh_rsa_alloc,
557b1066cf3Schristos 	/* .cleanup = */	ssh_rsa_cleanup,
558b1066cf3Schristos 	/* .equal = */		ssh_rsa_equal,
559b1066cf3Schristos 	/* .ssh_serialize_public = */ ssh_rsa_serialize_public,
560b1066cf3Schristos 	/* .ssh_deserialize_public = */ ssh_rsa_deserialize_public,
561b1066cf3Schristos 	/* .ssh_serialize_private = */ ssh_rsa_serialize_private,
562b1066cf3Schristos 	/* .ssh_deserialize_private = */ ssh_rsa_deserialize_private,
563b1066cf3Schristos 	/* .generate = */	ssh_rsa_generate,
564b1066cf3Schristos 	/* .copy_public = */	ssh_rsa_copy_public,
565b1066cf3Schristos 	/* .sign = */		ssh_rsa_sign,
566b1066cf3Schristos 	/* .verify = */		ssh_rsa_verify,
567b1066cf3Schristos };
568b1066cf3Schristos 
569b1066cf3Schristos const struct sshkey_impl sshkey_rsa_impl = {
570b1066cf3Schristos 	/* .name = */		"ssh-rsa",
571b1066cf3Schristos 	/* .shortname = */	"RSA",
572b1066cf3Schristos 	/* .sigalg = */		NULL,
573b1066cf3Schristos 	/* .type = */		KEY_RSA,
574b1066cf3Schristos 	/* .nid = */		0,
575b1066cf3Schristos 	/* .cert = */		0,
576b1066cf3Schristos 	/* .sigonly = */	0,
577b1066cf3Schristos 	/* .keybits = */	0,
578b1066cf3Schristos 	/* .funcs = */		&sshkey_rsa_funcs,
579b1066cf3Schristos };
580b1066cf3Schristos 
581b1066cf3Schristos const struct sshkey_impl sshkey_rsa_cert_impl = {
582b1066cf3Schristos 	/* .name = */		"ssh-rsa-cert-v01@openssh.com",
583b1066cf3Schristos 	/* .shortname = */	"RSA-CERT",
584b1066cf3Schristos 	/* .sigalg = */		NULL,
585b1066cf3Schristos 	/* .type = */		KEY_RSA_CERT,
586b1066cf3Schristos 	/* .nid = */		0,
587b1066cf3Schristos 	/* .cert = */		1,
588b1066cf3Schristos 	/* .sigonly = */	0,
589b1066cf3Schristos 	/* .keybits = */	0,
590b1066cf3Schristos 	/* .funcs = */		&sshkey_rsa_funcs,
591b1066cf3Schristos };
592b1066cf3Schristos 
593b1066cf3Schristos /* SHA2 signature algorithms */
594b1066cf3Schristos 
595b1066cf3Schristos const struct sshkey_impl sshkey_rsa_sha256_impl = {
596b1066cf3Schristos 	/* .name = */		"rsa-sha2-256",
597b1066cf3Schristos 	/* .shortname = */	"RSA",
598b1066cf3Schristos 	/* .sigalg = */		NULL,
599b1066cf3Schristos 	/* .type = */		KEY_RSA,
600b1066cf3Schristos 	/* .nid = */		0,
601b1066cf3Schristos 	/* .cert = */		0,
602b1066cf3Schristos 	/* .sigonly = */	1,
603b1066cf3Schristos 	/* .keybits = */	0,
604b1066cf3Schristos 	/* .funcs = */		&sshkey_rsa_funcs,
605b1066cf3Schristos };
606b1066cf3Schristos 
607b1066cf3Schristos const struct sshkey_impl sshkey_rsa_sha512_impl = {
608b1066cf3Schristos 	/* .name = */		"rsa-sha2-512",
609b1066cf3Schristos 	/* .shortname = */	"RSA",
610b1066cf3Schristos 	/* .sigalg = */		NULL,
611b1066cf3Schristos 	/* .type = */		KEY_RSA,
612b1066cf3Schristos 	/* .nid = */		0,
613b1066cf3Schristos 	/* .cert = */		0,
614b1066cf3Schristos 	/* .sigonly = */	1,
615b1066cf3Schristos 	/* .keybits = */	0,
616b1066cf3Schristos 	/* .funcs = */		&sshkey_rsa_funcs,
617b1066cf3Schristos };
618b1066cf3Schristos 
619b1066cf3Schristos const struct sshkey_impl sshkey_rsa_sha256_cert_impl = {
620b1066cf3Schristos 	/* .name = */		"rsa-sha2-256-cert-v01@openssh.com",
621b1066cf3Schristos 	/* .shortname = */	"RSA-CERT",
622b1066cf3Schristos 	/* .sigalg = */		"rsa-sha2-256",
623b1066cf3Schristos 	/* .type = */		KEY_RSA_CERT,
624b1066cf3Schristos 	/* .nid = */		0,
625b1066cf3Schristos 	/* .cert = */		1,
626b1066cf3Schristos 	/* .sigonly = */	1,
627b1066cf3Schristos 	/* .keybits = */	0,
628b1066cf3Schristos 	/* .funcs = */		&sshkey_rsa_funcs,
629b1066cf3Schristos };
630b1066cf3Schristos 
631b1066cf3Schristos const struct sshkey_impl sshkey_rsa_sha512_cert_impl = {
632b1066cf3Schristos 	/* .name = */		"rsa-sha2-512-cert-v01@openssh.com",
633b1066cf3Schristos 	/* .shortname = */	"RSA-CERT",
634b1066cf3Schristos 	/* .sigalg = */		"rsa-sha2-512",
635b1066cf3Schristos 	/* .type = */		KEY_RSA_CERT,
636b1066cf3Schristos 	/* .nid = */		0,
637b1066cf3Schristos 	/* .cert = */		1,
638b1066cf3Schristos 	/* .sigonly = */	1,
639b1066cf3Schristos 	/* .keybits = */	0,
640b1066cf3Schristos 	/* .funcs = */		&sshkey_rsa_funcs,
641b1066cf3Schristos };
642