xref: /dflybsd-src/crypto/openssh/ssh-rsa.c (revision 856ea928c995e02ea88a6865c1f1983842decc66)
1*856ea928SPeter Avalos /* $OpenBSD: ssh-rsa.c,v 1.44 2010/07/16 14:07:35 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 
2018de8d7fSPeter Avalos #include <sys/types.h>
2118de8d7fSPeter Avalos 
2218de8d7fSPeter Avalos #include <openssl/evp.h>
2318de8d7fSPeter Avalos #include <openssl/err.h>
2418de8d7fSPeter Avalos 
2518de8d7fSPeter Avalos #include <stdarg.h>
2618de8d7fSPeter Avalos #include <string.h>
2718de8d7fSPeter Avalos 
2818de8d7fSPeter Avalos #include "xmalloc.h"
2918de8d7fSPeter Avalos #include "log.h"
3018de8d7fSPeter Avalos #include "buffer.h"
3118de8d7fSPeter Avalos #include "key.h"
3218de8d7fSPeter Avalos #include "compat.h"
33*856ea928SPeter Avalos #include "misc.h"
3418de8d7fSPeter Avalos #include "ssh.h"
3518de8d7fSPeter Avalos 
3618de8d7fSPeter Avalos static int openssh_RSA_verify(int, u_char *, u_int, u_char *, u_int, RSA *);
3718de8d7fSPeter Avalos 
3818de8d7fSPeter Avalos /* RSASSA-PKCS1-v1_5 (PKCS #1 v2.0 signature) with SHA1 */
3918de8d7fSPeter Avalos int
4018de8d7fSPeter Avalos ssh_rsa_sign(const Key *key, u_char **sigp, u_int *lenp,
4118de8d7fSPeter Avalos     const u_char *data, u_int datalen)
4218de8d7fSPeter Avalos {
4318de8d7fSPeter Avalos 	const EVP_MD *evp_md;
4418de8d7fSPeter Avalos 	EVP_MD_CTX md;
4518de8d7fSPeter Avalos 	u_char digest[EVP_MAX_MD_SIZE], *sig;
4618de8d7fSPeter Avalos 	u_int slen, dlen, len;
4718de8d7fSPeter Avalos 	int ok, nid;
4818de8d7fSPeter Avalos 	Buffer b;
4918de8d7fSPeter Avalos 
50*856ea928SPeter Avalos 	if (key == NULL || key->rsa == NULL || (key->type != KEY_RSA &&
51*856ea928SPeter Avalos 	    key->type != KEY_RSA_CERT && key->type != KEY_RSA_CERT_V00)) {
5218de8d7fSPeter Avalos 		error("ssh_rsa_sign: no RSA key");
5318de8d7fSPeter Avalos 		return -1;
5418de8d7fSPeter Avalos 	}
5518de8d7fSPeter Avalos 	nid = (datafellows & SSH_BUG_RSASIGMD5) ? NID_md5 : NID_sha1;
5618de8d7fSPeter Avalos 	if ((evp_md = EVP_get_digestbynid(nid)) == NULL) {
5718de8d7fSPeter Avalos 		error("ssh_rsa_sign: EVP_get_digestbynid %d failed", nid);
5818de8d7fSPeter Avalos 		return -1;
5918de8d7fSPeter Avalos 	}
6018de8d7fSPeter Avalos 	EVP_DigestInit(&md, evp_md);
6118de8d7fSPeter Avalos 	EVP_DigestUpdate(&md, data, datalen);
6218de8d7fSPeter Avalos 	EVP_DigestFinal(&md, digest, &dlen);
6318de8d7fSPeter Avalos 
6418de8d7fSPeter Avalos 	slen = RSA_size(key->rsa);
6518de8d7fSPeter Avalos 	sig = xmalloc(slen);
6618de8d7fSPeter Avalos 
6718de8d7fSPeter Avalos 	ok = RSA_sign(nid, digest, dlen, sig, &len, key->rsa);
6818de8d7fSPeter Avalos 	memset(digest, 'd', sizeof(digest));
6918de8d7fSPeter Avalos 
7018de8d7fSPeter Avalos 	if (ok != 1) {
7118de8d7fSPeter Avalos 		int ecode = ERR_get_error();
7218de8d7fSPeter Avalos 
7318de8d7fSPeter Avalos 		error("ssh_rsa_sign: RSA_sign failed: %s",
7418de8d7fSPeter Avalos 		    ERR_error_string(ecode, NULL));
7518de8d7fSPeter Avalos 		xfree(sig);
7618de8d7fSPeter Avalos 		return -1;
7718de8d7fSPeter Avalos 	}
7818de8d7fSPeter Avalos 	if (len < slen) {
7918de8d7fSPeter Avalos 		u_int diff = slen - len;
8018de8d7fSPeter Avalos 		debug("slen %u > len %u", slen, len);
8118de8d7fSPeter Avalos 		memmove(sig + diff, sig, len);
8218de8d7fSPeter Avalos 		memset(sig, 0, diff);
8318de8d7fSPeter Avalos 	} else if (len > slen) {
8418de8d7fSPeter Avalos 		error("ssh_rsa_sign: slen %u slen2 %u", slen, len);
8518de8d7fSPeter Avalos 		xfree(sig);
8618de8d7fSPeter Avalos 		return -1;
8718de8d7fSPeter Avalos 	}
8818de8d7fSPeter Avalos 	/* encode signature */
8918de8d7fSPeter Avalos 	buffer_init(&b);
9018de8d7fSPeter Avalos 	buffer_put_cstring(&b, "ssh-rsa");
9118de8d7fSPeter Avalos 	buffer_put_string(&b, sig, slen);
9218de8d7fSPeter Avalos 	len = buffer_len(&b);
9318de8d7fSPeter Avalos 	if (lenp != NULL)
9418de8d7fSPeter Avalos 		*lenp = len;
9518de8d7fSPeter Avalos 	if (sigp != NULL) {
9618de8d7fSPeter Avalos 		*sigp = xmalloc(len);
9718de8d7fSPeter Avalos 		memcpy(*sigp, buffer_ptr(&b), len);
9818de8d7fSPeter Avalos 	}
9918de8d7fSPeter Avalos 	buffer_free(&b);
10018de8d7fSPeter Avalos 	memset(sig, 's', slen);
10118de8d7fSPeter Avalos 	xfree(sig);
10218de8d7fSPeter Avalos 
10318de8d7fSPeter Avalos 	return 0;
10418de8d7fSPeter Avalos }
10518de8d7fSPeter Avalos 
10618de8d7fSPeter Avalos int
10718de8d7fSPeter Avalos ssh_rsa_verify(const Key *key, const u_char *signature, u_int signaturelen,
10818de8d7fSPeter Avalos     const u_char *data, u_int datalen)
10918de8d7fSPeter Avalos {
11018de8d7fSPeter Avalos 	Buffer b;
11118de8d7fSPeter Avalos 	const EVP_MD *evp_md;
11218de8d7fSPeter Avalos 	EVP_MD_CTX md;
11318de8d7fSPeter Avalos 	char *ktype;
11418de8d7fSPeter Avalos 	u_char digest[EVP_MAX_MD_SIZE], *sigblob;
11518de8d7fSPeter Avalos 	u_int len, dlen, modlen;
11618de8d7fSPeter Avalos 	int rlen, ret, nid;
11718de8d7fSPeter Avalos 
118*856ea928SPeter Avalos 	if (key == NULL || key->rsa == NULL || (key->type != KEY_RSA &&
119*856ea928SPeter Avalos 	    key->type != KEY_RSA_CERT && key->type != KEY_RSA_CERT_V00)) {
12018de8d7fSPeter Avalos 		error("ssh_rsa_verify: no RSA key");
12118de8d7fSPeter Avalos 		return -1;
12218de8d7fSPeter Avalos 	}
12318de8d7fSPeter Avalos 	if (BN_num_bits(key->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) {
12418de8d7fSPeter Avalos 		error("ssh_rsa_verify: RSA modulus too small: %d < minimum %d bits",
12518de8d7fSPeter Avalos 		    BN_num_bits(key->rsa->n), SSH_RSA_MINIMUM_MODULUS_SIZE);
12618de8d7fSPeter Avalos 		return -1;
12718de8d7fSPeter Avalos 	}
12818de8d7fSPeter Avalos 	buffer_init(&b);
12918de8d7fSPeter Avalos 	buffer_append(&b, signature, signaturelen);
13018de8d7fSPeter Avalos 	ktype = buffer_get_string(&b, NULL);
13118de8d7fSPeter Avalos 	if (strcmp("ssh-rsa", ktype) != 0) {
13218de8d7fSPeter Avalos 		error("ssh_rsa_verify: cannot handle type %s", ktype);
13318de8d7fSPeter Avalos 		buffer_free(&b);
13418de8d7fSPeter Avalos 		xfree(ktype);
13518de8d7fSPeter Avalos 		return -1;
13618de8d7fSPeter Avalos 	}
13718de8d7fSPeter Avalos 	xfree(ktype);
13818de8d7fSPeter Avalos 	sigblob = buffer_get_string(&b, &len);
13918de8d7fSPeter Avalos 	rlen = buffer_len(&b);
14018de8d7fSPeter Avalos 	buffer_free(&b);
14118de8d7fSPeter Avalos 	if (rlen != 0) {
14218de8d7fSPeter Avalos 		error("ssh_rsa_verify: remaining bytes in signature %d", rlen);
14318de8d7fSPeter Avalos 		xfree(sigblob);
14418de8d7fSPeter Avalos 		return -1;
14518de8d7fSPeter Avalos 	}
14618de8d7fSPeter Avalos 	/* RSA_verify expects a signature of RSA_size */
14718de8d7fSPeter Avalos 	modlen = RSA_size(key->rsa);
14818de8d7fSPeter Avalos 	if (len > modlen) {
14918de8d7fSPeter Avalos 		error("ssh_rsa_verify: len %u > modlen %u", len, modlen);
15018de8d7fSPeter Avalos 		xfree(sigblob);
15118de8d7fSPeter Avalos 		return -1;
15218de8d7fSPeter Avalos 	} else if (len < modlen) {
15318de8d7fSPeter Avalos 		u_int diff = modlen - len;
15418de8d7fSPeter Avalos 		debug("ssh_rsa_verify: add padding: modlen %u > len %u",
15518de8d7fSPeter Avalos 		    modlen, len);
15618de8d7fSPeter Avalos 		sigblob = xrealloc(sigblob, 1, modlen);
15718de8d7fSPeter Avalos 		memmove(sigblob + diff, sigblob, len);
15818de8d7fSPeter Avalos 		memset(sigblob, 0, diff);
15918de8d7fSPeter Avalos 		len = modlen;
16018de8d7fSPeter Avalos 	}
16118de8d7fSPeter Avalos 	nid = (datafellows & SSH_BUG_RSASIGMD5) ? NID_md5 : NID_sha1;
16218de8d7fSPeter Avalos 	if ((evp_md = EVP_get_digestbynid(nid)) == NULL) {
16318de8d7fSPeter Avalos 		error("ssh_rsa_verify: EVP_get_digestbynid %d failed", nid);
16418de8d7fSPeter Avalos 		xfree(sigblob);
16518de8d7fSPeter Avalos 		return -1;
16618de8d7fSPeter Avalos 	}
16718de8d7fSPeter Avalos 	EVP_DigestInit(&md, evp_md);
16818de8d7fSPeter Avalos 	EVP_DigestUpdate(&md, data, datalen);
16918de8d7fSPeter Avalos 	EVP_DigestFinal(&md, digest, &dlen);
17018de8d7fSPeter Avalos 
17118de8d7fSPeter Avalos 	ret = openssh_RSA_verify(nid, digest, dlen, sigblob, len, key->rsa);
17218de8d7fSPeter Avalos 	memset(digest, 'd', sizeof(digest));
17318de8d7fSPeter Avalos 	memset(sigblob, 's', len);
17418de8d7fSPeter Avalos 	xfree(sigblob);
17518de8d7fSPeter Avalos 	debug("ssh_rsa_verify: signature %scorrect", (ret==0) ? "in" : "");
17618de8d7fSPeter Avalos 	return ret;
17718de8d7fSPeter Avalos }
17818de8d7fSPeter Avalos 
17918de8d7fSPeter Avalos /*
18018de8d7fSPeter Avalos  * See:
18118de8d7fSPeter Avalos  * http://www.rsasecurity.com/rsalabs/pkcs/pkcs-1/
18218de8d7fSPeter Avalos  * ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1.asn
18318de8d7fSPeter Avalos  */
18418de8d7fSPeter Avalos /*
18518de8d7fSPeter Avalos  * id-sha1 OBJECT IDENTIFIER ::= { iso(1) identified-organization(3)
18618de8d7fSPeter Avalos  *	oiw(14) secsig(3) algorithms(2) 26 }
18718de8d7fSPeter Avalos  */
18818de8d7fSPeter Avalos static const u_char id_sha1[] = {
18918de8d7fSPeter Avalos 	0x30, 0x21, /* type Sequence, length 0x21 (33) */
19018de8d7fSPeter Avalos 	0x30, 0x09, /* type Sequence, length 0x09 */
19118de8d7fSPeter Avalos 	0x06, 0x05, /* type OID, length 0x05 */
19218de8d7fSPeter Avalos 	0x2b, 0x0e, 0x03, 0x02, 0x1a, /* id-sha1 OID */
19318de8d7fSPeter Avalos 	0x05, 0x00, /* NULL */
19418de8d7fSPeter Avalos 	0x04, 0x14  /* Octet string, length 0x14 (20), followed by sha1 hash */
19518de8d7fSPeter Avalos };
19618de8d7fSPeter Avalos /*
19718de8d7fSPeter Avalos  * id-md5 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840)
19818de8d7fSPeter Avalos  *	rsadsi(113549) digestAlgorithm(2) 5 }
19918de8d7fSPeter Avalos  */
20018de8d7fSPeter Avalos static const u_char id_md5[] = {
20118de8d7fSPeter Avalos 	0x30, 0x20, /* type Sequence, length 0x20 (32) */
20218de8d7fSPeter Avalos 	0x30, 0x0c, /* type Sequence, length 0x09 */
20318de8d7fSPeter Avalos 	0x06, 0x08, /* type OID, length 0x05 */
20418de8d7fSPeter Avalos 	0x2a, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x05, /* id-md5 */
20518de8d7fSPeter Avalos 	0x05, 0x00, /* NULL */
20618de8d7fSPeter Avalos 	0x04, 0x10  /* Octet string, length 0x10 (16), followed by md5 hash */
20718de8d7fSPeter Avalos };
20818de8d7fSPeter Avalos 
20918de8d7fSPeter Avalos static int
21018de8d7fSPeter Avalos openssh_RSA_verify(int type, u_char *hash, u_int hashlen,
21118de8d7fSPeter Avalos     u_char *sigbuf, u_int siglen, RSA *rsa)
21218de8d7fSPeter Avalos {
21318de8d7fSPeter Avalos 	u_int ret, rsasize, oidlen = 0, hlen = 0;
214*856ea928SPeter Avalos 	int len, oidmatch, hashmatch;
21518de8d7fSPeter Avalos 	const u_char *oid = NULL;
21618de8d7fSPeter Avalos 	u_char *decrypted = NULL;
21718de8d7fSPeter Avalos 
21818de8d7fSPeter Avalos 	ret = 0;
21918de8d7fSPeter Avalos 	switch (type) {
22018de8d7fSPeter Avalos 	case NID_sha1:
22118de8d7fSPeter Avalos 		oid = id_sha1;
22218de8d7fSPeter Avalos 		oidlen = sizeof(id_sha1);
22318de8d7fSPeter Avalos 		hlen = 20;
22418de8d7fSPeter Avalos 		break;
22518de8d7fSPeter Avalos 	case NID_md5:
22618de8d7fSPeter Avalos 		oid = id_md5;
22718de8d7fSPeter Avalos 		oidlen = sizeof(id_md5);
22818de8d7fSPeter Avalos 		hlen = 16;
22918de8d7fSPeter Avalos 		break;
23018de8d7fSPeter Avalos 	default:
23118de8d7fSPeter Avalos 		goto done;
23218de8d7fSPeter Avalos 	}
23318de8d7fSPeter Avalos 	if (hashlen != hlen) {
23418de8d7fSPeter Avalos 		error("bad hashlen");
23518de8d7fSPeter Avalos 		goto done;
23618de8d7fSPeter Avalos 	}
23718de8d7fSPeter Avalos 	rsasize = RSA_size(rsa);
23818de8d7fSPeter Avalos 	if (siglen == 0 || siglen > rsasize) {
23918de8d7fSPeter Avalos 		error("bad siglen");
24018de8d7fSPeter Avalos 		goto done;
24118de8d7fSPeter Avalos 	}
24218de8d7fSPeter Avalos 	decrypted = xmalloc(rsasize);
24318de8d7fSPeter Avalos 	if ((len = RSA_public_decrypt(siglen, sigbuf, decrypted, rsa,
24418de8d7fSPeter Avalos 	    RSA_PKCS1_PADDING)) < 0) {
24518de8d7fSPeter Avalos 		error("RSA_public_decrypt failed: %s",
24618de8d7fSPeter Avalos 		    ERR_error_string(ERR_get_error(), NULL));
24718de8d7fSPeter Avalos 		goto done;
24818de8d7fSPeter Avalos 	}
24918de8d7fSPeter Avalos 	if (len < 0 || (u_int)len != hlen + oidlen) {
25018de8d7fSPeter Avalos 		error("bad decrypted len: %d != %d + %d", len, hlen, oidlen);
25118de8d7fSPeter Avalos 		goto done;
25218de8d7fSPeter Avalos 	}
253*856ea928SPeter Avalos 	oidmatch = timingsafe_bcmp(decrypted, oid, oidlen) == 0;
254*856ea928SPeter Avalos 	hashmatch = timingsafe_bcmp(decrypted + oidlen, hash, hlen) == 0;
255*856ea928SPeter Avalos 	if (!oidmatch) {
25618de8d7fSPeter Avalos 		error("oid mismatch");
25718de8d7fSPeter Avalos 		goto done;
25818de8d7fSPeter Avalos 	}
259*856ea928SPeter Avalos 	if (!hashmatch) {
26018de8d7fSPeter Avalos 		error("hash mismatch");
26118de8d7fSPeter Avalos 		goto done;
26218de8d7fSPeter Avalos 	}
26318de8d7fSPeter Avalos 	ret = 1;
26418de8d7fSPeter Avalos done:
26518de8d7fSPeter Avalos 	if (decrypted)
26618de8d7fSPeter Avalos 		xfree(decrypted);
26718de8d7fSPeter Avalos 	return ret;
26818de8d7fSPeter Avalos }
269