xref: /freebsd/crypto/openssh/ssh-rsa.c (revision 1e8db6e2f63ea90b361b3bbc9ebe9990660cb596)
11e8db6e2SBrian Feldman /*
21e8db6e2SBrian Feldman  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
31e8db6e2SBrian Feldman  *
41e8db6e2SBrian Feldman  * Redistribution and use in source and binary forms, with or without
51e8db6e2SBrian Feldman  * modification, are permitted provided that the following conditions
61e8db6e2SBrian Feldman  * are met:
71e8db6e2SBrian Feldman  * 1. Redistributions of source code must retain the above copyright
81e8db6e2SBrian Feldman  *    notice, this list of conditions and the following disclaimer.
91e8db6e2SBrian Feldman  * 2. Redistributions in binary form must reproduce the above copyright
101e8db6e2SBrian Feldman  *    notice, this list of conditions and the following disclaimer in the
111e8db6e2SBrian Feldman  *    documentation and/or other materials provided with the distribution.
121e8db6e2SBrian Feldman  *
131e8db6e2SBrian Feldman  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
141e8db6e2SBrian Feldman  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
151e8db6e2SBrian Feldman  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
161e8db6e2SBrian Feldman  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
171e8db6e2SBrian Feldman  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
181e8db6e2SBrian Feldman  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
191e8db6e2SBrian Feldman  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
201e8db6e2SBrian Feldman  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
211e8db6e2SBrian Feldman  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
221e8db6e2SBrian Feldman  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
231e8db6e2SBrian Feldman  */
241e8db6e2SBrian Feldman 
251e8db6e2SBrian Feldman #include "includes.h"
261e8db6e2SBrian Feldman RCSID("$OpenBSD: ssh-rsa.c,v 1.8 2001/03/27 10:57:00 markus Exp $");
271e8db6e2SBrian Feldman 
281e8db6e2SBrian Feldman #include <openssl/evp.h>
291e8db6e2SBrian Feldman #include <openssl/err.h>
301e8db6e2SBrian Feldman 
311e8db6e2SBrian Feldman #include "xmalloc.h"
321e8db6e2SBrian Feldman #include "log.h"
331e8db6e2SBrian Feldman #include "buffer.h"
341e8db6e2SBrian Feldman #include "bufaux.h"
351e8db6e2SBrian Feldman #include "key.h"
361e8db6e2SBrian Feldman #include "ssh-rsa.h"
371e8db6e2SBrian Feldman #include "compat.h"
381e8db6e2SBrian Feldman 
391e8db6e2SBrian Feldman /* RSASSA-PKCS1-v1_5 (PKCS #1 v2.0 signature) with SHA1 */
401e8db6e2SBrian Feldman int
411e8db6e2SBrian Feldman ssh_rsa_sign(
421e8db6e2SBrian Feldman     Key *key,
431e8db6e2SBrian Feldman     u_char **sigp, int *lenp,
441e8db6e2SBrian Feldman     u_char *data, int datalen)
451e8db6e2SBrian Feldman {
461e8db6e2SBrian Feldman 	const EVP_MD *evp_md;
471e8db6e2SBrian Feldman 	EVP_MD_CTX md;
481e8db6e2SBrian Feldman 	u_char *digest, *sig, *ret;
491e8db6e2SBrian Feldman 	u_int slen, dlen, len;
501e8db6e2SBrian Feldman 	int ok, nid;
511e8db6e2SBrian Feldman 	Buffer b;
521e8db6e2SBrian Feldman 
531e8db6e2SBrian Feldman 	if (key == NULL || key->type != KEY_RSA || key->rsa == NULL) {
541e8db6e2SBrian Feldman 		error("ssh_rsa_sign: no RSA key");
551e8db6e2SBrian Feldman 		return -1;
561e8db6e2SBrian Feldman 	}
571e8db6e2SBrian Feldman 	nid = (datafellows & SSH_BUG_RSASIGMD5) ? NID_md5 : NID_sha1;
581e8db6e2SBrian Feldman 	if ((evp_md = EVP_get_digestbynid(nid)) == NULL) {
591e8db6e2SBrian Feldman 		error("ssh_rsa_sign: EVP_get_digestbynid %d failed", nid);
601e8db6e2SBrian Feldman 		return -1;
611e8db6e2SBrian Feldman 	}
621e8db6e2SBrian Feldman 	dlen = evp_md->md_size;
631e8db6e2SBrian Feldman 	digest = xmalloc(dlen);
641e8db6e2SBrian Feldman 	EVP_DigestInit(&md, evp_md);
651e8db6e2SBrian Feldman 	EVP_DigestUpdate(&md, data, datalen);
661e8db6e2SBrian Feldman 	EVP_DigestFinal(&md, digest, NULL);
671e8db6e2SBrian Feldman 
681e8db6e2SBrian Feldman 	slen = RSA_size(key->rsa);
691e8db6e2SBrian Feldman 	sig = xmalloc(slen);
701e8db6e2SBrian Feldman 
711e8db6e2SBrian Feldman 	ok = RSA_sign(nid, digest, dlen, sig, &len, key->rsa);
721e8db6e2SBrian Feldman 	memset(digest, 'd', dlen);
731e8db6e2SBrian Feldman 	xfree(digest);
741e8db6e2SBrian Feldman 
751e8db6e2SBrian Feldman 	if (ok != 1) {
761e8db6e2SBrian Feldman 		int ecode = ERR_get_error();
771e8db6e2SBrian Feldman 		error("ssh_rsa_sign: RSA_sign failed: %s", ERR_error_string(ecode, NULL));
781e8db6e2SBrian Feldman 		xfree(sig);
791e8db6e2SBrian Feldman 		return -1;
801e8db6e2SBrian Feldman 	}
811e8db6e2SBrian Feldman 	if (len < slen) {
821e8db6e2SBrian Feldman 		int diff = slen - len;
831e8db6e2SBrian Feldman 		debug("slen %d > len %d", slen, len);
841e8db6e2SBrian Feldman 		memmove(sig + diff, sig, len);
851e8db6e2SBrian Feldman 		memset(sig, 0, diff);
861e8db6e2SBrian Feldman 	} else if (len > slen) {
871e8db6e2SBrian Feldman 		error("ssh_rsa_sign: slen %d slen2 %d", slen, len);
881e8db6e2SBrian Feldman 		xfree(sig);
891e8db6e2SBrian Feldman 		return -1;
901e8db6e2SBrian Feldman 	}
911e8db6e2SBrian Feldman 	/* encode signature */
921e8db6e2SBrian Feldman 	buffer_init(&b);
931e8db6e2SBrian Feldman 	buffer_put_cstring(&b, "ssh-rsa");
941e8db6e2SBrian Feldman 	buffer_put_string(&b, sig, slen);
951e8db6e2SBrian Feldman 	len = buffer_len(&b);
961e8db6e2SBrian Feldman 	ret = xmalloc(len);
971e8db6e2SBrian Feldman 	memcpy(ret, buffer_ptr(&b), len);
981e8db6e2SBrian Feldman 	buffer_free(&b);
991e8db6e2SBrian Feldman 	memset(sig, 's', slen);
1001e8db6e2SBrian Feldman 	xfree(sig);
1011e8db6e2SBrian Feldman 
1021e8db6e2SBrian Feldman 	if (lenp != NULL)
1031e8db6e2SBrian Feldman 		*lenp = len;
1041e8db6e2SBrian Feldman 	if (sigp != NULL)
1051e8db6e2SBrian Feldman 		*sigp = ret;
1061e8db6e2SBrian Feldman 	debug2("ssh_rsa_sign: done");
1071e8db6e2SBrian Feldman 	return 0;
1081e8db6e2SBrian Feldman }
1091e8db6e2SBrian Feldman 
1101e8db6e2SBrian Feldman int
1111e8db6e2SBrian Feldman ssh_rsa_verify(
1121e8db6e2SBrian Feldman     Key *key,
1131e8db6e2SBrian Feldman     u_char *signature, int signaturelen,
1141e8db6e2SBrian Feldman     u_char *data, int datalen)
1151e8db6e2SBrian Feldman {
1161e8db6e2SBrian Feldman 	Buffer b;
1171e8db6e2SBrian Feldman 	const EVP_MD *evp_md;
1181e8db6e2SBrian Feldman 	EVP_MD_CTX md;
1191e8db6e2SBrian Feldman 	char *ktype;
1201e8db6e2SBrian Feldman 	u_char *sigblob, *digest;
1211e8db6e2SBrian Feldman 	u_int len, dlen;
1221e8db6e2SBrian Feldman 	int rlen, ret, nid;
1231e8db6e2SBrian Feldman 
1241e8db6e2SBrian Feldman 	if (key == NULL || key->type != KEY_RSA || key->rsa == NULL) {
1251e8db6e2SBrian Feldman 		error("ssh_rsa_verify: no RSA key");
1261e8db6e2SBrian Feldman 		return -1;
1271e8db6e2SBrian Feldman 	}
1281e8db6e2SBrian Feldman 	if (BN_num_bits(key->rsa->n) < 768) {
1291e8db6e2SBrian Feldman 		error("ssh_rsa_verify: n too small: %d bits",
1301e8db6e2SBrian Feldman 		    BN_num_bits(key->rsa->n));
1311e8db6e2SBrian Feldman 		return -1;
1321e8db6e2SBrian Feldman 	}
1331e8db6e2SBrian Feldman 	buffer_init(&b);
1341e8db6e2SBrian Feldman 	buffer_append(&b, (char *) signature, signaturelen);
1351e8db6e2SBrian Feldman 	ktype = buffer_get_string(&b, NULL);
1361e8db6e2SBrian Feldman 	if (strcmp("ssh-rsa", ktype) != 0) {
1371e8db6e2SBrian Feldman 		error("ssh_rsa_verify: cannot handle type %s", ktype);
1381e8db6e2SBrian Feldman 		buffer_free(&b);
1391e8db6e2SBrian Feldman 		xfree(ktype);
1401e8db6e2SBrian Feldman 		return -1;
1411e8db6e2SBrian Feldman 	}
1421e8db6e2SBrian Feldman 	xfree(ktype);
1431e8db6e2SBrian Feldman 	sigblob = (u_char *)buffer_get_string(&b, &len);
1441e8db6e2SBrian Feldman 	rlen = buffer_len(&b);
1451e8db6e2SBrian Feldman 	buffer_free(&b);
1461e8db6e2SBrian Feldman 	if(rlen != 0) {
1471e8db6e2SBrian Feldman 		xfree(sigblob);
1481e8db6e2SBrian Feldman 		error("ssh_rsa_verify: remaining bytes in signature %d", rlen);
1491e8db6e2SBrian Feldman 		return -1;
1501e8db6e2SBrian Feldman 	}
1511e8db6e2SBrian Feldman 	nid = (datafellows & SSH_BUG_RSASIGMD5) ? NID_md5 : NID_sha1;
1521e8db6e2SBrian Feldman 	if ((evp_md = EVP_get_digestbynid(nid)) == NULL) {
1531e8db6e2SBrian Feldman 		xfree(sigblob);
1541e8db6e2SBrian Feldman 		error("ssh_rsa_verify: EVP_get_digestbynid %d failed", nid);
1551e8db6e2SBrian Feldman 		return -1;
1561e8db6e2SBrian Feldman 	}
1571e8db6e2SBrian Feldman 	dlen = evp_md->md_size;
1581e8db6e2SBrian Feldman 	digest = xmalloc(dlen);
1591e8db6e2SBrian Feldman 	EVP_DigestInit(&md, evp_md);
1601e8db6e2SBrian Feldman 	EVP_DigestUpdate(&md, data, datalen);
1611e8db6e2SBrian Feldman 	EVP_DigestFinal(&md, digest, NULL);
1621e8db6e2SBrian Feldman 
1631e8db6e2SBrian Feldman 	ret = RSA_verify(nid, digest, dlen, sigblob, len, key->rsa);
1641e8db6e2SBrian Feldman 	memset(digest, 'd', dlen);
1651e8db6e2SBrian Feldman 	xfree(digest);
1661e8db6e2SBrian Feldman 	memset(sigblob, 's', len);
1671e8db6e2SBrian Feldman 	xfree(sigblob);
1681e8db6e2SBrian Feldman 	if (ret == 0) {
1691e8db6e2SBrian Feldman 		int ecode = ERR_get_error();
1701e8db6e2SBrian Feldman 		error("ssh_rsa_verify: RSA_verify failed: %s", ERR_error_string(ecode, NULL));
1711e8db6e2SBrian Feldman 	}
1721e8db6e2SBrian Feldman 	debug("ssh_rsa_verify: signature %scorrect", (ret==0) ? "in" : "");
1731e8db6e2SBrian Feldman 	return ret;
1741e8db6e2SBrian Feldman }
175