xref: /freebsd/crypto/openssh/ssh-dss.c (revision 2a01feabb3d0fce30c4a1c4b883e50e09a457a96)
147dd1d1bSDag-Erling Smørgrav /* $OpenBSD: ssh-dss.c,v 1.37 2018/02/07 02:06:51 jsing 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 
28bc5531deSDag-Erling Smørgrav #ifdef WITH_OPENSSL
29bc5531deSDag-Erling Smørgrav 
30761efaa7SDag-Erling Smørgrav #include <sys/types.h>
311e8db6e2SBrian Feldman 
321e8db6e2SBrian Feldman #include <openssl/bn.h>
33a0ee8cc6SDag-Erling Smørgrav #include <openssl/dsa.h>
341e8db6e2SBrian Feldman #include <openssl/evp.h>
351e8db6e2SBrian Feldman 
36761efaa7SDag-Erling Smørgrav #include <stdarg.h>
37761efaa7SDag-Erling Smørgrav #include <string.h>
38761efaa7SDag-Erling Smørgrav 
39a0ee8cc6SDag-Erling Smørgrav #include "sshbuf.h"
401e8db6e2SBrian Feldman #include "compat.h"
41a0ee8cc6SDag-Erling Smørgrav #include "ssherr.h"
42f7167e0eSDag-Erling Smørgrav #include "digest.h"
43a0ee8cc6SDag-Erling Smørgrav #define SSHKEY_INTERNAL
44a0ee8cc6SDag-Erling Smørgrav #include "sshkey.h"
451e8db6e2SBrian Feldman 
46*2a01feabSEd Maste #include "openbsd-compat/openssl-compat.h"
47*2a01feabSEd Maste 
481e8db6e2SBrian Feldman #define INTBLOB_LEN	20
491e8db6e2SBrian Feldman #define SIGBLOB_LEN	(2*INTBLOB_LEN)
501e8db6e2SBrian Feldman 
511e8db6e2SBrian Feldman int
52a0ee8cc6SDag-Erling Smørgrav ssh_dss_sign(const struct sshkey *key, u_char **sigp, size_t *lenp,
53a0ee8cc6SDag-Erling Smørgrav     const u_char *data, size_t datalen, u_int compat)
541e8db6e2SBrian Feldman {
55a0ee8cc6SDag-Erling Smørgrav 	DSA_SIG *sig = NULL;
56*2a01feabSEd Maste 	const BIGNUM *sig_r, *sig_s;
57f7167e0eSDag-Erling Smørgrav 	u_char digest[SSH_DIGEST_MAX_LENGTH], sigblob[SIGBLOB_LEN];
58a0ee8cc6SDag-Erling Smørgrav 	size_t rlen, slen, len, dlen = ssh_digest_bytes(SSH_DIGEST_SHA1);
59a0ee8cc6SDag-Erling Smørgrav 	struct sshbuf *b = NULL;
60a0ee8cc6SDag-Erling Smørgrav 	int ret = SSH_ERR_INVALID_ARGUMENT;
611e8db6e2SBrian Feldman 
62a0ee8cc6SDag-Erling Smørgrav 	if (lenp != NULL)
63a0ee8cc6SDag-Erling Smørgrav 		*lenp = 0;
64a0ee8cc6SDag-Erling Smørgrav 	if (sigp != NULL)
65a0ee8cc6SDag-Erling Smørgrav 		*sigp = NULL;
66f7167e0eSDag-Erling Smørgrav 
67a0ee8cc6SDag-Erling Smørgrav 	if (key == NULL || key->dsa == NULL ||
68a0ee8cc6SDag-Erling Smørgrav 	    sshkey_type_plain(key->type) != KEY_DSA)
69a0ee8cc6SDag-Erling Smørgrav 		return SSH_ERR_INVALID_ARGUMENT;
70a0ee8cc6SDag-Erling Smørgrav 	if (dlen == 0)
71a0ee8cc6SDag-Erling Smørgrav 		return SSH_ERR_INTERNAL_ERROR;
721e8db6e2SBrian Feldman 
73a0ee8cc6SDag-Erling Smørgrav 	if ((ret = ssh_digest_memory(SSH_DIGEST_SHA1, data, datalen,
74a0ee8cc6SDag-Erling Smørgrav 	    digest, sizeof(digest))) != 0)
75a0ee8cc6SDag-Erling Smørgrav 		goto out;
76ae1f160dSDag-Erling Smørgrav 
77a0ee8cc6SDag-Erling Smørgrav 	if ((sig = DSA_do_sign(digest, dlen, key->dsa)) == NULL) {
78a0ee8cc6SDag-Erling Smørgrav 		ret = SSH_ERR_LIBCRYPTO_ERROR;
79a0ee8cc6SDag-Erling Smørgrav 		goto out;
801e8db6e2SBrian Feldman 	}
811e8db6e2SBrian Feldman 
82*2a01feabSEd Maste 	DSA_SIG_get0(sig, &sig_r, &sig_s);
83*2a01feabSEd Maste 	rlen = BN_num_bytes(sig_r);
84*2a01feabSEd Maste 	slen = BN_num_bytes(sig_s);
851e8db6e2SBrian Feldman 	if (rlen > INTBLOB_LEN || slen > INTBLOB_LEN) {
86a0ee8cc6SDag-Erling Smørgrav 		ret = SSH_ERR_INTERNAL_ERROR;
87a0ee8cc6SDag-Erling Smørgrav 		goto out;
881e8db6e2SBrian Feldman 	}
89b83788ffSDag-Erling Smørgrav 	explicit_bzero(sigblob, SIGBLOB_LEN);
90*2a01feabSEd Maste 	BN_bn2bin(sig_r, sigblob + SIGBLOB_LEN - INTBLOB_LEN - rlen);
91*2a01feabSEd Maste 	BN_bn2bin(sig_s, sigblob + SIGBLOB_LEN - slen);
921e8db6e2SBrian Feldman 
93a0ee8cc6SDag-Erling Smørgrav 	if ((b = sshbuf_new()) == NULL) {
94a0ee8cc6SDag-Erling Smørgrav 		ret = SSH_ERR_ALLOC_FAIL;
95a0ee8cc6SDag-Erling Smørgrav 		goto out;
96a0ee8cc6SDag-Erling Smørgrav 	}
97a0ee8cc6SDag-Erling Smørgrav 	if ((ret = sshbuf_put_cstring(b, "ssh-dss")) != 0 ||
98a0ee8cc6SDag-Erling Smørgrav 	    (ret = sshbuf_put_string(b, sigblob, SIGBLOB_LEN)) != 0)
99a0ee8cc6SDag-Erling Smørgrav 		goto out;
10047dd1d1bSDag-Erling Smørgrav 
101a0ee8cc6SDag-Erling Smørgrav 	len = sshbuf_len(b);
102a0ee8cc6SDag-Erling Smørgrav 	if (sigp != NULL) {
103a0ee8cc6SDag-Erling Smørgrav 		if ((*sigp = malloc(len)) == NULL) {
104a0ee8cc6SDag-Erling Smørgrav 			ret = SSH_ERR_ALLOC_FAIL;
105a0ee8cc6SDag-Erling Smørgrav 			goto out;
106a0ee8cc6SDag-Erling Smørgrav 		}
107a0ee8cc6SDag-Erling Smørgrav 		memcpy(*sigp, sshbuf_ptr(b), len);
108a0ee8cc6SDag-Erling Smørgrav 	}
1091e8db6e2SBrian Feldman 	if (lenp != NULL)
1101e8db6e2SBrian Feldman 		*lenp = len;
111a0ee8cc6SDag-Erling Smørgrav 	ret = 0;
112a0ee8cc6SDag-Erling Smørgrav  out:
113a0ee8cc6SDag-Erling Smørgrav 	explicit_bzero(digest, sizeof(digest));
114a0ee8cc6SDag-Erling Smørgrav 	DSA_SIG_free(sig);
115a0ee8cc6SDag-Erling Smørgrav 	sshbuf_free(b);
116a0ee8cc6SDag-Erling Smørgrav 	return ret;
1171e8db6e2SBrian Feldman }
1181e8db6e2SBrian Feldman 
119a0ee8cc6SDag-Erling Smørgrav int
120a0ee8cc6SDag-Erling Smørgrav ssh_dss_verify(const struct sshkey *key,
121a0ee8cc6SDag-Erling Smørgrav     const u_char *signature, size_t signaturelen,
122a0ee8cc6SDag-Erling Smørgrav     const u_char *data, size_t datalen, u_int compat)
123a0ee8cc6SDag-Erling Smørgrav {
124a0ee8cc6SDag-Erling Smørgrav 	DSA_SIG *sig = NULL;
125*2a01feabSEd Maste 	BIGNUM *sig_r = NULL, *sig_s = NULL;
126a0ee8cc6SDag-Erling Smørgrav 	u_char digest[SSH_DIGEST_MAX_LENGTH], *sigblob = NULL;
127a0ee8cc6SDag-Erling Smørgrav 	size_t len, dlen = ssh_digest_bytes(SSH_DIGEST_SHA1);
128a0ee8cc6SDag-Erling Smørgrav 	int ret = SSH_ERR_INTERNAL_ERROR;
129a0ee8cc6SDag-Erling Smørgrav 	struct sshbuf *b = NULL;
130a0ee8cc6SDag-Erling Smørgrav 	char *ktype = NULL;
131a0ee8cc6SDag-Erling Smørgrav 
132a0ee8cc6SDag-Erling Smørgrav 	if (key == NULL || key->dsa == NULL ||
133076ad2f8SDag-Erling Smørgrav 	    sshkey_type_plain(key->type) != KEY_DSA ||
134076ad2f8SDag-Erling Smørgrav 	    signature == NULL || signaturelen == 0)
135a0ee8cc6SDag-Erling Smørgrav 		return SSH_ERR_INVALID_ARGUMENT;
136a0ee8cc6SDag-Erling Smørgrav 	if (dlen == 0)
137a0ee8cc6SDag-Erling Smørgrav 		return SSH_ERR_INTERNAL_ERROR;
1381e8db6e2SBrian Feldman 
1391e8db6e2SBrian Feldman 	/* fetch signature */
140a0ee8cc6SDag-Erling Smørgrav 	if ((b = sshbuf_from(signature, signaturelen)) == NULL)
141a0ee8cc6SDag-Erling Smørgrav 		return SSH_ERR_ALLOC_FAIL;
142a0ee8cc6SDag-Erling Smørgrav 	if (sshbuf_get_cstring(b, &ktype, NULL) != 0 ||
143a0ee8cc6SDag-Erling Smørgrav 	    sshbuf_get_string(b, &sigblob, &len) != 0) {
144a0ee8cc6SDag-Erling Smørgrav 		ret = SSH_ERR_INVALID_FORMAT;
145a0ee8cc6SDag-Erling Smørgrav 		goto out;
146ae1f160dSDag-Erling Smørgrav 	}
147a0ee8cc6SDag-Erling Smørgrav 	if (strcmp("ssh-dss", ktype) != 0) {
148a0ee8cc6SDag-Erling Smørgrav 		ret = SSH_ERR_KEY_TYPE_MISMATCH;
149a0ee8cc6SDag-Erling Smørgrav 		goto out;
150a0ee8cc6SDag-Erling Smørgrav 	}
151a0ee8cc6SDag-Erling Smørgrav 	if (sshbuf_len(b) != 0) {
152a0ee8cc6SDag-Erling Smørgrav 		ret = SSH_ERR_UNEXPECTED_TRAILING_DATA;
153a0ee8cc6SDag-Erling Smørgrav 		goto out;
154ae1f160dSDag-Erling Smørgrav 	}
1551e8db6e2SBrian Feldman 
1561e8db6e2SBrian Feldman 	if (len != SIGBLOB_LEN) {
157a0ee8cc6SDag-Erling Smørgrav 		ret = SSH_ERR_INVALID_FORMAT;
158a0ee8cc6SDag-Erling Smørgrav 		goto out;
1591e8db6e2SBrian Feldman 	}
1601e8db6e2SBrian Feldman 
1611e8db6e2SBrian Feldman 	/* parse signature */
162a0ee8cc6SDag-Erling Smørgrav 	if ((sig = DSA_SIG_new()) == NULL ||
163*2a01feabSEd Maste 	    (sig_r = BN_new()) == NULL ||
164*2a01feabSEd Maste 	    (sig_s = BN_new()) == NULL) {
165a0ee8cc6SDag-Erling Smørgrav 		ret = SSH_ERR_ALLOC_FAIL;
166a0ee8cc6SDag-Erling Smørgrav 		goto out;
167a0ee8cc6SDag-Erling Smørgrav 	}
168*2a01feabSEd Maste 	if ((BN_bin2bn(sigblob, INTBLOB_LEN, sig_r) == NULL) ||
169*2a01feabSEd Maste 	    (BN_bin2bn(sigblob + INTBLOB_LEN, INTBLOB_LEN, sig_s) == NULL)) {
170a0ee8cc6SDag-Erling Smørgrav 		ret = SSH_ERR_LIBCRYPTO_ERROR;
171a0ee8cc6SDag-Erling Smørgrav 		goto out;
172f7167e0eSDag-Erling Smørgrav 	}
173*2a01feabSEd Maste 	if (!DSA_SIG_set0(sig, sig_r, sig_s)) {
174*2a01feabSEd Maste 		ret = SSH_ERR_LIBCRYPTO_ERROR;
175*2a01feabSEd Maste 		goto out;
176*2a01feabSEd Maste 	}
177*2a01feabSEd Maste 	sig_r = sig_s = NULL; /* transferred */
1781e8db6e2SBrian Feldman 
179a0ee8cc6SDag-Erling Smørgrav 	/* sha1 the data */
180a0ee8cc6SDag-Erling Smørgrav 	if ((ret = ssh_digest_memory(SSH_DIGEST_SHA1, data, datalen,
181a0ee8cc6SDag-Erling Smørgrav 	    digest, sizeof(digest))) != 0)
182a0ee8cc6SDag-Erling Smørgrav 		goto out;
183a0ee8cc6SDag-Erling Smørgrav 
184a0ee8cc6SDag-Erling Smørgrav 	switch (DSA_do_verify(digest, dlen, sig, key->dsa)) {
185a0ee8cc6SDag-Erling Smørgrav 	case 1:
186a0ee8cc6SDag-Erling Smørgrav 		ret = 0;
187a0ee8cc6SDag-Erling Smørgrav 		break;
188a0ee8cc6SDag-Erling Smørgrav 	case 0:
189a0ee8cc6SDag-Erling Smørgrav 		ret = SSH_ERR_SIGNATURE_INVALID;
190a0ee8cc6SDag-Erling Smørgrav 		goto out;
191a0ee8cc6SDag-Erling Smørgrav 	default:
192a0ee8cc6SDag-Erling Smørgrav 		ret = SSH_ERR_LIBCRYPTO_ERROR;
193a0ee8cc6SDag-Erling Smørgrav 		goto out;
194a0ee8cc6SDag-Erling Smørgrav 	}
195a0ee8cc6SDag-Erling Smørgrav 
196a0ee8cc6SDag-Erling Smørgrav  out:
197b83788ffSDag-Erling Smørgrav 	explicit_bzero(digest, sizeof(digest));
1981e8db6e2SBrian Feldman 	DSA_SIG_free(sig);
199*2a01feabSEd Maste 	BN_clear_free(sig_r);
200*2a01feabSEd Maste 	BN_clear_free(sig_s);
201a0ee8cc6SDag-Erling Smørgrav 	sshbuf_free(b);
202a0ee8cc6SDag-Erling Smørgrav 	free(ktype);
203a0ee8cc6SDag-Erling Smørgrav 	if (sigblob != NULL) {
204a0ee8cc6SDag-Erling Smørgrav 		explicit_bzero(sigblob, len);
205a0ee8cc6SDag-Erling Smørgrav 		free(sigblob);
206a0ee8cc6SDag-Erling Smørgrav 	}
2071e8db6e2SBrian Feldman 	return ret;
2081e8db6e2SBrian Feldman }
209bc5531deSDag-Erling Smørgrav #endif /* WITH_OPENSSL */
210