xref: /freebsd/crypto/openssh/ssh-dss.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-dss.c,v 1.6 2001/02/08 19:30:52 itojun Exp $");
271e8db6e2SBrian Feldman 
281e8db6e2SBrian Feldman #include <openssl/bn.h>
291e8db6e2SBrian Feldman #include <openssl/evp.h>
301e8db6e2SBrian Feldman 
311e8db6e2SBrian Feldman #include "xmalloc.h"
321e8db6e2SBrian Feldman #include "buffer.h"
331e8db6e2SBrian Feldman #include "bufaux.h"
341e8db6e2SBrian Feldman #include "compat.h"
351e8db6e2SBrian Feldman #include "log.h"
361e8db6e2SBrian Feldman #include "key.h"
371e8db6e2SBrian Feldman #include "ssh-dss.h"
381e8db6e2SBrian Feldman 
391e8db6e2SBrian Feldman #define INTBLOB_LEN	20
401e8db6e2SBrian Feldman #define SIGBLOB_LEN	(2*INTBLOB_LEN)
411e8db6e2SBrian Feldman 
421e8db6e2SBrian Feldman int
431e8db6e2SBrian Feldman ssh_dss_sign(
441e8db6e2SBrian Feldman     Key *key,
451e8db6e2SBrian Feldman     u_char **sigp, int *lenp,
461e8db6e2SBrian Feldman     u_char *data, int datalen)
471e8db6e2SBrian Feldman {
481e8db6e2SBrian Feldman 	u_char *digest;
491e8db6e2SBrian Feldman 	u_char *ret;
501e8db6e2SBrian Feldman 	DSA_SIG *sig;
511e8db6e2SBrian Feldman 	EVP_MD *evp_md = EVP_sha1();
521e8db6e2SBrian Feldman 	EVP_MD_CTX md;
531e8db6e2SBrian Feldman 	u_int rlen;
541e8db6e2SBrian Feldman 	u_int slen;
551e8db6e2SBrian Feldman 	u_int len, dlen;
561e8db6e2SBrian Feldman 	u_char sigblob[SIGBLOB_LEN];
571e8db6e2SBrian Feldman 	Buffer b;
581e8db6e2SBrian Feldman 
591e8db6e2SBrian Feldman 	if (key == NULL || key->type != KEY_DSA || key->dsa == NULL) {
601e8db6e2SBrian Feldman 		error("ssh_dss_sign: no DSA key");
611e8db6e2SBrian Feldman 		return -1;
621e8db6e2SBrian Feldman 	}
631e8db6e2SBrian Feldman 	dlen = evp_md->md_size;
641e8db6e2SBrian Feldman 	digest = xmalloc(dlen);
651e8db6e2SBrian Feldman 	EVP_DigestInit(&md, evp_md);
661e8db6e2SBrian Feldman 	EVP_DigestUpdate(&md, data, datalen);
671e8db6e2SBrian Feldman 	EVP_DigestFinal(&md, digest, NULL);
681e8db6e2SBrian Feldman 
691e8db6e2SBrian Feldman 	sig = DSA_do_sign(digest, dlen, key->dsa);
701e8db6e2SBrian Feldman 	if (sig == NULL) {
711e8db6e2SBrian Feldman 		fatal("ssh_dss_sign: cannot sign");
721e8db6e2SBrian Feldman 	}
731e8db6e2SBrian Feldman 	memset(digest, 0, dlen);
741e8db6e2SBrian Feldman 	xfree(digest);
751e8db6e2SBrian Feldman 
761e8db6e2SBrian Feldman 	rlen = BN_num_bytes(sig->r);
771e8db6e2SBrian Feldman 	slen = BN_num_bytes(sig->s);
781e8db6e2SBrian Feldman 	if (rlen > INTBLOB_LEN || slen > INTBLOB_LEN) {
791e8db6e2SBrian Feldman 		error("bad sig size %d %d", rlen, slen);
801e8db6e2SBrian Feldman 		DSA_SIG_free(sig);
811e8db6e2SBrian Feldman 		return -1;
821e8db6e2SBrian Feldman 	}
831e8db6e2SBrian Feldman 	debug("sig size %d %d", rlen, slen);
841e8db6e2SBrian Feldman 
851e8db6e2SBrian Feldman 	memset(sigblob, 0, SIGBLOB_LEN);
861e8db6e2SBrian Feldman 	BN_bn2bin(sig->r, sigblob+ SIGBLOB_LEN - INTBLOB_LEN - rlen);
871e8db6e2SBrian Feldman 	BN_bn2bin(sig->s, sigblob+ SIGBLOB_LEN - slen);
881e8db6e2SBrian Feldman 	DSA_SIG_free(sig);
891e8db6e2SBrian Feldman 
901e8db6e2SBrian Feldman 	if (datafellows & SSH_BUG_SIGBLOB) {
911e8db6e2SBrian Feldman 		debug("datafellows");
921e8db6e2SBrian Feldman 		ret = xmalloc(SIGBLOB_LEN);
931e8db6e2SBrian Feldman 		memcpy(ret, sigblob, SIGBLOB_LEN);
941e8db6e2SBrian Feldman 		if (lenp != NULL)
951e8db6e2SBrian Feldman 			*lenp = SIGBLOB_LEN;
961e8db6e2SBrian Feldman 		if (sigp != NULL)
971e8db6e2SBrian Feldman 			*sigp = ret;
981e8db6e2SBrian Feldman 	} else {
991e8db6e2SBrian Feldman 		/* ietf-drafts */
1001e8db6e2SBrian Feldman 		buffer_init(&b);
1011e8db6e2SBrian Feldman 		buffer_put_cstring(&b, "ssh-dss");
1021e8db6e2SBrian Feldman 		buffer_put_string(&b, sigblob, SIGBLOB_LEN);
1031e8db6e2SBrian Feldman 		len = buffer_len(&b);
1041e8db6e2SBrian Feldman 		ret = xmalloc(len);
1051e8db6e2SBrian Feldman 		memcpy(ret, buffer_ptr(&b), len);
1061e8db6e2SBrian Feldman 		buffer_free(&b);
1071e8db6e2SBrian Feldman 		if (lenp != NULL)
1081e8db6e2SBrian Feldman 			*lenp = len;
1091e8db6e2SBrian Feldman 		if (sigp != NULL)
1101e8db6e2SBrian Feldman 			*sigp = ret;
1111e8db6e2SBrian Feldman 	}
1121e8db6e2SBrian Feldman 	return 0;
1131e8db6e2SBrian Feldman }
1141e8db6e2SBrian Feldman int
1151e8db6e2SBrian Feldman ssh_dss_verify(
1161e8db6e2SBrian Feldman     Key *key,
1171e8db6e2SBrian Feldman     u_char *signature, int signaturelen,
1181e8db6e2SBrian Feldman     u_char *data, int datalen)
1191e8db6e2SBrian Feldman {
1201e8db6e2SBrian Feldman 	Buffer b;
1211e8db6e2SBrian Feldman 	u_char *digest;
1221e8db6e2SBrian Feldman 	DSA_SIG *sig;
1231e8db6e2SBrian Feldman 	EVP_MD *evp_md = EVP_sha1();
1241e8db6e2SBrian Feldman 	EVP_MD_CTX md;
1251e8db6e2SBrian Feldman 	u_char *sigblob;
1261e8db6e2SBrian Feldman 	char *txt;
1271e8db6e2SBrian Feldman 	u_int len, dlen;
1281e8db6e2SBrian Feldman 	int rlen;
1291e8db6e2SBrian Feldman 	int ret;
1301e8db6e2SBrian Feldman 
1311e8db6e2SBrian Feldman 	if (key == NULL || key->type != KEY_DSA || key->dsa == NULL) {
1321e8db6e2SBrian Feldman 		error("ssh_dss_verify: no DSA key");
1331e8db6e2SBrian Feldman 		return -1;
1341e8db6e2SBrian Feldman 	}
1351e8db6e2SBrian Feldman 
1361e8db6e2SBrian Feldman 	if (!(datafellows & SSH_BUG_SIGBLOB) &&
1371e8db6e2SBrian Feldman 	    signaturelen == SIGBLOB_LEN) {
1381e8db6e2SBrian Feldman 		datafellows |= ~SSH_BUG_SIGBLOB;
1391e8db6e2SBrian Feldman 		log("autodetect SSH_BUG_SIGBLOB");
1401e8db6e2SBrian Feldman 	} else if ((datafellows & SSH_BUG_SIGBLOB) &&
1411e8db6e2SBrian Feldman 	    signaturelen != SIGBLOB_LEN) {
1421e8db6e2SBrian Feldman 		log("autoremove SSH_BUG_SIGBLOB");
1431e8db6e2SBrian Feldman 		datafellows &= ~SSH_BUG_SIGBLOB;
1441e8db6e2SBrian Feldman 	}
1451e8db6e2SBrian Feldman 
1461e8db6e2SBrian Feldman 	debug("len %d datafellows %d", signaturelen, datafellows);
1471e8db6e2SBrian Feldman 
1481e8db6e2SBrian Feldman 	/* fetch signature */
1491e8db6e2SBrian Feldman 	if (datafellows & SSH_BUG_SIGBLOB) {
1501e8db6e2SBrian Feldman 		sigblob = signature;
1511e8db6e2SBrian Feldman 		len = signaturelen;
1521e8db6e2SBrian Feldman 	} else {
1531e8db6e2SBrian Feldman 		/* ietf-drafts */
1541e8db6e2SBrian Feldman 		char *ktype;
1551e8db6e2SBrian Feldman 		buffer_init(&b);
1561e8db6e2SBrian Feldman 		buffer_append(&b, (char *) signature, signaturelen);
1571e8db6e2SBrian Feldman 		ktype = buffer_get_string(&b, NULL);
1581e8db6e2SBrian Feldman 		if (strcmp("ssh-dss", ktype) != 0) {
1591e8db6e2SBrian Feldman 			error("ssh_dss_verify: cannot handle type %s", ktype);
1601e8db6e2SBrian Feldman 			buffer_free(&b);
1611e8db6e2SBrian Feldman 			return -1;
1621e8db6e2SBrian Feldman 		}
1631e8db6e2SBrian Feldman 		sigblob = (u_char *)buffer_get_string(&b, &len);
1641e8db6e2SBrian Feldman 		rlen = buffer_len(&b);
1651e8db6e2SBrian Feldman 		if(rlen != 0) {
1661e8db6e2SBrian Feldman 			error("remaining bytes in signature %d", rlen);
1671e8db6e2SBrian Feldman 			buffer_free(&b);
1681e8db6e2SBrian Feldman 			return -1;
1691e8db6e2SBrian Feldman 		}
1701e8db6e2SBrian Feldman 		buffer_free(&b);
1711e8db6e2SBrian Feldman 		xfree(ktype);
1721e8db6e2SBrian Feldman 	}
1731e8db6e2SBrian Feldman 
1741e8db6e2SBrian Feldman 	if (len != SIGBLOB_LEN) {
1751e8db6e2SBrian Feldman 		fatal("bad sigbloblen %d != SIGBLOB_LEN", len);
1761e8db6e2SBrian Feldman 	}
1771e8db6e2SBrian Feldman 
1781e8db6e2SBrian Feldman 	/* parse signature */
1791e8db6e2SBrian Feldman 	sig = DSA_SIG_new();
1801e8db6e2SBrian Feldman 	sig->r = BN_new();
1811e8db6e2SBrian Feldman 	sig->s = BN_new();
1821e8db6e2SBrian Feldman 	BN_bin2bn(sigblob, INTBLOB_LEN, sig->r);
1831e8db6e2SBrian Feldman 	BN_bin2bn(sigblob+ INTBLOB_LEN, INTBLOB_LEN, sig->s);
1841e8db6e2SBrian Feldman 
1851e8db6e2SBrian Feldman 	if (!(datafellows & SSH_BUG_SIGBLOB)) {
1861e8db6e2SBrian Feldman 		memset(sigblob, 0, len);
1871e8db6e2SBrian Feldman 		xfree(sigblob);
1881e8db6e2SBrian Feldman 	}
1891e8db6e2SBrian Feldman 
1901e8db6e2SBrian Feldman 	/* sha1 the data */
1911e8db6e2SBrian Feldman 	dlen = evp_md->md_size;
1921e8db6e2SBrian Feldman 	digest = xmalloc(dlen);
1931e8db6e2SBrian Feldman 	EVP_DigestInit(&md, evp_md);
1941e8db6e2SBrian Feldman 	EVP_DigestUpdate(&md, data, datalen);
1951e8db6e2SBrian Feldman 	EVP_DigestFinal(&md, digest, NULL);
1961e8db6e2SBrian Feldman 
1971e8db6e2SBrian Feldman 	ret = DSA_do_verify(digest, dlen, sig, key->dsa);
1981e8db6e2SBrian Feldman 
1991e8db6e2SBrian Feldman 	memset(digest, 0, dlen);
2001e8db6e2SBrian Feldman 	xfree(digest);
2011e8db6e2SBrian Feldman 	DSA_SIG_free(sig);
2021e8db6e2SBrian Feldman 
2031e8db6e2SBrian Feldman 	switch (ret) {
2041e8db6e2SBrian Feldman 	case 1:
2051e8db6e2SBrian Feldman 		txt = "correct";
2061e8db6e2SBrian Feldman 		break;
2071e8db6e2SBrian Feldman 	case 0:
2081e8db6e2SBrian Feldman 		txt = "incorrect";
2091e8db6e2SBrian Feldman 		break;
2101e8db6e2SBrian Feldman 	case -1:
2111e8db6e2SBrian Feldman 	default:
2121e8db6e2SBrian Feldman 		txt = "error";
2131e8db6e2SBrian Feldman 		break;
2141e8db6e2SBrian Feldman 	}
2151e8db6e2SBrian Feldman 	debug("ssh_dss_verify: signature %s", txt);
2161e8db6e2SBrian Feldman 	return ret;
2171e8db6e2SBrian Feldman }
218