1/*	$NetBSD: ssh-rsa.c,v 1.19 2023/07/26 17:58:16 christos Exp $	*/
2/* $OpenBSD: ssh-rsa.c,v 1.79 2023/03/05 05:34:09 dtucker Exp $ */
3/*
4 * Copyright (c) 2000, 2003 Markus Friedl <markus@openbsd.org>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19#include "includes.h"
20__RCSID("$NetBSD: ssh-rsa.c,v 1.19 2023/07/26 17:58:16 christos Exp $");
21#include <sys/types.h>
22
23#include <openssl/evp.h>
24#include <openssl/err.h>
25
26#include <string.h>
27
28#include "sshbuf.h"
29#include "ssherr.h"
30#define SSHKEY_INTERNAL
31#include "sshkey.h"
32#include "digest.h"
33#include "log.h"
34
35static int openssh_RSA_verify(int, u_char *, size_t, u_char *, size_t, RSA *);
36
37static u_int
38ssh_rsa_size(const struct sshkey *key)
39{
40	const BIGNUM *rsa_n;
41
42	if (key->rsa == NULL)
43		return 0;
44	RSA_get0_key(key->rsa, &rsa_n, NULL, NULL);
45	return BN_num_bits(rsa_n);
46}
47
48static int
49ssh_rsa_alloc(struct sshkey *k)
50{
51	if ((k->rsa = RSA_new()) == NULL)
52		return SSH_ERR_ALLOC_FAIL;
53	return 0;
54}
55
56static void
57ssh_rsa_cleanup(struct sshkey *k)
58{
59	RSA_free(k->rsa);
60	k->rsa = NULL;
61}
62
63static int
64ssh_rsa_equal(const struct sshkey *a, const struct sshkey *b)
65{
66	const BIGNUM *rsa_e_a, *rsa_n_a;
67	const BIGNUM *rsa_e_b, *rsa_n_b;
68
69	if (a->rsa == NULL || b->rsa == NULL)
70		return 0;
71	RSA_get0_key(a->rsa, &rsa_n_a, &rsa_e_a, NULL);
72	RSA_get0_key(b->rsa, &rsa_n_b, &rsa_e_b, NULL);
73	if (rsa_e_a == NULL || rsa_e_b == NULL)
74		return 0;
75	if (rsa_n_a == NULL || rsa_n_b == NULL)
76		return 0;
77	if (BN_cmp(rsa_e_a, rsa_e_b) != 0)
78		return 0;
79	if (BN_cmp(rsa_n_a, rsa_n_b) != 0)
80		return 0;
81	return 1;
82}
83
84static int
85ssh_rsa_serialize_public(const struct sshkey *key, struct sshbuf *b,
86    enum sshkey_serialize_rep opts)
87{
88	int r;
89	const BIGNUM *rsa_n, *rsa_e;
90
91	if (key->rsa == NULL)
92		return SSH_ERR_INVALID_ARGUMENT;
93	RSA_get0_key(key->rsa, &rsa_n, &rsa_e, NULL);
94	if ((r = sshbuf_put_bignum2(b, rsa_e)) != 0 ||
95	    (r = sshbuf_put_bignum2(b, rsa_n)) != 0)
96		return r;
97
98	return 0;
99}
100
101static int
102ssh_rsa_serialize_private(const struct sshkey *key, struct sshbuf *b,
103    enum sshkey_serialize_rep opts)
104{
105	int r;
106	const BIGNUM *rsa_n, *rsa_e, *rsa_d, *rsa_iqmp, *rsa_p, *rsa_q;
107
108	RSA_get0_key(key->rsa, &rsa_n, &rsa_e, &rsa_d);
109	RSA_get0_factors(key->rsa, &rsa_p, &rsa_q);
110	RSA_get0_crt_params(key->rsa, NULL, NULL, &rsa_iqmp);
111
112	if (!sshkey_is_cert(key)) {
113		/* Note: can't reuse ssh_rsa_serialize_public: e, n vs. n, e */
114		if ((r = sshbuf_put_bignum2(b, rsa_n)) != 0 ||
115		    (r = sshbuf_put_bignum2(b, rsa_e)) != 0)
116			return r;
117	}
118	if ((r = sshbuf_put_bignum2(b, rsa_d)) != 0 ||
119	    (r = sshbuf_put_bignum2(b, rsa_iqmp)) != 0 ||
120	    (r = sshbuf_put_bignum2(b, rsa_p)) != 0 ||
121	    (r = sshbuf_put_bignum2(b, rsa_q)) != 0)
122		return r;
123
124	return 0;
125}
126
127static int
128ssh_rsa_generate(struct sshkey *k, int bits)
129{
130	RSA *private = NULL;
131	BIGNUM *f4 = NULL;
132	int ret = SSH_ERR_INTERNAL_ERROR;
133
134	if (bits < SSH_RSA_MINIMUM_MODULUS_SIZE ||
135	    bits > SSHBUF_MAX_BIGNUM * 8)
136		return SSH_ERR_KEY_LENGTH;
137	if ((private = RSA_new()) == NULL || (f4 = BN_new()) == NULL) {
138		ret = SSH_ERR_ALLOC_FAIL;
139		goto out;
140	}
141	if (!BN_set_word(f4, RSA_F4) ||
142	    !RSA_generate_key_ex(private, bits, f4, NULL)) {
143		ret = SSH_ERR_LIBCRYPTO_ERROR;
144		goto out;
145	}
146	k->rsa = private;
147	private = NULL;
148	ret = 0;
149 out:
150	RSA_free(private);
151	BN_free(f4);
152	return ret;
153}
154
155static int
156ssh_rsa_copy_public(const struct sshkey *from, struct sshkey *to)
157{
158	const BIGNUM *rsa_n, *rsa_e;
159	BIGNUM *rsa_n_dup = NULL, *rsa_e_dup = NULL;
160	int r = SSH_ERR_INTERNAL_ERROR;
161
162	RSA_get0_key(from->rsa, &rsa_n, &rsa_e, NULL);
163	if ((rsa_n_dup = BN_dup(rsa_n)) == NULL ||
164	    (rsa_e_dup = BN_dup(rsa_e)) == NULL) {
165		r = SSH_ERR_ALLOC_FAIL;
166		goto out;
167	}
168	if (!RSA_set0_key(to->rsa, rsa_n_dup, rsa_e_dup, NULL)) {
169		r = SSH_ERR_LIBCRYPTO_ERROR;
170		goto out;
171	}
172	rsa_n_dup = rsa_e_dup = NULL; /* transferred */
173	/* success */
174	r = 0;
175 out:
176	BN_clear_free(rsa_n_dup);
177	BN_clear_free(rsa_e_dup);
178	return r;
179}
180
181static int
182ssh_rsa_deserialize_public(const char *ktype, struct sshbuf *b,
183    struct sshkey *key)
184{
185	int ret = SSH_ERR_INTERNAL_ERROR;
186	BIGNUM *rsa_n = NULL, *rsa_e = NULL;
187
188	if (sshbuf_get_bignum2(b, &rsa_e) != 0 ||
189	    sshbuf_get_bignum2(b, &rsa_n) != 0) {
190		ret = SSH_ERR_INVALID_FORMAT;
191		goto out;
192	}
193	if (!RSA_set0_key(key->rsa, rsa_n, rsa_e, NULL)) {
194		ret = SSH_ERR_LIBCRYPTO_ERROR;
195		goto out;
196	}
197	rsa_n = rsa_e = NULL; /* transferred */
198	if ((ret = sshkey_check_rsa_length(key, 0)) != 0)
199		goto out;
200#ifdef DEBUG_PK
201	RSA_print_fp(stderr, key->rsa, 8);
202#endif
203	/* success */
204	ret = 0;
205 out:
206	BN_clear_free(rsa_n);
207	BN_clear_free(rsa_e);
208	return ret;
209}
210
211static int
212ssh_rsa_deserialize_private(const char *ktype, struct sshbuf *b,
213    struct sshkey *key)
214{
215	int r;
216	BIGNUM *rsa_n = NULL, *rsa_e = NULL, *rsa_d = NULL;
217	BIGNUM *rsa_iqmp = NULL, *rsa_p = NULL, *rsa_q = NULL;
218
219	/* Note: can't reuse ssh_rsa_deserialize_public: e, n vs. n, e */
220	if (!sshkey_is_cert(key)) {
221		if ((r = sshbuf_get_bignum2(b, &rsa_n)) != 0 ||
222		    (r = sshbuf_get_bignum2(b, &rsa_e)) != 0)
223			goto out;
224		if (!RSA_set0_key(key->rsa, rsa_n, rsa_e, NULL)) {
225			r = SSH_ERR_LIBCRYPTO_ERROR;
226			goto out;
227		}
228		rsa_n = rsa_e = NULL; /* transferred */
229	}
230	if ((r = sshbuf_get_bignum2(b, &rsa_d)) != 0 ||
231	    (r = sshbuf_get_bignum2(b, &rsa_iqmp)) != 0 ||
232	    (r = sshbuf_get_bignum2(b, &rsa_p)) != 0 ||
233	    (r = sshbuf_get_bignum2(b, &rsa_q)) != 0)
234		goto out;
235	if (!RSA_set0_key(key->rsa, NULL, NULL, rsa_d)) {
236		r = SSH_ERR_LIBCRYPTO_ERROR;
237		goto out;
238	}
239	rsa_d = NULL; /* transferred */
240	if (!RSA_set0_factors(key->rsa, rsa_p, rsa_q)) {
241		r = SSH_ERR_LIBCRYPTO_ERROR;
242		goto out;
243	}
244	rsa_p = rsa_q = NULL; /* transferred */
245	if ((r = sshkey_check_rsa_length(key, 0)) != 0)
246		goto out;
247	if ((r = ssh_rsa_complete_crt_parameters(key, rsa_iqmp)) != 0)
248		goto out;
249	if (RSA_blinding_on(key->rsa, NULL) != 1) {
250		r = SSH_ERR_LIBCRYPTO_ERROR;
251		goto out;
252	}
253	/* success */
254	r = 0;
255 out:
256	BN_clear_free(rsa_n);
257	BN_clear_free(rsa_e);
258	BN_clear_free(rsa_d);
259	BN_clear_free(rsa_p);
260	BN_clear_free(rsa_q);
261	BN_clear_free(rsa_iqmp);
262	return r;
263}
264
265static const char *
266rsa_hash_alg_ident(int hash_alg)
267{
268	switch (hash_alg) {
269	case SSH_DIGEST_SHA1:
270		return "ssh-rsa";
271	case SSH_DIGEST_SHA256:
272		return "rsa-sha2-256";
273	case SSH_DIGEST_SHA512:
274		return "rsa-sha2-512";
275	}
276	return NULL;
277}
278
279/*
280 * Returns the hash algorithm ID for a given algorithm identifier as used
281 * inside the signature blob,
282 */
283static int
284rsa_hash_id_from_ident(const char *ident)
285{
286	if (strcmp(ident, "ssh-rsa") == 0)
287		return SSH_DIGEST_SHA1;
288	if (strcmp(ident, "rsa-sha2-256") == 0)
289		return SSH_DIGEST_SHA256;
290	if (strcmp(ident, "rsa-sha2-512") == 0)
291		return SSH_DIGEST_SHA512;
292	return -1;
293}
294
295/*
296 * Return the hash algorithm ID for the specified key name. This includes
297 * all the cases of rsa_hash_id_from_ident() but also the certificate key
298 * types.
299 */
300static int
301rsa_hash_id_from_keyname(const char *alg)
302{
303	int r;
304
305	if ((r = rsa_hash_id_from_ident(alg)) != -1)
306		return r;
307	if (strcmp(alg, "ssh-rsa-cert-v01@openssh.com") == 0)
308		return SSH_DIGEST_SHA1;
309	if (strcmp(alg, "rsa-sha2-256-cert-v01@openssh.com") == 0)
310		return SSH_DIGEST_SHA256;
311	if (strcmp(alg, "rsa-sha2-512-cert-v01@openssh.com") == 0)
312		return SSH_DIGEST_SHA512;
313	return -1;
314}
315
316static int
317rsa_hash_alg_nid(int type)
318{
319	switch (type) {
320	case SSH_DIGEST_SHA1:
321		return NID_sha1;
322	case SSH_DIGEST_SHA256:
323		return NID_sha256;
324	case SSH_DIGEST_SHA512:
325		return NID_sha512;
326	default:
327		return -1;
328	}
329}
330
331int
332ssh_rsa_complete_crt_parameters(struct sshkey *key, const BIGNUM *iqmp)
333{
334	const BIGNUM *rsa_p, *rsa_q, *rsa_d;
335	BIGNUM *aux = NULL, *d_consttime = NULL;
336	BIGNUM *rsa_dmq1 = NULL, *rsa_dmp1 = NULL, *rsa_iqmp = NULL;
337	BN_CTX *ctx = NULL;
338	int r;
339
340	if (key == NULL || key->rsa == NULL ||
341	    sshkey_type_plain(key->type) != KEY_RSA)
342		return SSH_ERR_INVALID_ARGUMENT;
343
344	RSA_get0_key(key->rsa, NULL, NULL, &rsa_d);
345	RSA_get0_factors(key->rsa, &rsa_p, &rsa_q);
346
347	if ((ctx = BN_CTX_new()) == NULL)
348		return SSH_ERR_ALLOC_FAIL;
349	if ((aux = BN_new()) == NULL ||
350	    (rsa_dmq1 = BN_new()) == NULL ||
351	    (rsa_dmp1 = BN_new()) == NULL)
352		return SSH_ERR_ALLOC_FAIL;
353	if ((d_consttime = BN_dup(rsa_d)) == NULL ||
354	    (rsa_iqmp = BN_dup(iqmp)) == NULL) {
355		r = SSH_ERR_ALLOC_FAIL;
356		goto out;
357	}
358	BN_set_flags(aux, BN_FLG_CONSTTIME);
359	BN_set_flags(d_consttime, BN_FLG_CONSTTIME);
360
361	if ((BN_sub(aux, rsa_q, BN_value_one()) == 0) ||
362	    (BN_mod(rsa_dmq1, d_consttime, aux, ctx) == 0) ||
363	    (BN_sub(aux, rsa_p, BN_value_one()) == 0) ||
364	    (BN_mod(rsa_dmp1, d_consttime, aux, ctx) == 0)) {
365		r = SSH_ERR_LIBCRYPTO_ERROR;
366		goto out;
367	}
368	if (!RSA_set0_crt_params(key->rsa, rsa_dmp1, rsa_dmq1, rsa_iqmp)) {
369		r = SSH_ERR_LIBCRYPTO_ERROR;
370		goto out;
371	}
372	rsa_dmp1 = rsa_dmq1 = rsa_iqmp = NULL; /* transferred */
373	/* success */
374	r = 0;
375 out:
376	BN_clear_free(aux);
377	BN_clear_free(d_consttime);
378	BN_clear_free(rsa_dmp1);
379	BN_clear_free(rsa_dmq1);
380	BN_clear_free(rsa_iqmp);
381	BN_CTX_free(ctx);
382	return r;
383}
384
385/* RSASSA-PKCS1-v1_5 (PKCS #1 v2.0 signature) with SHA1 */
386static int
387ssh_rsa_sign(struct sshkey *key,
388    u_char **sigp, size_t *lenp,
389    const u_char *data, size_t datalen,
390    const char *alg, const char *sk_provider, const char *sk_pin, u_int compat)
391{
392	const BIGNUM *rsa_n;
393	u_char digest[SSH_DIGEST_MAX_LENGTH], *sig = NULL;
394	size_t slen = 0;
395	u_int hlen, len;
396	int nid, hash_alg, ret = SSH_ERR_INTERNAL_ERROR;
397	struct sshbuf *b = NULL;
398
399	if (lenp != NULL)
400		*lenp = 0;
401	if (sigp != NULL)
402		*sigp = NULL;
403
404	if (alg == NULL || strlen(alg) == 0)
405		hash_alg = SSH_DIGEST_SHA1;
406	else
407		hash_alg = rsa_hash_id_from_keyname(alg);
408	if (key == NULL || key->rsa == NULL || hash_alg == -1 ||
409	    sshkey_type_plain(key->type) != KEY_RSA)
410		return SSH_ERR_INVALID_ARGUMENT;
411	RSA_get0_key(key->rsa, &rsa_n, NULL, NULL);
412	if (BN_num_bits(rsa_n) < SSH_RSA_MINIMUM_MODULUS_SIZE)
413		return SSH_ERR_KEY_LENGTH;
414	slen = RSA_size(key->rsa);
415	if (slen == 0 || slen > SSHBUF_MAX_BIGNUM)
416		return SSH_ERR_INVALID_ARGUMENT;
417
418	/* hash the data */
419	nid = rsa_hash_alg_nid(hash_alg);
420	if ((hlen = ssh_digest_bytes(hash_alg)) == 0)
421		return SSH_ERR_INTERNAL_ERROR;
422	if ((ret = ssh_digest_memory(hash_alg, data, datalen,
423	    digest, sizeof(digest))) != 0)
424		goto out;
425
426	if ((sig = malloc(slen)) == NULL) {
427		ret = SSH_ERR_ALLOC_FAIL;
428		goto out;
429	}
430
431	if (RSA_sign(nid, digest, hlen, sig, &len, key->rsa) != 1) {
432		ret = SSH_ERR_LIBCRYPTO_ERROR;
433		goto out;
434	}
435	if (len < slen) {
436		size_t diff = slen - len;
437		memmove(sig + diff, sig, len);
438		explicit_bzero(sig, diff);
439	} else if (len > slen) {
440		ret = SSH_ERR_INTERNAL_ERROR;
441		goto out;
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	explicit_bzero(digest, sizeof(digest));
464	freezero(sig, slen);
465	sshbuf_free(b);
466	return ret;
467}
468
469static int
470ssh_rsa_verify(const struct sshkey *key,
471    const u_char *sig, size_t siglen,
472    const u_char *data, size_t dlen, const char *alg, u_int compat,
473    struct sshkey_sig_details **detailsp)
474{
475	const BIGNUM *rsa_n;
476	char *sigtype = NULL;
477	int hash_alg, want_alg, ret = SSH_ERR_INTERNAL_ERROR;
478	size_t len = 0, diff, modlen, hlen;
479	struct sshbuf *b = NULL;
480	u_char digest[SSH_DIGEST_MAX_LENGTH], *osigblob, *sigblob = NULL;
481
482	if (key == NULL || key->rsa == NULL ||
483	    sshkey_type_plain(key->type) != KEY_RSA ||
484	    sig == NULL || siglen == 0)
485		return SSH_ERR_INVALID_ARGUMENT;
486	RSA_get0_key(key->rsa, &rsa_n, NULL, NULL);
487	if (BN_num_bits(rsa_n) < SSH_RSA_MINIMUM_MODULUS_SIZE)
488		return SSH_ERR_KEY_LENGTH;
489
490	if ((b = sshbuf_from(sig, siglen)) == NULL)
491		return SSH_ERR_ALLOC_FAIL;
492	if (sshbuf_get_cstring(b, &sigtype, NULL) != 0) {
493		ret = SSH_ERR_INVALID_FORMAT;
494		goto out;
495	}
496	if ((hash_alg = rsa_hash_id_from_ident(sigtype)) == -1) {
497		ret = SSH_ERR_KEY_TYPE_MISMATCH;
498		goto out;
499	}
500	/*
501	 * Allow ssh-rsa-cert-v01 certs to generate SHA2 signatures for
502	 * legacy reasons, but otherwise the signature type should match.
503	 */
504	if (alg != NULL && strcmp(alg, "ssh-rsa-cert-v01@openssh.com") != 0) {
505		if ((want_alg = rsa_hash_id_from_keyname(alg)) == -1) {
506			ret = SSH_ERR_INVALID_ARGUMENT;
507			goto out;
508		}
509		if (hash_alg != want_alg) {
510			ret = SSH_ERR_SIGNATURE_INVALID;
511			goto out;
512		}
513	}
514	if (sshbuf_get_string(b, &sigblob, &len) != 0) {
515		ret = SSH_ERR_INVALID_FORMAT;
516		goto out;
517	}
518	if (sshbuf_len(b) != 0) {
519		ret = SSH_ERR_UNEXPECTED_TRAILING_DATA;
520		goto out;
521	}
522	/* RSA_verify expects a signature of RSA_size */
523	modlen = RSA_size(key->rsa);
524	if (len > modlen) {
525		ret = SSH_ERR_KEY_BITS_MISMATCH;
526		goto out;
527	} else if (len < modlen) {
528		diff = modlen - len;
529		osigblob = sigblob;
530		if ((sigblob = realloc(sigblob, modlen)) == NULL) {
531			sigblob = osigblob; /* put it back for clear/free */
532			ret = SSH_ERR_ALLOC_FAIL;
533			goto out;
534		}
535		memmove(sigblob + diff, sigblob, len);
536		explicit_bzero(sigblob, diff);
537		len = modlen;
538	}
539	if ((hlen = ssh_digest_bytes(hash_alg)) == 0) {
540		ret = SSH_ERR_INTERNAL_ERROR;
541		goto out;
542	}
543	if ((ret = ssh_digest_memory(hash_alg, data, dlen,
544	    digest, sizeof(digest))) != 0)
545		goto out;
546
547	ret = openssh_RSA_verify(hash_alg, digest, hlen, sigblob, len,
548	    key->rsa);
549 out:
550	freezero(sigblob, len);
551	free(sigtype);
552	sshbuf_free(b);
553	explicit_bzero(digest, sizeof(digest));
554	return ret;
555}
556
557/*
558 * See:
559 * http://www.rsasecurity.com/rsalabs/pkcs/pkcs-1/
560 * ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1.asn
561 */
562
563/*
564 * id-sha1 OBJECT IDENTIFIER ::= { iso(1) identified-organization(3)
565 *	oiw(14) secsig(3) algorithms(2) 26 }
566 */
567static const u_char id_sha1[] = {
568	0x30, 0x21, /* type Sequence, length 0x21 (33) */
569	0x30, 0x09, /* type Sequence, length 0x09 */
570	0x06, 0x05, /* type OID, length 0x05 */
571	0x2b, 0x0e, 0x03, 0x02, 0x1a, /* id-sha1 OID */
572	0x05, 0x00, /* NULL */
573	0x04, 0x14  /* Octet string, length 0x14 (20), followed by sha1 hash */
574};
575
576/*
577 * See http://csrc.nist.gov/groups/ST/crypto_apps_infra/csor/algorithms.html
578 * id-sha256 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840)
579 *      organization(1) gov(101) csor(3) nistAlgorithm(4) hashAlgs(2)
580 *      id-sha256(1) }
581 */
582static const u_char id_sha256[] = {
583	0x30, 0x31, /* type Sequence, length 0x31 (49) */
584	0x30, 0x0d, /* type Sequence, length 0x0d (13) */
585	0x06, 0x09, /* type OID, length 0x09 */
586	0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, /* id-sha256 */
587	0x05, 0x00, /* NULL */
588	0x04, 0x20  /* Octet string, length 0x20 (32), followed by sha256 hash */
589};
590
591/*
592 * See http://csrc.nist.gov/groups/ST/crypto_apps_infra/csor/algorithms.html
593 * id-sha512 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840)
594 *      organization(1) gov(101) csor(3) nistAlgorithm(4) hashAlgs(2)
595 *      id-sha256(3) }
596 */
597static const u_char id_sha512[] = {
598	0x30, 0x51, /* type Sequence, length 0x51 (81) */
599	0x30, 0x0d, /* type Sequence, length 0x0d (13) */
600	0x06, 0x09, /* type OID, length 0x09 */
601	0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, /* id-sha512 */
602	0x05, 0x00, /* NULL */
603	0x04, 0x40  /* Octet string, length 0x40 (64), followed by sha512 hash */
604};
605
606static int
607rsa_hash_alg_oid(int hash_alg, const u_char **oidp, size_t *oidlenp)
608{
609	switch (hash_alg) {
610	case SSH_DIGEST_SHA1:
611		*oidp = id_sha1;
612		*oidlenp = sizeof(id_sha1);
613		break;
614	case SSH_DIGEST_SHA256:
615		*oidp = id_sha256;
616		*oidlenp = sizeof(id_sha256);
617		break;
618	case SSH_DIGEST_SHA512:
619		*oidp = id_sha512;
620		*oidlenp = sizeof(id_sha512);
621		break;
622	default:
623		return SSH_ERR_INVALID_ARGUMENT;
624	}
625	return 0;
626}
627
628static int
629openssh_RSA_verify(int hash_alg, u_char *hash, size_t hashlen,
630    u_char *sigbuf, size_t siglen, RSA *rsa)
631{
632	size_t rsasize = 0, oidlen = 0, hlen = 0;
633	int ret, len, oidmatch, hashmatch;
634	const u_char *oid = NULL;
635	u_char *decrypted = NULL;
636
637	if ((ret = rsa_hash_alg_oid(hash_alg, &oid, &oidlen)) != 0)
638		return ret;
639	ret = SSH_ERR_INTERNAL_ERROR;
640	hlen = ssh_digest_bytes(hash_alg);
641	if (hashlen != hlen) {
642		ret = SSH_ERR_INVALID_ARGUMENT;
643		goto done;
644	}
645	rsasize = RSA_size(rsa);
646	if (rsasize <= 0 || rsasize > SSHBUF_MAX_BIGNUM ||
647	    siglen == 0 || siglen > rsasize) {
648		ret = SSH_ERR_INVALID_ARGUMENT;
649		goto done;
650	}
651	if ((decrypted = malloc(rsasize)) == NULL) {
652		ret = SSH_ERR_ALLOC_FAIL;
653		goto done;
654	}
655	if ((len = RSA_public_decrypt(siglen, sigbuf, decrypted, rsa,
656	    RSA_PKCS1_PADDING)) < 0) {
657		ret = SSH_ERR_LIBCRYPTO_ERROR;
658		goto done;
659	}
660	if (len < 0 || (size_t)len != hlen + oidlen) {
661		ret = SSH_ERR_INVALID_FORMAT;
662		goto done;
663	}
664	oidmatch = timingsafe_bcmp(decrypted, oid, oidlen) == 0;
665	hashmatch = timingsafe_bcmp(decrypted + oidlen, hash, hlen) == 0;
666	if (!oidmatch || !hashmatch) {
667		ret = SSH_ERR_SIGNATURE_INVALID;
668		goto done;
669	}
670	ret = 0;
671done:
672	freezero(decrypted, rsasize);
673	return ret;
674}
675
676static const struct sshkey_impl_funcs sshkey_rsa_funcs = {
677	/* .size = */		ssh_rsa_size,
678	/* .alloc = */		ssh_rsa_alloc,
679	/* .cleanup = */	ssh_rsa_cleanup,
680	/* .equal = */		ssh_rsa_equal,
681	/* .ssh_serialize_public = */ ssh_rsa_serialize_public,
682	/* .ssh_deserialize_public = */ ssh_rsa_deserialize_public,
683	/* .ssh_serialize_private = */ ssh_rsa_serialize_private,
684	/* .ssh_deserialize_private = */ ssh_rsa_deserialize_private,
685	/* .generate = */	ssh_rsa_generate,
686	/* .copy_public = */	ssh_rsa_copy_public,
687	/* .sign = */		ssh_rsa_sign,
688	/* .verify = */		ssh_rsa_verify,
689};
690
691const struct sshkey_impl sshkey_rsa_impl = {
692	/* .name = */		"ssh-rsa",
693	/* .shortname = */	"RSA",
694	/* .sigalg = */		NULL,
695	/* .type = */		KEY_RSA,
696	/* .nid = */		0,
697	/* .cert = */		0,
698	/* .sigonly = */	0,
699	/* .keybits = */	0,
700	/* .funcs = */		&sshkey_rsa_funcs,
701};
702
703const struct sshkey_impl sshkey_rsa_cert_impl = {
704	/* .name = */		"ssh-rsa-cert-v01@openssh.com",
705	/* .shortname = */	"RSA-CERT",
706	/* .sigalg = */		NULL,
707	/* .type = */		KEY_RSA_CERT,
708	/* .nid = */		0,
709	/* .cert = */		1,
710	/* .sigonly = */	0,
711	/* .keybits = */	0,
712	/* .funcs = */		&sshkey_rsa_funcs,
713};
714
715/* SHA2 signature algorithms */
716
717const struct sshkey_impl sshkey_rsa_sha256_impl = {
718	/* .name = */		"rsa-sha2-256",
719	/* .shortname = */	"RSA",
720	/* .sigalg = */		NULL,
721	/* .type = */		KEY_RSA,
722	/* .nid = */		0,
723	/* .cert = */		0,
724	/* .sigonly = */	1,
725	/* .keybits = */	0,
726	/* .funcs = */		&sshkey_rsa_funcs,
727};
728
729const struct sshkey_impl sshkey_rsa_sha512_impl = {
730	/* .name = */		"rsa-sha2-512",
731	/* .shortname = */	"RSA",
732	/* .sigalg = */		NULL,
733	/* .type = */		KEY_RSA,
734	/* .nid = */		0,
735	/* .cert = */		0,
736	/* .sigonly = */	1,
737	/* .keybits = */	0,
738	/* .funcs = */		&sshkey_rsa_funcs,
739};
740
741const struct sshkey_impl sshkey_rsa_sha256_cert_impl = {
742	/* .name = */		"rsa-sha2-256-cert-v01@openssh.com",
743	/* .shortname = */	"RSA-CERT",
744	/* .sigalg = */		"rsa-sha2-256",
745	/* .type = */		KEY_RSA_CERT,
746	/* .nid = */		0,
747	/* .cert = */		1,
748	/* .sigonly = */	1,
749	/* .keybits = */	0,
750	/* .funcs = */		&sshkey_rsa_funcs,
751};
752
753const struct sshkey_impl sshkey_rsa_sha512_cert_impl = {
754	/* .name = */		"rsa-sha2-512-cert-v01@openssh.com",
755	/* .shortname = */	"RSA-CERT",
756	/* .sigalg = */		"rsa-sha2-512",
757	/* .type = */		KEY_RSA_CERT,
758	/* .nid = */		0,
759	/* .cert = */		1,
760	/* .sigonly = */	1,
761	/* .keybits = */	0,
762	/* .funcs = */		&sshkey_rsa_funcs,
763};
764