xref: /netbsd-src/crypto/external/bsd/openssh/dist/sshbuf-getput-crypto.c (revision bdc22b2e01993381dcefeff2bc9b56ca75a4235c)
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 #include "includes.h"
18 __RCSID("$NetBSD: sshbuf-getput-crypto.c,v 1.8 2017/04/18 18:41:46 christos Exp $");
19 
20 #include <sys/types.h>
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include <string.h>
24 
25 #include <openssl/bn.h>
26 #include <openssl/ec.h>
27 
28 #include "ssherr.h"
29 #define SSHBUF_INTERNAL
30 #include "sshbuf.h"
31 
32 int
33 sshbuf_get_bignum2(struct sshbuf *buf, BIGNUM *v)
34 {
35 	const u_char *d;
36 	size_t len;
37 	int r;
38 
39 	if ((r = sshbuf_get_bignum2_bytes_direct(buf, &d, &len)) != 0)
40 		return r;
41 	if (v != NULL && BN_bin2bn(d, len, v) == NULL)
42 		return SSH_ERR_ALLOC_FAIL;
43 	return 0;
44 }
45 
46 int
47 sshbuf_get_bignum1(struct sshbuf *buf, BIGNUM *v)
48 {
49 	const u_char *d = sshbuf_ptr(buf);
50 	u_int16_t len_bits;
51 	size_t len_bytes;
52 
53 	/* Length in bits */
54 	if (sshbuf_len(buf) < 2)
55 		return SSH_ERR_MESSAGE_INCOMPLETE;
56 	len_bits = PEEK_U16(d);
57 	len_bytes = (len_bits + 7) >> 3;
58 	if (len_bytes > SSHBUF_MAX_BIGNUM)
59 		return SSH_ERR_BIGNUM_TOO_LARGE;
60 	if (sshbuf_len(buf) < 2 + len_bytes)
61 		return SSH_ERR_MESSAGE_INCOMPLETE;
62 	if (v != NULL && BN_bin2bn(d + 2, len_bytes, v) == NULL)
63 		return SSH_ERR_ALLOC_FAIL;
64 	if (sshbuf_consume(buf, 2 + len_bytes) != 0) {
65 		SSHBUF_DBG(("SSH_ERR_INTERNAL_ERROR"));
66 		SSHBUF_ABORT();
67 		return SSH_ERR_INTERNAL_ERROR;
68 	}
69 	return 0;
70 }
71 
72 static int
73 get_ec(const u_char *d, size_t len, EC_POINT *v, const EC_GROUP *g)
74 {
75 	/* Refuse overlong bignums */
76 	if (len == 0 || len > SSHBUF_MAX_ECPOINT)
77 		return SSH_ERR_ECPOINT_TOO_LARGE;
78 	/* Only handle uncompressed points */
79 	if (*d != POINT_CONVERSION_UNCOMPRESSED)
80 		return SSH_ERR_INVALID_FORMAT;
81 	if (v != NULL && EC_POINT_oct2point(g, v, d, len, NULL) != 1)
82 		return SSH_ERR_INVALID_FORMAT; /* XXX assumption */
83 	return 0;
84 }
85 
86 int
87 sshbuf_get_ec(struct sshbuf *buf, EC_POINT *v, const EC_GROUP *g)
88 {
89 	const u_char *d;
90 	size_t len;
91 	int r;
92 
93 	if ((r = sshbuf_peek_string_direct(buf, &d, &len)) < 0)
94 		return r;
95 	if ((r = get_ec(d, len, v, g)) != 0)
96 		return r;
97 	/* Skip string */
98 	if (sshbuf_get_string_direct(buf, NULL, NULL) != 0) {
99 		/* Shouldn't happen */
100 		SSHBUF_DBG(("SSH_ERR_INTERNAL_ERROR"));
101 		SSHBUF_ABORT();
102 		return SSH_ERR_INTERNAL_ERROR;
103 	}
104 	return 0;
105 }
106 
107 int
108 sshbuf_get_eckey(struct sshbuf *buf, EC_KEY *v)
109 {
110 	EC_POINT *pt = EC_POINT_new(EC_KEY_get0_group(v));
111 	int r;
112 	const u_char *d;
113 	size_t len;
114 
115 	if (pt == NULL) {
116 		SSHBUF_DBG(("SSH_ERR_ALLOC_FAIL"));
117 		return SSH_ERR_ALLOC_FAIL;
118 	}
119 	if ((r = sshbuf_peek_string_direct(buf, &d, &len)) < 0) {
120 		EC_POINT_free(pt);
121 		return r;
122 	}
123 	if ((r = get_ec(d, len, pt, EC_KEY_get0_group(v))) != 0) {
124 		EC_POINT_free(pt);
125 		return r;
126 	}
127 	if (EC_KEY_set_public_key(v, pt) != 1) {
128 		EC_POINT_free(pt);
129 		return SSH_ERR_ALLOC_FAIL; /* XXX assumption */
130 	}
131 	EC_POINT_free(pt);
132 	/* Skip string */
133 	if (sshbuf_get_string_direct(buf, NULL, NULL) != 0) {
134 		/* Shouldn't happen */
135 		SSHBUF_DBG(("SSH_ERR_INTERNAL_ERROR"));
136 		SSHBUF_ABORT();
137 		return SSH_ERR_INTERNAL_ERROR;
138 	}
139 	return 0;
140 }
141 
142 int
143 sshbuf_put_bignum2(struct sshbuf *buf, const BIGNUM *v)
144 {
145 	u_char d[SSHBUF_MAX_BIGNUM + 1];
146 	int len = BN_num_bytes(v), prepend = 0, r;
147 
148 	if (len < 0 || len > SSHBUF_MAX_BIGNUM)
149 		return SSH_ERR_INVALID_ARGUMENT;
150 	*d = '\0';
151 	if (BN_bn2bin(v, d + 1) != len)
152 		return SSH_ERR_INTERNAL_ERROR; /* Shouldn't happen */
153 	/* If MSB is set, prepend a \0 */
154 	if (len > 0 && (d[1] & 0x80) != 0)
155 		prepend = 1;
156 	if ((r = sshbuf_put_string(buf, d + 1 - prepend, len + prepend)) < 0) {
157 		explicit_bzero(d, sizeof(d));
158 		return r;
159 	}
160 	explicit_bzero(d, sizeof(d));
161 	return 0;
162 }
163 
164 int
165 sshbuf_put_bignum1(struct sshbuf *buf, const BIGNUM *v)
166 {
167 	int r, len_bits = BN_num_bits(v);
168 	size_t len_bytes = (len_bits + 7) / 8;
169 	u_char d[SSHBUF_MAX_BIGNUM], *dp;
170 
171 	if (len_bits < 0 || len_bytes > SSHBUF_MAX_BIGNUM)
172 		return SSH_ERR_INVALID_ARGUMENT;
173 	if (BN_bn2bin(v, d) != (int)len_bytes)
174 		return SSH_ERR_INTERNAL_ERROR; /* Shouldn't happen */
175 	if ((r = sshbuf_reserve(buf, len_bytes + 2, &dp)) < 0) {
176 		explicit_bzero(d, sizeof(d));
177 		return r;
178 	}
179 	POKE_U16(dp, len_bits);
180 	if (len_bytes != 0)
181 		memcpy(dp + 2, d, len_bytes);
182 	explicit_bzero(d, sizeof(d));
183 	return 0;
184 }
185 
186 int
187 sshbuf_put_ec(struct sshbuf *buf, const EC_POINT *v, const EC_GROUP *g)
188 {
189 	u_char d[SSHBUF_MAX_ECPOINT];
190 	BN_CTX *bn_ctx;
191 	size_t len;
192 	int ret;
193 
194 	if ((bn_ctx = BN_CTX_new()) == NULL)
195 		return SSH_ERR_ALLOC_FAIL;
196 	if ((len = EC_POINT_point2oct(g, v, POINT_CONVERSION_UNCOMPRESSED,
197 	    NULL, 0, bn_ctx)) > SSHBUF_MAX_ECPOINT) {
198 		BN_CTX_free(bn_ctx);
199 		return SSH_ERR_INVALID_ARGUMENT;
200 	}
201 	if (EC_POINT_point2oct(g, v, POINT_CONVERSION_UNCOMPRESSED,
202 	    d, len, bn_ctx) != len) {
203 		BN_CTX_free(bn_ctx);
204 		return SSH_ERR_INTERNAL_ERROR; /* Shouldn't happen */
205 	}
206 	BN_CTX_free(bn_ctx);
207 	ret = sshbuf_put_string(buf, d, len);
208 	explicit_bzero(d, len);
209 	return ret;
210 }
211 
212 int
213 sshbuf_put_eckey(struct sshbuf *buf, const EC_KEY *v)
214 {
215 	return sshbuf_put_ec(buf, EC_KEY_get0_public_key(v),
216 	    EC_KEY_get0_group(v));
217 }
218 
219