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