xref: /dflybsd-src/crypto/openssh/ssh-rsa.c (revision 664f47636b7e6e9e2c54a4799ca4884a9c628df5)
1*664f4763Szrj /* $OpenBSD: ssh-rsa.c,v 1.67 2018/07/03 11:39:54 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"
36*664f4763Szrj #include "log.h"
37*664f4763Szrj 
38*664f4763Szrj #include "openbsd-compat/openssl-compat.h"
3918de8d7fSPeter Avalos 
4036e94dc5SPeter Avalos static int openssh_RSA_verify(int, u_char *, size_t, u_char *, size_t, RSA *);
4118de8d7fSPeter Avalos 
42e9778795SPeter Avalos static const char *
43e9778795SPeter Avalos rsa_hash_alg_ident(int hash_alg)
44e9778795SPeter Avalos {
45e9778795SPeter Avalos 	switch (hash_alg) {
46e9778795SPeter Avalos 	case SSH_DIGEST_SHA1:
47e9778795SPeter Avalos 		return "ssh-rsa";
48e9778795SPeter Avalos 	case SSH_DIGEST_SHA256:
49e9778795SPeter Avalos 		return "rsa-sha2-256";
50e9778795SPeter Avalos 	case SSH_DIGEST_SHA512:
51e9778795SPeter Avalos 		return "rsa-sha2-512";
52e9778795SPeter Avalos 	}
53e9778795SPeter Avalos 	return NULL;
54e9778795SPeter Avalos }
55e9778795SPeter Avalos 
56*664f4763Szrj /*
57*664f4763Szrj  * Returns the hash algorithm ID for a given algorithm identifier as used
58*664f4763Szrj  * inside the signature blob,
59*664f4763Szrj  */
60e9778795SPeter Avalos static int
61*664f4763Szrj rsa_hash_id_from_ident(const char *ident)
62e9778795SPeter Avalos {
63*664f4763Szrj 	if (strcmp(ident, "ssh-rsa") == 0)
64e9778795SPeter Avalos 		return SSH_DIGEST_SHA1;
65e9778795SPeter Avalos 	if (strcmp(ident, "rsa-sha2-256") == 0)
66e9778795SPeter Avalos 		return SSH_DIGEST_SHA256;
67e9778795SPeter Avalos 	if (strcmp(ident, "rsa-sha2-512") == 0)
68e9778795SPeter Avalos 		return SSH_DIGEST_SHA512;
69e9778795SPeter Avalos 	return -1;
70e9778795SPeter Avalos }
71e9778795SPeter Avalos 
72*664f4763Szrj /*
73*664f4763Szrj  * Return the hash algorithm ID for the specified key name. This includes
74*664f4763Szrj  * all the cases of rsa_hash_id_from_ident() but also the certificate key
75*664f4763Szrj  * types.
76*664f4763Szrj  */
77*664f4763Szrj static int
78*664f4763Szrj rsa_hash_id_from_keyname(const char *alg)
79*664f4763Szrj {
80*664f4763Szrj 	int r;
81*664f4763Szrj 
82*664f4763Szrj 	if ((r = rsa_hash_id_from_ident(alg)) != -1)
83*664f4763Szrj 		return r;
84*664f4763Szrj 	if (strcmp(alg, "ssh-rsa-cert-v01@openssh.com") == 0)
85*664f4763Szrj 		return SSH_DIGEST_SHA1;
86*664f4763Szrj 	if (strcmp(alg, "rsa-sha2-256-cert-v01@openssh.com") == 0)
87*664f4763Szrj 		return SSH_DIGEST_SHA256;
88*664f4763Szrj 	if (strcmp(alg, "rsa-sha2-512-cert-v01@openssh.com") == 0)
89*664f4763Szrj 		return SSH_DIGEST_SHA512;
90*664f4763Szrj 	return -1;
91*664f4763Szrj }
92*664f4763Szrj 
93e9778795SPeter Avalos static int
94e9778795SPeter Avalos rsa_hash_alg_nid(int type)
95e9778795SPeter Avalos {
96e9778795SPeter Avalos 	switch (type) {
97e9778795SPeter Avalos 	case SSH_DIGEST_SHA1:
98e9778795SPeter Avalos 		return NID_sha1;
99e9778795SPeter Avalos 	case SSH_DIGEST_SHA256:
100e9778795SPeter Avalos 		return NID_sha256;
101e9778795SPeter Avalos 	case SSH_DIGEST_SHA512:
102e9778795SPeter Avalos 		return NID_sha512;
103e9778795SPeter Avalos 	default:
104e9778795SPeter Avalos 		return -1;
105e9778795SPeter Avalos 	}
106e9778795SPeter Avalos }
107e9778795SPeter Avalos 
108ce74bacaSMatthew Dillon int
109*664f4763Szrj ssh_rsa_complete_crt_parameters(struct sshkey *key, const BIGNUM *iqmp)
110ce74bacaSMatthew Dillon {
111*664f4763Szrj 	const BIGNUM *rsa_p, *rsa_q, *rsa_d;
112*664f4763Szrj 	BIGNUM *aux = NULL, *d_consttime = NULL;
113*664f4763Szrj 	BIGNUM *rsa_dmq1 = NULL, *rsa_dmp1 = NULL, *rsa_iqmp = NULL;
114ce74bacaSMatthew Dillon 	BN_CTX *ctx = NULL;
115ce74bacaSMatthew Dillon 	int r;
116ce74bacaSMatthew Dillon 
117ce74bacaSMatthew Dillon 	if (key == NULL || key->rsa == NULL ||
118ce74bacaSMatthew Dillon 	    sshkey_type_plain(key->type) != KEY_RSA)
119ce74bacaSMatthew Dillon 		return SSH_ERR_INVALID_ARGUMENT;
120ce74bacaSMatthew Dillon 
121*664f4763Szrj 	RSA_get0_key(key->rsa, NULL, NULL, &rsa_d);
122*664f4763Szrj 	RSA_get0_factors(key->rsa, &rsa_p, &rsa_q);
123*664f4763Szrj 
124ce74bacaSMatthew Dillon 	if ((ctx = BN_CTX_new()) == NULL)
125ce74bacaSMatthew Dillon 		return SSH_ERR_ALLOC_FAIL;
126*664f4763Szrj 	if ((aux = BN_new()) == NULL ||
127*664f4763Szrj 	    (rsa_dmq1 = BN_new()) == NULL ||
128*664f4763Szrj 	    (rsa_dmp1 = BN_new()) == NULL)
129*664f4763Szrj 		return SSH_ERR_ALLOC_FAIL;
130*664f4763Szrj 	if ((d_consttime = BN_dup(rsa_d)) == NULL ||
131*664f4763Szrj 	    (rsa_iqmp = BN_dup(iqmp)) == NULL) {
132ce74bacaSMatthew Dillon 		r = SSH_ERR_ALLOC_FAIL;
133ce74bacaSMatthew Dillon 		goto out;
134ce74bacaSMatthew Dillon 	}
135*664f4763Szrj 	BN_set_flags(aux, BN_FLG_CONSTTIME);
136*664f4763Szrj 	BN_set_flags(d_consttime, BN_FLG_CONSTTIME);
137ce74bacaSMatthew Dillon 
138*664f4763Szrj 	if ((BN_sub(aux, rsa_q, BN_value_one()) == 0) ||
139*664f4763Szrj 	    (BN_mod(rsa_dmq1, d_consttime, aux, ctx) == 0) ||
140*664f4763Szrj 	    (BN_sub(aux, rsa_p, BN_value_one()) == 0) ||
141*664f4763Szrj 	    (BN_mod(rsa_dmp1, d_consttime, aux, ctx) == 0)) {
142ce74bacaSMatthew Dillon 		r = SSH_ERR_LIBCRYPTO_ERROR;
143ce74bacaSMatthew Dillon 		goto out;
144ce74bacaSMatthew Dillon 	}
145*664f4763Szrj 	if (!RSA_set0_crt_params(key->rsa, rsa_dmp1, rsa_dmq1, rsa_iqmp)) {
146*664f4763Szrj 		r = SSH_ERR_LIBCRYPTO_ERROR;
147*664f4763Szrj 		goto out;
148*664f4763Szrj 	}
149*664f4763Szrj 	rsa_dmp1 = rsa_dmq1 = rsa_iqmp = NULL; /* transferred */
150*664f4763Szrj 	/* success */
151ce74bacaSMatthew Dillon 	r = 0;
152ce74bacaSMatthew Dillon  out:
153ce74bacaSMatthew Dillon 	BN_clear_free(aux);
154*664f4763Szrj 	BN_clear_free(d_consttime);
155*664f4763Szrj 	BN_clear_free(rsa_dmp1);
156*664f4763Szrj 	BN_clear_free(rsa_dmq1);
157*664f4763Szrj 	BN_clear_free(rsa_iqmp);
158ce74bacaSMatthew Dillon 	BN_CTX_free(ctx);
159ce74bacaSMatthew Dillon 	return r;
160ce74bacaSMatthew Dillon }
161ce74bacaSMatthew Dillon 
16218de8d7fSPeter Avalos /* RSASSA-PKCS1-v1_5 (PKCS #1 v2.0 signature) with SHA1 */
16318de8d7fSPeter Avalos int
16436e94dc5SPeter Avalos ssh_rsa_sign(const struct sshkey *key, u_char **sigp, size_t *lenp,
165e9778795SPeter Avalos     const u_char *data, size_t datalen, const char *alg_ident)
16618de8d7fSPeter Avalos {
167*664f4763Szrj 	const BIGNUM *rsa_n;
16836e94dc5SPeter Avalos 	u_char digest[SSH_DIGEST_MAX_LENGTH], *sig = NULL;
169*664f4763Szrj 	size_t slen = 0;
17036e94dc5SPeter Avalos 	u_int dlen, len;
171e9778795SPeter Avalos 	int nid, hash_alg, ret = SSH_ERR_INTERNAL_ERROR;
17236e94dc5SPeter Avalos 	struct sshbuf *b = NULL;
17318de8d7fSPeter Avalos 
17436e94dc5SPeter Avalos 	if (lenp != NULL)
17536e94dc5SPeter Avalos 		*lenp = 0;
17636e94dc5SPeter Avalos 	if (sigp != NULL)
17736e94dc5SPeter Avalos 		*sigp = NULL;
17818de8d7fSPeter Avalos 
179ce74bacaSMatthew Dillon 	if (alg_ident == NULL || strlen(alg_ident) == 0)
180e9778795SPeter Avalos 		hash_alg = SSH_DIGEST_SHA1;
181e9778795SPeter Avalos 	else
182*664f4763Szrj 		hash_alg = rsa_hash_id_from_keyname(alg_ident);
183e9778795SPeter Avalos 	if (key == NULL || key->rsa == NULL || hash_alg == -1 ||
184ce74bacaSMatthew Dillon 	    sshkey_type_plain(key->type) != KEY_RSA)
18536e94dc5SPeter Avalos 		return SSH_ERR_INVALID_ARGUMENT;
186*664f4763Szrj 	RSA_get0_key(key->rsa, &rsa_n, NULL, NULL);
187*664f4763Szrj 	if (BN_num_bits(rsa_n) < SSH_RSA_MINIMUM_MODULUS_SIZE)
188ce74bacaSMatthew Dillon 		return SSH_ERR_KEY_LENGTH;
18918de8d7fSPeter Avalos 	slen = RSA_size(key->rsa);
19036e94dc5SPeter Avalos 	if (slen <= 0 || slen > SSHBUF_MAX_BIGNUM)
19136e94dc5SPeter Avalos 		return SSH_ERR_INVALID_ARGUMENT;
19218de8d7fSPeter Avalos 
19336e94dc5SPeter Avalos 	/* hash the data */
194e9778795SPeter Avalos 	nid = rsa_hash_alg_nid(hash_alg);
19536e94dc5SPeter Avalos 	if ((dlen = ssh_digest_bytes(hash_alg)) == 0)
19636e94dc5SPeter Avalos 		return SSH_ERR_INTERNAL_ERROR;
19736e94dc5SPeter Avalos 	if ((ret = ssh_digest_memory(hash_alg, data, datalen,
19836e94dc5SPeter Avalos 	    digest, sizeof(digest))) != 0)
19936e94dc5SPeter Avalos 		goto out;
20018de8d7fSPeter Avalos 
20136e94dc5SPeter Avalos 	if ((sig = malloc(slen)) == NULL) {
20236e94dc5SPeter Avalos 		ret = SSH_ERR_ALLOC_FAIL;
20336e94dc5SPeter Avalos 		goto out;
20436e94dc5SPeter Avalos 	}
20518de8d7fSPeter Avalos 
20636e94dc5SPeter Avalos 	if (RSA_sign(nid, digest, dlen, sig, &len, key->rsa) != 1) {
20736e94dc5SPeter Avalos 		ret = SSH_ERR_LIBCRYPTO_ERROR;
20836e94dc5SPeter Avalos 		goto out;
20918de8d7fSPeter Avalos 	}
21018de8d7fSPeter Avalos 	if (len < slen) {
21136e94dc5SPeter Avalos 		size_t diff = slen - len;
21218de8d7fSPeter Avalos 		memmove(sig + diff, sig, len);
21336e94dc5SPeter Avalos 		explicit_bzero(sig, diff);
21418de8d7fSPeter Avalos 	} else if (len > slen) {
21536e94dc5SPeter Avalos 		ret = SSH_ERR_INTERNAL_ERROR;
21636e94dc5SPeter Avalos 		goto out;
21718de8d7fSPeter Avalos 	}
21818de8d7fSPeter Avalos 	/* encode signature */
21936e94dc5SPeter Avalos 	if ((b = sshbuf_new()) == NULL) {
22036e94dc5SPeter Avalos 		ret = SSH_ERR_ALLOC_FAIL;
22136e94dc5SPeter Avalos 		goto out;
22236e94dc5SPeter Avalos 	}
223e9778795SPeter Avalos 	if ((ret = sshbuf_put_cstring(b, rsa_hash_alg_ident(hash_alg))) != 0 ||
22436e94dc5SPeter Avalos 	    (ret = sshbuf_put_string(b, sig, slen)) != 0)
22536e94dc5SPeter Avalos 		goto out;
22636e94dc5SPeter Avalos 	len = sshbuf_len(b);
22736e94dc5SPeter Avalos 	if (sigp != NULL) {
22836e94dc5SPeter Avalos 		if ((*sigp = malloc(len)) == NULL) {
22936e94dc5SPeter Avalos 			ret = SSH_ERR_ALLOC_FAIL;
23036e94dc5SPeter Avalos 			goto out;
23136e94dc5SPeter Avalos 		}
23236e94dc5SPeter Avalos 		memcpy(*sigp, sshbuf_ptr(b), len);
23336e94dc5SPeter Avalos 	}
23418de8d7fSPeter Avalos 	if (lenp != NULL)
23518de8d7fSPeter Avalos 		*lenp = len;
23636e94dc5SPeter Avalos 	ret = 0;
23736e94dc5SPeter Avalos  out:
23836e94dc5SPeter Avalos 	explicit_bzero(digest, sizeof(digest));
239*664f4763Szrj 	freezero(sig, slen);
24036e94dc5SPeter Avalos 	sshbuf_free(b);
241e9778795SPeter Avalos 	return ret;
24218de8d7fSPeter Avalos }
24318de8d7fSPeter Avalos 
24418de8d7fSPeter Avalos int
24536e94dc5SPeter Avalos ssh_rsa_verify(const struct sshkey *key,
246*664f4763Szrj     const u_char *sig, size_t siglen, const u_char *data, size_t datalen,
247*664f4763Szrj     const char *alg)
24818de8d7fSPeter Avalos {
249*664f4763Szrj 	const BIGNUM *rsa_n;
250*664f4763Szrj 	char *sigtype = NULL;
251*664f4763Szrj 	int hash_alg, want_alg, ret = SSH_ERR_INTERNAL_ERROR;
252*664f4763Szrj 	size_t len = 0, diff, modlen, dlen;
25336e94dc5SPeter Avalos 	struct sshbuf *b = NULL;
25436e94dc5SPeter Avalos 	u_char digest[SSH_DIGEST_MAX_LENGTH], *osigblob, *sigblob = NULL;
25518de8d7fSPeter Avalos 
25636e94dc5SPeter Avalos 	if (key == NULL || key->rsa == NULL ||
25736e94dc5SPeter Avalos 	    sshkey_type_plain(key->type) != KEY_RSA ||
258e9778795SPeter Avalos 	    sig == NULL || siglen == 0)
25936e94dc5SPeter Avalos 		return SSH_ERR_INVALID_ARGUMENT;
260*664f4763Szrj 	RSA_get0_key(key->rsa, &rsa_n, NULL, NULL);
261*664f4763Szrj 	if (BN_num_bits(rsa_n) < SSH_RSA_MINIMUM_MODULUS_SIZE)
262ce74bacaSMatthew Dillon 		return SSH_ERR_KEY_LENGTH;
26336e94dc5SPeter Avalos 
264e9778795SPeter Avalos 	if ((b = sshbuf_from(sig, siglen)) == NULL)
26536e94dc5SPeter Avalos 		return SSH_ERR_ALLOC_FAIL;
266*664f4763Szrj 	if (sshbuf_get_cstring(b, &sigtype, NULL) != 0) {
26736e94dc5SPeter Avalos 		ret = SSH_ERR_INVALID_FORMAT;
26836e94dc5SPeter Avalos 		goto out;
26918de8d7fSPeter Avalos 	}
270*664f4763Szrj 	if ((hash_alg = rsa_hash_id_from_ident(sigtype)) == -1) {
27136e94dc5SPeter Avalos 		ret = SSH_ERR_KEY_TYPE_MISMATCH;
27236e94dc5SPeter Avalos 		goto out;
27318de8d7fSPeter Avalos 	}
274*664f4763Szrj 	/*
275*664f4763Szrj 	 * Allow ssh-rsa-cert-v01 certs to generate SHA2 signatures for
276*664f4763Szrj 	 * legacy reasons, but otherwise the signature type should match.
277*664f4763Szrj 	 */
278*664f4763Szrj 	if (alg != NULL && strcmp(alg, "ssh-rsa-cert-v01@openssh.com") != 0) {
279*664f4763Szrj 		if ((want_alg = rsa_hash_id_from_keyname(alg)) == -1) {
280*664f4763Szrj 			ret = SSH_ERR_INVALID_ARGUMENT;
281*664f4763Szrj 			goto out;
282*664f4763Szrj 		}
283*664f4763Szrj 		if (hash_alg != want_alg) {
284*664f4763Szrj 			ret = SSH_ERR_SIGNATURE_INVALID;
285*664f4763Szrj 			goto out;
286*664f4763Szrj 		}
287*664f4763Szrj 	}
28836e94dc5SPeter Avalos 	if (sshbuf_get_string(b, &sigblob, &len) != 0) {
28936e94dc5SPeter Avalos 		ret = SSH_ERR_INVALID_FORMAT;
29036e94dc5SPeter Avalos 		goto out;
29136e94dc5SPeter Avalos 	}
29236e94dc5SPeter Avalos 	if (sshbuf_len(b) != 0) {
29336e94dc5SPeter Avalos 		ret = SSH_ERR_UNEXPECTED_TRAILING_DATA;
29436e94dc5SPeter Avalos 		goto out;
29518de8d7fSPeter Avalos 	}
29618de8d7fSPeter Avalos 	/* RSA_verify expects a signature of RSA_size */
29718de8d7fSPeter Avalos 	modlen = RSA_size(key->rsa);
29818de8d7fSPeter Avalos 	if (len > modlen) {
29936e94dc5SPeter Avalos 		ret = SSH_ERR_KEY_BITS_MISMATCH;
30036e94dc5SPeter Avalos 		goto out;
30118de8d7fSPeter Avalos 	} else if (len < modlen) {
30236e94dc5SPeter Avalos 		diff = modlen - len;
30336e94dc5SPeter Avalos 		osigblob = sigblob;
30436e94dc5SPeter Avalos 		if ((sigblob = realloc(sigblob, modlen)) == NULL) {
30536e94dc5SPeter Avalos 			sigblob = osigblob; /* put it back for clear/free */
30636e94dc5SPeter Avalos 			ret = SSH_ERR_ALLOC_FAIL;
30736e94dc5SPeter Avalos 			goto out;
30836e94dc5SPeter Avalos 		}
30918de8d7fSPeter Avalos 		memmove(sigblob + diff, sigblob, len);
31036e94dc5SPeter Avalos 		explicit_bzero(sigblob, diff);
31118de8d7fSPeter Avalos 		len = modlen;
31218de8d7fSPeter Avalos 	}
31336e94dc5SPeter Avalos 	if ((dlen = ssh_digest_bytes(hash_alg)) == 0) {
31436e94dc5SPeter Avalos 		ret = SSH_ERR_INTERNAL_ERROR;
31536e94dc5SPeter Avalos 		goto out;
31618de8d7fSPeter Avalos 	}
31736e94dc5SPeter Avalos 	if ((ret = ssh_digest_memory(hash_alg, data, datalen,
31836e94dc5SPeter Avalos 	    digest, sizeof(digest))) != 0)
31936e94dc5SPeter Avalos 		goto out;
32018de8d7fSPeter Avalos 
32136e94dc5SPeter Avalos 	ret = openssh_RSA_verify(hash_alg, digest, dlen, sigblob, len,
32236e94dc5SPeter Avalos 	    key->rsa);
32336e94dc5SPeter Avalos  out:
324*664f4763Szrj 	freezero(sigblob, len);
325*664f4763Szrj 	free(sigtype);
32636e94dc5SPeter Avalos 	sshbuf_free(b);
32736e94dc5SPeter Avalos 	explicit_bzero(digest, sizeof(digest));
32818de8d7fSPeter Avalos 	return ret;
32918de8d7fSPeter Avalos }
33018de8d7fSPeter Avalos 
33118de8d7fSPeter Avalos /*
33218de8d7fSPeter Avalos  * See:
33318de8d7fSPeter Avalos  * http://www.rsasecurity.com/rsalabs/pkcs/pkcs-1/
33418de8d7fSPeter Avalos  * ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1.asn
33518de8d7fSPeter Avalos  */
336e9778795SPeter Avalos 
33718de8d7fSPeter Avalos /*
33818de8d7fSPeter Avalos  * id-sha1 OBJECT IDENTIFIER ::= { iso(1) identified-organization(3)
33918de8d7fSPeter Avalos  *	oiw(14) secsig(3) algorithms(2) 26 }
34018de8d7fSPeter Avalos  */
34118de8d7fSPeter Avalos static const u_char id_sha1[] = {
34218de8d7fSPeter Avalos 	0x30, 0x21, /* type Sequence, length 0x21 (33) */
34318de8d7fSPeter Avalos 	0x30, 0x09, /* type Sequence, length 0x09 */
34418de8d7fSPeter Avalos 	0x06, 0x05, /* type OID, length 0x05 */
34518de8d7fSPeter Avalos 	0x2b, 0x0e, 0x03, 0x02, 0x1a, /* id-sha1 OID */
34618de8d7fSPeter Avalos 	0x05, 0x00, /* NULL */
34718de8d7fSPeter Avalos 	0x04, 0x14  /* Octet string, length 0x14 (20), followed by sha1 hash */
34818de8d7fSPeter Avalos };
34918de8d7fSPeter Avalos 
350e9778795SPeter Avalos /*
351e9778795SPeter Avalos  * See http://csrc.nist.gov/groups/ST/crypto_apps_infra/csor/algorithms.html
352e9778795SPeter Avalos  * id-sha256 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840)
353e9778795SPeter Avalos  *      organization(1) gov(101) csor(3) nistAlgorithm(4) hashAlgs(2)
354e9778795SPeter Avalos  *      id-sha256(1) }
355e9778795SPeter Avalos  */
356e9778795SPeter Avalos static const u_char id_sha256[] = {
357e9778795SPeter Avalos 	0x30, 0x31, /* type Sequence, length 0x31 (49) */
358e9778795SPeter Avalos 	0x30, 0x0d, /* type Sequence, length 0x0d (13) */
359e9778795SPeter Avalos 	0x06, 0x09, /* type OID, length 0x09 */
360e9778795SPeter Avalos 	0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, /* id-sha256 */
361e9778795SPeter Avalos 	0x05, 0x00, /* NULL */
362e9778795SPeter Avalos 	0x04, 0x20  /* Octet string, length 0x20 (32), followed by sha256 hash */
363e9778795SPeter Avalos };
364e9778795SPeter Avalos 
365e9778795SPeter Avalos /*
366e9778795SPeter Avalos  * See http://csrc.nist.gov/groups/ST/crypto_apps_infra/csor/algorithms.html
367e9778795SPeter Avalos  * id-sha512 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840)
368e9778795SPeter Avalos  *      organization(1) gov(101) csor(3) nistAlgorithm(4) hashAlgs(2)
369e9778795SPeter Avalos  *      id-sha256(3) }
370e9778795SPeter Avalos  */
371e9778795SPeter Avalos static const u_char id_sha512[] = {
372e9778795SPeter Avalos 	0x30, 0x51, /* type Sequence, length 0x51 (81) */
373e9778795SPeter Avalos 	0x30, 0x0d, /* type Sequence, length 0x0d (13) */
374e9778795SPeter Avalos 	0x06, 0x09, /* type OID, length 0x09 */
375e9778795SPeter Avalos 	0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, /* id-sha512 */
376e9778795SPeter Avalos 	0x05, 0x00, /* NULL */
377e9778795SPeter Avalos 	0x04, 0x40  /* Octet string, length 0x40 (64), followed by sha512 hash */
378e9778795SPeter Avalos };
379e9778795SPeter Avalos 
380e9778795SPeter Avalos static int
381e9778795SPeter Avalos rsa_hash_alg_oid(int hash_alg, const u_char **oidp, size_t *oidlenp)
382e9778795SPeter Avalos {
383e9778795SPeter Avalos 	switch (hash_alg) {
384e9778795SPeter Avalos 	case SSH_DIGEST_SHA1:
385e9778795SPeter Avalos 		*oidp = id_sha1;
386e9778795SPeter Avalos 		*oidlenp = sizeof(id_sha1);
387e9778795SPeter Avalos 		break;
388e9778795SPeter Avalos 	case SSH_DIGEST_SHA256:
389e9778795SPeter Avalos 		*oidp = id_sha256;
390e9778795SPeter Avalos 		*oidlenp = sizeof(id_sha256);
391e9778795SPeter Avalos 		break;
392e9778795SPeter Avalos 	case SSH_DIGEST_SHA512:
393e9778795SPeter Avalos 		*oidp = id_sha512;
394e9778795SPeter Avalos 		*oidlenp = sizeof(id_sha512);
395e9778795SPeter Avalos 		break;
396e9778795SPeter Avalos 	default:
397e9778795SPeter Avalos 		return SSH_ERR_INVALID_ARGUMENT;
398e9778795SPeter Avalos 	}
399e9778795SPeter Avalos 	return 0;
400e9778795SPeter Avalos }
401e9778795SPeter Avalos 
40218de8d7fSPeter Avalos static int
40336e94dc5SPeter Avalos openssh_RSA_verify(int hash_alg, u_char *hash, size_t hashlen,
40436e94dc5SPeter Avalos     u_char *sigbuf, size_t siglen, RSA *rsa)
40518de8d7fSPeter Avalos {
406e9778795SPeter Avalos 	size_t rsasize = 0, oidlen = 0, hlen = 0;
407e9778795SPeter Avalos 	int ret, len, oidmatch, hashmatch;
40818de8d7fSPeter Avalos 	const u_char *oid = NULL;
40918de8d7fSPeter Avalos 	u_char *decrypted = NULL;
41018de8d7fSPeter Avalos 
411e9778795SPeter Avalos 	if ((ret = rsa_hash_alg_oid(hash_alg, &oid, &oidlen)) != 0)
412e9778795SPeter Avalos 		return ret;
41336e94dc5SPeter Avalos 	ret = SSH_ERR_INTERNAL_ERROR;
414e9778795SPeter Avalos 	hlen = ssh_digest_bytes(hash_alg);
41518de8d7fSPeter Avalos 	if (hashlen != hlen) {
41636e94dc5SPeter Avalos 		ret = SSH_ERR_INVALID_ARGUMENT;
41718de8d7fSPeter Avalos 		goto done;
41818de8d7fSPeter Avalos 	}
41918de8d7fSPeter Avalos 	rsasize = RSA_size(rsa);
42036e94dc5SPeter Avalos 	if (rsasize <= 0 || rsasize > SSHBUF_MAX_BIGNUM ||
42136e94dc5SPeter Avalos 	    siglen == 0 || siglen > rsasize) {
42236e94dc5SPeter Avalos 		ret = SSH_ERR_INVALID_ARGUMENT;
42318de8d7fSPeter Avalos 		goto done;
42418de8d7fSPeter Avalos 	}
42536e94dc5SPeter Avalos 	if ((decrypted = malloc(rsasize)) == NULL) {
42636e94dc5SPeter Avalos 		ret = SSH_ERR_ALLOC_FAIL;
42736e94dc5SPeter Avalos 		goto done;
42836e94dc5SPeter Avalos 	}
42918de8d7fSPeter Avalos 	if ((len = RSA_public_decrypt(siglen, sigbuf, decrypted, rsa,
43018de8d7fSPeter Avalos 	    RSA_PKCS1_PADDING)) < 0) {
43136e94dc5SPeter Avalos 		ret = SSH_ERR_LIBCRYPTO_ERROR;
43218de8d7fSPeter Avalos 		goto done;
43318de8d7fSPeter Avalos 	}
43436e94dc5SPeter Avalos 	if (len < 0 || (size_t)len != hlen + oidlen) {
43536e94dc5SPeter Avalos 		ret = SSH_ERR_INVALID_FORMAT;
43618de8d7fSPeter Avalos 		goto done;
43718de8d7fSPeter Avalos 	}
438856ea928SPeter Avalos 	oidmatch = timingsafe_bcmp(decrypted, oid, oidlen) == 0;
439856ea928SPeter Avalos 	hashmatch = timingsafe_bcmp(decrypted + oidlen, hash, hlen) == 0;
44036e94dc5SPeter Avalos 	if (!oidmatch || !hashmatch) {
44136e94dc5SPeter Avalos 		ret = SSH_ERR_SIGNATURE_INVALID;
44218de8d7fSPeter Avalos 		goto done;
44318de8d7fSPeter Avalos 	}
44436e94dc5SPeter Avalos 	ret = 0;
44518de8d7fSPeter Avalos done:
446*664f4763Szrj 	freezero(decrypted, rsasize);
44718de8d7fSPeter Avalos 	return ret;
44818de8d7fSPeter Avalos }
449e9778795SPeter Avalos #endif /* WITH_OPENSSL */
450