xref: /titanic_50/usr/src/cmd/ssh/libssh/common/ssh-dss.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * Redistribution and use in source and binary forms, with or without
5*7c478bd9Sstevel@tonic-gate  * modification, are permitted provided that the following conditions
6*7c478bd9Sstevel@tonic-gate  * are met:
7*7c478bd9Sstevel@tonic-gate  * 1. Redistributions of source code must retain the above copyright
8*7c478bd9Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer.
9*7c478bd9Sstevel@tonic-gate  * 2. Redistributions in binary form must reproduce the above copyright
10*7c478bd9Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer in the
11*7c478bd9Sstevel@tonic-gate  *    documentation and/or other materials provided with the distribution.
12*7c478bd9Sstevel@tonic-gate  *
13*7c478bd9Sstevel@tonic-gate  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14*7c478bd9Sstevel@tonic-gate  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15*7c478bd9Sstevel@tonic-gate  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16*7c478bd9Sstevel@tonic-gate  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17*7c478bd9Sstevel@tonic-gate  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18*7c478bd9Sstevel@tonic-gate  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19*7c478bd9Sstevel@tonic-gate  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20*7c478bd9Sstevel@tonic-gate  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21*7c478bd9Sstevel@tonic-gate  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22*7c478bd9Sstevel@tonic-gate  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23*7c478bd9Sstevel@tonic-gate  */
24*7c478bd9Sstevel@tonic-gate 
25*7c478bd9Sstevel@tonic-gate #include "includes.h"
26*7c478bd9Sstevel@tonic-gate RCSID("$OpenBSD: ssh-dss.c,v 1.17 2002/07/04 10:41:47 markus Exp $");
27*7c478bd9Sstevel@tonic-gate 
28*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
29*7c478bd9Sstevel@tonic-gate 
30*7c478bd9Sstevel@tonic-gate #include <openssl/bn.h>
31*7c478bd9Sstevel@tonic-gate #include <openssl/evp.h>
32*7c478bd9Sstevel@tonic-gate 
33*7c478bd9Sstevel@tonic-gate #include "xmalloc.h"
34*7c478bd9Sstevel@tonic-gate #include "buffer.h"
35*7c478bd9Sstevel@tonic-gate #include "bufaux.h"
36*7c478bd9Sstevel@tonic-gate #include "compat.h"
37*7c478bd9Sstevel@tonic-gate #include "log.h"
38*7c478bd9Sstevel@tonic-gate #include "key.h"
39*7c478bd9Sstevel@tonic-gate #include "ssh-dss.h"
40*7c478bd9Sstevel@tonic-gate 
41*7c478bd9Sstevel@tonic-gate #define INTBLOB_LEN	20
42*7c478bd9Sstevel@tonic-gate #define SIGBLOB_LEN	(2*INTBLOB_LEN)
43*7c478bd9Sstevel@tonic-gate 
44*7c478bd9Sstevel@tonic-gate int
ssh_dss_sign(Key * key,u_char ** sigp,u_int * lenp,u_char * data,u_int datalen)45*7c478bd9Sstevel@tonic-gate ssh_dss_sign(Key *key, u_char **sigp, u_int *lenp,
46*7c478bd9Sstevel@tonic-gate     u_char *data, u_int datalen)
47*7c478bd9Sstevel@tonic-gate {
48*7c478bd9Sstevel@tonic-gate 	DSA_SIG *sig;
49*7c478bd9Sstevel@tonic-gate 	const EVP_MD *evp_md = EVP_sha1();
50*7c478bd9Sstevel@tonic-gate 	EVP_MD_CTX md;
51*7c478bd9Sstevel@tonic-gate 	u_char digest[EVP_MAX_MD_SIZE], sigblob[SIGBLOB_LEN];
52*7c478bd9Sstevel@tonic-gate 	u_int rlen, slen, len, dlen;
53*7c478bd9Sstevel@tonic-gate 	Buffer b;
54*7c478bd9Sstevel@tonic-gate 
55*7c478bd9Sstevel@tonic-gate 	if (key == NULL || key->type != KEY_DSA || key->dsa == NULL) {
56*7c478bd9Sstevel@tonic-gate 		error("ssh_dss_sign: no DSA key");
57*7c478bd9Sstevel@tonic-gate 		return -1;
58*7c478bd9Sstevel@tonic-gate 	}
59*7c478bd9Sstevel@tonic-gate 	EVP_DigestInit(&md, evp_md);
60*7c478bd9Sstevel@tonic-gate 	EVP_DigestUpdate(&md, data, datalen);
61*7c478bd9Sstevel@tonic-gate 	EVP_DigestFinal(&md, digest, &dlen);
62*7c478bd9Sstevel@tonic-gate 
63*7c478bd9Sstevel@tonic-gate 	sig = DSA_do_sign(digest, dlen, key->dsa);
64*7c478bd9Sstevel@tonic-gate 	memset(digest, 'd', sizeof(digest));
65*7c478bd9Sstevel@tonic-gate 
66*7c478bd9Sstevel@tonic-gate 	if (sig == NULL) {
67*7c478bd9Sstevel@tonic-gate 		error("ssh_dss_sign: sign failed");
68*7c478bd9Sstevel@tonic-gate 		return -1;
69*7c478bd9Sstevel@tonic-gate 	}
70*7c478bd9Sstevel@tonic-gate 
71*7c478bd9Sstevel@tonic-gate 	rlen = BN_num_bytes(sig->r);
72*7c478bd9Sstevel@tonic-gate 	slen = BN_num_bytes(sig->s);
73*7c478bd9Sstevel@tonic-gate 	if (rlen > INTBLOB_LEN || slen > INTBLOB_LEN) {
74*7c478bd9Sstevel@tonic-gate 		error("bad sig size %u %u", rlen, slen);
75*7c478bd9Sstevel@tonic-gate 		DSA_SIG_free(sig);
76*7c478bd9Sstevel@tonic-gate 		return -1;
77*7c478bd9Sstevel@tonic-gate 	}
78*7c478bd9Sstevel@tonic-gate 	memset(sigblob, 0, SIGBLOB_LEN);
79*7c478bd9Sstevel@tonic-gate 	BN_bn2bin(sig->r, sigblob+ SIGBLOB_LEN - INTBLOB_LEN - rlen);
80*7c478bd9Sstevel@tonic-gate 	BN_bn2bin(sig->s, sigblob+ SIGBLOB_LEN - slen);
81*7c478bd9Sstevel@tonic-gate 	DSA_SIG_free(sig);
82*7c478bd9Sstevel@tonic-gate 
83*7c478bd9Sstevel@tonic-gate 	if (datafellows & SSH_BUG_SIGBLOB) {
84*7c478bd9Sstevel@tonic-gate 		if (lenp != NULL)
85*7c478bd9Sstevel@tonic-gate 			*lenp = SIGBLOB_LEN;
86*7c478bd9Sstevel@tonic-gate 		if (sigp != NULL) {
87*7c478bd9Sstevel@tonic-gate 			*sigp = xmalloc(SIGBLOB_LEN);
88*7c478bd9Sstevel@tonic-gate 			memcpy(*sigp, sigblob, SIGBLOB_LEN);
89*7c478bd9Sstevel@tonic-gate 		}
90*7c478bd9Sstevel@tonic-gate 	} else {
91*7c478bd9Sstevel@tonic-gate 		/* ietf-drafts */
92*7c478bd9Sstevel@tonic-gate 		buffer_init(&b);
93*7c478bd9Sstevel@tonic-gate 		buffer_put_cstring(&b, "ssh-dss");
94*7c478bd9Sstevel@tonic-gate 		buffer_put_string(&b, sigblob, SIGBLOB_LEN);
95*7c478bd9Sstevel@tonic-gate 		len = buffer_len(&b);
96*7c478bd9Sstevel@tonic-gate 		if (lenp != NULL)
97*7c478bd9Sstevel@tonic-gate 			*lenp = len;
98*7c478bd9Sstevel@tonic-gate 		if (sigp != NULL) {
99*7c478bd9Sstevel@tonic-gate 			*sigp = xmalloc(len);
100*7c478bd9Sstevel@tonic-gate 			memcpy(*sigp, buffer_ptr(&b), len);
101*7c478bd9Sstevel@tonic-gate 		}
102*7c478bd9Sstevel@tonic-gate 		buffer_free(&b);
103*7c478bd9Sstevel@tonic-gate 	}
104*7c478bd9Sstevel@tonic-gate 	return 0;
105*7c478bd9Sstevel@tonic-gate }
106*7c478bd9Sstevel@tonic-gate int
ssh_dss_verify(Key * key,u_char * signature,u_int signaturelen,u_char * data,u_int datalen)107*7c478bd9Sstevel@tonic-gate ssh_dss_verify(Key *key, u_char *signature, u_int signaturelen,
108*7c478bd9Sstevel@tonic-gate     u_char *data, u_int datalen)
109*7c478bd9Sstevel@tonic-gate {
110*7c478bd9Sstevel@tonic-gate 	DSA_SIG *sig;
111*7c478bd9Sstevel@tonic-gate 	const EVP_MD *evp_md = EVP_sha1();
112*7c478bd9Sstevel@tonic-gate 	EVP_MD_CTX md;
113*7c478bd9Sstevel@tonic-gate 	u_char digest[EVP_MAX_MD_SIZE], *sigblob;
114*7c478bd9Sstevel@tonic-gate 	u_int len, dlen;
115*7c478bd9Sstevel@tonic-gate 	int rlen, ret;
116*7c478bd9Sstevel@tonic-gate 	Buffer b;
117*7c478bd9Sstevel@tonic-gate 
118*7c478bd9Sstevel@tonic-gate 	if (key == NULL || key->type != KEY_DSA || key->dsa == NULL) {
119*7c478bd9Sstevel@tonic-gate 		error("ssh_dss_verify: no DSA key");
120*7c478bd9Sstevel@tonic-gate 		return -1;
121*7c478bd9Sstevel@tonic-gate 	}
122*7c478bd9Sstevel@tonic-gate 
123*7c478bd9Sstevel@tonic-gate 	/* fetch signature */
124*7c478bd9Sstevel@tonic-gate 	if (datafellows & SSH_BUG_SIGBLOB) {
125*7c478bd9Sstevel@tonic-gate 		sigblob = signature;
126*7c478bd9Sstevel@tonic-gate 		len = signaturelen;
127*7c478bd9Sstevel@tonic-gate 	} else {
128*7c478bd9Sstevel@tonic-gate 		/* ietf-drafts */
129*7c478bd9Sstevel@tonic-gate 		char *ktype;
130*7c478bd9Sstevel@tonic-gate 		buffer_init(&b);
131*7c478bd9Sstevel@tonic-gate 		buffer_append(&b, signature, signaturelen);
132*7c478bd9Sstevel@tonic-gate 		ktype = buffer_get_string(&b, NULL);
133*7c478bd9Sstevel@tonic-gate 		if (strcmp("ssh-dss", ktype) != 0) {
134*7c478bd9Sstevel@tonic-gate 			error("ssh_dss_verify: cannot handle type %s", ktype);
135*7c478bd9Sstevel@tonic-gate 			buffer_free(&b);
136*7c478bd9Sstevel@tonic-gate 			xfree(ktype);
137*7c478bd9Sstevel@tonic-gate 			return -1;
138*7c478bd9Sstevel@tonic-gate 		}
139*7c478bd9Sstevel@tonic-gate 		xfree(ktype);
140*7c478bd9Sstevel@tonic-gate 		sigblob = buffer_get_string(&b, &len);
141*7c478bd9Sstevel@tonic-gate 		rlen = buffer_len(&b);
142*7c478bd9Sstevel@tonic-gate 		buffer_free(&b);
143*7c478bd9Sstevel@tonic-gate 		if (rlen != 0) {
144*7c478bd9Sstevel@tonic-gate 			error("ssh_dss_verify: "
145*7c478bd9Sstevel@tonic-gate 			    "remaining bytes in signature %d", rlen);
146*7c478bd9Sstevel@tonic-gate 			xfree(sigblob);
147*7c478bd9Sstevel@tonic-gate 			return -1;
148*7c478bd9Sstevel@tonic-gate 		}
149*7c478bd9Sstevel@tonic-gate 	}
150*7c478bd9Sstevel@tonic-gate 
151*7c478bd9Sstevel@tonic-gate 	if (len != SIGBLOB_LEN) {
152*7c478bd9Sstevel@tonic-gate 		fatal("bad sigbloblen %u != SIGBLOB_LEN", len);
153*7c478bd9Sstevel@tonic-gate 	}
154*7c478bd9Sstevel@tonic-gate 
155*7c478bd9Sstevel@tonic-gate 	/* parse signature */
156*7c478bd9Sstevel@tonic-gate 	if ((sig = DSA_SIG_new()) == NULL)
157*7c478bd9Sstevel@tonic-gate 		fatal("ssh_dss_verify: DSA_SIG_new failed");
158*7c478bd9Sstevel@tonic-gate 	if ((sig->r = BN_new()) == NULL)
159*7c478bd9Sstevel@tonic-gate 		fatal("ssh_dss_verify: BN_new failed");
160*7c478bd9Sstevel@tonic-gate 	if ((sig->s = BN_new()) == NULL)
161*7c478bd9Sstevel@tonic-gate 		fatal("ssh_dss_verify: BN_new failed");
162*7c478bd9Sstevel@tonic-gate 	BN_bin2bn(sigblob, INTBLOB_LEN, sig->r);
163*7c478bd9Sstevel@tonic-gate 	BN_bin2bn(sigblob+ INTBLOB_LEN, INTBLOB_LEN, sig->s);
164*7c478bd9Sstevel@tonic-gate 
165*7c478bd9Sstevel@tonic-gate 	if (!(datafellows & SSH_BUG_SIGBLOB)) {
166*7c478bd9Sstevel@tonic-gate 		memset(sigblob, 0, len);
167*7c478bd9Sstevel@tonic-gate 		xfree(sigblob);
168*7c478bd9Sstevel@tonic-gate 	}
169*7c478bd9Sstevel@tonic-gate 
170*7c478bd9Sstevel@tonic-gate 	/* sha1 the data */
171*7c478bd9Sstevel@tonic-gate 	EVP_DigestInit(&md, evp_md);
172*7c478bd9Sstevel@tonic-gate 	EVP_DigestUpdate(&md, data, datalen);
173*7c478bd9Sstevel@tonic-gate 	EVP_DigestFinal(&md, digest, &dlen);
174*7c478bd9Sstevel@tonic-gate 
175*7c478bd9Sstevel@tonic-gate 	ret = DSA_do_verify(digest, dlen, sig, key->dsa);
176*7c478bd9Sstevel@tonic-gate 	memset(digest, 'd', sizeof(digest));
177*7c478bd9Sstevel@tonic-gate 
178*7c478bd9Sstevel@tonic-gate 	DSA_SIG_free(sig);
179*7c478bd9Sstevel@tonic-gate 
180*7c478bd9Sstevel@tonic-gate 	debug("ssh_dss_verify: signature %s",
181*7c478bd9Sstevel@tonic-gate 	    ret == 1 ? "correct" : ret == 0 ? "incorrect" : "error");
182*7c478bd9Sstevel@tonic-gate 	return ret;
183*7c478bd9Sstevel@tonic-gate }
184