xref: /freebsd/crypto/openssh/sshbuf-getput-crypto.c (revision a0ee8cc636cd5c2374ec44ca71226564ea0bca95)
1*a0ee8cc6SDag-Erling Smørgrav /*	$OpenBSD: sshbuf-getput-crypto.c,v 1.2 2014/06/18 15:42:09 naddy Exp $	*/
2*a0ee8cc6SDag-Erling Smørgrav /*
3*a0ee8cc6SDag-Erling Smørgrav  * Copyright (c) 2011 Damien Miller
4*a0ee8cc6SDag-Erling Smørgrav  *
5*a0ee8cc6SDag-Erling Smørgrav  * Permission to use, copy, modify, and distribute this software for any
6*a0ee8cc6SDag-Erling Smørgrav  * purpose with or without fee is hereby granted, provided that the above
7*a0ee8cc6SDag-Erling Smørgrav  * copyright notice and this permission notice appear in all copies.
8*a0ee8cc6SDag-Erling Smørgrav  *
9*a0ee8cc6SDag-Erling Smørgrav  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10*a0ee8cc6SDag-Erling Smørgrav  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11*a0ee8cc6SDag-Erling Smørgrav  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12*a0ee8cc6SDag-Erling Smørgrav  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13*a0ee8cc6SDag-Erling Smørgrav  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14*a0ee8cc6SDag-Erling Smørgrav  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15*a0ee8cc6SDag-Erling Smørgrav  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16*a0ee8cc6SDag-Erling Smørgrav  */
17*a0ee8cc6SDag-Erling Smørgrav 
18*a0ee8cc6SDag-Erling Smørgrav #define SSHBUF_INTERNAL
19*a0ee8cc6SDag-Erling Smørgrav #include "includes.h"
20*a0ee8cc6SDag-Erling Smørgrav 
21*a0ee8cc6SDag-Erling Smørgrav #include <sys/types.h>
22*a0ee8cc6SDag-Erling Smørgrav #include <stdlib.h>
23*a0ee8cc6SDag-Erling Smørgrav #include <stdio.h>
24*a0ee8cc6SDag-Erling Smørgrav #include <string.h>
25*a0ee8cc6SDag-Erling Smørgrav 
26*a0ee8cc6SDag-Erling Smørgrav #include <openssl/bn.h>
27*a0ee8cc6SDag-Erling Smørgrav #ifdef OPENSSL_HAS_ECC
28*a0ee8cc6SDag-Erling Smørgrav # include <openssl/ec.h>
29*a0ee8cc6SDag-Erling Smørgrav #endif /* OPENSSL_HAS_ECC */
30*a0ee8cc6SDag-Erling Smørgrav 
31*a0ee8cc6SDag-Erling Smørgrav #include "ssherr.h"
32*a0ee8cc6SDag-Erling Smørgrav #include "sshbuf.h"
33*a0ee8cc6SDag-Erling Smørgrav 
34*a0ee8cc6SDag-Erling Smørgrav int
35*a0ee8cc6SDag-Erling Smørgrav sshbuf_get_bignum2(struct sshbuf *buf, BIGNUM *v)
36*a0ee8cc6SDag-Erling Smørgrav {
37*a0ee8cc6SDag-Erling Smørgrav 	const u_char *d;
38*a0ee8cc6SDag-Erling Smørgrav 	size_t len;
39*a0ee8cc6SDag-Erling Smørgrav 	int r;
40*a0ee8cc6SDag-Erling Smørgrav 
41*a0ee8cc6SDag-Erling Smørgrav 	if ((r = sshbuf_peek_string_direct(buf, &d, &len)) < 0)
42*a0ee8cc6SDag-Erling Smørgrav 		return r;
43*a0ee8cc6SDag-Erling Smørgrav 	/* Refuse negative (MSB set) bignums */
44*a0ee8cc6SDag-Erling Smørgrav 	if ((len != 0 && (*d & 0x80) != 0))
45*a0ee8cc6SDag-Erling Smørgrav 		return SSH_ERR_BIGNUM_IS_NEGATIVE;
46*a0ee8cc6SDag-Erling Smørgrav 	/* Refuse overlong bignums, allow prepended \0 to avoid MSB set */
47*a0ee8cc6SDag-Erling Smørgrav 	if (len > SSHBUF_MAX_BIGNUM + 1 ||
48*a0ee8cc6SDag-Erling Smørgrav 	    (len == SSHBUF_MAX_BIGNUM + 1 && *d != 0))
49*a0ee8cc6SDag-Erling Smørgrav 		return SSH_ERR_BIGNUM_TOO_LARGE;
50*a0ee8cc6SDag-Erling Smørgrav 	if (v != NULL && BN_bin2bn(d, len, v) == NULL)
51*a0ee8cc6SDag-Erling Smørgrav 		return SSH_ERR_ALLOC_FAIL;
52*a0ee8cc6SDag-Erling Smørgrav 	/* Consume the string */
53*a0ee8cc6SDag-Erling Smørgrav 	if (sshbuf_get_string_direct(buf, NULL, NULL) != 0) {
54*a0ee8cc6SDag-Erling Smørgrav 		/* Shouldn't happen */
55*a0ee8cc6SDag-Erling Smørgrav 		SSHBUF_DBG(("SSH_ERR_INTERNAL_ERROR"));
56*a0ee8cc6SDag-Erling Smørgrav 		SSHBUF_ABORT();
57*a0ee8cc6SDag-Erling Smørgrav 		return SSH_ERR_INTERNAL_ERROR;
58*a0ee8cc6SDag-Erling Smørgrav 	}
59*a0ee8cc6SDag-Erling Smørgrav 	return 0;
60*a0ee8cc6SDag-Erling Smørgrav }
61*a0ee8cc6SDag-Erling Smørgrav 
62*a0ee8cc6SDag-Erling Smørgrav int
63*a0ee8cc6SDag-Erling Smørgrav sshbuf_get_bignum1(struct sshbuf *buf, BIGNUM *v)
64*a0ee8cc6SDag-Erling Smørgrav {
65*a0ee8cc6SDag-Erling Smørgrav 	const u_char *d = sshbuf_ptr(buf);
66*a0ee8cc6SDag-Erling Smørgrav 	u_int16_t len_bits;
67*a0ee8cc6SDag-Erling Smørgrav 	size_t len_bytes;
68*a0ee8cc6SDag-Erling Smørgrav 
69*a0ee8cc6SDag-Erling Smørgrav 	/* Length in bits */
70*a0ee8cc6SDag-Erling Smørgrav 	if (sshbuf_len(buf) < 2)
71*a0ee8cc6SDag-Erling Smørgrav 		return SSH_ERR_MESSAGE_INCOMPLETE;
72*a0ee8cc6SDag-Erling Smørgrav 	len_bits = PEEK_U16(d);
73*a0ee8cc6SDag-Erling Smørgrav 	len_bytes = (len_bits + 7) >> 3;
74*a0ee8cc6SDag-Erling Smørgrav 	if (len_bytes > SSHBUF_MAX_BIGNUM)
75*a0ee8cc6SDag-Erling Smørgrav 		return SSH_ERR_BIGNUM_TOO_LARGE;
76*a0ee8cc6SDag-Erling Smørgrav 	if (sshbuf_len(buf) < 2 + len_bytes)
77*a0ee8cc6SDag-Erling Smørgrav 		return SSH_ERR_MESSAGE_INCOMPLETE;
78*a0ee8cc6SDag-Erling Smørgrav 	if (v != NULL && BN_bin2bn(d + 2, len_bytes, v) == NULL)
79*a0ee8cc6SDag-Erling Smørgrav 		return SSH_ERR_ALLOC_FAIL;
80*a0ee8cc6SDag-Erling Smørgrav 	if (sshbuf_consume(buf, 2 + len_bytes) != 0) {
81*a0ee8cc6SDag-Erling Smørgrav 		SSHBUF_DBG(("SSH_ERR_INTERNAL_ERROR"));
82*a0ee8cc6SDag-Erling Smørgrav 		SSHBUF_ABORT();
83*a0ee8cc6SDag-Erling Smørgrav 		return SSH_ERR_INTERNAL_ERROR;
84*a0ee8cc6SDag-Erling Smørgrav 	}
85*a0ee8cc6SDag-Erling Smørgrav 	return 0;
86*a0ee8cc6SDag-Erling Smørgrav }
87*a0ee8cc6SDag-Erling Smørgrav 
88*a0ee8cc6SDag-Erling Smørgrav #ifdef OPENSSL_HAS_ECC
89*a0ee8cc6SDag-Erling Smørgrav static int
90*a0ee8cc6SDag-Erling Smørgrav get_ec(const u_char *d, size_t len, EC_POINT *v, const EC_GROUP *g)
91*a0ee8cc6SDag-Erling Smørgrav {
92*a0ee8cc6SDag-Erling Smørgrav 	/* Refuse overlong bignums */
93*a0ee8cc6SDag-Erling Smørgrav 	if (len == 0 || len > SSHBUF_MAX_ECPOINT)
94*a0ee8cc6SDag-Erling Smørgrav 		return SSH_ERR_ECPOINT_TOO_LARGE;
95*a0ee8cc6SDag-Erling Smørgrav 	/* Only handle uncompressed points */
96*a0ee8cc6SDag-Erling Smørgrav 	if (*d != POINT_CONVERSION_UNCOMPRESSED)
97*a0ee8cc6SDag-Erling Smørgrav 		return SSH_ERR_INVALID_FORMAT;
98*a0ee8cc6SDag-Erling Smørgrav 	if (v != NULL && EC_POINT_oct2point(g, v, d, len, NULL) != 1)
99*a0ee8cc6SDag-Erling Smørgrav 		return SSH_ERR_INVALID_FORMAT; /* XXX assumption */
100*a0ee8cc6SDag-Erling Smørgrav 	return 0;
101*a0ee8cc6SDag-Erling Smørgrav }
102*a0ee8cc6SDag-Erling Smørgrav 
103*a0ee8cc6SDag-Erling Smørgrav int
104*a0ee8cc6SDag-Erling Smørgrav sshbuf_get_ec(struct sshbuf *buf, EC_POINT *v, const EC_GROUP *g)
105*a0ee8cc6SDag-Erling Smørgrav {
106*a0ee8cc6SDag-Erling Smørgrav 	const u_char *d;
107*a0ee8cc6SDag-Erling Smørgrav 	size_t len;
108*a0ee8cc6SDag-Erling Smørgrav 	int r;
109*a0ee8cc6SDag-Erling Smørgrav 
110*a0ee8cc6SDag-Erling Smørgrav 	if ((r = sshbuf_peek_string_direct(buf, &d, &len)) < 0)
111*a0ee8cc6SDag-Erling Smørgrav 		return r;
112*a0ee8cc6SDag-Erling Smørgrav 	if ((r = get_ec(d, len, v, g)) != 0)
113*a0ee8cc6SDag-Erling Smørgrav 		return r;
114*a0ee8cc6SDag-Erling Smørgrav 	/* Skip string */
115*a0ee8cc6SDag-Erling Smørgrav 	if (sshbuf_get_string_direct(buf, NULL, NULL) != 0) {
116*a0ee8cc6SDag-Erling Smørgrav 		/* Shouldn't happen */
117*a0ee8cc6SDag-Erling Smørgrav 		SSHBUF_DBG(("SSH_ERR_INTERNAL_ERROR"));
118*a0ee8cc6SDag-Erling Smørgrav 		SSHBUF_ABORT();
119*a0ee8cc6SDag-Erling Smørgrav 		return SSH_ERR_INTERNAL_ERROR;
120*a0ee8cc6SDag-Erling Smørgrav 	}
121*a0ee8cc6SDag-Erling Smørgrav 	return 0;
122*a0ee8cc6SDag-Erling Smørgrav }
123*a0ee8cc6SDag-Erling Smørgrav 
124*a0ee8cc6SDag-Erling Smørgrav int
125*a0ee8cc6SDag-Erling Smørgrav sshbuf_get_eckey(struct sshbuf *buf, EC_KEY *v)
126*a0ee8cc6SDag-Erling Smørgrav {
127*a0ee8cc6SDag-Erling Smørgrav 	EC_POINT *pt = EC_POINT_new(EC_KEY_get0_group(v));
128*a0ee8cc6SDag-Erling Smørgrav 	int r;
129*a0ee8cc6SDag-Erling Smørgrav 	const u_char *d;
130*a0ee8cc6SDag-Erling Smørgrav 	size_t len;
131*a0ee8cc6SDag-Erling Smørgrav 
132*a0ee8cc6SDag-Erling Smørgrav 	if (pt == NULL) {
133*a0ee8cc6SDag-Erling Smørgrav 		SSHBUF_DBG(("SSH_ERR_ALLOC_FAIL"));
134*a0ee8cc6SDag-Erling Smørgrav 		return SSH_ERR_ALLOC_FAIL;
135*a0ee8cc6SDag-Erling Smørgrav 	}
136*a0ee8cc6SDag-Erling Smørgrav 	if ((r = sshbuf_peek_string_direct(buf, &d, &len)) < 0) {
137*a0ee8cc6SDag-Erling Smørgrav 		EC_POINT_free(pt);
138*a0ee8cc6SDag-Erling Smørgrav 		return r;
139*a0ee8cc6SDag-Erling Smørgrav 	}
140*a0ee8cc6SDag-Erling Smørgrav 	if ((r = get_ec(d, len, pt, EC_KEY_get0_group(v))) != 0) {
141*a0ee8cc6SDag-Erling Smørgrav 		EC_POINT_free(pt);
142*a0ee8cc6SDag-Erling Smørgrav 		return r;
143*a0ee8cc6SDag-Erling Smørgrav 	}
144*a0ee8cc6SDag-Erling Smørgrav 	if (EC_KEY_set_public_key(v, pt) != 1) {
145*a0ee8cc6SDag-Erling Smørgrav 		EC_POINT_free(pt);
146*a0ee8cc6SDag-Erling Smørgrav 		return SSH_ERR_ALLOC_FAIL; /* XXX assumption */
147*a0ee8cc6SDag-Erling Smørgrav 	}
148*a0ee8cc6SDag-Erling Smørgrav 	EC_POINT_free(pt);
149*a0ee8cc6SDag-Erling Smørgrav 	/* Skip string */
150*a0ee8cc6SDag-Erling Smørgrav 	if (sshbuf_get_string_direct(buf, NULL, NULL) != 0) {
151*a0ee8cc6SDag-Erling Smørgrav 		/* Shouldn't happen */
152*a0ee8cc6SDag-Erling Smørgrav 		SSHBUF_DBG(("SSH_ERR_INTERNAL_ERROR"));
153*a0ee8cc6SDag-Erling Smørgrav 		SSHBUF_ABORT();
154*a0ee8cc6SDag-Erling Smørgrav 		return SSH_ERR_INTERNAL_ERROR;
155*a0ee8cc6SDag-Erling Smørgrav 	}
156*a0ee8cc6SDag-Erling Smørgrav 	return 0;
157*a0ee8cc6SDag-Erling Smørgrav }
158*a0ee8cc6SDag-Erling Smørgrav #endif /* OPENSSL_HAS_ECC */
159*a0ee8cc6SDag-Erling Smørgrav 
160*a0ee8cc6SDag-Erling Smørgrav int
161*a0ee8cc6SDag-Erling Smørgrav sshbuf_put_bignum2(struct sshbuf *buf, const BIGNUM *v)
162*a0ee8cc6SDag-Erling Smørgrav {
163*a0ee8cc6SDag-Erling Smørgrav 	u_char d[SSHBUF_MAX_BIGNUM + 1];
164*a0ee8cc6SDag-Erling Smørgrav 	int len = BN_num_bytes(v), prepend = 0, r;
165*a0ee8cc6SDag-Erling Smørgrav 
166*a0ee8cc6SDag-Erling Smørgrav 	if (len < 0 || len > SSHBUF_MAX_BIGNUM)
167*a0ee8cc6SDag-Erling Smørgrav 		return SSH_ERR_INVALID_ARGUMENT;
168*a0ee8cc6SDag-Erling Smørgrav 	*d = '\0';
169*a0ee8cc6SDag-Erling Smørgrav 	if (BN_bn2bin(v, d + 1) != len)
170*a0ee8cc6SDag-Erling Smørgrav 		return SSH_ERR_INTERNAL_ERROR; /* Shouldn't happen */
171*a0ee8cc6SDag-Erling Smørgrav 	/* If MSB is set, prepend a \0 */
172*a0ee8cc6SDag-Erling Smørgrav 	if (len > 0 && (d[1] & 0x80) != 0)
173*a0ee8cc6SDag-Erling Smørgrav 		prepend = 1;
174*a0ee8cc6SDag-Erling Smørgrav 	if ((r = sshbuf_put_string(buf, d + 1 - prepend, len + prepend)) < 0) {
175*a0ee8cc6SDag-Erling Smørgrav 		bzero(d, sizeof(d));
176*a0ee8cc6SDag-Erling Smørgrav 		return r;
177*a0ee8cc6SDag-Erling Smørgrav 	}
178*a0ee8cc6SDag-Erling Smørgrav 	bzero(d, sizeof(d));
179*a0ee8cc6SDag-Erling Smørgrav 	return 0;
180*a0ee8cc6SDag-Erling Smørgrav }
181*a0ee8cc6SDag-Erling Smørgrav 
182*a0ee8cc6SDag-Erling Smørgrav int
183*a0ee8cc6SDag-Erling Smørgrav sshbuf_put_bignum1(struct sshbuf *buf, const BIGNUM *v)
184*a0ee8cc6SDag-Erling Smørgrav {
185*a0ee8cc6SDag-Erling Smørgrav 	int r, len_bits = BN_num_bits(v);
186*a0ee8cc6SDag-Erling Smørgrav 	size_t len_bytes = (len_bits + 7) / 8;
187*a0ee8cc6SDag-Erling Smørgrav 	u_char d[SSHBUF_MAX_BIGNUM], *dp;
188*a0ee8cc6SDag-Erling Smørgrav 
189*a0ee8cc6SDag-Erling Smørgrav 	if (len_bits < 0 || len_bytes > SSHBUF_MAX_BIGNUM)
190*a0ee8cc6SDag-Erling Smørgrav 		return SSH_ERR_INVALID_ARGUMENT;
191*a0ee8cc6SDag-Erling Smørgrav 	if (BN_bn2bin(v, d) != (int)len_bytes)
192*a0ee8cc6SDag-Erling Smørgrav 		return SSH_ERR_INTERNAL_ERROR; /* Shouldn't happen */
193*a0ee8cc6SDag-Erling Smørgrav 	if ((r = sshbuf_reserve(buf, len_bytes + 2, &dp)) < 0) {
194*a0ee8cc6SDag-Erling Smørgrav 		bzero(d, sizeof(d));
195*a0ee8cc6SDag-Erling Smørgrav 		return r;
196*a0ee8cc6SDag-Erling Smørgrav 	}
197*a0ee8cc6SDag-Erling Smørgrav 	POKE_U16(dp, len_bits);
198*a0ee8cc6SDag-Erling Smørgrav 	memcpy(dp + 2, d, len_bytes);
199*a0ee8cc6SDag-Erling Smørgrav 	bzero(d, sizeof(d));
200*a0ee8cc6SDag-Erling Smørgrav 	return 0;
201*a0ee8cc6SDag-Erling Smørgrav }
202*a0ee8cc6SDag-Erling Smørgrav 
203*a0ee8cc6SDag-Erling Smørgrav #ifdef OPENSSL_HAS_ECC
204*a0ee8cc6SDag-Erling Smørgrav int
205*a0ee8cc6SDag-Erling Smørgrav sshbuf_put_ec(struct sshbuf *buf, const EC_POINT *v, const EC_GROUP *g)
206*a0ee8cc6SDag-Erling Smørgrav {
207*a0ee8cc6SDag-Erling Smørgrav 	u_char d[SSHBUF_MAX_ECPOINT];
208*a0ee8cc6SDag-Erling Smørgrav 	BN_CTX *bn_ctx;
209*a0ee8cc6SDag-Erling Smørgrav 	size_t len;
210*a0ee8cc6SDag-Erling Smørgrav 	int ret;
211*a0ee8cc6SDag-Erling Smørgrav 
212*a0ee8cc6SDag-Erling Smørgrav 	if ((bn_ctx = BN_CTX_new()) == NULL)
213*a0ee8cc6SDag-Erling Smørgrav 		return SSH_ERR_ALLOC_FAIL;
214*a0ee8cc6SDag-Erling Smørgrav 	if ((len = EC_POINT_point2oct(g, v, POINT_CONVERSION_UNCOMPRESSED,
215*a0ee8cc6SDag-Erling Smørgrav 	    NULL, 0, bn_ctx)) > SSHBUF_MAX_ECPOINT) {
216*a0ee8cc6SDag-Erling Smørgrav 		BN_CTX_free(bn_ctx);
217*a0ee8cc6SDag-Erling Smørgrav 		return SSH_ERR_INVALID_ARGUMENT;
218*a0ee8cc6SDag-Erling Smørgrav 	}
219*a0ee8cc6SDag-Erling Smørgrav 	if (EC_POINT_point2oct(g, v, POINT_CONVERSION_UNCOMPRESSED,
220*a0ee8cc6SDag-Erling Smørgrav 	    d, len, bn_ctx) != len) {
221*a0ee8cc6SDag-Erling Smørgrav 		BN_CTX_free(bn_ctx);
222*a0ee8cc6SDag-Erling Smørgrav 		return SSH_ERR_INTERNAL_ERROR; /* Shouldn't happen */
223*a0ee8cc6SDag-Erling Smørgrav 	}
224*a0ee8cc6SDag-Erling Smørgrav 	BN_CTX_free(bn_ctx);
225*a0ee8cc6SDag-Erling Smørgrav 	ret = sshbuf_put_string(buf, d, len);
226*a0ee8cc6SDag-Erling Smørgrav 	bzero(d, len);
227*a0ee8cc6SDag-Erling Smørgrav 	return ret;
228*a0ee8cc6SDag-Erling Smørgrav }
229*a0ee8cc6SDag-Erling Smørgrav 
230*a0ee8cc6SDag-Erling Smørgrav int
231*a0ee8cc6SDag-Erling Smørgrav sshbuf_put_eckey(struct sshbuf *buf, const EC_KEY *v)
232*a0ee8cc6SDag-Erling Smørgrav {
233*a0ee8cc6SDag-Erling Smørgrav 	return sshbuf_put_ec(buf, EC_KEY_get0_public_key(v),
234*a0ee8cc6SDag-Erling Smørgrav 	    EC_KEY_get0_group(v));
235*a0ee8cc6SDag-Erling Smørgrav }
236*a0ee8cc6SDag-Erling Smørgrav #endif /* OPENSSL_HAS_ECC */
237*a0ee8cc6SDag-Erling Smørgrav 
238