GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/ssh/lib/../ssh-dss.c Lines: 69 98 70.4 %
Date: 2017-11-07 Branches: 37 83 44.6 %

Line Branch Exec Source
1
/* $OpenBSD: ssh-dss.c,v 1.35 2016/04/21 06:08:02 djm Exp $ */
2
/*
3
 * Copyright (c) 2000 Markus Friedl.  All rights reserved.
4
 *
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions
7
 * are met:
8
 * 1. Redistributions of source code must retain the above copyright
9
 *    notice, this list of conditions and the following disclaimer.
10
 * 2. Redistributions in binary form must reproduce the above copyright
11
 *    notice, this list of conditions and the following disclaimer in the
12
 *    documentation and/or other materials provided with the distribution.
13
 *
14
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24
 */
25
26
#include <sys/types.h>
27
28
#include <openssl/bn.h>
29
#include <openssl/evp.h>
30
31
#include <string.h>
32
33
#include "sshbuf.h"
34
#include "compat.h"
35
#include "ssherr.h"
36
#include "digest.h"
37
#define SSHKEY_INTERNAL
38
#include "sshkey.h"
39
40
#define INTBLOB_LEN	20
41
#define SIGBLOB_LEN	(2*INTBLOB_LEN)
42
43
int
44
ssh_dss_sign(const struct sshkey *key, u_char **sigp, size_t *lenp,
45
    const u_char *data, size_t datalen, u_int compat)
46
{
47
	DSA_SIG *sig = NULL;
48
8
	u_char digest[SSH_DIGEST_MAX_LENGTH], sigblob[SIGBLOB_LEN];
49
4
	size_t rlen, slen, len, dlen = ssh_digest_bytes(SSH_DIGEST_SHA1);
50
	struct sshbuf *b = NULL;
51
	int ret = SSH_ERR_INVALID_ARGUMENT;
52
53
4
	if (lenp != NULL)
54
4
		*lenp = 0;
55
4
	if (sigp != NULL)
56
4
		*sigp = NULL;
57
58

12
	if (key == NULL || key->dsa == NULL ||
59
4
	    sshkey_type_plain(key->type) != KEY_DSA)
60
		return SSH_ERR_INVALID_ARGUMENT;
61
4
	if (dlen == 0)
62
		return SSH_ERR_INTERNAL_ERROR;
63
64
8
	if ((ret = ssh_digest_memory(SSH_DIGEST_SHA1, data, datalen,
65
8
	    digest, sizeof(digest))) != 0)
66
		goto out;
67
68
4
	if ((sig = DSA_do_sign(digest, dlen, key->dsa)) == NULL) {
69
		ret = SSH_ERR_LIBCRYPTO_ERROR;
70
		goto out;
71
	}
72
73
4
	rlen = BN_num_bytes(sig->r);
74
4
	slen = BN_num_bytes(sig->s);
75
4
	if (rlen > INTBLOB_LEN || slen > INTBLOB_LEN) {
76
		ret = SSH_ERR_INTERNAL_ERROR;
77
		goto out;
78
	}
79
4
	explicit_bzero(sigblob, SIGBLOB_LEN);
80
4
	BN_bn2bin(sig->r, sigblob + SIGBLOB_LEN - INTBLOB_LEN - rlen);
81
4
	BN_bn2bin(sig->s, sigblob + SIGBLOB_LEN - slen);
82
83
4
	if (compat & SSH_BUG_SIGBLOB) {
84
		if (sigp != NULL) {
85
			if ((*sigp = malloc(SIGBLOB_LEN)) == NULL) {
86
				ret = SSH_ERR_ALLOC_FAIL;
87
				goto out;
88
			}
89
			memcpy(*sigp, sigblob, SIGBLOB_LEN);
90
		}
91
		if (lenp != NULL)
92
			*lenp = SIGBLOB_LEN;
93
		ret = 0;
94
	} else {
95
		/* ietf-drafts */
96
4
		if ((b = sshbuf_new()) == NULL) {
97
			ret = SSH_ERR_ALLOC_FAIL;
98
			goto out;
99
		}
100

8
		if ((ret = sshbuf_put_cstring(b, "ssh-dss")) != 0 ||
101
4
		    (ret = sshbuf_put_string(b, sigblob, SIGBLOB_LEN)) != 0)
102
			goto out;
103
4
		len = sshbuf_len(b);
104
4
		if (sigp != NULL) {
105
4
			if ((*sigp = malloc(len)) == NULL) {
106
				ret = SSH_ERR_ALLOC_FAIL;
107
				goto out;
108
			}
109
4
			memcpy(*sigp, sshbuf_ptr(b), len);
110
4
		}
111
4
		if (lenp != NULL)
112
4
			*lenp = len;
113
		ret = 0;
114
	}
115
 out:
116
4
	explicit_bzero(digest, sizeof(digest));
117
4
	if (sig != NULL)
118
4
		DSA_SIG_free(sig);
119
4
	sshbuf_free(b);
120
4
	return ret;
121
4
}
122
123
int
124
ssh_dss_verify(const struct sshkey *key,
125
    const u_char *signature, size_t signaturelen,
126
    const u_char *data, size_t datalen, u_int compat)
127
{
128
	DSA_SIG *sig = NULL;
129
8
	u_char digest[SSH_DIGEST_MAX_LENGTH], *sigblob = NULL;
130
4
	size_t len, dlen = ssh_digest_bytes(SSH_DIGEST_SHA1);
131
	int ret = SSH_ERR_INTERNAL_ERROR;
132
	struct sshbuf *b = NULL;
133
4
	char *ktype = NULL;
134
135

8
	if (key == NULL || key->dsa == NULL ||
136
12
	    sshkey_type_plain(key->type) != KEY_DSA ||
137
8
	    signature == NULL || signaturelen == 0)
138
		return SSH_ERR_INVALID_ARGUMENT;
139
4
	if (dlen == 0)
140
		return SSH_ERR_INTERNAL_ERROR;
141
142
	/* fetch signature */
143
4
	if (compat & SSH_BUG_SIGBLOB) {
144
		if ((sigblob = malloc(signaturelen)) == NULL)
145
			return SSH_ERR_ALLOC_FAIL;
146
		memcpy(sigblob, signature, signaturelen);
147
		len = signaturelen;
148
	} else {
149
		/* ietf-drafts */
150
4
		if ((b = sshbuf_from(signature, signaturelen)) == NULL)
151
			return SSH_ERR_ALLOC_FAIL;
152

8
		if (sshbuf_get_cstring(b, &ktype, NULL) != 0 ||
153
4
		    sshbuf_get_string(b, &sigblob, &len) != 0) {
154
			ret = SSH_ERR_INVALID_FORMAT;
155
			goto out;
156
		}
157
4
		if (strcmp("ssh-dss", ktype) != 0) {
158
			ret = SSH_ERR_KEY_TYPE_MISMATCH;
159
			goto out;
160
		}
161
4
		if (sshbuf_len(b) != 0) {
162
			ret = SSH_ERR_UNEXPECTED_TRAILING_DATA;
163
			goto out;
164
		}
165
	}
166
167
4
	if (len != SIGBLOB_LEN) {
168
		ret = SSH_ERR_INVALID_FORMAT;
169
		goto out;
170
	}
171
172
	/* parse signature */
173

8
	if ((sig = DSA_SIG_new()) == NULL ||
174
4
	    (sig->r = BN_new()) == NULL ||
175
4
	    (sig->s = BN_new()) == NULL) {
176
		ret = SSH_ERR_ALLOC_FAIL;
177
		goto out;
178
	}
179

8
	if ((BN_bin2bn(sigblob, INTBLOB_LEN, sig->r) == NULL) ||
180
4
	    (BN_bin2bn(sigblob+ INTBLOB_LEN, INTBLOB_LEN, sig->s) == NULL)) {
181
		ret = SSH_ERR_LIBCRYPTO_ERROR;
182
		goto out;
183
	}
184
185
	/* sha1 the data */
186
8
	if ((ret = ssh_digest_memory(SSH_DIGEST_SHA1, data, datalen,
187
8
	    digest, sizeof(digest))) != 0)
188
		goto out;
189
190
4
	switch (DSA_do_verify(digest, dlen, sig, key->dsa)) {
191
	case 1:
192
		ret = 0;
193
		break;
194
	case 0:
195
		ret = SSH_ERR_SIGNATURE_INVALID;
196
		goto out;
197
	default:
198
		ret = SSH_ERR_LIBCRYPTO_ERROR;
199
		goto out;
200
4
	}
201
202
 out:
203
4
	explicit_bzero(digest, sizeof(digest));
204
4
	if (sig != NULL)
205
4
		DSA_SIG_free(sig);
206
4
	sshbuf_free(b);
207
4
	free(ktype);
208
4
	if (sigblob != NULL) {
209
4
		explicit_bzero(sigblob, len);
210
4
		free(sigblob);
211
4
	}
212
4
	return ret;
213
4
}