GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/ssh/lib/../sshbuf-getput-crypto.c Lines: 42 103 40.8 %
Date: 2017-11-07 Branches: 19 66 28.8 %

Line Branch Exec Source
1
/*	$OpenBSD: sshbuf-getput-crypto.c,v 1.5 2016/01/12 23:42:54 djm Exp $	*/
2
/*
3
 * Copyright (c) 2011 Damien Miller
4
 *
5
 * Permission to use, copy, modify, and distribute this software for any
6
 * purpose with or without fee is hereby granted, provided that the above
7
 * copyright notice and this permission notice appear in all copies.
8
 *
9
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16
 */
17
18
#include <sys/types.h>
19
#include <stdlib.h>
20
#include <stdio.h>
21
#include <string.h>
22
23
#include <openssl/bn.h>
24
#include <openssl/ec.h>
25
26
#include "ssherr.h"
27
#define SSHBUF_INTERNAL
28
#include "sshbuf.h"
29
30
int
31
sshbuf_get_bignum2(struct sshbuf *buf, BIGNUM *v)
32
{
33
240
	const u_char *d;
34
120
	size_t len;
35
	int r;
36
37
120
	if ((r = sshbuf_get_bignum2_bytes_direct(buf, &d, &len)) != 0)
38
		return r;
39

240
	if (v != NULL && BN_bin2bn(d, len, v) == NULL)
40
		return SSH_ERR_ALLOC_FAIL;
41
120
	return 0;
42
120
}
43
44
int
45
sshbuf_get_bignum1(struct sshbuf *buf, BIGNUM *v)
46
{
47
	const u_char *d = sshbuf_ptr(buf);
48
	u_int16_t len_bits;
49
	size_t len_bytes;
50
51
	/* Length in bits */
52
	if (sshbuf_len(buf) < 2)
53
		return SSH_ERR_MESSAGE_INCOMPLETE;
54
	len_bits = PEEK_U16(d);
55
	len_bytes = (len_bits + 7) >> 3;
56
	if (len_bytes > SSHBUF_MAX_BIGNUM)
57
		return SSH_ERR_BIGNUM_TOO_LARGE;
58
	if (sshbuf_len(buf) < 2 + len_bytes)
59
		return SSH_ERR_MESSAGE_INCOMPLETE;
60
	if (v != NULL && BN_bin2bn(d + 2, len_bytes, v) == NULL)
61
		return SSH_ERR_ALLOC_FAIL;
62
	if (sshbuf_consume(buf, 2 + len_bytes) != 0) {
63
		SSHBUF_DBG(("SSH_ERR_INTERNAL_ERROR"));
64
		SSHBUF_ABORT();
65
		return SSH_ERR_INTERNAL_ERROR;
66
	}
67
	return 0;
68
}
69
70
static int
71
get_ec(const u_char *d, size_t len, EC_POINT *v, const EC_GROUP *g)
72
{
73
	/* Refuse overlong bignums */
74
18
	if (len == 0 || len > SSHBUF_MAX_ECPOINT)
75
		return SSH_ERR_ECPOINT_TOO_LARGE;
76
	/* Only handle uncompressed points */
77
9
	if (*d != POINT_CONVERSION_UNCOMPRESSED)
78
		return SSH_ERR_INVALID_FORMAT;
79

18
	if (v != NULL && EC_POINT_oct2point(g, v, d, len, NULL) != 1)
80
		return SSH_ERR_INVALID_FORMAT; /* XXX assumption */
81
9
	return 0;
82
9
}
83
84
int
85
sshbuf_get_ec(struct sshbuf *buf, EC_POINT *v, const EC_GROUP *g)
86
{
87
18
	const u_char *d;
88
9
	size_t len;
89
	int r;
90
91
9
	if ((r = sshbuf_peek_string_direct(buf, &d, &len)) < 0)
92
		return r;
93
9
	if ((r = get_ec(d, len, v, g)) != 0)
94
		return r;
95
	/* Skip string */
96
9
	if (sshbuf_get_string_direct(buf, NULL, NULL) != 0) {
97
		/* Shouldn't happen */
98
		SSHBUF_DBG(("SSH_ERR_INTERNAL_ERROR"));
99
		SSHBUF_ABORT();
100
		return SSH_ERR_INTERNAL_ERROR;
101
	}
102
9
	return 0;
103
9
}
104
105
int
106
sshbuf_get_eckey(struct sshbuf *buf, EC_KEY *v)
107
{
108
	EC_POINT *pt = EC_POINT_new(EC_KEY_get0_group(v));
109
	int r;
110
	const u_char *d;
111
	size_t len;
112
113
	if (pt == NULL) {
114
		SSHBUF_DBG(("SSH_ERR_ALLOC_FAIL"));
115
		return SSH_ERR_ALLOC_FAIL;
116
	}
117
	if ((r = sshbuf_peek_string_direct(buf, &d, &len)) < 0) {
118
		EC_POINT_free(pt);
119
		return r;
120
	}
121
	if ((r = get_ec(d, len, pt, EC_KEY_get0_group(v))) != 0) {
122
		EC_POINT_free(pt);
123
		return r;
124
	}
125
	if (EC_KEY_set_public_key(v, pt) != 1) {
126
		EC_POINT_free(pt);
127
		return SSH_ERR_ALLOC_FAIL; /* XXX assumption */
128
	}
129
	EC_POINT_free(pt);
130
	/* Skip string */
131
	if (sshbuf_get_string_direct(buf, NULL, NULL) != 0) {
132
		/* Shouldn't happen */
133
		SSHBUF_DBG(("SSH_ERR_INTERNAL_ERROR"));
134
		SSHBUF_ABORT();
135
		return SSH_ERR_INTERNAL_ERROR;
136
	}
137
	return 0;
138
}
139
140
int
141
sshbuf_put_bignum2(struct sshbuf *buf, const BIGNUM *v)
142
{
143
516
	u_char d[SSHBUF_MAX_BIGNUM + 1];
144
258
	int len = BN_num_bytes(v), prepend = 0, r;
145
146
258
	if (len < 0 || len > SSHBUF_MAX_BIGNUM)
147
		return SSH_ERR_INVALID_ARGUMENT;
148
258
	*d = '\0';
149
258
	if (BN_bn2bin(v, d + 1) != len)
150
		return SSH_ERR_INTERNAL_ERROR; /* Shouldn't happen */
151
	/* If MSB is set, prepend a \0 */
152

516
	if (len > 0 && (d[1] & 0x80) != 0)
153
137
		prepend = 1;
154
516
	if ((r = sshbuf_put_string(buf, d + 1 - prepend, len + prepend)) < 0) {
155
258
		explicit_bzero(d, sizeof(d));
156
		return r;
157
	}
158
	explicit_bzero(d, sizeof(d));
159
258
	return 0;
160
258
}
161
162
int
163
sshbuf_put_bignum1(struct sshbuf *buf, const BIGNUM *v)
164
{
165
	int r, len_bits = BN_num_bits(v);
166
	size_t len_bytes = (len_bits + 7) / 8;
167
	u_char d[SSHBUF_MAX_BIGNUM], *dp;
168
169
	if (len_bits < 0 || len_bytes > SSHBUF_MAX_BIGNUM)
170
		return SSH_ERR_INVALID_ARGUMENT;
171
	if (BN_bn2bin(v, d) != (int)len_bytes)
172
		return SSH_ERR_INTERNAL_ERROR; /* Shouldn't happen */
173
	if ((r = sshbuf_reserve(buf, len_bytes + 2, &dp)) < 0) {
174
		explicit_bzero(d, sizeof(d));
175
		return r;
176
	}
177
	POKE_U16(dp, len_bits);
178
	if (len_bytes != 0)
179
		memcpy(dp + 2, d, len_bytes);
180
	explicit_bzero(d, sizeof(d));
181
	return 0;
182
}
183
184
int
185
sshbuf_put_ec(struct sshbuf *buf, const EC_POINT *v, const EC_GROUP *g)
186
{
187
44
	u_char d[SSHBUF_MAX_ECPOINT];
188
	BN_CTX *bn_ctx;
189
	size_t len;
190
	int ret;
191
192
22
	if ((bn_ctx = BN_CTX_new()) == NULL)
193
		return SSH_ERR_ALLOC_FAIL;
194
44
	if ((len = EC_POINT_point2oct(g, v, POINT_CONVERSION_UNCOMPRESSED,
195
22
	    NULL, 0, bn_ctx)) > SSHBUF_MAX_ECPOINT) {
196
		BN_CTX_free(bn_ctx);
197
		return SSH_ERR_INVALID_ARGUMENT;
198
	}
199
44
	if (EC_POINT_point2oct(g, v, POINT_CONVERSION_UNCOMPRESSED,
200
44
	    d, len, bn_ctx) != len) {
201
22
		BN_CTX_free(bn_ctx);
202
		return SSH_ERR_INTERNAL_ERROR; /* Shouldn't happen */
203
	}
204
	BN_CTX_free(bn_ctx);
205
22
	ret = sshbuf_put_string(buf, d, len);
206
22
	explicit_bzero(d, len);
207
22
	return ret;
208
22
}
209
210
int
211
sshbuf_put_eckey(struct sshbuf *buf, const EC_KEY *v)
212
{
213
66
	return sshbuf_put_ec(buf, EC_KEY_get0_public_key(v),
214
22
	    EC_KEY_get0_group(v));
215
}
216