ssh-dss.c revision 92555
11553Srgrimes/*
21553Srgrimes * Copyright (c) 2000 Markus Friedl.  All rights reserved.
31553Srgrimes *
41553Srgrimes * Redistribution and use in source and binary forms, with or without
51553Srgrimes * modification, are permitted provided that the following conditions
61553Srgrimes * are met:
71553Srgrimes * 1. Redistributions of source code must retain the above copyright
81553Srgrimes *    notice, this list of conditions and the following disclaimer.
91553Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
101553Srgrimes *    notice, this list of conditions and the following disclaimer in the
111553Srgrimes *    documentation and/or other materials provided with the distribution.
121553Srgrimes *
131553Srgrimes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
141553Srgrimes * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
151553Srgrimes * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
161553Srgrimes * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
171553Srgrimes * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
181553Srgrimes * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
191553Srgrimes * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
201553Srgrimes * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
211553Srgrimes * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
221553Srgrimes * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
231553Srgrimes */
241553Srgrimes
251553Srgrimes#include "includes.h"
261553SrgrimesRCSID("$OpenBSD: ssh-dss.c,v 1.14 2002/02/28 15:46:33 markus Exp $");
271553Srgrimes
281553Srgrimes#include <openssl/bn.h>
291553Srgrimes#include <openssl/evp.h>
301553Srgrimes
3152007Speter#include "xmalloc.h"
321553Srgrimes#include "buffer.h"
331553Srgrimes#include "bufaux.h"
3479607Sdd#include "compat.h"
351553Srgrimes#include "log.h"
36205880Sru#include "key.h"
37264325Sasomers#include "ssh-dss.h"
386494Sbde
3916073Sphk#define INTBLOB_LEN	20
401553Srgrimes#define SIGBLOB_LEN	(2*INTBLOB_LEN)
411553Srgrimes
421553Srgrimesint
4379607Sddssh_dss_sign(
4479607Sdd    Key *key,
4579607Sdd    u_char **sigp, u_int *lenp,
4679607Sdd    u_char *data, u_int datalen)
4779607Sdd{
4879607Sdd	DSA_SIG *sig;
4979607Sdd	const EVP_MD *evp_md = EVP_sha1();
5079607Sdd	EVP_MD_CTX md;
5179607Sdd	u_char *ret, digest[EVP_MAX_MD_SIZE], sigblob[SIGBLOB_LEN];
5279607Sdd	u_int rlen, slen, len, dlen;
5379607Sdd	Buffer b;
5479607Sdd
5579607Sdd	if (key == NULL || key->type != KEY_DSA || key->dsa == NULL) {
561553Srgrimes		error("ssh_dss_sign: no DSA key");
571553Srgrimes		return -1;
581553Srgrimes	}
591553Srgrimes	EVP_DigestInit(&md, evp_md);
6072684Speter	EVP_DigestUpdate(&md, data, datalen);
611553Srgrimes	EVP_DigestFinal(&md, digest, &dlen);
621553Srgrimes
6346855Speter	sig = DSA_do_sign(digest, dlen, key->dsa);
641553Srgrimes	memset(digest, 'd', sizeof(digest));
65152018Sru
661553Srgrimes	if (sig == NULL) {
67141615Sdes		error("ssh_dss_sign: sign failed");
68111582Sru		return -1;
69141615Sdes	}
7082393Speter
7161640Speter	rlen = BN_num_bytes(sig->r);
721553Srgrimes	slen = BN_num_bytes(sig->s);
7352653Smarcel	if (rlen > INTBLOB_LEN || slen > INTBLOB_LEN) {
74153063Sru		error("bad sig size %d %d", rlen, slen);
751553Srgrimes		DSA_SIG_free(sig);
76111582Sru		return -1;
77152023Sru	}
781553Srgrimes	memset(sigblob, 0, SIGBLOB_LEN);
7967109Sphk	BN_bn2bin(sig->r, sigblob+ SIGBLOB_LEN - INTBLOB_LEN - rlen);
8048402Speter	BN_bn2bin(sig->s, sigblob+ SIGBLOB_LEN - slen);
811553Srgrimes	DSA_SIG_free(sig);
82111582Sru
83136429Sphk	if (datafellows & SSH_BUG_SIGBLOB) {
8479607Sdd		ret = xmalloc(SIGBLOB_LEN);
85129073Scognet		memcpy(ret, sigblob, SIGBLOB_LEN);
861553Srgrimes		if (lenp != NULL)
871553Srgrimes			*lenp = SIGBLOB_LEN;
8829451Scharnier		if (sigp != NULL)
8929451Scharnier			*sigp = ret;
9079607Sdd	} else {
9179607Sdd		/* ietf-drafts */
9261640Speter		buffer_init(&b);
9398555Sjmallett		buffer_put_cstring(&b, "ssh-dss");
9498555Sjmallett		buffer_put_string(&b, sigblob, SIGBLOB_LEN);
9579607Sdd		len = buffer_len(&b);
9629451Scharnier		ret = xmalloc(len);
97250926Sjkim		memcpy(ret, buffer_ptr(&b), len);
981553Srgrimes		buffer_free(&b);
99250227Sjkim		if (lenp != NULL)
100250227Sjkim			*lenp = len;
101250227Sjkim		if (sigp != NULL)
102250227Sjkim			*sigp = ret;
10346104Sluoqi	}
104180922Sobrien	return 0;
105134542Speter}
1061553Srgrimesint
107134542Speterssh_dss_verify(
1081553Srgrimes    Key *key,
1091553Srgrimes    u_char *signature, u_int signaturelen,
11046104Sluoqi    u_char *data, u_int datalen)
1111553Srgrimes{
1121553Srgrimes	DSA_SIG *sig;
1136494Sbde	const EVP_MD *evp_md = EVP_sha1();
1141553Srgrimes	EVP_MD_CTX md;
1151553Srgrimes	u_char digest[EVP_MAX_MD_SIZE], *sigblob;
1161553Srgrimes	u_int len, dlen;
1171553Srgrimes	int rlen, ret;
11812772Speter	Buffer b;
11946104Sluoqi
12046104Sluoqi	if (key == NULL || key->type != KEY_DSA || key->dsa == NULL) {
12146104Sluoqi		error("ssh_dss_verify: no DSA key");
12212772Speter		return -1;
12312772Speter	}
12412772Speter
1251553Srgrimes	/* fetch signature */
12646104Sluoqi	if (datafellows & SSH_BUG_SIGBLOB) {
12746104Sluoqi		sigblob = signature;
1286494Sbde		len = signaturelen;
1291553Srgrimes	} else {
1301553Srgrimes		/* ietf-drafts */
13148402Speter		char *ktype;
13246104Sluoqi		buffer_init(&b);
13346104Sluoqi		buffer_append(&b, signature, signaturelen);
13446104Sluoqi		ktype = buffer_get_string(&b, NULL);
13546104Sluoqi		if (strcmp("ssh-dss", ktype) != 0) {
1361553Srgrimes			error("ssh_dss_verify: cannot handle type %s", ktype);
1371553Srgrimes			buffer_free(&b);
1381553Srgrimes			xfree(ktype);
1391553Srgrimes			return -1;
1401553Srgrimes		}
1411553Srgrimes		xfree(ktype);
1421553Srgrimes		sigblob = buffer_get_string(&b, &len);
1431553Srgrimes		rlen = buffer_len(&b);
14446104Sluoqi		buffer_free(&b);
14546021Speter		if (rlen != 0) {
14646021Speter			error("ssh_dss_verify: "
14746021Speter			    "remaining bytes in signature %d", rlen);
1481553Srgrimes			xfree(sigblob);
1491553Srgrimes			return -1;
1501553Srgrimes		}
1511553Srgrimes	}
1521553Srgrimes
1531553Srgrimes	if (len != SIGBLOB_LEN) {
1541553Srgrimes		fatal("bad sigbloblen %d != SIGBLOB_LEN", len);
1551553Srgrimes	}
1561553Srgrimes
1571553Srgrimes	/* parse signature */
1581553Srgrimes	if ((sig = DSA_SIG_new()) == NULL)
1591553Srgrimes		fatal("ssh_dss_verify: DSA_SIG_new failed");
1604242Swollman	if ((sig->r = BN_new()) == NULL)
1611553Srgrimes		fatal("ssh_dss_verify: BN_new failed");
1621553Srgrimes	if ((sig->s = BN_new()) == NULL)
16346104Sluoqi		fatal("ssh_dss_verify: BN_new failed");
164185186Sthompsa	BN_bin2bn(sigblob, INTBLOB_LEN, sig->r);
16579607Sdd	BN_bin2bn(sigblob+ INTBLOB_LEN, INTBLOB_LEN, sig->s);
16679607Sdd
16779607Sdd	if (!(datafellows & SSH_BUG_SIGBLOB)) {
16879607Sdd		memset(sigblob, 0, len);
16979607Sdd		xfree(sigblob);
17079607Sdd	}
17179607Sdd
17279607Sdd	/* sha1 the data */
17379607Sdd	EVP_DigestInit(&md, evp_md);
17479607Sdd	EVP_DigestUpdate(&md, data, datalen);
175180922Sobrien	EVP_DigestFinal(&md, digest, &dlen);
176180922Sobrien
177180922Sobrien	ret = DSA_do_verify(digest, dlen, sig, key->dsa);
178180922Sobrien	memset(digest, 'd', sizeof(digest));
179180922Sobrien
1801553Srgrimes	DSA_SIG_free(sig);
1811553Srgrimes
1821553Srgrimes	debug("ssh_dss_verify: signature %s",
1831553Srgrimes	    ret == 1 ? "correct" : ret == 0 ? "incorrect" : "error");
1841553Srgrimes	return ret;
1851553Srgrimes}
1861553Srgrimes