xref: /openbsd/usr.bin/ssh/ssh-rsa.c (revision 274d7c50)
1 /* $OpenBSD: ssh-rsa.c,v 1.68 2018/09/13 02:08:33 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 #include "log.h"
32 
33 static int openssh_RSA_verify(int, u_char *, size_t, u_char *, size_t, RSA *);
34 
35 static const char *
36 rsa_hash_alg_ident(int hash_alg)
37 {
38 	switch (hash_alg) {
39 	case SSH_DIGEST_SHA1:
40 		return "ssh-rsa";
41 	case SSH_DIGEST_SHA256:
42 		return "rsa-sha2-256";
43 	case SSH_DIGEST_SHA512:
44 		return "rsa-sha2-512";
45 	}
46 	return NULL;
47 }
48 
49 /*
50  * Returns the hash algorithm ID for a given algorithm identifier as used
51  * inside the signature blob,
52  */
53 static int
54 rsa_hash_id_from_ident(const char *ident)
55 {
56 	if (strcmp(ident, "ssh-rsa") == 0)
57 		return SSH_DIGEST_SHA1;
58 	if (strcmp(ident, "rsa-sha2-256") == 0)
59 		return SSH_DIGEST_SHA256;
60 	if (strcmp(ident, "rsa-sha2-512") == 0)
61 		return SSH_DIGEST_SHA512;
62 	return -1;
63 }
64 
65 /*
66  * Return the hash algorithm ID for the specified key name. This includes
67  * all the cases of rsa_hash_id_from_ident() but also the certificate key
68  * types.
69  */
70 static int
71 rsa_hash_id_from_keyname(const char *alg)
72 {
73 	int r;
74 
75 	if ((r = rsa_hash_id_from_ident(alg)) != -1)
76 		return r;
77 	if (strcmp(alg, "ssh-rsa-cert-v01@openssh.com") == 0)
78 		return SSH_DIGEST_SHA1;
79 	if (strcmp(alg, "rsa-sha2-256-cert-v01@openssh.com") == 0)
80 		return SSH_DIGEST_SHA256;
81 	if (strcmp(alg, "rsa-sha2-512-cert-v01@openssh.com") == 0)
82 		return SSH_DIGEST_SHA512;
83 	return -1;
84 }
85 
86 static int
87 rsa_hash_alg_nid(int type)
88 {
89 	switch (type) {
90 	case SSH_DIGEST_SHA1:
91 		return NID_sha1;
92 	case SSH_DIGEST_SHA256:
93 		return NID_sha256;
94 	case SSH_DIGEST_SHA512:
95 		return NID_sha512;
96 	default:
97 		return -1;
98 	}
99 }
100 
101 int
102 ssh_rsa_complete_crt_parameters(struct sshkey *key, const BIGNUM *iqmp)
103 {
104 	const BIGNUM *rsa_p, *rsa_q, *rsa_d;
105 	BIGNUM *aux = NULL, *d_consttime = NULL;
106 	BIGNUM *rsa_dmq1 = NULL, *rsa_dmp1 = NULL, *rsa_iqmp = NULL;
107 	BN_CTX *ctx = NULL;
108 	int r;
109 
110 	if (key == NULL || key->rsa == NULL ||
111 	    sshkey_type_plain(key->type) != KEY_RSA)
112 		return SSH_ERR_INVALID_ARGUMENT;
113 
114 	RSA_get0_key(key->rsa, NULL, NULL, &rsa_d);
115 	RSA_get0_factors(key->rsa, &rsa_p, &rsa_q);
116 
117 	if ((ctx = BN_CTX_new()) == NULL)
118 		return SSH_ERR_ALLOC_FAIL;
119 	if ((aux = BN_new()) == NULL ||
120 	    (rsa_dmq1 = BN_new()) == NULL ||
121 	    (rsa_dmp1 = BN_new()) == NULL)
122 		return SSH_ERR_ALLOC_FAIL;
123 	if ((d_consttime = BN_dup(rsa_d)) == NULL ||
124 	    (rsa_iqmp = BN_dup(iqmp)) == NULL) {
125 		r = SSH_ERR_ALLOC_FAIL;
126 		goto out;
127 	}
128 	BN_set_flags(aux, BN_FLG_CONSTTIME);
129 	BN_set_flags(d_consttime, BN_FLG_CONSTTIME);
130 
131 	if ((BN_sub(aux, rsa_q, BN_value_one()) == 0) ||
132 	    (BN_mod(rsa_dmq1, d_consttime, aux, ctx) == 0) ||
133 	    (BN_sub(aux, rsa_p, BN_value_one()) == 0) ||
134 	    (BN_mod(rsa_dmp1, d_consttime, aux, ctx) == 0)) {
135 		r = SSH_ERR_LIBCRYPTO_ERROR;
136 		goto out;
137 	}
138 	if (!RSA_set0_crt_params(key->rsa, rsa_dmp1, rsa_dmq1, rsa_iqmp)) {
139 		r = SSH_ERR_LIBCRYPTO_ERROR;
140 		goto out;
141 	}
142 	rsa_dmp1 = rsa_dmq1 = rsa_iqmp = NULL; /* transferred */
143 	/* success */
144 	r = 0;
145  out:
146 	BN_clear_free(aux);
147 	BN_clear_free(d_consttime);
148 	BN_clear_free(rsa_dmp1);
149 	BN_clear_free(rsa_dmq1);
150 	BN_clear_free(rsa_iqmp);
151 	BN_CTX_free(ctx);
152 	return r;
153 }
154 
155 /* RSASSA-PKCS1-v1_5 (PKCS #1 v2.0 signature) with SHA1 */
156 int
157 ssh_rsa_sign(const struct sshkey *key, u_char **sigp, size_t *lenp,
158     const u_char *data, size_t datalen, const char *alg_ident)
159 {
160 	const BIGNUM *rsa_n;
161 	u_char digest[SSH_DIGEST_MAX_LENGTH], *sig = NULL;
162 	size_t slen = 0;
163 	u_int dlen, len;
164 	int nid, hash_alg, ret = SSH_ERR_INTERNAL_ERROR;
165 	struct sshbuf *b = NULL;
166 
167 	if (lenp != NULL)
168 		*lenp = 0;
169 	if (sigp != NULL)
170 		*sigp = NULL;
171 
172 	if (alg_ident == NULL || strlen(alg_ident) == 0)
173 		hash_alg = SSH_DIGEST_SHA1;
174 	else
175 		hash_alg = rsa_hash_id_from_keyname(alg_ident);
176 	if (key == NULL || key->rsa == NULL || hash_alg == -1 ||
177 	    sshkey_type_plain(key->type) != KEY_RSA)
178 		return SSH_ERR_INVALID_ARGUMENT;
179 	RSA_get0_key(key->rsa, &rsa_n, NULL, NULL);
180 	if (BN_num_bits(rsa_n) < SSH_RSA_MINIMUM_MODULUS_SIZE)
181 		return SSH_ERR_KEY_LENGTH;
182 	slen = RSA_size(key->rsa);
183 	if (slen <= 0 || slen > SSHBUF_MAX_BIGNUM)
184 		return SSH_ERR_INVALID_ARGUMENT;
185 
186 	/* hash the data */
187 	nid = rsa_hash_alg_nid(hash_alg);
188 	if ((dlen = ssh_digest_bytes(hash_alg)) == 0)
189 		return SSH_ERR_INTERNAL_ERROR;
190 	if ((ret = ssh_digest_memory(hash_alg, data, datalen,
191 	    digest, sizeof(digest))) != 0)
192 		goto out;
193 
194 	if ((sig = malloc(slen)) == NULL) {
195 		ret = SSH_ERR_ALLOC_FAIL;
196 		goto out;
197 	}
198 
199 	if (RSA_sign(nid, digest, dlen, sig, &len, key->rsa) != 1) {
200 		ret = SSH_ERR_LIBCRYPTO_ERROR;
201 		goto out;
202 	}
203 	if (len < slen) {
204 		size_t diff = slen - len;
205 		memmove(sig + diff, sig, len);
206 		explicit_bzero(sig, diff);
207 	} else if (len > slen) {
208 		ret = SSH_ERR_INTERNAL_ERROR;
209 		goto out;
210 	}
211 	/* encode signature */
212 	if ((b = sshbuf_new()) == NULL) {
213 		ret = SSH_ERR_ALLOC_FAIL;
214 		goto out;
215 	}
216 	if ((ret = sshbuf_put_cstring(b, rsa_hash_alg_ident(hash_alg))) != 0 ||
217 	    (ret = sshbuf_put_string(b, sig, slen)) != 0)
218 		goto out;
219 	len = sshbuf_len(b);
220 	if (sigp != NULL) {
221 		if ((*sigp = malloc(len)) == NULL) {
222 			ret = SSH_ERR_ALLOC_FAIL;
223 			goto out;
224 		}
225 		memcpy(*sigp, sshbuf_ptr(b), len);
226 	}
227 	if (lenp != NULL)
228 		*lenp = len;
229 	ret = 0;
230  out:
231 	explicit_bzero(digest, sizeof(digest));
232 	freezero(sig, slen);
233 	sshbuf_free(b);
234 	return ret;
235 }
236 
237 int
238 ssh_rsa_verify(const struct sshkey *key,
239     const u_char *sig, size_t siglen, const u_char *data, size_t datalen,
240     const char *alg)
241 {
242 	const BIGNUM *rsa_n;
243 	char *sigtype = NULL;
244 	int hash_alg, want_alg, ret = SSH_ERR_INTERNAL_ERROR;
245 	size_t len = 0, diff, modlen, dlen;
246 	struct sshbuf *b = NULL;
247 	u_char digest[SSH_DIGEST_MAX_LENGTH], *osigblob, *sigblob = NULL;
248 
249 	if (key == NULL || key->rsa == NULL ||
250 	    sshkey_type_plain(key->type) != KEY_RSA ||
251 	    sig == NULL || siglen == 0)
252 		return SSH_ERR_INVALID_ARGUMENT;
253 	RSA_get0_key(key->rsa, &rsa_n, NULL, NULL);
254 	if (BN_num_bits(rsa_n) < SSH_RSA_MINIMUM_MODULUS_SIZE)
255 		return SSH_ERR_KEY_LENGTH;
256 
257 	if ((b = sshbuf_from(sig, siglen)) == NULL)
258 		return SSH_ERR_ALLOC_FAIL;
259 	if (sshbuf_get_cstring(b, &sigtype, NULL) != 0) {
260 		ret = SSH_ERR_INVALID_FORMAT;
261 		goto out;
262 	}
263 	if ((hash_alg = rsa_hash_id_from_ident(sigtype)) == -1) {
264 		ret = SSH_ERR_KEY_TYPE_MISMATCH;
265 		goto out;
266 	}
267 	/*
268 	 * Allow ssh-rsa-cert-v01 certs to generate SHA2 signatures for
269 	 * legacy reasons, but otherwise the signature type should match.
270 	 */
271 	if (alg != NULL && strcmp(alg, "ssh-rsa-cert-v01@openssh.com") != 0) {
272 		if ((want_alg = rsa_hash_id_from_keyname(alg)) == -1) {
273 			ret = SSH_ERR_INVALID_ARGUMENT;
274 			goto out;
275 		}
276 		if (hash_alg != want_alg) {
277 			ret = SSH_ERR_SIGNATURE_INVALID;
278 			goto out;
279 		}
280 	}
281 	if (sshbuf_get_string(b, &sigblob, &len) != 0) {
282 		ret = SSH_ERR_INVALID_FORMAT;
283 		goto out;
284 	}
285 	if (sshbuf_len(b) != 0) {
286 		ret = SSH_ERR_UNEXPECTED_TRAILING_DATA;
287 		goto out;
288 	}
289 	/* RSA_verify expects a signature of RSA_size */
290 	modlen = RSA_size(key->rsa);
291 	if (len > modlen) {
292 		ret = SSH_ERR_KEY_BITS_MISMATCH;
293 		goto out;
294 	} else if (len < modlen) {
295 		diff = modlen - len;
296 		osigblob = sigblob;
297 		if ((sigblob = realloc(sigblob, modlen)) == NULL) {
298 			sigblob = osigblob; /* put it back for clear/free */
299 			ret = SSH_ERR_ALLOC_FAIL;
300 			goto out;
301 		}
302 		memmove(sigblob + diff, sigblob, len);
303 		explicit_bzero(sigblob, diff);
304 		len = modlen;
305 	}
306 	if ((dlen = ssh_digest_bytes(hash_alg)) == 0) {
307 		ret = SSH_ERR_INTERNAL_ERROR;
308 		goto out;
309 	}
310 	if ((ret = ssh_digest_memory(hash_alg, data, datalen,
311 	    digest, sizeof(digest))) != 0)
312 		goto out;
313 
314 	ret = openssh_RSA_verify(hash_alg, digest, dlen, sigblob, len,
315 	    key->rsa);
316  out:
317 	freezero(sigblob, len);
318 	free(sigtype);
319 	sshbuf_free(b);
320 	explicit_bzero(digest, sizeof(digest));
321 	return ret;
322 }
323 
324 /*
325  * See:
326  * http://www.rsasecurity.com/rsalabs/pkcs/pkcs-1/
327  * ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1.asn
328  */
329 
330 /*
331  * id-sha1 OBJECT IDENTIFIER ::= { iso(1) identified-organization(3)
332  *	oiw(14) secsig(3) algorithms(2) 26 }
333  */
334 static const u_char id_sha1[] = {
335 	0x30, 0x21, /* type Sequence, length 0x21 (33) */
336 	0x30, 0x09, /* type Sequence, length 0x09 */
337 	0x06, 0x05, /* type OID, length 0x05 */
338 	0x2b, 0x0e, 0x03, 0x02, 0x1a, /* id-sha1 OID */
339 	0x05, 0x00, /* NULL */
340 	0x04, 0x14  /* Octet string, length 0x14 (20), followed by sha1 hash */
341 };
342 
343 /*
344  * See http://csrc.nist.gov/groups/ST/crypto_apps_infra/csor/algorithms.html
345  * id-sha256 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840)
346  *      organization(1) gov(101) csor(3) nistAlgorithm(4) hashAlgs(2)
347  *      id-sha256(1) }
348  */
349 static const u_char id_sha256[] = {
350 	0x30, 0x31, /* type Sequence, length 0x31 (49) */
351 	0x30, 0x0d, /* type Sequence, length 0x0d (13) */
352 	0x06, 0x09, /* type OID, length 0x09 */
353 	0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, /* id-sha256 */
354 	0x05, 0x00, /* NULL */
355 	0x04, 0x20  /* Octet string, length 0x20 (32), followed by sha256 hash */
356 };
357 
358 /*
359  * See http://csrc.nist.gov/groups/ST/crypto_apps_infra/csor/algorithms.html
360  * id-sha512 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840)
361  *      organization(1) gov(101) csor(3) nistAlgorithm(4) hashAlgs(2)
362  *      id-sha256(3) }
363  */
364 static const u_char id_sha512[] = {
365 	0x30, 0x51, /* type Sequence, length 0x51 (81) */
366 	0x30, 0x0d, /* type Sequence, length 0x0d (13) */
367 	0x06, 0x09, /* type OID, length 0x09 */
368 	0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, /* id-sha512 */
369 	0x05, 0x00, /* NULL */
370 	0x04, 0x40  /* Octet string, length 0x40 (64), followed by sha512 hash */
371 };
372 
373 static int
374 rsa_hash_alg_oid(int hash_alg, const u_char **oidp, size_t *oidlenp)
375 {
376 	switch (hash_alg) {
377 	case SSH_DIGEST_SHA1:
378 		*oidp = id_sha1;
379 		*oidlenp = sizeof(id_sha1);
380 		break;
381 	case SSH_DIGEST_SHA256:
382 		*oidp = id_sha256;
383 		*oidlenp = sizeof(id_sha256);
384 		break;
385 	case SSH_DIGEST_SHA512:
386 		*oidp = id_sha512;
387 		*oidlenp = sizeof(id_sha512);
388 		break;
389 	default:
390 		return SSH_ERR_INVALID_ARGUMENT;
391 	}
392 	return 0;
393 }
394 
395 static int
396 openssh_RSA_verify(int hash_alg, u_char *hash, size_t hashlen,
397     u_char *sigbuf, size_t siglen, RSA *rsa)
398 {
399 	size_t rsasize = 0, oidlen = 0, hlen = 0;
400 	int ret, len, oidmatch, hashmatch;
401 	const u_char *oid = NULL;
402 	u_char *decrypted = NULL;
403 
404 	if ((ret = rsa_hash_alg_oid(hash_alg, &oid, &oidlen)) != 0)
405 		return ret;
406 	ret = SSH_ERR_INTERNAL_ERROR;
407 	hlen = ssh_digest_bytes(hash_alg);
408 	if (hashlen != hlen) {
409 		ret = SSH_ERR_INVALID_ARGUMENT;
410 		goto done;
411 	}
412 	rsasize = RSA_size(rsa);
413 	if (rsasize <= 0 || rsasize > SSHBUF_MAX_BIGNUM ||
414 	    siglen == 0 || siglen > rsasize) {
415 		ret = SSH_ERR_INVALID_ARGUMENT;
416 		goto done;
417 	}
418 	if ((decrypted = malloc(rsasize)) == NULL) {
419 		ret = SSH_ERR_ALLOC_FAIL;
420 		goto done;
421 	}
422 	if ((len = RSA_public_decrypt(siglen, sigbuf, decrypted, rsa,
423 	    RSA_PKCS1_PADDING)) < 0) {
424 		ret = SSH_ERR_LIBCRYPTO_ERROR;
425 		goto done;
426 	}
427 	if (len < 0 || (size_t)len != hlen + oidlen) {
428 		ret = SSH_ERR_INVALID_FORMAT;
429 		goto done;
430 	}
431 	oidmatch = timingsafe_bcmp(decrypted, oid, oidlen) == 0;
432 	hashmatch = timingsafe_bcmp(decrypted + oidlen, hash, hlen) == 0;
433 	if (!oidmatch || !hashmatch) {
434 		ret = SSH_ERR_SIGNATURE_INVALID;
435 		goto done;
436 	}
437 	ret = 0;
438 done:
439 	freezero(decrypted, rsasize);
440 	return ret;
441 }
442