xref: /netbsd-src/crypto/external/bsd/openssh/dist/ssh-rsa.c (revision 9469f4f13c84743995b7d51c506f9c9849ba30de)
1 /*	$NetBSD: ssh-rsa.c,v 1.20 2024/09/24 21:32:19 christos Exp $	*/
2 /* $OpenBSD: ssh-rsa.c,v 1.80 2024/08/15 00:51:51 djm Exp $ */
3 
4 /*
5  * Copyright (c) 2000, 2003 Markus Friedl <markus@openbsd.org>
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #include "includes.h"
21 __RCSID("$NetBSD: ssh-rsa.c,v 1.20 2024/09/24 21:32:19 christos Exp $");
22 #include <sys/types.h>
23 
24 #include <openssl/evp.h>
25 #include <openssl/err.h>
26 
27 #include <string.h>
28 
29 #include "sshbuf.h"
30 #include "ssherr.h"
31 #define SSHKEY_INTERNAL
32 #include "sshkey.h"
33 #include "digest.h"
34 #include "log.h"
35 
36 static u_int
37 ssh_rsa_size(const struct sshkey *k)
38 {
39 	if (k->pkey == NULL)
40 		return 0;
41 	return EVP_PKEY_bits(k->pkey);
42 }
43 
44 static int
45 ssh_rsa_alloc(struct sshkey *k)
46 {
47 	if ((k->pkey = EVP_PKEY_new()) == NULL)
48 		return SSH_ERR_ALLOC_FAIL;
49 	return 0;
50 }
51 
52 static void
53 ssh_rsa_cleanup(struct sshkey *k)
54 {
55 	EVP_PKEY_free(k->pkey);
56 	k->pkey = NULL;
57 }
58 
59 static int
60 ssh_rsa_equal(const struct sshkey *a, const struct sshkey *b)
61 {
62 	if (a->pkey == NULL || b->pkey == NULL)
63 		return 0;
64 	return EVP_PKEY_cmp(a->pkey, b->pkey) == 1;
65 }
66 
67 static int
68 ssh_rsa_serialize_public(const struct sshkey *key, struct sshbuf *b,
69     enum sshkey_serialize_rep opts)
70 {
71 	int r;
72 	const BIGNUM *rsa_n, *rsa_e;
73 	const RSA *rsa;
74 
75 	if (key->pkey == NULL)
76 		return SSH_ERR_INVALID_ARGUMENT;
77 	if ((rsa = EVP_PKEY_get0_RSA(key->pkey)) == NULL)
78 		return SSH_ERR_LIBCRYPTO_ERROR;
79 
80 	RSA_get0_key(rsa, &rsa_n, &rsa_e, NULL);
81 	if ((r = sshbuf_put_bignum2(b, rsa_e)) != 0 ||
82 	    (r = sshbuf_put_bignum2(b, rsa_n)) != 0)
83 		return r;
84 
85 	return 0;
86 }
87 
88 static int
89 ssh_rsa_serialize_private(const struct sshkey *key, struct sshbuf *b,
90     enum sshkey_serialize_rep opts)
91 {
92 	int r;
93 	const BIGNUM *rsa_n, *rsa_e, *rsa_d, *rsa_iqmp, *rsa_p, *rsa_q;
94 	const RSA *rsa;
95 
96 	if ((rsa = EVP_PKEY_get0_RSA(key->pkey)) == NULL)
97 		return SSH_ERR_LIBCRYPTO_ERROR;
98 	RSA_get0_key(rsa, &rsa_n, &rsa_e, &rsa_d);
99 	RSA_get0_factors(rsa, &rsa_p, &rsa_q);
100 	RSA_get0_crt_params(rsa, NULL, NULL, &rsa_iqmp);
101 
102 	if (!sshkey_is_cert(key)) {
103 		/* Note: can't reuse ssh_rsa_serialize_public: e, n vs. n, e */
104 		if ((r = sshbuf_put_bignum2(b, rsa_n)) != 0 ||
105 		    (r = sshbuf_put_bignum2(b, rsa_e)) != 0)
106 			return r;
107 	}
108 	if ((r = sshbuf_put_bignum2(b, rsa_d)) != 0 ||
109 	    (r = sshbuf_put_bignum2(b, rsa_iqmp)) != 0 ||
110 	    (r = sshbuf_put_bignum2(b, rsa_p)) != 0 ||
111 	    (r = sshbuf_put_bignum2(b, rsa_q)) != 0)
112 		return r;
113 
114 	return 0;
115 }
116 
117 static int
118 ssh_rsa_generate(struct sshkey *k, int bits)
119 {
120 	EVP_PKEY_CTX *ctx = NULL;
121 	EVP_PKEY *res = NULL;
122 
123 	int ret = SSH_ERR_INTERNAL_ERROR;
124 
125 	if (bits < SSH_RSA_MINIMUM_MODULUS_SIZE ||
126 	    bits > SSHBUF_MAX_BIGNUM * 8)
127 		return SSH_ERR_KEY_LENGTH;
128 
129 	if ((ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL)) == NULL) {
130 		ret = SSH_ERR_ALLOC_FAIL;
131 		goto out;
132 	}
133 	if (EVP_PKEY_keygen_init(ctx) <= 0) {
134 		ret = SSH_ERR_LIBCRYPTO_ERROR;
135 		goto out;
136 	}
137 	if (EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, bits) <= 0) {
138 		ret = SSH_ERR_KEY_LENGTH;
139 		goto out;
140 	}
141 	if (EVP_PKEY_keygen(ctx, &res) <= 0 || res == NULL) {
142 		ret = SSH_ERR_LIBCRYPTO_ERROR;
143 		goto out;
144 	}
145 	/* success */
146 	k->pkey = res;
147 	ret = 0;
148  out:
149 	EVP_PKEY_CTX_free(ctx);
150 	return ret;
151 }
152 
153 static int
154 ssh_rsa_copy_public(const struct sshkey *from, struct sshkey *to)
155 {
156 	const BIGNUM *rsa_n, *rsa_e;
157 	BIGNUM *rsa_n_dup = NULL, *rsa_e_dup = NULL;
158 	int r = SSH_ERR_INTERNAL_ERROR;
159 	const RSA *rsa_from;
160 	RSA *rsa_to = NULL;
161 
162 	if ((rsa_from = EVP_PKEY_get0_RSA(from->pkey)) == NULL ||
163 	    (rsa_to = RSA_new()) == NULL)
164 		return SSH_ERR_LIBCRYPTO_ERROR;
165 
166 	RSA_get0_key(rsa_from, &rsa_n, &rsa_e, NULL);
167 	if ((rsa_n_dup = BN_dup(rsa_n)) == NULL ||
168 	    (rsa_e_dup = BN_dup(rsa_e)) == NULL) {
169 		r = SSH_ERR_ALLOC_FAIL;
170 		goto out;
171 	}
172 	if (!RSA_set0_key(rsa_to, rsa_n_dup, rsa_e_dup, NULL)) {
173 		r = SSH_ERR_LIBCRYPTO_ERROR;
174 		goto out;
175 	}
176 	rsa_n_dup = rsa_e_dup = NULL; /* transferred */
177 
178 	if (EVP_PKEY_set1_RSA(to->pkey, rsa_to) != 1) {
179 		r = SSH_ERR_LIBCRYPTO_ERROR;
180 		goto out;
181 	}
182 	/* success */
183 	r = 0;
184  out:
185 	RSA_free(rsa_to);
186 	BN_clear_free(rsa_n_dup);
187 	BN_clear_free(rsa_e_dup);
188 	return r;
189 }
190 
191 static int
192 ssh_rsa_deserialize_public(const char *ktype, struct sshbuf *b,
193     struct sshkey *key)
194 {
195 	int ret = SSH_ERR_INTERNAL_ERROR;
196 	BIGNUM *rsa_n = NULL, *rsa_e = NULL;
197 	RSA *rsa = NULL;
198 
199 	if ((rsa = RSA_new()) == NULL)
200 		return SSH_ERR_LIBCRYPTO_ERROR;
201 
202 	if (sshbuf_get_bignum2(b, &rsa_e) != 0 ||
203 	    sshbuf_get_bignum2(b, &rsa_n) != 0) {
204 		ret = SSH_ERR_INVALID_FORMAT;
205 		goto out;
206 	}
207 	if (!RSA_set0_key(rsa, rsa_n, rsa_e, NULL)) {
208 		ret = SSH_ERR_LIBCRYPTO_ERROR;
209 		goto out;
210 	}
211 	rsa_n = rsa_e = NULL; /* transferred */
212 	if (EVP_PKEY_set1_RSA(key->pkey, rsa) != 1) {
213 		ret = SSH_ERR_LIBCRYPTO_ERROR;
214 		goto out;
215 	}
216 	if ((ret = sshkey_check_rsa_length(key, 0)) != 0)
217 		goto out;
218 #ifdef DEBUG_PK
219 	RSA_print_fp(stderr, rsa, 8);
220 #endif
221 	/* success */
222 	ret = 0;
223  out:
224 	RSA_free(rsa);
225 	BN_clear_free(rsa_n);
226 	BN_clear_free(rsa_e);
227 	return ret;
228 }
229 
230 static int
231 ssh_rsa_deserialize_private(const char *ktype, struct sshbuf *b,
232     struct sshkey *key)
233 {
234 	int r;
235 	BIGNUM *rsa_n = NULL, *rsa_e = NULL, *rsa_d = NULL;
236 	BIGNUM *rsa_iqmp = NULL, *rsa_p = NULL, *rsa_q = NULL;
237 	BIGNUM *rsa_dmp1 = NULL, *rsa_dmq1 = NULL;
238 	RSA *rsa = NULL;
239 
240 	if (sshkey_is_cert(key)) {
241 		/* sshkey_private_deserialize already has pubkey from cert */
242 		if ((rsa = EVP_PKEY_get1_RSA(key->pkey)) == NULL) {
243 			r = SSH_ERR_LIBCRYPTO_ERROR;
244 			goto out;
245 		}
246 	} else {
247 		if ((rsa = RSA_new()) == NULL) {
248 			r = SSH_ERR_LIBCRYPTO_ERROR;
249 			goto out;
250 		}
251 		/* Note: can't reuse ssh_rsa_deserialize_public: e,n vs. n,e */
252 		if ((r = sshbuf_get_bignum2(b, &rsa_n)) != 0 ||
253 		    (r = sshbuf_get_bignum2(b, &rsa_e)) != 0)
254 			goto out;
255 		if (!RSA_set0_key(rsa, rsa_n, rsa_e, NULL)) {
256 			r = SSH_ERR_LIBCRYPTO_ERROR;
257 			goto out;
258 		}
259 		rsa_n = rsa_e = NULL; /* transferred */
260 	}
261 	if ((r = sshbuf_get_bignum2(b, &rsa_d)) != 0 ||
262 	    (r = sshbuf_get_bignum2(b, &rsa_iqmp)) != 0 ||
263 	    (r = sshbuf_get_bignum2(b, &rsa_p)) != 0 ||
264 	    (r = sshbuf_get_bignum2(b, &rsa_q)) != 0)
265 		goto out;
266 	if ((r = ssh_rsa_complete_crt_parameters(rsa_d, rsa_p, rsa_q,
267 	    rsa_iqmp, &rsa_dmp1, &rsa_dmq1)) != 0)
268 		goto out;
269 	if (!RSA_set0_key(rsa, NULL, NULL, rsa_d)) {
270 		r = SSH_ERR_LIBCRYPTO_ERROR;
271 		goto out;
272 	}
273 	rsa_d = NULL; /* transferred */
274 	if (!RSA_set0_factors(rsa, rsa_p, rsa_q)) {
275 		r = SSH_ERR_LIBCRYPTO_ERROR;
276 		goto out;
277 	}
278 	rsa_p = rsa_q = NULL; /* transferred */
279 	if (!RSA_set0_crt_params(rsa, rsa_dmp1, rsa_dmq1, rsa_iqmp)) {
280 		r = SSH_ERR_LIBCRYPTO_ERROR;
281 		goto out;
282 	}
283 	rsa_dmp1 = rsa_dmq1 = rsa_iqmp = NULL;
284 	if (RSA_blinding_on(rsa, NULL) != 1) {
285 		r = SSH_ERR_LIBCRYPTO_ERROR;
286 		goto out;
287 	}
288 	if (EVP_PKEY_set1_RSA(key->pkey, rsa) != 1) {
289 		r = SSH_ERR_LIBCRYPTO_ERROR;
290 		goto out;
291 	}
292 	if ((r = sshkey_check_rsa_length(key, 0)) != 0)
293 		goto out;
294 	/* success */
295 	r = 0;
296  out:
297 	RSA_free(rsa);
298 	BN_clear_free(rsa_n);
299 	BN_clear_free(rsa_e);
300 	BN_clear_free(rsa_d);
301 	BN_clear_free(rsa_p);
302 	BN_clear_free(rsa_q);
303 	BN_clear_free(rsa_iqmp);
304 	BN_clear_free(rsa_dmp1);
305 	BN_clear_free(rsa_dmq1);
306 	return r;
307 }
308 
309 static const char *
310 rsa_hash_alg_ident(int hash_alg)
311 {
312 	switch (hash_alg) {
313 	case SSH_DIGEST_SHA1:
314 		return "ssh-rsa";
315 	case SSH_DIGEST_SHA256:
316 		return "rsa-sha2-256";
317 	case SSH_DIGEST_SHA512:
318 		return "rsa-sha2-512";
319 	}
320 	return NULL;
321 }
322 
323 /*
324  * Returns the hash algorithm ID for a given algorithm identifier as used
325  * inside the signature blob,
326  */
327 static int
328 rsa_hash_id_from_ident(const char *ident)
329 {
330 	if (strcmp(ident, "ssh-rsa") == 0)
331 		return SSH_DIGEST_SHA1;
332 	if (strcmp(ident, "rsa-sha2-256") == 0)
333 		return SSH_DIGEST_SHA256;
334 	if (strcmp(ident, "rsa-sha2-512") == 0)
335 		return SSH_DIGEST_SHA512;
336 	return -1;
337 }
338 
339 /*
340  * Return the hash algorithm ID for the specified key name. This includes
341  * all the cases of rsa_hash_id_from_ident() but also the certificate key
342  * types.
343  */
344 static int
345 rsa_hash_id_from_keyname(const char *alg)
346 {
347 	int r;
348 
349 	if ((r = rsa_hash_id_from_ident(alg)) != -1)
350 		return r;
351 	if (strcmp(alg, "ssh-rsa-cert-v01@openssh.com") == 0)
352 		return SSH_DIGEST_SHA1;
353 	if (strcmp(alg, "rsa-sha2-256-cert-v01@openssh.com") == 0)
354 		return SSH_DIGEST_SHA256;
355 	if (strcmp(alg, "rsa-sha2-512-cert-v01@openssh.com") == 0)
356 		return SSH_DIGEST_SHA512;
357 	return -1;
358 }
359 
360 int
361 ssh_rsa_complete_crt_parameters(const BIGNUM *rsa_d, const BIGNUM *rsa_p,
362     const BIGNUM *rsa_q, const BIGNUM *rsa_iqmp, BIGNUM **rsa_dmp1,
363     BIGNUM **rsa_dmq1)
364 {
365 	BIGNUM *aux = NULL, *d_consttime = NULL;
366 	BN_CTX *ctx = NULL;
367 	int r;
368 
369 	*rsa_dmq1 = *rsa_dmp1 = NULL;
370 	if ((ctx = BN_CTX_new()) == NULL)
371 		return SSH_ERR_ALLOC_FAIL;
372 	if ((aux = BN_new()) == NULL ||
373 	    (*rsa_dmq1 = BN_new()) == NULL ||
374 	    (*rsa_dmp1 = BN_new()) == NULL)
375 		return SSH_ERR_ALLOC_FAIL;
376 	if ((d_consttime = BN_dup(rsa_d)) == NULL) {
377 		r = SSH_ERR_ALLOC_FAIL;
378 		goto out;
379 	}
380 	BN_set_flags(aux, BN_FLG_CONSTTIME);
381 	BN_set_flags(d_consttime, BN_FLG_CONSTTIME);
382 
383 	if ((BN_sub(aux, rsa_q, BN_value_one()) == 0) ||
384 	    (BN_mod(*rsa_dmq1, d_consttime, aux, ctx) == 0) ||
385 	    (BN_sub(aux, rsa_p, BN_value_one()) == 0) ||
386 	    (BN_mod(*rsa_dmp1, d_consttime, aux, ctx) == 0)) {
387 		r = SSH_ERR_LIBCRYPTO_ERROR;
388 		goto out;
389 	}
390 	/* success */
391 	r = 0;
392  out:
393 	BN_clear_free(aux);
394 	BN_clear_free(d_consttime);
395 	BN_CTX_free(ctx);
396 	return r;
397 }
398 
399 /* RSASSA-PKCS1-v1_5 (PKCS #1 v2.0 signature) with SHA1 */
400 static int
401 ssh_rsa_sign(struct sshkey *key,
402     u_char **sigp, size_t *lenp,
403     const u_char *data, size_t datalen,
404     const char *alg, const char *sk_provider, const char *sk_pin, u_int compat)
405 {
406 	u_char *sig = NULL;
407 	size_t diff, len = 0;
408 	int slen = 0;
409 	int hash_alg, ret = SSH_ERR_INTERNAL_ERROR;
410 	struct sshbuf *b = NULL;
411 
412 	if (lenp != NULL)
413 		*lenp = 0;
414 	if (sigp != NULL)
415 		*sigp = NULL;
416 
417 	if (alg == NULL || strlen(alg) == 0)
418 		hash_alg = SSH_DIGEST_SHA1;
419 	else
420 		hash_alg = rsa_hash_id_from_keyname(alg);
421 
422 	if (key == NULL || key->pkey == NULL || hash_alg == -1 ||
423 	    sshkey_type_plain(key->type) != KEY_RSA)
424 		return SSH_ERR_INVALID_ARGUMENT;
425 	slen = EVP_PKEY_size(key->pkey);
426 	if (slen <= 0 || slen > SSHBUF_MAX_BIGNUM)
427 		return SSH_ERR_INVALID_ARGUMENT;
428 	if (EVP_PKEY_bits(key->pkey) < SSH_RSA_MINIMUM_MODULUS_SIZE)
429 		return SSH_ERR_KEY_LENGTH;
430 
431 	if ((ret = sshkey_pkey_digest_sign(key->pkey, hash_alg, &sig, &len,
432 	    data, datalen)) < 0)
433 		goto out;
434 	if (len < (size_t)slen) {
435 		diff = slen - len;
436 		memmove(sig + diff, sig, len);
437 		explicit_bzero(sig, diff);
438 	} else if (len > (size_t)slen) {
439 		ret = SSH_ERR_INTERNAL_ERROR;
440 		goto out;
441 	}
442 
443 	/* encode signature */
444 	if ((b = sshbuf_new()) == NULL) {
445 		ret = SSH_ERR_ALLOC_FAIL;
446 		goto out;
447 	}
448 	if ((ret = sshbuf_put_cstring(b, rsa_hash_alg_ident(hash_alg))) != 0 ||
449 	    (ret = sshbuf_put_string(b, sig, slen)) != 0)
450 		goto out;
451 	len = sshbuf_len(b);
452 	if (sigp != NULL) {
453 		if ((*sigp = malloc(len)) == NULL) {
454 			ret = SSH_ERR_ALLOC_FAIL;
455 			goto out;
456 		}
457 		memcpy(*sigp, sshbuf_ptr(b), len);
458 	}
459 	if (lenp != NULL)
460 		*lenp = len;
461 	ret = 0;
462  out:
463 	freezero(sig, slen);
464 	sshbuf_free(b);
465 	return ret;
466 }
467 
468 static int
469 ssh_rsa_verify(const struct sshkey *key,
470     const u_char *sig, size_t siglen,
471     const u_char *data, size_t dlen, const char *alg, u_int compat,
472     struct sshkey_sig_details **detailsp)
473 {
474 	char *sigtype = NULL;
475 	int hash_alg, want_alg, ret = SSH_ERR_INTERNAL_ERROR;
476 	size_t len = 0, diff, modlen, rsasize;
477 	struct sshbuf *b = NULL;
478 	u_char digest[SSH_DIGEST_MAX_LENGTH], *osigblob, *sigblob = NULL;
479 
480 	if (key == NULL || key->pkey == NULL ||
481 	    sshkey_type_plain(key->type) != KEY_RSA ||
482 	    sig == NULL || siglen == 0)
483 		return SSH_ERR_INVALID_ARGUMENT;
484 	if (EVP_PKEY_bits(key->pkey) < SSH_RSA_MINIMUM_MODULUS_SIZE)
485 		return SSH_ERR_KEY_LENGTH;
486 
487 	if ((b = sshbuf_from(sig, siglen)) == NULL)
488 		return SSH_ERR_ALLOC_FAIL;
489 	if (sshbuf_get_cstring(b, &sigtype, NULL) != 0) {
490 		ret = SSH_ERR_INVALID_FORMAT;
491 		goto out;
492 	}
493 	if ((hash_alg = rsa_hash_id_from_ident(sigtype)) == -1) {
494 		ret = SSH_ERR_KEY_TYPE_MISMATCH;
495 		goto out;
496 	}
497 	/*
498 	 * Allow ssh-rsa-cert-v01 certs to generate SHA2 signatures for
499 	 * legacy reasons, but otherwise the signature type should match.
500 	 */
501 	if (alg != NULL && strcmp(alg, "ssh-rsa-cert-v01@openssh.com") != 0) {
502 		if ((want_alg = rsa_hash_id_from_keyname(alg)) == -1) {
503 			ret = SSH_ERR_INVALID_ARGUMENT;
504 			goto out;
505 		}
506 		if (hash_alg != want_alg) {
507 			ret = SSH_ERR_SIGNATURE_INVALID;
508 			goto out;
509 		}
510 	}
511 	if (sshbuf_get_string(b, &sigblob, &len) != 0) {
512 		ret = SSH_ERR_INVALID_FORMAT;
513 		goto out;
514 	}
515 	if (sshbuf_len(b) != 0) {
516 		ret = SSH_ERR_UNEXPECTED_TRAILING_DATA;
517 		goto out;
518 	}
519 	/* RSA_verify expects a signature of RSA_size */
520 	modlen = EVP_PKEY_size(key->pkey);
521 	if (len > modlen) {
522 		ret = SSH_ERR_KEY_BITS_MISMATCH;
523 		goto out;
524 	} else if (len < modlen) {
525 		diff = modlen - len;
526 		osigblob = sigblob;
527 		if ((sigblob = realloc(sigblob, modlen)) == NULL) {
528 			sigblob = osigblob; /* put it back for clear/free */
529 			ret = SSH_ERR_ALLOC_FAIL;
530 			goto out;
531 		}
532 		memmove(sigblob + diff, sigblob, len);
533 		explicit_bzero(sigblob, diff);
534 		len = modlen;
535 	}
536 
537 	rsasize = EVP_PKEY_size(key->pkey);
538 	if (rsasize <= 0 || rsasize > SSHBUF_MAX_BIGNUM ||
539 	    len == 0 || len > rsasize) {
540 		ret = SSH_ERR_INVALID_ARGUMENT;
541 		goto out;
542 	}
543 	ret = sshkey_pkey_digest_verify(key->pkey, hash_alg, data, dlen,
544 	    sigblob, len);
545 
546  out:
547 	freezero(sigblob, len);
548 	free(sigtype);
549 	sshbuf_free(b);
550 	explicit_bzero(digest, sizeof(digest));
551 	return ret;
552 }
553 
554 static const struct sshkey_impl_funcs sshkey_rsa_funcs = {
555 	/* .size = */		ssh_rsa_size,
556 	/* .alloc = */		ssh_rsa_alloc,
557 	/* .cleanup = */	ssh_rsa_cleanup,
558 	/* .equal = */		ssh_rsa_equal,
559 	/* .ssh_serialize_public = */ ssh_rsa_serialize_public,
560 	/* .ssh_deserialize_public = */ ssh_rsa_deserialize_public,
561 	/* .ssh_serialize_private = */ ssh_rsa_serialize_private,
562 	/* .ssh_deserialize_private = */ ssh_rsa_deserialize_private,
563 	/* .generate = */	ssh_rsa_generate,
564 	/* .copy_public = */	ssh_rsa_copy_public,
565 	/* .sign = */		ssh_rsa_sign,
566 	/* .verify = */		ssh_rsa_verify,
567 };
568 
569 const struct sshkey_impl sshkey_rsa_impl = {
570 	/* .name = */		"ssh-rsa",
571 	/* .shortname = */	"RSA",
572 	/* .sigalg = */		NULL,
573 	/* .type = */		KEY_RSA,
574 	/* .nid = */		0,
575 	/* .cert = */		0,
576 	/* .sigonly = */	0,
577 	/* .keybits = */	0,
578 	/* .funcs = */		&sshkey_rsa_funcs,
579 };
580 
581 const struct sshkey_impl sshkey_rsa_cert_impl = {
582 	/* .name = */		"ssh-rsa-cert-v01@openssh.com",
583 	/* .shortname = */	"RSA-CERT",
584 	/* .sigalg = */		NULL,
585 	/* .type = */		KEY_RSA_CERT,
586 	/* .nid = */		0,
587 	/* .cert = */		1,
588 	/* .sigonly = */	0,
589 	/* .keybits = */	0,
590 	/* .funcs = */		&sshkey_rsa_funcs,
591 };
592 
593 /* SHA2 signature algorithms */
594 
595 const struct sshkey_impl sshkey_rsa_sha256_impl = {
596 	/* .name = */		"rsa-sha2-256",
597 	/* .shortname = */	"RSA",
598 	/* .sigalg = */		NULL,
599 	/* .type = */		KEY_RSA,
600 	/* .nid = */		0,
601 	/* .cert = */		0,
602 	/* .sigonly = */	1,
603 	/* .keybits = */	0,
604 	/* .funcs = */		&sshkey_rsa_funcs,
605 };
606 
607 const struct sshkey_impl sshkey_rsa_sha512_impl = {
608 	/* .name = */		"rsa-sha2-512",
609 	/* .shortname = */	"RSA",
610 	/* .sigalg = */		NULL,
611 	/* .type = */		KEY_RSA,
612 	/* .nid = */		0,
613 	/* .cert = */		0,
614 	/* .sigonly = */	1,
615 	/* .keybits = */	0,
616 	/* .funcs = */		&sshkey_rsa_funcs,
617 };
618 
619 const struct sshkey_impl sshkey_rsa_sha256_cert_impl = {
620 	/* .name = */		"rsa-sha2-256-cert-v01@openssh.com",
621 	/* .shortname = */	"RSA-CERT",
622 	/* .sigalg = */		"rsa-sha2-256",
623 	/* .type = */		KEY_RSA_CERT,
624 	/* .nid = */		0,
625 	/* .cert = */		1,
626 	/* .sigonly = */	1,
627 	/* .keybits = */	0,
628 	/* .funcs = */		&sshkey_rsa_funcs,
629 };
630 
631 const struct sshkey_impl sshkey_rsa_sha512_cert_impl = {
632 	/* .name = */		"rsa-sha2-512-cert-v01@openssh.com",
633 	/* .shortname = */	"RSA-CERT",
634 	/* .sigalg = */		"rsa-sha2-512",
635 	/* .type = */		KEY_RSA_CERT,
636 	/* .nid = */		0,
637 	/* .cert = */		1,
638 	/* .sigonly = */	1,
639 	/* .keybits = */	0,
640 	/* .funcs = */		&sshkey_rsa_funcs,
641 };
642