xref: /freebsd/crypto/openssh/ssh-dss.c (revision a0ee8cc636cd5c2374ec44ca71226564ea0bca95)
1*a0ee8cc6SDag-Erling Smørgrav /* $OpenBSD: ssh-dss.c,v 1.32 2014/06/24 01:13:21 djm Exp $ */
21e8db6e2SBrian Feldman /*
31e8db6e2SBrian Feldman  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
41e8db6e2SBrian Feldman  *
51e8db6e2SBrian Feldman  * Redistribution and use in source and binary forms, with or without
61e8db6e2SBrian Feldman  * modification, are permitted provided that the following conditions
71e8db6e2SBrian Feldman  * are met:
81e8db6e2SBrian Feldman  * 1. Redistributions of source code must retain the above copyright
91e8db6e2SBrian Feldman  *    notice, this list of conditions and the following disclaimer.
101e8db6e2SBrian Feldman  * 2. Redistributions in binary form must reproduce the above copyright
111e8db6e2SBrian Feldman  *    notice, this list of conditions and the following disclaimer in the
121e8db6e2SBrian Feldman  *    documentation and/or other materials provided with the distribution.
131e8db6e2SBrian Feldman  *
141e8db6e2SBrian Feldman  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
151e8db6e2SBrian Feldman  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
161e8db6e2SBrian Feldman  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
171e8db6e2SBrian Feldman  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
181e8db6e2SBrian Feldman  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
191e8db6e2SBrian Feldman  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
201e8db6e2SBrian Feldman  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
211e8db6e2SBrian Feldman  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
221e8db6e2SBrian Feldman  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
231e8db6e2SBrian Feldman  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
241e8db6e2SBrian Feldman  */
251e8db6e2SBrian Feldman 
261e8db6e2SBrian Feldman #include "includes.h"
27761efaa7SDag-Erling Smørgrav 
28761efaa7SDag-Erling Smørgrav #include <sys/types.h>
291e8db6e2SBrian Feldman 
301e8db6e2SBrian Feldman #include <openssl/bn.h>
31*a0ee8cc6SDag-Erling Smørgrav #include <openssl/dsa.h>
321e8db6e2SBrian Feldman #include <openssl/evp.h>
331e8db6e2SBrian Feldman 
34761efaa7SDag-Erling Smørgrav #include <stdarg.h>
35761efaa7SDag-Erling Smørgrav #include <string.h>
36761efaa7SDag-Erling Smørgrav 
37*a0ee8cc6SDag-Erling Smørgrav #include "sshbuf.h"
381e8db6e2SBrian Feldman #include "compat.h"
39*a0ee8cc6SDag-Erling Smørgrav #include "ssherr.h"
40f7167e0eSDag-Erling Smørgrav #include "digest.h"
41*a0ee8cc6SDag-Erling Smørgrav #define SSHKEY_INTERNAL
42*a0ee8cc6SDag-Erling Smørgrav #include "sshkey.h"
431e8db6e2SBrian Feldman 
441e8db6e2SBrian Feldman #define INTBLOB_LEN	20
451e8db6e2SBrian Feldman #define SIGBLOB_LEN	(2*INTBLOB_LEN)
461e8db6e2SBrian Feldman 
471e8db6e2SBrian Feldman int
48*a0ee8cc6SDag-Erling Smørgrav ssh_dss_sign(const struct sshkey *key, u_char **sigp, size_t *lenp,
49*a0ee8cc6SDag-Erling Smørgrav     const u_char *data, size_t datalen, u_int compat)
501e8db6e2SBrian Feldman {
51*a0ee8cc6SDag-Erling Smørgrav 	DSA_SIG *sig = NULL;
52f7167e0eSDag-Erling Smørgrav 	u_char digest[SSH_DIGEST_MAX_LENGTH], sigblob[SIGBLOB_LEN];
53*a0ee8cc6SDag-Erling Smørgrav 	size_t rlen, slen, len, dlen = ssh_digest_bytes(SSH_DIGEST_SHA1);
54*a0ee8cc6SDag-Erling Smørgrav 	struct sshbuf *b = NULL;
55*a0ee8cc6SDag-Erling Smørgrav 	int ret = SSH_ERR_INVALID_ARGUMENT;
561e8db6e2SBrian Feldman 
57*a0ee8cc6SDag-Erling Smørgrav 	if (lenp != NULL)
58*a0ee8cc6SDag-Erling Smørgrav 		*lenp = 0;
59*a0ee8cc6SDag-Erling Smørgrav 	if (sigp != NULL)
60*a0ee8cc6SDag-Erling Smørgrav 		*sigp = NULL;
61f7167e0eSDag-Erling Smørgrav 
62*a0ee8cc6SDag-Erling Smørgrav 	if (key == NULL || key->dsa == NULL ||
63*a0ee8cc6SDag-Erling Smørgrav 	    sshkey_type_plain(key->type) != KEY_DSA)
64*a0ee8cc6SDag-Erling Smørgrav 		return SSH_ERR_INVALID_ARGUMENT;
65*a0ee8cc6SDag-Erling Smørgrav 	if (dlen == 0)
66*a0ee8cc6SDag-Erling Smørgrav 		return SSH_ERR_INTERNAL_ERROR;
671e8db6e2SBrian Feldman 
68*a0ee8cc6SDag-Erling Smørgrav 	if ((ret = ssh_digest_memory(SSH_DIGEST_SHA1, data, datalen,
69*a0ee8cc6SDag-Erling Smørgrav 	    digest, sizeof(digest))) != 0)
70*a0ee8cc6SDag-Erling Smørgrav 		goto out;
71ae1f160dSDag-Erling Smørgrav 
72*a0ee8cc6SDag-Erling Smørgrav 	if ((sig = DSA_do_sign(digest, dlen, key->dsa)) == NULL) {
73*a0ee8cc6SDag-Erling Smørgrav 		ret = SSH_ERR_LIBCRYPTO_ERROR;
74*a0ee8cc6SDag-Erling Smørgrav 		goto out;
751e8db6e2SBrian Feldman 	}
761e8db6e2SBrian Feldman 
771e8db6e2SBrian Feldman 	rlen = BN_num_bytes(sig->r);
781e8db6e2SBrian Feldman 	slen = BN_num_bytes(sig->s);
791e8db6e2SBrian Feldman 	if (rlen > INTBLOB_LEN || slen > INTBLOB_LEN) {
80*a0ee8cc6SDag-Erling Smørgrav 		ret = SSH_ERR_INTERNAL_ERROR;
81*a0ee8cc6SDag-Erling Smørgrav 		goto out;
821e8db6e2SBrian Feldman 	}
83b83788ffSDag-Erling Smørgrav 	explicit_bzero(sigblob, SIGBLOB_LEN);
841e8db6e2SBrian Feldman 	BN_bn2bin(sig->r, sigblob + SIGBLOB_LEN - INTBLOB_LEN - rlen);
851e8db6e2SBrian Feldman 	BN_bn2bin(sig->s, sigblob + SIGBLOB_LEN - slen);
861e8db6e2SBrian Feldman 
87*a0ee8cc6SDag-Erling Smørgrav 	if (compat & SSH_BUG_SIGBLOB) {
884b17dab0SDag-Erling Smørgrav 		if (sigp != NULL) {
89*a0ee8cc6SDag-Erling Smørgrav 			if ((*sigp = malloc(SIGBLOB_LEN)) == NULL) {
90*a0ee8cc6SDag-Erling Smørgrav 				ret = SSH_ERR_ALLOC_FAIL;
91*a0ee8cc6SDag-Erling Smørgrav 				goto out;
92*a0ee8cc6SDag-Erling Smørgrav 			}
934b17dab0SDag-Erling Smørgrav 			memcpy(*sigp, sigblob, SIGBLOB_LEN);
944b17dab0SDag-Erling Smørgrav 		}
95*a0ee8cc6SDag-Erling Smørgrav 		if (lenp != NULL)
96*a0ee8cc6SDag-Erling Smørgrav 			*lenp = SIGBLOB_LEN;
97*a0ee8cc6SDag-Erling Smørgrav 		ret = 0;
981e8db6e2SBrian Feldman 	} else {
991e8db6e2SBrian Feldman 		/* ietf-drafts */
100*a0ee8cc6SDag-Erling Smørgrav 		if ((b = sshbuf_new()) == NULL) {
101*a0ee8cc6SDag-Erling Smørgrav 			ret = SSH_ERR_ALLOC_FAIL;
102*a0ee8cc6SDag-Erling Smørgrav 			goto out;
103*a0ee8cc6SDag-Erling Smørgrav 		}
104*a0ee8cc6SDag-Erling Smørgrav 		if ((ret = sshbuf_put_cstring(b, "ssh-dss")) != 0 ||
105*a0ee8cc6SDag-Erling Smørgrav 		    (ret = sshbuf_put_string(b, sigblob, SIGBLOB_LEN)) != 0)
106*a0ee8cc6SDag-Erling Smørgrav 			goto out;
107*a0ee8cc6SDag-Erling Smørgrav 		len = sshbuf_len(b);
108*a0ee8cc6SDag-Erling Smørgrav 		if (sigp != NULL) {
109*a0ee8cc6SDag-Erling Smørgrav 			if ((*sigp = malloc(len)) == NULL) {
110*a0ee8cc6SDag-Erling Smørgrav 				ret = SSH_ERR_ALLOC_FAIL;
111*a0ee8cc6SDag-Erling Smørgrav 				goto out;
112*a0ee8cc6SDag-Erling Smørgrav 			}
113*a0ee8cc6SDag-Erling Smørgrav 			memcpy(*sigp, sshbuf_ptr(b), len);
114*a0ee8cc6SDag-Erling Smørgrav 		}
1151e8db6e2SBrian Feldman 		if (lenp != NULL)
1161e8db6e2SBrian Feldman 			*lenp = len;
117*a0ee8cc6SDag-Erling Smørgrav 		ret = 0;
1184b17dab0SDag-Erling Smørgrav 	}
119*a0ee8cc6SDag-Erling Smørgrav  out:
120*a0ee8cc6SDag-Erling Smørgrav 	explicit_bzero(digest, sizeof(digest));
121*a0ee8cc6SDag-Erling Smørgrav 	if (sig != NULL)
122*a0ee8cc6SDag-Erling Smørgrav 		DSA_SIG_free(sig);
123*a0ee8cc6SDag-Erling Smørgrav 	if (b != NULL)
124*a0ee8cc6SDag-Erling Smørgrav 		sshbuf_free(b);
125*a0ee8cc6SDag-Erling Smørgrav 	return ret;
1261e8db6e2SBrian Feldman }
1271e8db6e2SBrian Feldman 
128*a0ee8cc6SDag-Erling Smørgrav int
129*a0ee8cc6SDag-Erling Smørgrav ssh_dss_verify(const struct sshkey *key,
130*a0ee8cc6SDag-Erling Smørgrav     const u_char *signature, size_t signaturelen,
131*a0ee8cc6SDag-Erling Smørgrav     const u_char *data, size_t datalen, u_int compat)
132*a0ee8cc6SDag-Erling Smørgrav {
133*a0ee8cc6SDag-Erling Smørgrav 	DSA_SIG *sig = NULL;
134*a0ee8cc6SDag-Erling Smørgrav 	u_char digest[SSH_DIGEST_MAX_LENGTH], *sigblob = NULL;
135*a0ee8cc6SDag-Erling Smørgrav 	size_t len, dlen = ssh_digest_bytes(SSH_DIGEST_SHA1);
136*a0ee8cc6SDag-Erling Smørgrav 	int ret = SSH_ERR_INTERNAL_ERROR;
137*a0ee8cc6SDag-Erling Smørgrav 	struct sshbuf *b = NULL;
138*a0ee8cc6SDag-Erling Smørgrav 	char *ktype = NULL;
139*a0ee8cc6SDag-Erling Smørgrav 
140*a0ee8cc6SDag-Erling Smørgrav 	if (key == NULL || key->dsa == NULL ||
141*a0ee8cc6SDag-Erling Smørgrav 	    sshkey_type_plain(key->type) != KEY_DSA)
142*a0ee8cc6SDag-Erling Smørgrav 		return SSH_ERR_INVALID_ARGUMENT;
143*a0ee8cc6SDag-Erling Smørgrav 	if (dlen == 0)
144*a0ee8cc6SDag-Erling Smørgrav 		return SSH_ERR_INTERNAL_ERROR;
1451e8db6e2SBrian Feldman 
1461e8db6e2SBrian Feldman 	/* fetch signature */
147*a0ee8cc6SDag-Erling Smørgrav 	if (compat & SSH_BUG_SIGBLOB) {
148*a0ee8cc6SDag-Erling Smørgrav 		if ((sigblob = malloc(signaturelen)) == NULL)
149*a0ee8cc6SDag-Erling Smørgrav 			return SSH_ERR_ALLOC_FAIL;
150efcad6b7SDag-Erling Smørgrav 		memcpy(sigblob, signature, signaturelen);
1511e8db6e2SBrian Feldman 		len = signaturelen;
1521e8db6e2SBrian Feldman 	} else {
1531e8db6e2SBrian Feldman 		/* ietf-drafts */
154*a0ee8cc6SDag-Erling Smørgrav 		if ((b = sshbuf_from(signature, signaturelen)) == NULL)
155*a0ee8cc6SDag-Erling Smørgrav 			return SSH_ERR_ALLOC_FAIL;
156*a0ee8cc6SDag-Erling Smørgrav 		if (sshbuf_get_cstring(b, &ktype, NULL) != 0 ||
157*a0ee8cc6SDag-Erling Smørgrav 		    sshbuf_get_string(b, &sigblob, &len) != 0) {
158*a0ee8cc6SDag-Erling Smørgrav 			ret = SSH_ERR_INVALID_FORMAT;
159*a0ee8cc6SDag-Erling Smørgrav 			goto out;
160ae1f160dSDag-Erling Smørgrav 		}
161*a0ee8cc6SDag-Erling Smørgrav 		if (strcmp("ssh-dss", ktype) != 0) {
162*a0ee8cc6SDag-Erling Smørgrav 			ret = SSH_ERR_KEY_TYPE_MISMATCH;
163*a0ee8cc6SDag-Erling Smørgrav 			goto out;
164*a0ee8cc6SDag-Erling Smørgrav 		}
165*a0ee8cc6SDag-Erling Smørgrav 		if (sshbuf_len(b) != 0) {
166*a0ee8cc6SDag-Erling Smørgrav 			ret = SSH_ERR_UNEXPECTED_TRAILING_DATA;
167*a0ee8cc6SDag-Erling Smørgrav 			goto out;
168ae1f160dSDag-Erling Smørgrav 		}
1691e8db6e2SBrian Feldman 	}
1701e8db6e2SBrian Feldman 
1711e8db6e2SBrian Feldman 	if (len != SIGBLOB_LEN) {
172*a0ee8cc6SDag-Erling Smørgrav 		ret = SSH_ERR_INVALID_FORMAT;
173*a0ee8cc6SDag-Erling Smørgrav 		goto out;
1741e8db6e2SBrian Feldman 	}
1751e8db6e2SBrian Feldman 
1761e8db6e2SBrian Feldman 	/* parse signature */
177*a0ee8cc6SDag-Erling Smørgrav 	if ((sig = DSA_SIG_new()) == NULL ||
178*a0ee8cc6SDag-Erling Smørgrav 	    (sig->r = BN_new()) == NULL ||
179*a0ee8cc6SDag-Erling Smørgrav 	    (sig->s = BN_new()) == NULL) {
180*a0ee8cc6SDag-Erling Smørgrav 		ret = SSH_ERR_ALLOC_FAIL;
181*a0ee8cc6SDag-Erling Smørgrav 		goto out;
182*a0ee8cc6SDag-Erling Smørgrav 	}
18392eb0aa1SDag-Erling Smørgrav 	if ((BN_bin2bn(sigblob, INTBLOB_LEN, sig->r) == NULL) ||
184*a0ee8cc6SDag-Erling Smørgrav 	    (BN_bin2bn(sigblob+ INTBLOB_LEN, INTBLOB_LEN, sig->s) == NULL)) {
185*a0ee8cc6SDag-Erling Smørgrav 		ret = SSH_ERR_LIBCRYPTO_ERROR;
186*a0ee8cc6SDag-Erling Smørgrav 		goto out;
187f7167e0eSDag-Erling Smørgrav 	}
1881e8db6e2SBrian Feldman 
189*a0ee8cc6SDag-Erling Smørgrav 	/* sha1 the data */
190*a0ee8cc6SDag-Erling Smørgrav 	if ((ret = ssh_digest_memory(SSH_DIGEST_SHA1, data, datalen,
191*a0ee8cc6SDag-Erling Smørgrav 	    digest, sizeof(digest))) != 0)
192*a0ee8cc6SDag-Erling Smørgrav 		goto out;
193*a0ee8cc6SDag-Erling Smørgrav 
194*a0ee8cc6SDag-Erling Smørgrav 	switch (DSA_do_verify(digest, dlen, sig, key->dsa)) {
195*a0ee8cc6SDag-Erling Smørgrav 	case 1:
196*a0ee8cc6SDag-Erling Smørgrav 		ret = 0;
197*a0ee8cc6SDag-Erling Smørgrav 		break;
198*a0ee8cc6SDag-Erling Smørgrav 	case 0:
199*a0ee8cc6SDag-Erling Smørgrav 		ret = SSH_ERR_SIGNATURE_INVALID;
200*a0ee8cc6SDag-Erling Smørgrav 		goto out;
201*a0ee8cc6SDag-Erling Smørgrav 	default:
202*a0ee8cc6SDag-Erling Smørgrav 		ret = SSH_ERR_LIBCRYPTO_ERROR;
203*a0ee8cc6SDag-Erling Smørgrav 		goto out;
204*a0ee8cc6SDag-Erling Smørgrav 	}
205*a0ee8cc6SDag-Erling Smørgrav 
206*a0ee8cc6SDag-Erling Smørgrav  out:
207b83788ffSDag-Erling Smørgrav 	explicit_bzero(digest, sizeof(digest));
208*a0ee8cc6SDag-Erling Smørgrav 	if (sig != NULL)
2091e8db6e2SBrian Feldman 		DSA_SIG_free(sig);
210*a0ee8cc6SDag-Erling Smørgrav 	if (b != NULL)
211*a0ee8cc6SDag-Erling Smørgrav 		sshbuf_free(b);
212*a0ee8cc6SDag-Erling Smørgrav 	if (ktype != NULL)
213*a0ee8cc6SDag-Erling Smørgrav 		free(ktype);
214*a0ee8cc6SDag-Erling Smørgrav 	if (sigblob != NULL) {
215*a0ee8cc6SDag-Erling Smørgrav 		explicit_bzero(sigblob, len);
216*a0ee8cc6SDag-Erling Smørgrav 		free(sigblob);
217*a0ee8cc6SDag-Erling Smørgrav 	}
2181e8db6e2SBrian Feldman 	return ret;
2191e8db6e2SBrian Feldman }
220