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