GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/ssh/lib/../ssh-ecdsa.c Lines: 29 75 38.7 %
Date: 2017-11-07 Branches: 17 73 23.3 %

Line Branch Exec Source
1
/* $OpenBSD: ssh-ecdsa.c,v 1.13 2016/04/21 06:08:02 djm Exp $ */
2
/*
3
 * Copyright (c) 2000 Markus Friedl.  All rights reserved.
4
 * Copyright (c) 2010 Damien Miller.  All rights reserved.
5
 *
6
 * Redistribution and use in source and binary forms, with or without
7
 * modification, are permitted provided that the following conditions
8
 * are met:
9
 * 1. Redistributions of source code must retain the above copyright
10
 *    notice, this list of conditions and the following disclaimer.
11
 * 2. Redistributions in binary form must reproduce the above copyright
12
 *    notice, this list of conditions and the following disclaimer in the
13
 *    documentation and/or other materials provided with the distribution.
14
 *
15
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25
 */
26
27
#include <sys/types.h>
28
29
#include <openssl/bn.h>
30
#include <openssl/ec.h>
31
#include <openssl/ecdsa.h>
32
#include <openssl/evp.h>
33
34
#include <string.h>
35
36
#include "sshbuf.h"
37
#include "ssherr.h"
38
#include "digest.h"
39
#define SSHKEY_INTERNAL
40
#include "sshkey.h"
41
42
/* ARGSUSED */
43
int
44
ssh_ecdsa_sign(const struct sshkey *key, u_char **sigp, size_t *lenp,
45
    const u_char *data, size_t datalen, u_int compat)
46
{
47
	ECDSA_SIG *sig = NULL;
48
	int hash_alg;
49
	u_char digest[SSH_DIGEST_MAX_LENGTH];
50
	size_t len, dlen;
51
	struct sshbuf *b = NULL, *bb = NULL;
52
	int ret = SSH_ERR_INTERNAL_ERROR;
53
54
	if (lenp != NULL)
55
		*lenp = 0;
56
	if (sigp != NULL)
57
		*sigp = NULL;
58
59
	if (key == NULL || key->ecdsa == NULL ||
60
	    sshkey_type_plain(key->type) != KEY_ECDSA)
61
		return SSH_ERR_INVALID_ARGUMENT;
62
63
	if ((hash_alg = sshkey_ec_nid_to_hash_alg(key->ecdsa_nid)) == -1 ||
64
	    (dlen = ssh_digest_bytes(hash_alg)) == 0)
65
		return SSH_ERR_INTERNAL_ERROR;
66
	if ((ret = ssh_digest_memory(hash_alg, data, datalen,
67
	    digest, sizeof(digest))) != 0)
68
		goto out;
69
70
	if ((sig = ECDSA_do_sign(digest, dlen, key->ecdsa)) == NULL) {
71
		ret = SSH_ERR_LIBCRYPTO_ERROR;
72
		goto out;
73
	}
74
75
	if ((bb = sshbuf_new()) == NULL || (b = sshbuf_new()) == NULL) {
76
		ret = SSH_ERR_ALLOC_FAIL;
77
		goto out;
78
	}
79
	if ((ret = sshbuf_put_bignum2(bb, sig->r)) != 0 ||
80
	    (ret = sshbuf_put_bignum2(bb, sig->s)) != 0)
81
		goto out;
82
	if ((ret = sshbuf_put_cstring(b, sshkey_ssh_name_plain(key))) != 0 ||
83
	    (ret = sshbuf_put_stringb(b, bb)) != 0)
84
		goto out;
85
	len = sshbuf_len(b);
86
	if (sigp != NULL) {
87
		if ((*sigp = malloc(len)) == NULL) {
88
			ret = SSH_ERR_ALLOC_FAIL;
89
			goto out;
90
		}
91
		memcpy(*sigp, sshbuf_ptr(b), len);
92
	}
93
	if (lenp != NULL)
94
		*lenp = len;
95
	ret = 0;
96
 out:
97
	explicit_bzero(digest, sizeof(digest));
98
	sshbuf_free(b);
99
	sshbuf_free(bb);
100
	if (sig != NULL)
101
		ECDSA_SIG_free(sig);
102
	return ret;
103
}
104
105
/* ARGSUSED */
106
int
107
ssh_ecdsa_verify(const struct sshkey *key,
108
    const u_char *signature, size_t signaturelen,
109
    const u_char *data, size_t datalen, u_int compat)
110
{
111
	ECDSA_SIG *sig = NULL;
112
	int hash_alg;
113
2
	u_char digest[SSH_DIGEST_MAX_LENGTH];
114
	size_t dlen;
115
	int ret = SSH_ERR_INTERNAL_ERROR;
116
1
	struct sshbuf *b = NULL, *sigbuf = NULL;
117
1
	char *ktype = NULL;
118
119

2
	if (key == NULL || key->ecdsa == NULL ||
120
3
	    sshkey_type_plain(key->type) != KEY_ECDSA ||
121
2
	    signature == NULL || signaturelen == 0)
122
		return SSH_ERR_INVALID_ARGUMENT;
123
124

2
	if ((hash_alg = sshkey_ec_nid_to_hash_alg(key->ecdsa_nid)) == -1 ||
125
1
	    (dlen = ssh_digest_bytes(hash_alg)) == 0)
126
		return SSH_ERR_INTERNAL_ERROR;
127
128
	/* fetch signature */
129
1
	if ((b = sshbuf_from(signature, signaturelen)) == NULL)
130
		return SSH_ERR_ALLOC_FAIL;
131

2
	if (sshbuf_get_cstring(b, &ktype, NULL) != 0 ||
132
1
	    sshbuf_froms(b, &sigbuf) != 0) {
133
		ret = SSH_ERR_INVALID_FORMAT;
134
		goto out;
135
	}
136
1
	if (strcmp(sshkey_ssh_name_plain(key), ktype) != 0) {
137
		ret = SSH_ERR_KEY_TYPE_MISMATCH;
138
		goto out;
139
	}
140
1
	if (sshbuf_len(b) != 0) {
141
		ret = SSH_ERR_UNEXPECTED_TRAILING_DATA;
142
		goto out;
143
	}
144
145
	/* parse signature */
146
1
	if ((sig = ECDSA_SIG_new()) == NULL) {
147
		ret = SSH_ERR_ALLOC_FAIL;
148
		goto out;
149
	}
150

2
	if (sshbuf_get_bignum2(sigbuf, sig->r) != 0 ||
151
1
	    sshbuf_get_bignum2(sigbuf, sig->s) != 0) {
152
		ret = SSH_ERR_INVALID_FORMAT;
153
		goto out;
154
	}
155
1
	if (sshbuf_len(sigbuf) != 0) {
156
		ret = SSH_ERR_UNEXPECTED_TRAILING_DATA;
157
		goto out;
158
	}
159
2
	if ((ret = ssh_digest_memory(hash_alg, data, datalen,
160
2
	    digest, sizeof(digest))) != 0)
161
		goto out;
162
163
1
	switch (ECDSA_do_verify(digest, dlen, sig, key->ecdsa)) {
164
	case 1:
165
		ret = 0;
166
		break;
167
	case 0:
168
		ret = SSH_ERR_SIGNATURE_INVALID;
169
		goto out;
170
	default:
171
		ret = SSH_ERR_LIBCRYPTO_ERROR;
172
		goto out;
173
1
	}
174
175
 out:
176
1
	explicit_bzero(digest, sizeof(digest));
177
1
	sshbuf_free(sigbuf);
178
1
	sshbuf_free(b);
179
1
	if (sig != NULL)
180
1
		ECDSA_SIG_free(sig);
181
1
	free(ktype);
182
1
	return ret;
183
1
}