xref: /openbsd-src/usr.bin/ssh/ssh-rsa.c (revision c7e8ea31cd41a963f06f0a8ba93948b06aa6b4a4)
1 /* $OpenBSD: ssh-rsa.c,v 1.62 2017/07/01 13:50:45 djm Exp $ */
2 /*
3  * Copyright (c) 2000, 2003 Markus Friedl <markus@openbsd.org>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include <sys/types.h>
19 
20 #include <openssl/evp.h>
21 #include <openssl/err.h>
22 
23 #include <string.h>
24 
25 #include "sshbuf.h"
26 #include "compat.h"
27 #include "ssherr.h"
28 #define SSHKEY_INTERNAL
29 #include "sshkey.h"
30 #include "digest.h"
31 
32 static int openssh_RSA_verify(int, u_char *, size_t, u_char *, size_t, RSA *);
33 
34 static const char *
35 rsa_hash_alg_ident(int hash_alg)
36 {
37 	switch (hash_alg) {
38 	case SSH_DIGEST_SHA1:
39 		return "ssh-rsa";
40 	case SSH_DIGEST_SHA256:
41 		return "rsa-sha2-256";
42 	case SSH_DIGEST_SHA512:
43 		return "rsa-sha2-512";
44 	}
45 	return NULL;
46 }
47 
48 static int
49 rsa_hash_alg_from_ident(const char *ident)
50 {
51 	if (strcmp(ident, "ssh-rsa") == 0 ||
52 	    strcmp(ident, "ssh-rsa-cert-v01@openssh.com") == 0)
53 		return SSH_DIGEST_SHA1;
54 	if (strcmp(ident, "rsa-sha2-256") == 0)
55 		return SSH_DIGEST_SHA256;
56 	if (strcmp(ident, "rsa-sha2-512") == 0)
57 		return SSH_DIGEST_SHA512;
58 	return -1;
59 }
60 
61 static int
62 rsa_hash_alg_nid(int type)
63 {
64 	switch (type) {
65 	case SSH_DIGEST_SHA1:
66 		return NID_sha1;
67 	case SSH_DIGEST_SHA256:
68 		return NID_sha256;
69 	case SSH_DIGEST_SHA512:
70 		return NID_sha512;
71 	default:
72 		return -1;
73 	}
74 }
75 
76 /* calculate p-1 and q-1 */
77 int
78 ssh_rsa_generate_additional_parameters(struct sshkey *key)
79 {
80 	RSA *rsa;
81 	BIGNUM *aux = NULL;
82 	BN_CTX *ctx = NULL;
83 	int r;
84 
85 	if (key == NULL || key->rsa == NULL ||
86 	    sshkey_type_plain(key->type) != KEY_RSA)
87 		return SSH_ERR_INVALID_ARGUMENT;
88 
89 	if ((ctx = BN_CTX_new()) == NULL)
90 		return SSH_ERR_ALLOC_FAIL;
91 	if ((aux = BN_new()) == NULL) {
92 		r = SSH_ERR_ALLOC_FAIL;
93 		goto out;
94 	}
95 	rsa = key->rsa;
96 
97 	if ((BN_sub(aux, rsa->q, BN_value_one()) == 0) ||
98 	    (BN_mod(rsa->dmq1, rsa->d, aux, ctx) == 0) ||
99 	    (BN_sub(aux, rsa->p, BN_value_one()) == 0) ||
100 	    (BN_mod(rsa->dmp1, rsa->d, aux, ctx) == 0)) {
101 		r = SSH_ERR_LIBCRYPTO_ERROR;
102 		goto out;
103 	}
104 	r = 0;
105  out:
106 	BN_clear_free(aux);
107 	BN_CTX_free(ctx);
108 	return r;
109 }
110 
111 /* RSASSA-PKCS1-v1_5 (PKCS #1 v2.0 signature) with SHA1 */
112 int
113 ssh_rsa_sign(const struct sshkey *key, u_char **sigp, size_t *lenp,
114     const u_char *data, size_t datalen, const char *alg_ident)
115 {
116 	u_char digest[SSH_DIGEST_MAX_LENGTH], *sig = NULL;
117 	size_t slen;
118 	u_int dlen, len;
119 	int nid, hash_alg, ret = SSH_ERR_INTERNAL_ERROR;
120 	struct sshbuf *b = NULL;
121 
122 	if (lenp != NULL)
123 		*lenp = 0;
124 	if (sigp != NULL)
125 		*sigp = NULL;
126 
127 	if (alg_ident == NULL || strlen(alg_ident) == 0)
128 		hash_alg = SSH_DIGEST_SHA1;
129 	else
130 		hash_alg = rsa_hash_alg_from_ident(alg_ident);
131 	if (key == NULL || key->rsa == NULL || hash_alg == -1 ||
132 	    sshkey_type_plain(key->type) != KEY_RSA)
133 		return SSH_ERR_INVALID_ARGUMENT;
134 	if (BN_num_bits(key->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE)
135 		return SSH_ERR_KEY_LENGTH;
136 	slen = RSA_size(key->rsa);
137 	if (slen <= 0 || slen > SSHBUF_MAX_BIGNUM)
138 		return SSH_ERR_INVALID_ARGUMENT;
139 
140 	/* hash the data */
141 	nid = rsa_hash_alg_nid(hash_alg);
142 	if ((dlen = ssh_digest_bytes(hash_alg)) == 0)
143 		return SSH_ERR_INTERNAL_ERROR;
144 	if ((ret = ssh_digest_memory(hash_alg, data, datalen,
145 	    digest, sizeof(digest))) != 0)
146 		goto out;
147 
148 	if ((sig = malloc(slen)) == NULL) {
149 		ret = SSH_ERR_ALLOC_FAIL;
150 		goto out;
151 	}
152 
153 	if (RSA_sign(nid, digest, dlen, sig, &len, key->rsa) != 1) {
154 		ret = SSH_ERR_LIBCRYPTO_ERROR;
155 		goto out;
156 	}
157 	if (len < slen) {
158 		size_t diff = slen - len;
159 		memmove(sig + diff, sig, len);
160 		explicit_bzero(sig, diff);
161 	} else if (len > slen) {
162 		ret = SSH_ERR_INTERNAL_ERROR;
163 		goto out;
164 	}
165 	/* encode signature */
166 	if ((b = sshbuf_new()) == NULL) {
167 		ret = SSH_ERR_ALLOC_FAIL;
168 		goto out;
169 	}
170 	if ((ret = sshbuf_put_cstring(b, rsa_hash_alg_ident(hash_alg))) != 0 ||
171 	    (ret = sshbuf_put_string(b, sig, slen)) != 0)
172 		goto out;
173 	len = sshbuf_len(b);
174 	if (sigp != NULL) {
175 		if ((*sigp = malloc(len)) == NULL) {
176 			ret = SSH_ERR_ALLOC_FAIL;
177 			goto out;
178 		}
179 		memcpy(*sigp, sshbuf_ptr(b), len);
180 	}
181 	if (lenp != NULL)
182 		*lenp = len;
183 	ret = 0;
184  out:
185 	explicit_bzero(digest, sizeof(digest));
186 	if (sig != NULL) {
187 		explicit_bzero(sig, slen);
188 		free(sig);
189 	}
190 	sshbuf_free(b);
191 	return ret;
192 }
193 
194 int
195 ssh_rsa_verify(const struct sshkey *key,
196     const u_char *sig, size_t siglen, const u_char *data, size_t datalen)
197 {
198 	char *ktype = NULL;
199 	int hash_alg, ret = SSH_ERR_INTERNAL_ERROR;
200 	size_t len, diff, modlen, dlen;
201 	struct sshbuf *b = NULL;
202 	u_char digest[SSH_DIGEST_MAX_LENGTH], *osigblob, *sigblob = NULL;
203 
204 	if (key == NULL || key->rsa == NULL ||
205 	    sshkey_type_plain(key->type) != KEY_RSA ||
206 	    sig == NULL || siglen == 0)
207 		return SSH_ERR_INVALID_ARGUMENT;
208 	if (BN_num_bits(key->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE)
209 		return SSH_ERR_KEY_LENGTH;
210 
211 	if ((b = sshbuf_from(sig, siglen)) == NULL)
212 		return SSH_ERR_ALLOC_FAIL;
213 	if (sshbuf_get_cstring(b, &ktype, NULL) != 0) {
214 		ret = SSH_ERR_INVALID_FORMAT;
215 		goto out;
216 	}
217 	if ((hash_alg = rsa_hash_alg_from_ident(ktype)) == -1) {
218 		ret = SSH_ERR_KEY_TYPE_MISMATCH;
219 		goto out;
220 	}
221 	if (sshbuf_get_string(b, &sigblob, &len) != 0) {
222 		ret = SSH_ERR_INVALID_FORMAT;
223 		goto out;
224 	}
225 	if (sshbuf_len(b) != 0) {
226 		ret = SSH_ERR_UNEXPECTED_TRAILING_DATA;
227 		goto out;
228 	}
229 	/* RSA_verify expects a signature of RSA_size */
230 	modlen = RSA_size(key->rsa);
231 	if (len > modlen) {
232 		ret = SSH_ERR_KEY_BITS_MISMATCH;
233 		goto out;
234 	} else if (len < modlen) {
235 		diff = modlen - len;
236 		osigblob = sigblob;
237 		if ((sigblob = realloc(sigblob, modlen)) == NULL) {
238 			sigblob = osigblob; /* put it back for clear/free */
239 			ret = SSH_ERR_ALLOC_FAIL;
240 			goto out;
241 		}
242 		memmove(sigblob + diff, sigblob, len);
243 		explicit_bzero(sigblob, diff);
244 		len = modlen;
245 	}
246 	if ((dlen = ssh_digest_bytes(hash_alg)) == 0) {
247 		ret = SSH_ERR_INTERNAL_ERROR;
248 		goto out;
249 	}
250 	if ((ret = ssh_digest_memory(hash_alg, data, datalen,
251 	    digest, sizeof(digest))) != 0)
252 		goto out;
253 
254 	ret = openssh_RSA_verify(hash_alg, digest, dlen, sigblob, len,
255 	    key->rsa);
256  out:
257 	if (sigblob != NULL) {
258 		explicit_bzero(sigblob, len);
259 		free(sigblob);
260 	}
261 	free(ktype);
262 	sshbuf_free(b);
263 	explicit_bzero(digest, sizeof(digest));
264 	return ret;
265 }
266 
267 /*
268  * See:
269  * http://www.rsasecurity.com/rsalabs/pkcs/pkcs-1/
270  * ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1.asn
271  */
272 
273 /*
274  * id-sha1 OBJECT IDENTIFIER ::= { iso(1) identified-organization(3)
275  *	oiw(14) secsig(3) algorithms(2) 26 }
276  */
277 static const u_char id_sha1[] = {
278 	0x30, 0x21, /* type Sequence, length 0x21 (33) */
279 	0x30, 0x09, /* type Sequence, length 0x09 */
280 	0x06, 0x05, /* type OID, length 0x05 */
281 	0x2b, 0x0e, 0x03, 0x02, 0x1a, /* id-sha1 OID */
282 	0x05, 0x00, /* NULL */
283 	0x04, 0x14  /* Octet string, length 0x14 (20), followed by sha1 hash */
284 };
285 
286 /*
287  * See http://csrc.nist.gov/groups/ST/crypto_apps_infra/csor/algorithms.html
288  * id-sha256 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840)
289  *      organization(1) gov(101) csor(3) nistAlgorithm(4) hashAlgs(2)
290  *      id-sha256(1) }
291  */
292 static const u_char id_sha256[] = {
293 	0x30, 0x31, /* type Sequence, length 0x31 (49) */
294 	0x30, 0x0d, /* type Sequence, length 0x0d (13) */
295 	0x06, 0x09, /* type OID, length 0x09 */
296 	0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, /* id-sha256 */
297 	0x05, 0x00, /* NULL */
298 	0x04, 0x20  /* Octet string, length 0x20 (32), followed by sha256 hash */
299 };
300 
301 /*
302  * See http://csrc.nist.gov/groups/ST/crypto_apps_infra/csor/algorithms.html
303  * id-sha512 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840)
304  *      organization(1) gov(101) csor(3) nistAlgorithm(4) hashAlgs(2)
305  *      id-sha256(3) }
306  */
307 static const u_char id_sha512[] = {
308 	0x30, 0x51, /* type Sequence, length 0x51 (81) */
309 	0x30, 0x0d, /* type Sequence, length 0x0d (13) */
310 	0x06, 0x09, /* type OID, length 0x09 */
311 	0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, /* id-sha512 */
312 	0x05, 0x00, /* NULL */
313 	0x04, 0x40  /* Octet string, length 0x40 (64), followed by sha512 hash */
314 };
315 
316 static int
317 rsa_hash_alg_oid(int hash_alg, const u_char **oidp, size_t *oidlenp)
318 {
319 	switch (hash_alg) {
320 	case SSH_DIGEST_SHA1:
321 		*oidp = id_sha1;
322 		*oidlenp = sizeof(id_sha1);
323 		break;
324 	case SSH_DIGEST_SHA256:
325 		*oidp = id_sha256;
326 		*oidlenp = sizeof(id_sha256);
327 		break;
328 	case SSH_DIGEST_SHA512:
329 		*oidp = id_sha512;
330 		*oidlenp = sizeof(id_sha512);
331 		break;
332 	default:
333 		return SSH_ERR_INVALID_ARGUMENT;
334 	}
335 	return 0;
336 }
337 
338 static int
339 openssh_RSA_verify(int hash_alg, u_char *hash, size_t hashlen,
340     u_char *sigbuf, size_t siglen, RSA *rsa)
341 {
342 	size_t rsasize = 0, oidlen = 0, hlen = 0;
343 	int ret, len, oidmatch, hashmatch;
344 	const u_char *oid = NULL;
345 	u_char *decrypted = NULL;
346 
347 	if ((ret = rsa_hash_alg_oid(hash_alg, &oid, &oidlen)) != 0)
348 		return ret;
349 	ret = SSH_ERR_INTERNAL_ERROR;
350 	hlen = ssh_digest_bytes(hash_alg);
351 	if (hashlen != hlen) {
352 		ret = SSH_ERR_INVALID_ARGUMENT;
353 		goto done;
354 	}
355 	rsasize = RSA_size(rsa);
356 	if (rsasize <= 0 || rsasize > SSHBUF_MAX_BIGNUM ||
357 	    siglen == 0 || siglen > rsasize) {
358 		ret = SSH_ERR_INVALID_ARGUMENT;
359 		goto done;
360 	}
361 	if ((decrypted = malloc(rsasize)) == NULL) {
362 		ret = SSH_ERR_ALLOC_FAIL;
363 		goto done;
364 	}
365 	if ((len = RSA_public_decrypt(siglen, sigbuf, decrypted, rsa,
366 	    RSA_PKCS1_PADDING)) < 0) {
367 		ret = SSH_ERR_LIBCRYPTO_ERROR;
368 		goto done;
369 	}
370 	if (len < 0 || (size_t)len != hlen + oidlen) {
371 		ret = SSH_ERR_INVALID_FORMAT;
372 		goto done;
373 	}
374 	oidmatch = timingsafe_bcmp(decrypted, oid, oidlen) == 0;
375 	hashmatch = timingsafe_bcmp(decrypted + oidlen, hash, hlen) == 0;
376 	if (!oidmatch || !hashmatch) {
377 		ret = SSH_ERR_SIGNATURE_INVALID;
378 		goto done;
379 	}
380 	ret = 0;
381 done:
382 	if (decrypted) {
383 		explicit_bzero(decrypted, rsasize);
384 		free(decrypted);
385 	}
386 	return ret;
387 }
388