xref: /dflybsd-src/crypto/openssh/ssh-rsa.c (revision ce74baca94b6dd2a80af6a625aba2cf14ab7fec8)
1*ce74bacaSMatthew Dillon /* $OpenBSD: ssh-rsa.c,v 1.62 2017/07/01 13:50:45 djm Exp $ */
218de8d7fSPeter Avalos /*
318de8d7fSPeter Avalos  * Copyright (c) 2000, 2003 Markus Friedl <markus@openbsd.org>
418de8d7fSPeter Avalos  *
518de8d7fSPeter Avalos  * Permission to use, copy, modify, and distribute this software for any
618de8d7fSPeter Avalos  * purpose with or without fee is hereby granted, provided that the above
718de8d7fSPeter Avalos  * copyright notice and this permission notice appear in all copies.
818de8d7fSPeter Avalos  *
918de8d7fSPeter Avalos  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1018de8d7fSPeter Avalos  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1118de8d7fSPeter Avalos  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1218de8d7fSPeter Avalos  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1318de8d7fSPeter Avalos  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1418de8d7fSPeter Avalos  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1518de8d7fSPeter Avalos  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1618de8d7fSPeter Avalos  */
1718de8d7fSPeter Avalos 
1818de8d7fSPeter Avalos #include "includes.h"
1918de8d7fSPeter Avalos 
20e9778795SPeter Avalos #ifdef WITH_OPENSSL
21e9778795SPeter Avalos 
2218de8d7fSPeter Avalos #include <sys/types.h>
2318de8d7fSPeter Avalos 
2418de8d7fSPeter Avalos #include <openssl/evp.h>
2518de8d7fSPeter Avalos #include <openssl/err.h>
2618de8d7fSPeter Avalos 
2718de8d7fSPeter Avalos #include <stdarg.h>
2818de8d7fSPeter Avalos #include <string.h>
2918de8d7fSPeter Avalos 
3036e94dc5SPeter Avalos #include "sshbuf.h"
3118de8d7fSPeter Avalos #include "compat.h"
3236e94dc5SPeter Avalos #include "ssherr.h"
3336e94dc5SPeter Avalos #define SSHKEY_INTERNAL
3436e94dc5SPeter Avalos #include "sshkey.h"
3536e94dc5SPeter Avalos #include "digest.h"
3618de8d7fSPeter Avalos 
3736e94dc5SPeter Avalos static int openssh_RSA_verify(int, u_char *, size_t, u_char *, size_t, RSA *);
3818de8d7fSPeter Avalos 
39e9778795SPeter Avalos static const char *
40e9778795SPeter Avalos rsa_hash_alg_ident(int hash_alg)
41e9778795SPeter Avalos {
42e9778795SPeter Avalos 	switch (hash_alg) {
43e9778795SPeter Avalos 	case SSH_DIGEST_SHA1:
44e9778795SPeter Avalos 		return "ssh-rsa";
45e9778795SPeter Avalos 	case SSH_DIGEST_SHA256:
46e9778795SPeter Avalos 		return "rsa-sha2-256";
47e9778795SPeter Avalos 	case SSH_DIGEST_SHA512:
48e9778795SPeter Avalos 		return "rsa-sha2-512";
49e9778795SPeter Avalos 	}
50e9778795SPeter Avalos 	return NULL;
51e9778795SPeter Avalos }
52e9778795SPeter Avalos 
53e9778795SPeter Avalos static int
54e9778795SPeter Avalos rsa_hash_alg_from_ident(const char *ident)
55e9778795SPeter Avalos {
56*ce74bacaSMatthew Dillon 	if (strcmp(ident, "ssh-rsa") == 0 ||
57*ce74bacaSMatthew Dillon 	    strcmp(ident, "ssh-rsa-cert-v01@openssh.com") == 0)
58e9778795SPeter Avalos 		return SSH_DIGEST_SHA1;
59e9778795SPeter Avalos 	if (strcmp(ident, "rsa-sha2-256") == 0)
60e9778795SPeter Avalos 		return SSH_DIGEST_SHA256;
61e9778795SPeter Avalos 	if (strcmp(ident, "rsa-sha2-512") == 0)
62e9778795SPeter Avalos 		return SSH_DIGEST_SHA512;
63e9778795SPeter Avalos 	return -1;
64e9778795SPeter Avalos }
65e9778795SPeter Avalos 
66e9778795SPeter Avalos static int
67e9778795SPeter Avalos rsa_hash_alg_nid(int type)
68e9778795SPeter Avalos {
69e9778795SPeter Avalos 	switch (type) {
70e9778795SPeter Avalos 	case SSH_DIGEST_SHA1:
71e9778795SPeter Avalos 		return NID_sha1;
72e9778795SPeter Avalos 	case SSH_DIGEST_SHA256:
73e9778795SPeter Avalos 		return NID_sha256;
74e9778795SPeter Avalos 	case SSH_DIGEST_SHA512:
75e9778795SPeter Avalos 		return NID_sha512;
76e9778795SPeter Avalos 	default:
77e9778795SPeter Avalos 		return -1;
78e9778795SPeter Avalos 	}
79e9778795SPeter Avalos }
80e9778795SPeter Avalos 
81*ce74bacaSMatthew Dillon /* calculate p-1 and q-1 */
82*ce74bacaSMatthew Dillon int
83*ce74bacaSMatthew Dillon ssh_rsa_generate_additional_parameters(struct sshkey *key)
84*ce74bacaSMatthew Dillon {
85*ce74bacaSMatthew Dillon 	RSA *rsa;
86*ce74bacaSMatthew Dillon 	BIGNUM *aux = NULL;
87*ce74bacaSMatthew Dillon 	BN_CTX *ctx = NULL;
88*ce74bacaSMatthew Dillon 	int r;
89*ce74bacaSMatthew Dillon 
90*ce74bacaSMatthew Dillon 	if (key == NULL || key->rsa == NULL ||
91*ce74bacaSMatthew Dillon 	    sshkey_type_plain(key->type) != KEY_RSA)
92*ce74bacaSMatthew Dillon 		return SSH_ERR_INVALID_ARGUMENT;
93*ce74bacaSMatthew Dillon 
94*ce74bacaSMatthew Dillon 	if ((ctx = BN_CTX_new()) == NULL)
95*ce74bacaSMatthew Dillon 		return SSH_ERR_ALLOC_FAIL;
96*ce74bacaSMatthew Dillon 	if ((aux = BN_new()) == NULL) {
97*ce74bacaSMatthew Dillon 		r = SSH_ERR_ALLOC_FAIL;
98*ce74bacaSMatthew Dillon 		goto out;
99*ce74bacaSMatthew Dillon 	}
100*ce74bacaSMatthew Dillon 	rsa = key->rsa;
101*ce74bacaSMatthew Dillon 
102*ce74bacaSMatthew Dillon 	if ((BN_sub(aux, rsa->q, BN_value_one()) == 0) ||
103*ce74bacaSMatthew Dillon 	    (BN_mod(rsa->dmq1, rsa->d, aux, ctx) == 0) ||
104*ce74bacaSMatthew Dillon 	    (BN_sub(aux, rsa->p, BN_value_one()) == 0) ||
105*ce74bacaSMatthew Dillon 	    (BN_mod(rsa->dmp1, rsa->d, aux, ctx) == 0)) {
106*ce74bacaSMatthew Dillon 		r = SSH_ERR_LIBCRYPTO_ERROR;
107*ce74bacaSMatthew Dillon 		goto out;
108*ce74bacaSMatthew Dillon 	}
109*ce74bacaSMatthew Dillon 	r = 0;
110*ce74bacaSMatthew Dillon  out:
111*ce74bacaSMatthew Dillon 	BN_clear_free(aux);
112*ce74bacaSMatthew Dillon 	BN_CTX_free(ctx);
113*ce74bacaSMatthew Dillon 	return r;
114*ce74bacaSMatthew Dillon }
115*ce74bacaSMatthew Dillon 
11618de8d7fSPeter Avalos /* RSASSA-PKCS1-v1_5 (PKCS #1 v2.0 signature) with SHA1 */
11718de8d7fSPeter Avalos int
11836e94dc5SPeter Avalos ssh_rsa_sign(const struct sshkey *key, u_char **sigp, size_t *lenp,
119e9778795SPeter Avalos     const u_char *data, size_t datalen, const char *alg_ident)
12018de8d7fSPeter Avalos {
12136e94dc5SPeter Avalos 	u_char digest[SSH_DIGEST_MAX_LENGTH], *sig = NULL;
12236e94dc5SPeter Avalos 	size_t slen;
12336e94dc5SPeter Avalos 	u_int dlen, len;
124e9778795SPeter Avalos 	int nid, hash_alg, ret = SSH_ERR_INTERNAL_ERROR;
12536e94dc5SPeter Avalos 	struct sshbuf *b = NULL;
12618de8d7fSPeter Avalos 
12736e94dc5SPeter Avalos 	if (lenp != NULL)
12836e94dc5SPeter Avalos 		*lenp = 0;
12936e94dc5SPeter Avalos 	if (sigp != NULL)
13036e94dc5SPeter Avalos 		*sigp = NULL;
13118de8d7fSPeter Avalos 
132*ce74bacaSMatthew Dillon 	if (alg_ident == NULL || strlen(alg_ident) == 0)
133e9778795SPeter Avalos 		hash_alg = SSH_DIGEST_SHA1;
134e9778795SPeter Avalos 	else
135e9778795SPeter Avalos 		hash_alg = rsa_hash_alg_from_ident(alg_ident);
136e9778795SPeter Avalos 	if (key == NULL || key->rsa == NULL || hash_alg == -1 ||
137*ce74bacaSMatthew Dillon 	    sshkey_type_plain(key->type) != KEY_RSA)
13836e94dc5SPeter Avalos 		return SSH_ERR_INVALID_ARGUMENT;
139*ce74bacaSMatthew Dillon 	if (BN_num_bits(key->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE)
140*ce74bacaSMatthew Dillon 		return SSH_ERR_KEY_LENGTH;
14118de8d7fSPeter Avalos 	slen = RSA_size(key->rsa);
14236e94dc5SPeter Avalos 	if (slen <= 0 || slen > SSHBUF_MAX_BIGNUM)
14336e94dc5SPeter Avalos 		return SSH_ERR_INVALID_ARGUMENT;
14418de8d7fSPeter Avalos 
14536e94dc5SPeter Avalos 	/* hash the data */
146e9778795SPeter Avalos 	nid = rsa_hash_alg_nid(hash_alg);
14736e94dc5SPeter Avalos 	if ((dlen = ssh_digest_bytes(hash_alg)) == 0)
14836e94dc5SPeter Avalos 		return SSH_ERR_INTERNAL_ERROR;
14936e94dc5SPeter Avalos 	if ((ret = ssh_digest_memory(hash_alg, data, datalen,
15036e94dc5SPeter Avalos 	    digest, sizeof(digest))) != 0)
15136e94dc5SPeter Avalos 		goto out;
15218de8d7fSPeter Avalos 
15336e94dc5SPeter Avalos 	if ((sig = malloc(slen)) == NULL) {
15436e94dc5SPeter Avalos 		ret = SSH_ERR_ALLOC_FAIL;
15536e94dc5SPeter Avalos 		goto out;
15636e94dc5SPeter Avalos 	}
15718de8d7fSPeter Avalos 
15836e94dc5SPeter Avalos 	if (RSA_sign(nid, digest, dlen, sig, &len, key->rsa) != 1) {
15936e94dc5SPeter Avalos 		ret = SSH_ERR_LIBCRYPTO_ERROR;
16036e94dc5SPeter Avalos 		goto out;
16118de8d7fSPeter Avalos 	}
16218de8d7fSPeter Avalos 	if (len < slen) {
16336e94dc5SPeter Avalos 		size_t diff = slen - len;
16418de8d7fSPeter Avalos 		memmove(sig + diff, sig, len);
16536e94dc5SPeter Avalos 		explicit_bzero(sig, diff);
16618de8d7fSPeter Avalos 	} else if (len > slen) {
16736e94dc5SPeter Avalos 		ret = SSH_ERR_INTERNAL_ERROR;
16836e94dc5SPeter Avalos 		goto out;
16918de8d7fSPeter Avalos 	}
17018de8d7fSPeter Avalos 	/* encode signature */
17136e94dc5SPeter Avalos 	if ((b = sshbuf_new()) == NULL) {
17236e94dc5SPeter Avalos 		ret = SSH_ERR_ALLOC_FAIL;
17336e94dc5SPeter Avalos 		goto out;
17436e94dc5SPeter Avalos 	}
175e9778795SPeter Avalos 	if ((ret = sshbuf_put_cstring(b, rsa_hash_alg_ident(hash_alg))) != 0 ||
17636e94dc5SPeter Avalos 	    (ret = sshbuf_put_string(b, sig, slen)) != 0)
17736e94dc5SPeter Avalos 		goto out;
17836e94dc5SPeter Avalos 	len = sshbuf_len(b);
17936e94dc5SPeter Avalos 	if (sigp != NULL) {
18036e94dc5SPeter Avalos 		if ((*sigp = malloc(len)) == NULL) {
18136e94dc5SPeter Avalos 			ret = SSH_ERR_ALLOC_FAIL;
18236e94dc5SPeter Avalos 			goto out;
18336e94dc5SPeter Avalos 		}
18436e94dc5SPeter Avalos 		memcpy(*sigp, sshbuf_ptr(b), len);
18536e94dc5SPeter Avalos 	}
18618de8d7fSPeter Avalos 	if (lenp != NULL)
18718de8d7fSPeter Avalos 		*lenp = len;
18836e94dc5SPeter Avalos 	ret = 0;
18936e94dc5SPeter Avalos  out:
19036e94dc5SPeter Avalos 	explicit_bzero(digest, sizeof(digest));
19136e94dc5SPeter Avalos 	if (sig != NULL) {
19236e94dc5SPeter Avalos 		explicit_bzero(sig, slen);
19336e94dc5SPeter Avalos 		free(sig);
19418de8d7fSPeter Avalos 	}
19536e94dc5SPeter Avalos 	sshbuf_free(b);
196e9778795SPeter Avalos 	return ret;
19718de8d7fSPeter Avalos }
19818de8d7fSPeter Avalos 
19918de8d7fSPeter Avalos int
20036e94dc5SPeter Avalos ssh_rsa_verify(const struct sshkey *key,
201e9778795SPeter Avalos     const u_char *sig, size_t siglen, const u_char *data, size_t datalen)
20218de8d7fSPeter Avalos {
20336e94dc5SPeter Avalos 	char *ktype = NULL;
20436e94dc5SPeter Avalos 	int hash_alg, ret = SSH_ERR_INTERNAL_ERROR;
20536e94dc5SPeter Avalos 	size_t len, diff, modlen, dlen;
20636e94dc5SPeter Avalos 	struct sshbuf *b = NULL;
20736e94dc5SPeter Avalos 	u_char digest[SSH_DIGEST_MAX_LENGTH], *osigblob, *sigblob = NULL;
20818de8d7fSPeter Avalos 
20936e94dc5SPeter Avalos 	if (key == NULL || key->rsa == NULL ||
21036e94dc5SPeter Avalos 	    sshkey_type_plain(key->type) != KEY_RSA ||
211e9778795SPeter Avalos 	    sig == NULL || siglen == 0)
21236e94dc5SPeter Avalos 		return SSH_ERR_INVALID_ARGUMENT;
213*ce74bacaSMatthew Dillon 	if (BN_num_bits(key->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE)
214*ce74bacaSMatthew Dillon 		return SSH_ERR_KEY_LENGTH;
21536e94dc5SPeter Avalos 
216e9778795SPeter Avalos 	if ((b = sshbuf_from(sig, siglen)) == NULL)
21736e94dc5SPeter Avalos 		return SSH_ERR_ALLOC_FAIL;
21836e94dc5SPeter Avalos 	if (sshbuf_get_cstring(b, &ktype, NULL) != 0) {
21936e94dc5SPeter Avalos 		ret = SSH_ERR_INVALID_FORMAT;
22036e94dc5SPeter Avalos 		goto out;
22118de8d7fSPeter Avalos 	}
222e9778795SPeter Avalos 	if ((hash_alg = rsa_hash_alg_from_ident(ktype)) == -1) {
22336e94dc5SPeter Avalos 		ret = SSH_ERR_KEY_TYPE_MISMATCH;
22436e94dc5SPeter Avalos 		goto out;
22518de8d7fSPeter Avalos 	}
22636e94dc5SPeter Avalos 	if (sshbuf_get_string(b, &sigblob, &len) != 0) {
22736e94dc5SPeter Avalos 		ret = SSH_ERR_INVALID_FORMAT;
22836e94dc5SPeter Avalos 		goto out;
22936e94dc5SPeter Avalos 	}
23036e94dc5SPeter Avalos 	if (sshbuf_len(b) != 0) {
23136e94dc5SPeter Avalos 		ret = SSH_ERR_UNEXPECTED_TRAILING_DATA;
23236e94dc5SPeter Avalos 		goto out;
23318de8d7fSPeter Avalos 	}
23418de8d7fSPeter Avalos 	/* RSA_verify expects a signature of RSA_size */
23518de8d7fSPeter Avalos 	modlen = RSA_size(key->rsa);
23618de8d7fSPeter Avalos 	if (len > modlen) {
23736e94dc5SPeter Avalos 		ret = SSH_ERR_KEY_BITS_MISMATCH;
23836e94dc5SPeter Avalos 		goto out;
23918de8d7fSPeter Avalos 	} else if (len < modlen) {
24036e94dc5SPeter Avalos 		diff = modlen - len;
24136e94dc5SPeter Avalos 		osigblob = sigblob;
24236e94dc5SPeter Avalos 		if ((sigblob = realloc(sigblob, modlen)) == NULL) {
24336e94dc5SPeter Avalos 			sigblob = osigblob; /* put it back for clear/free */
24436e94dc5SPeter Avalos 			ret = SSH_ERR_ALLOC_FAIL;
24536e94dc5SPeter Avalos 			goto out;
24636e94dc5SPeter Avalos 		}
24718de8d7fSPeter Avalos 		memmove(sigblob + diff, sigblob, len);
24836e94dc5SPeter Avalos 		explicit_bzero(sigblob, diff);
24918de8d7fSPeter Avalos 		len = modlen;
25018de8d7fSPeter Avalos 	}
25136e94dc5SPeter Avalos 	if ((dlen = ssh_digest_bytes(hash_alg)) == 0) {
25236e94dc5SPeter Avalos 		ret = SSH_ERR_INTERNAL_ERROR;
25336e94dc5SPeter Avalos 		goto out;
25418de8d7fSPeter Avalos 	}
25536e94dc5SPeter Avalos 	if ((ret = ssh_digest_memory(hash_alg, data, datalen,
25636e94dc5SPeter Avalos 	    digest, sizeof(digest))) != 0)
25736e94dc5SPeter Avalos 		goto out;
25818de8d7fSPeter Avalos 
25936e94dc5SPeter Avalos 	ret = openssh_RSA_verify(hash_alg, digest, dlen, sigblob, len,
26036e94dc5SPeter Avalos 	    key->rsa);
26136e94dc5SPeter Avalos  out:
26236e94dc5SPeter Avalos 	if (sigblob != NULL) {
26336e94dc5SPeter Avalos 		explicit_bzero(sigblob, len);
26436e94dc5SPeter Avalos 		free(sigblob);
26536e94dc5SPeter Avalos 	}
26636e94dc5SPeter Avalos 	free(ktype);
26736e94dc5SPeter Avalos 	sshbuf_free(b);
26836e94dc5SPeter Avalos 	explicit_bzero(digest, sizeof(digest));
26918de8d7fSPeter Avalos 	return ret;
27018de8d7fSPeter Avalos }
27118de8d7fSPeter Avalos 
27218de8d7fSPeter Avalos /*
27318de8d7fSPeter Avalos  * See:
27418de8d7fSPeter Avalos  * http://www.rsasecurity.com/rsalabs/pkcs/pkcs-1/
27518de8d7fSPeter Avalos  * ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1.asn
27618de8d7fSPeter Avalos  */
277e9778795SPeter Avalos 
27818de8d7fSPeter Avalos /*
27918de8d7fSPeter Avalos  * id-sha1 OBJECT IDENTIFIER ::= { iso(1) identified-organization(3)
28018de8d7fSPeter Avalos  *	oiw(14) secsig(3) algorithms(2) 26 }
28118de8d7fSPeter Avalos  */
28218de8d7fSPeter Avalos static const u_char id_sha1[] = {
28318de8d7fSPeter Avalos 	0x30, 0x21, /* type Sequence, length 0x21 (33) */
28418de8d7fSPeter Avalos 	0x30, 0x09, /* type Sequence, length 0x09 */
28518de8d7fSPeter Avalos 	0x06, 0x05, /* type OID, length 0x05 */
28618de8d7fSPeter Avalos 	0x2b, 0x0e, 0x03, 0x02, 0x1a, /* id-sha1 OID */
28718de8d7fSPeter Avalos 	0x05, 0x00, /* NULL */
28818de8d7fSPeter Avalos 	0x04, 0x14  /* Octet string, length 0x14 (20), followed by sha1 hash */
28918de8d7fSPeter Avalos };
29018de8d7fSPeter Avalos 
291e9778795SPeter Avalos /*
292e9778795SPeter Avalos  * See http://csrc.nist.gov/groups/ST/crypto_apps_infra/csor/algorithms.html
293e9778795SPeter Avalos  * id-sha256 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840)
294e9778795SPeter Avalos  *      organization(1) gov(101) csor(3) nistAlgorithm(4) hashAlgs(2)
295e9778795SPeter Avalos  *      id-sha256(1) }
296e9778795SPeter Avalos  */
297e9778795SPeter Avalos static const u_char id_sha256[] = {
298e9778795SPeter Avalos 	0x30, 0x31, /* type Sequence, length 0x31 (49) */
299e9778795SPeter Avalos 	0x30, 0x0d, /* type Sequence, length 0x0d (13) */
300e9778795SPeter Avalos 	0x06, 0x09, /* type OID, length 0x09 */
301e9778795SPeter Avalos 	0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, /* id-sha256 */
302e9778795SPeter Avalos 	0x05, 0x00, /* NULL */
303e9778795SPeter Avalos 	0x04, 0x20  /* Octet string, length 0x20 (32), followed by sha256 hash */
304e9778795SPeter Avalos };
305e9778795SPeter Avalos 
306e9778795SPeter Avalos /*
307e9778795SPeter Avalos  * See http://csrc.nist.gov/groups/ST/crypto_apps_infra/csor/algorithms.html
308e9778795SPeter Avalos  * id-sha512 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840)
309e9778795SPeter Avalos  *      organization(1) gov(101) csor(3) nistAlgorithm(4) hashAlgs(2)
310e9778795SPeter Avalos  *      id-sha256(3) }
311e9778795SPeter Avalos  */
312e9778795SPeter Avalos static const u_char id_sha512[] = {
313e9778795SPeter Avalos 	0x30, 0x51, /* type Sequence, length 0x51 (81) */
314e9778795SPeter Avalos 	0x30, 0x0d, /* type Sequence, length 0x0d (13) */
315e9778795SPeter Avalos 	0x06, 0x09, /* type OID, length 0x09 */
316e9778795SPeter Avalos 	0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, /* id-sha512 */
317e9778795SPeter Avalos 	0x05, 0x00, /* NULL */
318e9778795SPeter Avalos 	0x04, 0x40  /* Octet string, length 0x40 (64), followed by sha512 hash */
319e9778795SPeter Avalos };
320e9778795SPeter Avalos 
321e9778795SPeter Avalos static int
322e9778795SPeter Avalos rsa_hash_alg_oid(int hash_alg, const u_char **oidp, size_t *oidlenp)
323e9778795SPeter Avalos {
324e9778795SPeter Avalos 	switch (hash_alg) {
325e9778795SPeter Avalos 	case SSH_DIGEST_SHA1:
326e9778795SPeter Avalos 		*oidp = id_sha1;
327e9778795SPeter Avalos 		*oidlenp = sizeof(id_sha1);
328e9778795SPeter Avalos 		break;
329e9778795SPeter Avalos 	case SSH_DIGEST_SHA256:
330e9778795SPeter Avalos 		*oidp = id_sha256;
331e9778795SPeter Avalos 		*oidlenp = sizeof(id_sha256);
332e9778795SPeter Avalos 		break;
333e9778795SPeter Avalos 	case SSH_DIGEST_SHA512:
334e9778795SPeter Avalos 		*oidp = id_sha512;
335e9778795SPeter Avalos 		*oidlenp = sizeof(id_sha512);
336e9778795SPeter Avalos 		break;
337e9778795SPeter Avalos 	default:
338e9778795SPeter Avalos 		return SSH_ERR_INVALID_ARGUMENT;
339e9778795SPeter Avalos 	}
340e9778795SPeter Avalos 	return 0;
341e9778795SPeter Avalos }
342e9778795SPeter Avalos 
34318de8d7fSPeter Avalos static int
34436e94dc5SPeter Avalos openssh_RSA_verify(int hash_alg, u_char *hash, size_t hashlen,
34536e94dc5SPeter Avalos     u_char *sigbuf, size_t siglen, RSA *rsa)
34618de8d7fSPeter Avalos {
347e9778795SPeter Avalos 	size_t rsasize = 0, oidlen = 0, hlen = 0;
348e9778795SPeter Avalos 	int ret, len, oidmatch, hashmatch;
34918de8d7fSPeter Avalos 	const u_char *oid = NULL;
35018de8d7fSPeter Avalos 	u_char *decrypted = NULL;
35118de8d7fSPeter Avalos 
352e9778795SPeter Avalos 	if ((ret = rsa_hash_alg_oid(hash_alg, &oid, &oidlen)) != 0)
353e9778795SPeter Avalos 		return ret;
35436e94dc5SPeter Avalos 	ret = SSH_ERR_INTERNAL_ERROR;
355e9778795SPeter Avalos 	hlen = ssh_digest_bytes(hash_alg);
35618de8d7fSPeter Avalos 	if (hashlen != hlen) {
35736e94dc5SPeter Avalos 		ret = SSH_ERR_INVALID_ARGUMENT;
35818de8d7fSPeter Avalos 		goto done;
35918de8d7fSPeter Avalos 	}
36018de8d7fSPeter Avalos 	rsasize = RSA_size(rsa);
36136e94dc5SPeter Avalos 	if (rsasize <= 0 || rsasize > SSHBUF_MAX_BIGNUM ||
36236e94dc5SPeter Avalos 	    siglen == 0 || siglen > rsasize) {
36336e94dc5SPeter Avalos 		ret = SSH_ERR_INVALID_ARGUMENT;
36418de8d7fSPeter Avalos 		goto done;
36518de8d7fSPeter Avalos 	}
36636e94dc5SPeter Avalos 	if ((decrypted = malloc(rsasize)) == NULL) {
36736e94dc5SPeter Avalos 		ret = SSH_ERR_ALLOC_FAIL;
36836e94dc5SPeter Avalos 		goto done;
36936e94dc5SPeter Avalos 	}
37018de8d7fSPeter Avalos 	if ((len = RSA_public_decrypt(siglen, sigbuf, decrypted, rsa,
37118de8d7fSPeter Avalos 	    RSA_PKCS1_PADDING)) < 0) {
37236e94dc5SPeter Avalos 		ret = SSH_ERR_LIBCRYPTO_ERROR;
37318de8d7fSPeter Avalos 		goto done;
37418de8d7fSPeter Avalos 	}
37536e94dc5SPeter Avalos 	if (len < 0 || (size_t)len != hlen + oidlen) {
37636e94dc5SPeter Avalos 		ret = SSH_ERR_INVALID_FORMAT;
37718de8d7fSPeter Avalos 		goto done;
37818de8d7fSPeter Avalos 	}
379856ea928SPeter Avalos 	oidmatch = timingsafe_bcmp(decrypted, oid, oidlen) == 0;
380856ea928SPeter Avalos 	hashmatch = timingsafe_bcmp(decrypted + oidlen, hash, hlen) == 0;
38136e94dc5SPeter Avalos 	if (!oidmatch || !hashmatch) {
38236e94dc5SPeter Avalos 		ret = SSH_ERR_SIGNATURE_INVALID;
38318de8d7fSPeter Avalos 		goto done;
38418de8d7fSPeter Avalos 	}
38536e94dc5SPeter Avalos 	ret = 0;
38618de8d7fSPeter Avalos done:
38736e94dc5SPeter Avalos 	if (decrypted) {
38836e94dc5SPeter Avalos 		explicit_bzero(decrypted, rsasize);
38936e94dc5SPeter Avalos 		free(decrypted);
39036e94dc5SPeter Avalos 	}
39118de8d7fSPeter Avalos 	return ret;
39218de8d7fSPeter Avalos }
393e9778795SPeter Avalos #endif /* WITH_OPENSSL */
394