diff options
-rw-r--r-- | ChangeLog | 14 | ||||
-rw-r--r-- | bufaux.c | 332 | ||||
-rw-r--r-- | bufbn.c | 210 | ||||
-rw-r--r-- | bufec.c | 107 | ||||
-rw-r--r-- | buffer.c | 245 | ||||
-rw-r--r-- | buffer.h | 64 | ||||
-rw-r--r-- | sshbuf-getput-basic.c | 421 | ||||
-rw-r--r-- | sshbuf-getput-crypto.c | 233 | ||||
-rw-r--r-- | sshbuf-misc.c | 129 | ||||
-rw-r--r-- | sshbuf.c | 405 | ||||
-rw-r--r-- | sshbuf.h | 325 | ||||
-rw-r--r-- | ssherr.c | 131 | ||||
-rw-r--r-- | ssherr.h | 80 |
13 files changed, 1977 insertions, 719 deletions
@@ -52,6 +52,20 @@ | |||
52 | Don't attempt to append a nul quote char to the filename. Should prevent | 52 | Don't attempt to append a nul quote char to the filename. Should prevent |
53 | fatal'ing with "el_insertstr failed" when there's a single quote char | 53 | fatal'ing with "el_insertstr failed" when there's a single quote char |
54 | somewhere in the string. bz#2238, ok markus@ | 54 | somewhere in the string. bz#2238, ok markus@ |
55 | - djm@cvs.openbsd.org 2014/04/30 05:29:56 | ||
56 | [bufaux.c bufbn.c bufec.c buffer.c buffer.h sshbuf-getput-basic.c] | ||
57 | [sshbuf-getput-crypto.c sshbuf-misc.c sshbuf.c sshbuf.h ssherr.c] | ||
58 | [ssherr.h] | ||
59 | New buffer API; the first installment of the conversion/replacement | ||
60 | of OpenSSH's internals to make them usable as a standalone library. | ||
61 | |||
62 | This includes a set of wrappers to make it compatible with the | ||
63 | existing buffer API so replacement can occur incrementally. | ||
64 | |||
65 | With and ok markus@ | ||
66 | |||
67 | Thanks also to Ben Hawkes, David Tomaschik, Ivan Fratric, Matthew | ||
68 | Dempsky and Ron Bowes for a detailed review. | ||
55 | 69 | ||
56 | 20140430 | 70 | 20140430 |
57 | - (dtucker) [defines.h] Define __GNUC_PREREQ__ macro if we don't already | 71 | - (dtucker) [defines.h] Define __GNUC_PREREQ__ macro if we don't already |
@@ -1,68 +1,38 @@ | |||
1 | /* $OpenBSD: bufaux.c,v 1.59 2014/04/29 18:01:49 markus Exp $ */ | 1 | /* $OpenBSD: bufaux.c,v 1.60 2014/04/30 05:29:56 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 3 | * Copyright (c) 2012 Damien Miller <djm@mindrot.org> |
4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | ||
5 | * All rights reserved | ||
6 | * Auxiliary functions for storing and retrieving various data types to/from | ||
7 | * Buffers. | ||
8 | * | 4 | * |
9 | * As far as I am concerned, the code I have written for this software | 5 | * Permission to use, copy, modify, and distribute this software for any |
10 | * can be used freely for any purpose. Any derived versions of this | 6 | * purpose with or without fee is hereby granted, provided that the above |
11 | * software must be clearly marked as such, and if the derived work is | 7 | * copyright notice and this permission notice appear in all copies. |
12 | * incompatible with the protocol description in the RFC file, it must be | ||
13 | * called by a name other than "ssh" or "Secure Shell". | ||
14 | * | 8 | * |
15 | * | 9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
16 | * SSH2 packet format added by Markus Friedl | 10 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
17 | * Copyright (c) 2000 Markus Friedl. All rights reserved. | 11 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
18 | * | 12 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
19 | * Redistribution and use in source and binary forms, with or without | 13 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
20 | * modification, are permitted provided that the following conditions | 14 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
21 | * are met: | 15 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
22 | * 1. Redistributions of source code must retain the above copyright | ||
23 | * notice, this list of conditions and the following disclaimer. | ||
24 | * 2. Redistributions in binary form must reproduce the above copyright | ||
25 | * notice, this list of conditions and the following disclaimer in the | ||
26 | * documentation and/or other materials provided with the distribution. | ||
27 | * | ||
28 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | ||
29 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | ||
30 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | ||
31 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
32 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||
33 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
34 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
35 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
36 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
37 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
38 | */ | 16 | */ |
39 | 17 | ||
40 | #include "includes.h" | 18 | /* Emulation wrappers for legacy OpenSSH buffer API atop sshbuf */ |
41 | 19 | ||
42 | #include <sys/types.h> | 20 | #include <sys/types.h> |
43 | 21 | ||
44 | #include <string.h> | ||
45 | #include <stdarg.h> | ||
46 | #include <stdlib.h> | ||
47 | |||
48 | #include "xmalloc.h" | ||
49 | #include "buffer.h" | 22 | #include "buffer.h" |
50 | #include "log.h" | 23 | #include "log.h" |
51 | #include "misc.h" | 24 | #include "ssherr.h" |
52 | |||
53 | /* | ||
54 | * Returns integers from the buffer (msb first). | ||
55 | */ | ||
56 | 25 | ||
57 | int | 26 | int |
58 | buffer_get_short_ret(u_short *ret, Buffer *buffer) | 27 | buffer_get_short_ret(u_short *v, Buffer *buffer) |
59 | { | 28 | { |
60 | u_char buf[2]; | 29 | int ret; |
61 | 30 | ||
62 | if (buffer_get_ret(buffer, (char *) buf, 2) == -1) | 31 | if ((ret = sshbuf_get_u16(buffer, v)) != 0) { |
63 | return (-1); | 32 | error("%s: %s", __func__, ssh_err(ret)); |
64 | *ret = get_u16(buf); | 33 | return -1; |
65 | return (0); | 34 | } |
35 | return 0; | ||
66 | } | 36 | } |
67 | 37 | ||
68 | u_short | 38 | u_short |
@@ -71,21 +41,21 @@ buffer_get_short(Buffer *buffer) | |||
71 | u_short ret; | 41 | u_short ret; |
72 | 42 | ||
73 | if (buffer_get_short_ret(&ret, buffer) == -1) | 43 | if (buffer_get_short_ret(&ret, buffer) == -1) |
74 | fatal("buffer_get_short: buffer error"); | 44 | fatal("%s: buffer error", __func__); |
75 | 45 | ||
76 | return (ret); | 46 | return (ret); |
77 | } | 47 | } |
78 | 48 | ||
79 | int | 49 | int |
80 | buffer_get_int_ret(u_int *ret, Buffer *buffer) | 50 | buffer_get_int_ret(u_int *v, Buffer *buffer) |
81 | { | 51 | { |
82 | u_char buf[4]; | 52 | int ret; |
83 | 53 | ||
84 | if (buffer_get_ret(buffer, (char *) buf, 4) == -1) | 54 | if ((ret = sshbuf_get_u32(buffer, v)) != 0) { |
85 | return (-1); | 55 | error("%s: %s", __func__, ssh_err(ret)); |
86 | if (ret != NULL) | 56 | return -1; |
87 | *ret = get_u32(buf); | 57 | } |
88 | return (0); | 58 | return 0; |
89 | } | 59 | } |
90 | 60 | ||
91 | u_int | 61 | u_int |
@@ -94,21 +64,21 @@ buffer_get_int(Buffer *buffer) | |||
94 | u_int ret; | 64 | u_int ret; |
95 | 65 | ||
96 | if (buffer_get_int_ret(&ret, buffer) == -1) | 66 | if (buffer_get_int_ret(&ret, buffer) == -1) |
97 | fatal("buffer_get_int: buffer error"); | 67 | fatal("%s: buffer error", __func__); |
98 | 68 | ||
99 | return (ret); | 69 | return (ret); |
100 | } | 70 | } |
101 | 71 | ||
102 | int | 72 | int |
103 | buffer_get_int64_ret(u_int64_t *ret, Buffer *buffer) | 73 | buffer_get_int64_ret(u_int64_t *v, Buffer *buffer) |
104 | { | 74 | { |
105 | u_char buf[8]; | 75 | int ret; |
106 | 76 | ||
107 | if (buffer_get_ret(buffer, (char *) buf, 8) == -1) | 77 | if ((ret = sshbuf_get_u64(buffer, v)) != 0) { |
108 | return (-1); | 78 | error("%s: %s", __func__, ssh_err(ret)); |
109 | if (ret != NULL) | 79 | return -1; |
110 | *ret = get_u64(buf); | 80 | } |
111 | return (0); | 81 | return 0; |
112 | } | 82 | } |
113 | 83 | ||
114 | u_int64_t | 84 | u_int64_t |
@@ -117,78 +87,52 @@ buffer_get_int64(Buffer *buffer) | |||
117 | u_int64_t ret; | 87 | u_int64_t ret; |
118 | 88 | ||
119 | if (buffer_get_int64_ret(&ret, buffer) == -1) | 89 | if (buffer_get_int64_ret(&ret, buffer) == -1) |
120 | fatal("buffer_get_int: buffer error"); | 90 | fatal("%s: buffer error", __func__); |
121 | 91 | ||
122 | return (ret); | 92 | return (ret); |
123 | } | 93 | } |
124 | 94 | ||
125 | /* | ||
126 | * Stores integers in the buffer, msb first. | ||
127 | */ | ||
128 | void | 95 | void |
129 | buffer_put_short(Buffer *buffer, u_short value) | 96 | buffer_put_short(Buffer *buffer, u_short value) |
130 | { | 97 | { |
131 | char buf[2]; | 98 | int ret; |
132 | 99 | ||
133 | put_u16(buf, value); | 100 | if ((ret = sshbuf_put_u16(buffer, value)) != 0) |
134 | buffer_append(buffer, buf, 2); | 101 | fatal("%s: %s", __func__, ssh_err(ret)); |
135 | } | 102 | } |
136 | 103 | ||
137 | void | 104 | void |
138 | buffer_put_int(Buffer *buffer, u_int value) | 105 | buffer_put_int(Buffer *buffer, u_int value) |
139 | { | 106 | { |
140 | char buf[4]; | 107 | int ret; |
141 | 108 | ||
142 | put_u32(buf, value); | 109 | if ((ret = sshbuf_put_u32(buffer, value)) != 0) |
143 | buffer_append(buffer, buf, 4); | 110 | fatal("%s: %s", __func__, ssh_err(ret)); |
144 | } | 111 | } |
145 | 112 | ||
146 | void | 113 | void |
147 | buffer_put_int64(Buffer *buffer, u_int64_t value) | 114 | buffer_put_int64(Buffer *buffer, u_int64_t value) |
148 | { | 115 | { |
149 | char buf[8]; | 116 | int ret; |
150 | 117 | ||
151 | put_u64(buf, value); | 118 | if ((ret = sshbuf_put_u64(buffer, value)) != 0) |
152 | buffer_append(buffer, buf, 8); | 119 | fatal("%s: %s", __func__, ssh_err(ret)); |
153 | } | 120 | } |
154 | 121 | ||
155 | /* | ||
156 | * Returns an arbitrary binary string from the buffer. The string cannot | ||
157 | * be longer than 256k. The returned value points to memory allocated | ||
158 | * with xmalloc; it is the responsibility of the calling function to free | ||
159 | * the data. If length_ptr is non-NULL, the length of the returned data | ||
160 | * will be stored there. A null character will be automatically appended | ||
161 | * to the returned string, and is not counted in length. | ||
162 | */ | ||
163 | void * | 122 | void * |
164 | buffer_get_string_ret(Buffer *buffer, u_int *length_ptr) | 123 | buffer_get_string_ret(Buffer *buffer, u_int *length_ptr) |
165 | { | 124 | { |
125 | size_t len; | ||
126 | int ret; | ||
166 | u_char *value; | 127 | u_char *value; |
167 | u_int len; | ||
168 | 128 | ||
169 | /* Get the length. */ | 129 | if ((ret = sshbuf_get_string(buffer, &value, &len)) != 0) { |
170 | if (buffer_get_int_ret(&len, buffer) != 0) { | 130 | error("%s: %s", __func__, ssh_err(ret)); |
171 | error("buffer_get_string_ret: cannot extract length"); | 131 | return NULL; |
172 | return (NULL); | ||
173 | } | ||
174 | if (len > 256 * 1024) { | ||
175 | error("buffer_get_string_ret: bad string length %u", len); | ||
176 | return (NULL); | ||
177 | } | ||
178 | /* Allocate space for the string. Add one byte for a null character. */ | ||
179 | value = xmalloc(len + 1); | ||
180 | /* Get the string. */ | ||
181 | if (buffer_get_ret(buffer, value, len) == -1) { | ||
182 | error("buffer_get_string_ret: buffer_get failed"); | ||
183 | free(value); | ||
184 | return (NULL); | ||
185 | } | 132 | } |
186 | /* Append a null character to make processing easier. */ | 133 | if (length_ptr != NULL) |
187 | value[len] = '\0'; | 134 | *length_ptr = len; /* Safe: sshbuf never stores len > 2^31 */ |
188 | /* Optionally return the length of the string. */ | 135 | return value; |
189 | if (length_ptr) | ||
190 | *length_ptr = len; | ||
191 | return (value); | ||
192 | } | 136 | } |
193 | 137 | ||
194 | void * | 138 | void * |
@@ -197,31 +141,24 @@ buffer_get_string(Buffer *buffer, u_int *length_ptr) | |||
197 | void *ret; | 141 | void *ret; |
198 | 142 | ||
199 | if ((ret = buffer_get_string_ret(buffer, length_ptr)) == NULL) | 143 | if ((ret = buffer_get_string_ret(buffer, length_ptr)) == NULL) |
200 | fatal("buffer_get_string: buffer error"); | 144 | fatal("%s: buffer error", __func__); |
201 | return (ret); | 145 | return (ret); |
202 | } | 146 | } |
203 | 147 | ||
204 | char * | 148 | char * |
205 | buffer_get_cstring_ret(Buffer *buffer, u_int *length_ptr) | 149 | buffer_get_cstring_ret(Buffer *buffer, u_int *length_ptr) |
206 | { | 150 | { |
207 | u_int length; | 151 | size_t len; |
208 | char *cp, *ret = buffer_get_string_ret(buffer, &length); | 152 | int ret; |
153 | char *value; | ||
209 | 154 | ||
210 | if (ret == NULL) | 155 | if ((ret = sshbuf_get_cstring(buffer, &value, &len)) != 0) { |
156 | error("%s: %s", __func__, ssh_err(ret)); | ||
211 | return NULL; | 157 | return NULL; |
212 | if ((cp = memchr(ret, '\0', length)) != NULL) { | ||
213 | /* XXX allow \0 at end-of-string for a while, remove later */ | ||
214 | if (cp == ret + length - 1) | ||
215 | error("buffer_get_cstring_ret: string contains \\0"); | ||
216 | else { | ||
217 | explicit_bzero(ret, length); | ||
218 | free(ret); | ||
219 | return NULL; | ||
220 | } | ||
221 | } | 158 | } |
222 | if (length_ptr != NULL) | 159 | if (length_ptr != NULL) |
223 | *length_ptr = length; | 160 | *length_ptr = len; /* Safe: sshbuf never stores len > 2^31 */ |
224 | return ret; | 161 | return value; |
225 | } | 162 | } |
226 | 163 | ||
227 | char * | 164 | char * |
@@ -230,27 +167,24 @@ buffer_get_cstring(Buffer *buffer, u_int *length_ptr) | |||
230 | char *ret; | 167 | char *ret; |
231 | 168 | ||
232 | if ((ret = buffer_get_cstring_ret(buffer, length_ptr)) == NULL) | 169 | if ((ret = buffer_get_cstring_ret(buffer, length_ptr)) == NULL) |
233 | fatal("buffer_get_cstring: buffer error"); | 170 | fatal("%s: buffer error", __func__); |
234 | return ret; | 171 | return ret; |
235 | } | 172 | } |
236 | 173 | ||
237 | const void * | 174 | const void * |
238 | buffer_get_string_ptr_ret(Buffer *buffer, u_int *length_ptr) | 175 | buffer_get_string_ptr_ret(Buffer *buffer, u_int *length_ptr) |
239 | { | 176 | { |
240 | void *ptr; | 177 | size_t len; |
241 | u_int len; | 178 | int ret; |
179 | const u_char *value; | ||
242 | 180 | ||
243 | if (buffer_get_int_ret(&len, buffer) != 0) | 181 | if ((ret = sshbuf_get_string_direct(buffer, &value, &len)) != 0) { |
244 | return NULL; | 182 | error("%s: %s", __func__, ssh_err(ret)); |
245 | if (len > 256 * 1024) { | ||
246 | error("buffer_get_string_ptr: bad string length %u", len); | ||
247 | return NULL; | 183 | return NULL; |
248 | } | 184 | } |
249 | ptr = buffer_ptr(buffer); | 185 | if (length_ptr != NULL) |
250 | buffer_consume(buffer, len); | 186 | *length_ptr = len; /* Safe: sshbuf never stores len > 2^31 */ |
251 | if (length_ptr) | 187 | return value; |
252 | *length_ptr = len; | ||
253 | return (ptr); | ||
254 | } | 188 | } |
255 | 189 | ||
256 | const void * | 190 | const void * |
@@ -259,133 +193,65 @@ buffer_get_string_ptr(Buffer *buffer, u_int *length_ptr) | |||
259 | const void *ret; | 193 | const void *ret; |
260 | 194 | ||
261 | if ((ret = buffer_get_string_ptr_ret(buffer, length_ptr)) == NULL) | 195 | if ((ret = buffer_get_string_ptr_ret(buffer, length_ptr)) == NULL) |
262 | fatal("buffer_get_string_ptr: buffer error"); | 196 | fatal("%s: buffer error", __func__); |
263 | return (ret); | 197 | return (ret); |
264 | } | 198 | } |
265 | 199 | ||
266 | /* | ||
267 | * Stores and arbitrary binary string in the buffer. | ||
268 | */ | ||
269 | void | 200 | void |
270 | buffer_put_string(Buffer *buffer, const void *buf, u_int len) | 201 | buffer_put_string(Buffer *buffer, const void *buf, u_int len) |
271 | { | 202 | { |
272 | buffer_put_int(buffer, len); | 203 | int ret; |
273 | buffer_append(buffer, buf, len); | 204 | |
205 | if ((ret = sshbuf_put_string(buffer, buf, len)) != 0) | ||
206 | fatal("%s: %s", __func__, ssh_err(ret)); | ||
274 | } | 207 | } |
208 | |||
275 | void | 209 | void |
276 | buffer_put_cstring(Buffer *buffer, const char *s) | 210 | buffer_put_cstring(Buffer *buffer, const char *s) |
277 | { | 211 | { |
278 | if (s == NULL) | 212 | int ret; |
279 | fatal("buffer_put_cstring: s == NULL"); | 213 | |
280 | buffer_put_string(buffer, s, strlen(s)); | 214 | if ((ret = sshbuf_put_cstring(buffer, s)) != 0) |
215 | fatal("%s: %s", __func__, ssh_err(ret)); | ||
281 | } | 216 | } |
282 | 217 | ||
283 | /* | ||
284 | * Returns a character from the buffer (0 - 255). | ||
285 | */ | ||
286 | int | 218 | int |
287 | buffer_get_char_ret(u_char *ret, Buffer *buffer) | 219 | buffer_get_char_ret(char *v, Buffer *buffer) |
288 | { | 220 | { |
289 | if (buffer_get_ret(buffer, ret, 1) == -1) { | 221 | int ret; |
290 | error("buffer_get_char_ret: buffer_get_ret failed"); | 222 | |
291 | return (-1); | 223 | if ((ret = sshbuf_get_u8(buffer, (u_char *)v)) != 0) { |
224 | error("%s: %s", __func__, ssh_err(ret)); | ||
225 | return -1; | ||
292 | } | 226 | } |
293 | return (0); | 227 | return 0; |
294 | } | 228 | } |
295 | 229 | ||
296 | int | 230 | int |
297 | buffer_get_char(Buffer *buffer) | 231 | buffer_get_char(Buffer *buffer) |
298 | { | 232 | { |
299 | u_char ch; | 233 | char ch; |
300 | 234 | ||
301 | if (buffer_get_char_ret(&ch, buffer) == -1) | 235 | if (buffer_get_char_ret(&ch, buffer) == -1) |
302 | fatal("buffer_get_char: buffer error"); | 236 | fatal("%s: buffer error", __func__); |
303 | return ch; | 237 | return (u_char) ch; |
304 | } | 238 | } |
305 | 239 | ||
306 | /* | ||
307 | * Stores a character in the buffer. | ||
308 | */ | ||
309 | void | 240 | void |
310 | buffer_put_char(Buffer *buffer, int value) | 241 | buffer_put_char(Buffer *buffer, int value) |
311 | { | 242 | { |
312 | char ch = value; | 243 | int ret; |
313 | |||
314 | buffer_append(buffer, &ch, 1); | ||
315 | } | ||
316 | |||
317 | /* Pseudo bignum functions */ | ||
318 | |||
319 | void * | ||
320 | buffer_get_bignum2_as_string_ret(Buffer *buffer, u_int *length_ptr) | ||
321 | { | ||
322 | u_int len; | ||
323 | u_char *bin, *p, *ret; | ||
324 | |||
325 | if ((p = bin = buffer_get_string_ret(buffer, &len)) == NULL) { | ||
326 | error("%s: invalid bignum", __func__); | ||
327 | return NULL; | ||
328 | } | ||
329 | |||
330 | if (len > 0 && (bin[0] & 0x80)) { | ||
331 | error("%s: negative numbers not supported", __func__); | ||
332 | free(bin); | ||
333 | return NULL; | ||
334 | } | ||
335 | if (len > 8 * 1024) { | ||
336 | error("%s: cannot handle BN of size %d", __func__, len); | ||
337 | free(bin); | ||
338 | return NULL; | ||
339 | } | ||
340 | /* Skip zero prefix on numbers with the MSB set */ | ||
341 | if (len > 1 && bin[0] == 0x00 && (bin[1] & 0x80) != 0) { | ||
342 | p++; | ||
343 | len--; | ||
344 | } | ||
345 | ret = xmalloc(len); | ||
346 | memcpy(ret, p, len); | ||
347 | explicit_bzero(p, len); | ||
348 | free(bin); | ||
349 | return ret; | ||
350 | } | ||
351 | |||
352 | void * | ||
353 | buffer_get_bignum2_as_string(Buffer *buffer, u_int *l) | ||
354 | { | ||
355 | void *ret = buffer_get_bignum2_as_string_ret(buffer, l); | ||
356 | 244 | ||
357 | if (ret == NULL) | 245 | if ((ret = sshbuf_put_u8(buffer, value)) != 0) |
358 | fatal("%s: buffer error", __func__); | 246 | fatal("%s: %s", __func__, ssh_err(ret)); |
359 | return ret; | ||
360 | } | 247 | } |
361 | 248 | ||
362 | /* | ||
363 | * Stores a string using the bignum encoding rules (\0 pad if MSB set). | ||
364 | */ | ||
365 | void | 249 | void |
366 | buffer_put_bignum2_from_string(Buffer *buffer, const u_char *s, u_int l) | 250 | buffer_put_bignum2_from_string(Buffer *buffer, const u_char *s, u_int l) |
367 | { | 251 | { |
368 | u_char *buf, *p; | 252 | int ret; |
369 | int pad = 0; | ||
370 | |||
371 | if (l > 8 * 1024) | ||
372 | fatal("%s: length %u too long", __func__, l); | ||
373 | /* Skip leading zero bytes */ | ||
374 | for (; l > 0 && *s == 0; l--, s++) | ||
375 | ; | ||
376 | p = buf = xmalloc(l + 1); | ||
377 | /* | ||
378 | * If most significant bit is set then prepend a zero byte to | ||
379 | * avoid interpretation as a negative number. | ||
380 | */ | ||
381 | if (l > 0 && (s[0] & 0x80) != 0) { | ||
382 | *p++ = '\0'; | ||
383 | pad = 1; | ||
384 | } | ||
385 | memcpy(p, s, l); | ||
386 | buffer_put_string(buffer, buf, l + pad); | ||
387 | explicit_bzero(buf, l + pad); | ||
388 | free(buf); | ||
389 | } | ||
390 | 253 | ||
254 | if ((ret = sshbuf_put_bignum2_bytes(buffer, s, l)) != 0) | ||
255 | fatal("%s: %s", __func__, ssh_err(ret)); | ||
256 | } | ||
391 | 257 | ||
@@ -1,229 +1,101 @@ | |||
1 | /* $OpenBSD: bufbn.c,v 1.11 2014/02/27 08:25:09 djm Exp $*/ | 1 | /* $OpenBSD: bufbn.c,v 1.12 2014/04/30 05:29:56 djm Exp $ */ |
2 | |||
2 | /* | 3 | /* |
3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 4 | * Copyright (c) 2012 Damien Miller <djm@mindrot.org> |
4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | ||
5 | * All rights reserved | ||
6 | * Auxiliary functions for storing and retrieving various data types to/from | ||
7 | * Buffers. | ||
8 | * | ||
9 | * As far as I am concerned, the code I have written for this software | ||
10 | * can be used freely for any purpose. Any derived versions of this | ||
11 | * software must be clearly marked as such, and if the derived work is | ||
12 | * incompatible with the protocol description in the RFC file, it must be | ||
13 | * called by a name other than "ssh" or "Secure Shell". | ||
14 | * | ||
15 | * | ||
16 | * SSH2 packet format added by Markus Friedl | ||
17 | * Copyright (c) 2000 Markus Friedl. All rights reserved. | ||
18 | * | 5 | * |
19 | * Redistribution and use in source and binary forms, with or without | 6 | * Permission to use, copy, modify, and distribute this software for any |
20 | * modification, are permitted provided that the following conditions | 7 | * purpose with or without fee is hereby granted, provided that the above |
21 | * are met: | 8 | * copyright notice and this permission notice appear in all copies. |
22 | * 1. Redistributions of source code must retain the above copyright | ||
23 | * notice, this list of conditions and the following disclaimer. | ||
24 | * 2. Redistributions in binary form must reproduce the above copyright | ||
25 | * notice, this list of conditions and the following disclaimer in the | ||
26 | * documentation and/or other materials provided with the distribution. | ||
27 | * | 9 | * |
28 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
29 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
30 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
31 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
32 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
33 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
34 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
35 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
36 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
37 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
38 | */ | 17 | */ |
39 | 18 | ||
40 | #include "includes.h" | 19 | /* Emulation wrappers for legacy OpenSSH buffer API atop sshbuf */ |
41 | 20 | ||
42 | #include <sys/types.h> | 21 | #include <sys/types.h> |
43 | 22 | ||
44 | #include <openssl/bn.h> | ||
45 | |||
46 | #include <string.h> | ||
47 | #include <stdarg.h> | ||
48 | #include <stdlib.h> | ||
49 | |||
50 | #include "xmalloc.h" | ||
51 | #include "buffer.h" | 23 | #include "buffer.h" |
52 | #include "log.h" | 24 | #include "log.h" |
53 | #include "misc.h" | 25 | #include "ssherr.h" |
54 | 26 | ||
55 | /* | ||
56 | * Stores an BIGNUM in the buffer with a 2-byte msb first bit count, followed | ||
57 | * by (bits+7)/8 bytes of binary data, msb first. | ||
58 | */ | ||
59 | int | 27 | int |
60 | buffer_put_bignum_ret(Buffer *buffer, const BIGNUM *value) | 28 | buffer_put_bignum_ret(Buffer *buffer, const BIGNUM *value) |
61 | { | 29 | { |
62 | int bits = BN_num_bits(value); | 30 | int ret; |
63 | int bin_size = (bits + 7) / 8; | ||
64 | u_char *buf = xmalloc(bin_size); | ||
65 | int oi; | ||
66 | char msg[2]; | ||
67 | |||
68 | /* Get the value of in binary */ | ||
69 | oi = BN_bn2bin(value, buf); | ||
70 | if (oi != bin_size) { | ||
71 | error("buffer_put_bignum_ret: BN_bn2bin() failed: oi %d != bin_size %d", | ||
72 | oi, bin_size); | ||
73 | free(buf); | ||
74 | return (-1); | ||
75 | } | ||
76 | |||
77 | /* Store the number of bits in the buffer in two bytes, msb first. */ | ||
78 | put_u16(msg, bits); | ||
79 | buffer_append(buffer, msg, 2); | ||
80 | /* Store the binary data. */ | ||
81 | buffer_append(buffer, buf, oi); | ||
82 | 31 | ||
83 | explicit_bzero(buf, bin_size); | 32 | if ((ret = sshbuf_put_bignum1(buffer, value)) != 0) { |
84 | free(buf); | 33 | error("%s: %s", __func__, ssh_err(ret)); |
85 | 34 | return -1; | |
86 | return (0); | 35 | } |
36 | return 0; | ||
87 | } | 37 | } |
88 | 38 | ||
89 | void | 39 | void |
90 | buffer_put_bignum(Buffer *buffer, const BIGNUM *value) | 40 | buffer_put_bignum(Buffer *buffer, const BIGNUM *value) |
91 | { | 41 | { |
92 | if (buffer_put_bignum_ret(buffer, value) == -1) | 42 | if (buffer_put_bignum_ret(buffer, value) == -1) |
93 | fatal("buffer_put_bignum: buffer error"); | 43 | fatal("%s: buffer error", __func__); |
94 | } | 44 | } |
95 | 45 | ||
96 | /* | ||
97 | * Retrieves a BIGNUM from the buffer. | ||
98 | */ | ||
99 | int | 46 | int |
100 | buffer_get_bignum_ret(Buffer *buffer, BIGNUM *value) | 47 | buffer_get_bignum_ret(Buffer *buffer, BIGNUM *value) |
101 | { | 48 | { |
102 | u_int bits, bytes; | 49 | int ret; |
103 | u_char buf[2], *bin; | ||
104 | 50 | ||
105 | /* Get the number of bits. */ | 51 | if ((ret = sshbuf_get_bignum1(buffer, value)) != 0) { |
106 | if (buffer_get_ret(buffer, (char *) buf, 2) == -1) { | 52 | error("%s: %s", __func__, ssh_err(ret)); |
107 | error("buffer_get_bignum_ret: invalid length"); | 53 | return -1; |
108 | return (-1); | ||
109 | } | ||
110 | bits = get_u16(buf); | ||
111 | if (bits > 65535-7) { | ||
112 | error("buffer_get_bignum_ret: cannot handle BN of size %d", | ||
113 | bits); | ||
114 | return (-1); | ||
115 | } | 54 | } |
116 | /* Compute the number of binary bytes that follow. */ | 55 | return 0; |
117 | bytes = (bits + 7) / 8; | ||
118 | if (bytes > 8 * 1024) { | ||
119 | error("buffer_get_bignum_ret: cannot handle BN of size %d", bytes); | ||
120 | return (-1); | ||
121 | } | ||
122 | if (buffer_len(buffer) < bytes) { | ||
123 | error("buffer_get_bignum_ret: input buffer too small"); | ||
124 | return (-1); | ||
125 | } | ||
126 | bin = buffer_ptr(buffer); | ||
127 | if (BN_bin2bn(bin, bytes, value) == NULL) { | ||
128 | error("buffer_get_bignum_ret: BN_bin2bn failed"); | ||
129 | return (-1); | ||
130 | } | ||
131 | if (buffer_consume_ret(buffer, bytes) == -1) { | ||
132 | error("buffer_get_bignum_ret: buffer_consume failed"); | ||
133 | return (-1); | ||
134 | } | ||
135 | return (0); | ||
136 | } | 56 | } |
137 | 57 | ||
138 | void | 58 | void |
139 | buffer_get_bignum(Buffer *buffer, BIGNUM *value) | 59 | buffer_get_bignum(Buffer *buffer, BIGNUM *value) |
140 | { | 60 | { |
141 | if (buffer_get_bignum_ret(buffer, value) == -1) | 61 | if (buffer_get_bignum_ret(buffer, value) == -1) |
142 | fatal("buffer_get_bignum: buffer error"); | 62 | fatal("%s: buffer error", __func__); |
143 | } | 63 | } |
144 | 64 | ||
145 | /* | ||
146 | * Stores a BIGNUM in the buffer in SSH2 format. | ||
147 | */ | ||
148 | int | 65 | int |
149 | buffer_put_bignum2_ret(Buffer *buffer, const BIGNUM *value) | 66 | buffer_put_bignum2_ret(Buffer *buffer, const BIGNUM *value) |
150 | { | 67 | { |
151 | u_int bytes; | 68 | int ret; |
152 | u_char *buf; | 69 | |
153 | int oi; | 70 | if ((ret = sshbuf_put_bignum2(buffer, value)) != 0) { |
154 | u_int hasnohigh = 0; | 71 | error("%s: %s", __func__, ssh_err(ret)); |
155 | 72 | return -1; | |
156 | if (BN_is_zero(value)) { | ||
157 | buffer_put_int(buffer, 0); | ||
158 | return 0; | ||
159 | } | ||
160 | if (value->neg) { | ||
161 | error("buffer_put_bignum2_ret: negative numbers not supported"); | ||
162 | return (-1); | ||
163 | } | ||
164 | bytes = BN_num_bytes(value) + 1; /* extra padding byte */ | ||
165 | if (bytes < 2) { | ||
166 | error("buffer_put_bignum2_ret: BN too small"); | ||
167 | return (-1); | ||
168 | } | ||
169 | buf = xmalloc(bytes); | ||
170 | buf[0] = 0x00; | ||
171 | /* Get the value of in binary */ | ||
172 | oi = BN_bn2bin(value, buf+1); | ||
173 | if (oi < 0 || (u_int)oi != bytes - 1) { | ||
174 | error("buffer_put_bignum2_ret: BN_bn2bin() failed: " | ||
175 | "oi %d != bin_size %d", oi, bytes); | ||
176 | free(buf); | ||
177 | return (-1); | ||
178 | } | 73 | } |
179 | hasnohigh = (buf[1] & 0x80) ? 0 : 1; | 74 | return 0; |
180 | buffer_put_string(buffer, buf+hasnohigh, bytes-hasnohigh); | ||
181 | explicit_bzero(buf, bytes); | ||
182 | free(buf); | ||
183 | return (0); | ||
184 | } | 75 | } |
185 | 76 | ||
186 | void | 77 | void |
187 | buffer_put_bignum2(Buffer *buffer, const BIGNUM *value) | 78 | buffer_put_bignum2(Buffer *buffer, const BIGNUM *value) |
188 | { | 79 | { |
189 | if (buffer_put_bignum2_ret(buffer, value) == -1) | 80 | if (buffer_put_bignum2_ret(buffer, value) == -1) |
190 | fatal("buffer_put_bignum2: buffer error"); | 81 | fatal("%s: buffer error", __func__); |
191 | } | 82 | } |
192 | 83 | ||
193 | int | 84 | int |
194 | buffer_get_bignum2_ret(Buffer *buffer, BIGNUM *value) | 85 | buffer_get_bignum2_ret(Buffer *buffer, BIGNUM *value) |
195 | { | 86 | { |
196 | u_int len; | 87 | int ret; |
197 | u_char *bin; | ||
198 | 88 | ||
199 | if ((bin = buffer_get_string_ret(buffer, &len)) == NULL) { | 89 | if ((ret = sshbuf_get_bignum2(buffer, value)) != 0) { |
200 | error("buffer_get_bignum2_ret: invalid bignum"); | 90 | error("%s: %s", __func__, ssh_err(ret)); |
201 | return (-1); | 91 | return -1; |
202 | } | ||
203 | |||
204 | if (len > 0 && (bin[0] & 0x80)) { | ||
205 | error("buffer_get_bignum2_ret: negative numbers not supported"); | ||
206 | free(bin); | ||
207 | return (-1); | ||
208 | } | ||
209 | if (len > 8 * 1024) { | ||
210 | error("buffer_get_bignum2_ret: cannot handle BN of size %d", | ||
211 | len); | ||
212 | free(bin); | ||
213 | return (-1); | ||
214 | } | ||
215 | if (BN_bin2bn(bin, len, value) == NULL) { | ||
216 | error("buffer_get_bignum2_ret: BN_bin2bn failed"); | ||
217 | free(bin); | ||
218 | return (-1); | ||
219 | } | 92 | } |
220 | free(bin); | 93 | return 0; |
221 | return (0); | ||
222 | } | 94 | } |
223 | 95 | ||
224 | void | 96 | void |
225 | buffer_get_bignum2(Buffer *buffer, BIGNUM *value) | 97 | buffer_get_bignum2(Buffer *buffer, BIGNUM *value) |
226 | { | 98 | { |
227 | if (buffer_get_bignum2_ret(buffer, value) == -1) | 99 | if (buffer_get_bignum2_ret(buffer, value) == -1) |
228 | fatal("buffer_get_bignum2: buffer error"); | 100 | fatal("%s: buffer error", __func__); |
229 | } | 101 | } |
@@ -1,6 +1,7 @@ | |||
1 | /* $OpenBSD: bufec.c,v 1.3 2014/01/31 16:39:19 tedu Exp $ */ | 1 | /* $OpenBSD: bufec.c,v 1.4 2014/04/30 05:29:56 djm Exp $ */ |
2 | |||
2 | /* | 3 | /* |
3 | * Copyright (c) 2010 Damien Miller <djm@mindrot.org> | 4 | * Copyright (c) 2012 Damien Miller <djm@mindrot.org> |
4 | * | 5 | * |
5 | * Permission to use, copy, modify, and distribute this software for any | 6 | * 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 | * purpose with or without fee is hereby granted, provided that the above |
@@ -15,73 +16,25 @@ | |||
15 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
16 | */ | 17 | */ |
17 | 18 | ||
18 | #include "includes.h" | 19 | /* Emulation wrappers for legacy OpenSSH buffer API atop sshbuf */ |
19 | |||
20 | #ifdef OPENSSL_HAS_ECC | ||
21 | 20 | ||
22 | #include <sys/types.h> | 21 | #include <sys/types.h> |
23 | 22 | ||
24 | #include <openssl/bn.h> | ||
25 | #include <openssl/ec.h> | ||
26 | |||
27 | #include <string.h> | ||
28 | #include <stdarg.h> | ||
29 | |||
30 | #include "xmalloc.h" | ||
31 | #include "buffer.h" | 23 | #include "buffer.h" |
32 | #include "log.h" | 24 | #include "log.h" |
33 | #include "misc.h" | 25 | #include "ssherr.h" |
34 | 26 | ||
35 | /* | ||
36 | * Maximum supported EC GFp field length is 528 bits. SEC1 uncompressed | ||
37 | * encoding represents this as two bitstring points that should each | ||
38 | * be no longer than the field length, SEC1 specifies a 1 byte | ||
39 | * point type header. | ||
40 | * Being paranoid here may insulate us to parsing problems in | ||
41 | * EC_POINT_oct2point. | ||
42 | */ | ||
43 | #define BUFFER_MAX_ECPOINT_LEN ((528*2 / 8) + 1) | ||
44 | |||
45 | /* | ||
46 | * Append an EC_POINT to the buffer as a string containing a SEC1 encoded | ||
47 | * uncompressed point. Fortunately OpenSSL handles the gory details for us. | ||
48 | */ | ||
49 | int | 27 | int |
50 | buffer_put_ecpoint_ret(Buffer *buffer, const EC_GROUP *curve, | 28 | buffer_put_ecpoint_ret(Buffer *buffer, const EC_GROUP *curve, |
51 | const EC_POINT *point) | 29 | const EC_POINT *point) |
52 | { | 30 | { |
53 | u_char *buf = NULL; | 31 | int ret; |
54 | size_t len; | ||
55 | BN_CTX *bnctx; | ||
56 | int ret = -1; | ||
57 | 32 | ||
58 | /* Determine length */ | 33 | if ((ret = sshbuf_put_ec(buffer, point, curve)) != 0) { |
59 | if ((bnctx = BN_CTX_new()) == NULL) | 34 | error("%s: %s", __func__, ssh_err(ret)); |
60 | fatal("%s: BN_CTX_new failed", __func__); | 35 | return -1; |
61 | len = EC_POINT_point2oct(curve, point, POINT_CONVERSION_UNCOMPRESSED, | ||
62 | NULL, 0, bnctx); | ||
63 | if (len > BUFFER_MAX_ECPOINT_LEN) { | ||
64 | error("%s: giant EC point: len = %lu (max %u)", | ||
65 | __func__, (u_long)len, BUFFER_MAX_ECPOINT_LEN); | ||
66 | goto out; | ||
67 | } | ||
68 | /* Convert */ | ||
69 | buf = xmalloc(len); | ||
70 | if (EC_POINT_point2oct(curve, point, POINT_CONVERSION_UNCOMPRESSED, | ||
71 | buf, len, bnctx) != len) { | ||
72 | error("%s: EC_POINT_point2oct length mismatch", __func__); | ||
73 | goto out; | ||
74 | } | ||
75 | /* Append */ | ||
76 | buffer_put_string(buffer, buf, len); | ||
77 | ret = 0; | ||
78 | out: | ||
79 | if (buf != NULL) { | ||
80 | explicit_bzero(buf, len); | ||
81 | free(buf); | ||
82 | } | 36 | } |
83 | BN_CTX_free(bnctx); | 37 | return 0; |
84 | return ret; | ||
85 | } | 38 | } |
86 | 39 | ||
87 | void | 40 | void |
@@ -96,43 +49,13 @@ int | |||
96 | buffer_get_ecpoint_ret(Buffer *buffer, const EC_GROUP *curve, | 49 | buffer_get_ecpoint_ret(Buffer *buffer, const EC_GROUP *curve, |
97 | EC_POINT *point) | 50 | EC_POINT *point) |
98 | { | 51 | { |
99 | u_char *buf; | 52 | int ret; |
100 | u_int len; | ||
101 | BN_CTX *bnctx; | ||
102 | int ret = -1; | ||
103 | 53 | ||
104 | if ((buf = buffer_get_string_ret(buffer, &len)) == NULL) { | 54 | if ((ret = sshbuf_get_ec(buffer, point, curve)) != 0) { |
105 | error("%s: invalid point", __func__); | 55 | error("%s: %s", __func__, ssh_err(ret)); |
106 | return -1; | 56 | return -1; |
107 | } | 57 | } |
108 | if ((bnctx = BN_CTX_new()) == NULL) | 58 | return 0; |
109 | fatal("%s: BN_CTX_new failed", __func__); | ||
110 | if (len > BUFFER_MAX_ECPOINT_LEN) { | ||
111 | error("%s: EC_POINT too long: %u > max %u", __func__, | ||
112 | len, BUFFER_MAX_ECPOINT_LEN); | ||
113 | goto out; | ||
114 | } | ||
115 | if (len == 0) { | ||
116 | error("%s: EC_POINT buffer is empty", __func__); | ||
117 | goto out; | ||
118 | } | ||
119 | if (buf[0] != POINT_CONVERSION_UNCOMPRESSED) { | ||
120 | error("%s: EC_POINT is in an incorrect form: " | ||
121 | "0x%02x (want 0x%02x)", __func__, buf[0], | ||
122 | POINT_CONVERSION_UNCOMPRESSED); | ||
123 | goto out; | ||
124 | } | ||
125 | if (EC_POINT_oct2point(curve, point, buf, len, bnctx) != 1) { | ||
126 | error("buffer_get_bignum2_ret: BN_bin2bn failed"); | ||
127 | goto out; | ||
128 | } | ||
129 | /* EC_POINT_oct2point verifies that the point is on the curve for us */ | ||
130 | ret = 0; | ||
131 | out: | ||
132 | BN_CTX_free(bnctx); | ||
133 | explicit_bzero(buf, len); | ||
134 | free(buf); | ||
135 | return ret; | ||
136 | } | 59 | } |
137 | 60 | ||
138 | void | 61 | void |
@@ -143,4 +66,4 @@ buffer_get_ecpoint(Buffer *buffer, const EC_GROUP *curve, | |||
143 | fatal("%s: buffer error", __func__); | 66 | fatal("%s: buffer error", __func__); |
144 | } | 67 | } |
145 | 68 | ||
146 | #endif /* OPENSSL_HAS_ECC */ | 69 | |
@@ -1,253 +1,116 @@ | |||
1 | /* $OpenBSD: buffer.c,v 1.35 2014/02/02 03:44:31 djm Exp $ */ | 1 | /* $OpenBSD: buffer.c,v 1.36 2014/04/30 05:29:56 djm Exp $ */ |
2 | |||
2 | /* | 3 | /* |
3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 4 | * Copyright (c) 2012 Damien Miller <djm@mindrot.org> |
4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 5 | * |
5 | * All rights reserved | 6 | * Permission to use, copy, modify, and distribute this software for any |
6 | * Functions for manipulating fifo buffers (that can grow if needed). | 7 | * purpose with or without fee is hereby granted, provided that the above |
8 | * copyright notice and this permission notice appear in all copies. | ||
7 | * | 9 | * |
8 | * As far as I am concerned, the code I have written for this software | 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
9 | * can be used freely for any purpose. Any derived versions of this | 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
10 | * software must be clearly marked as such, and if the derived work is | 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
11 | * incompatible with the protocol description in the RFC file, it must be | 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
12 | * called by a name other than "ssh" or "Secure Shell". | 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
13 | */ | 17 | */ |
14 | 18 | ||
15 | #include "includes.h" | 19 | /* Emulation wrappers for legacy OpenSSH buffer API atop sshbuf */ |
16 | 20 | ||
17 | #include <sys/param.h> | 21 | #include <sys/types.h> |
18 | 22 | ||
19 | #include <stdio.h> | ||
20 | #include <string.h> | ||
21 | #include <stdarg.h> | ||
22 | #include <stdlib.h> | ||
23 | |||
24 | #include "xmalloc.h" | ||
25 | #include "buffer.h" | 23 | #include "buffer.h" |
26 | #include "log.h" | 24 | #include "log.h" |
27 | 25 | #include "ssherr.h" | |
28 | #define BUFFER_MAX_CHUNK 0x100000 | ||
29 | #define BUFFER_MAX_LEN 0xa00000 | ||
30 | #define BUFFER_ALLOCSZ 0x008000 | ||
31 | |||
32 | /* Initializes the buffer structure. */ | ||
33 | |||
34 | void | ||
35 | buffer_init(Buffer *buffer) | ||
36 | { | ||
37 | const u_int len = 4096; | ||
38 | |||
39 | buffer->alloc = 0; | ||
40 | buffer->buf = xmalloc(len); | ||
41 | buffer->alloc = len; | ||
42 | buffer->offset = 0; | ||
43 | buffer->end = 0; | ||
44 | } | ||
45 | |||
46 | /* Frees any memory used for the buffer. */ | ||
47 | |||
48 | void | ||
49 | buffer_free(Buffer *buffer) | ||
50 | { | ||
51 | if (buffer->alloc > 0) { | ||
52 | explicit_bzero(buffer->buf, buffer->alloc); | ||
53 | buffer->alloc = 0; | ||
54 | free(buffer->buf); | ||
55 | } | ||
56 | } | ||
57 | |||
58 | /* | ||
59 | * Clears any data from the buffer, making it empty. This does not actually | ||
60 | * zero the memory. | ||
61 | */ | ||
62 | |||
63 | void | ||
64 | buffer_clear(Buffer *buffer) | ||
65 | { | ||
66 | buffer->offset = 0; | ||
67 | buffer->end = 0; | ||
68 | } | ||
69 | |||
70 | /* Appends data to the buffer, expanding it if necessary. */ | ||
71 | 26 | ||
72 | void | 27 | void |
73 | buffer_append(Buffer *buffer, const void *data, u_int len) | 28 | buffer_append(Buffer *buffer, const void *data, u_int len) |
74 | { | 29 | { |
75 | void *p; | 30 | int ret; |
76 | p = buffer_append_space(buffer, len); | ||
77 | memcpy(p, data, len); | ||
78 | } | ||
79 | 31 | ||
80 | static int | 32 | if ((ret = sshbuf_put(buffer, data, len)) != 0) |
81 | buffer_compact(Buffer *buffer) | 33 | fatal("%s: %s", __func__, ssh_err(ret)); |
82 | { | ||
83 | /* | ||
84 | * If the buffer is quite empty, but all data is at the end, move the | ||
85 | * data to the beginning. | ||
86 | */ | ||
87 | if (buffer->offset > MIN(buffer->alloc, BUFFER_MAX_CHUNK)) { | ||
88 | memmove(buffer->buf, buffer->buf + buffer->offset, | ||
89 | buffer->end - buffer->offset); | ||
90 | buffer->end -= buffer->offset; | ||
91 | buffer->offset = 0; | ||
92 | return (1); | ||
93 | } | ||
94 | return (0); | ||
95 | } | 34 | } |
96 | 35 | ||
97 | /* | ||
98 | * Appends space to the buffer, expanding the buffer if necessary. This does | ||
99 | * not actually copy the data into the buffer, but instead returns a pointer | ||
100 | * to the allocated region. | ||
101 | */ | ||
102 | |||
103 | void * | 36 | void * |
104 | buffer_append_space(Buffer *buffer, u_int len) | 37 | buffer_append_space(Buffer *buffer, u_int len) |
105 | { | 38 | { |
106 | u_int newlen; | 39 | int ret; |
107 | void *p; | 40 | u_char *p; |
108 | 41 | ||
109 | if (len > BUFFER_MAX_CHUNK) | 42 | if ((ret = sshbuf_reserve(buffer, len, &p)) != 0) |
110 | fatal("buffer_append_space: len %u not supported", len); | 43 | fatal("%s: %s", __func__, ssh_err(ret)); |
111 | 44 | return p; | |
112 | /* If the buffer is empty, start using it from the beginning. */ | ||
113 | if (buffer->offset == buffer->end) { | ||
114 | buffer->offset = 0; | ||
115 | buffer->end = 0; | ||
116 | } | ||
117 | restart: | ||
118 | /* If there is enough space to store all data, store it now. */ | ||
119 | if (buffer->end + len < buffer->alloc) { | ||
120 | p = buffer->buf + buffer->end; | ||
121 | buffer->end += len; | ||
122 | return p; | ||
123 | } | ||
124 | |||
125 | /* Compact data back to the start of the buffer if necessary */ | ||
126 | if (buffer_compact(buffer)) | ||
127 | goto restart; | ||
128 | |||
129 | /* Increase the size of the buffer and retry. */ | ||
130 | newlen = roundup(buffer->alloc + len, BUFFER_ALLOCSZ); | ||
131 | if (newlen > BUFFER_MAX_LEN) | ||
132 | fatal("buffer_append_space: alloc %u not supported", | ||
133 | newlen); | ||
134 | buffer->buf = xrealloc(buffer->buf, 1, newlen); | ||
135 | buffer->alloc = newlen; | ||
136 | goto restart; | ||
137 | /* NOTREACHED */ | ||
138 | } | 45 | } |
139 | 46 | ||
140 | /* | ||
141 | * Check whether an allocation of 'len' will fit in the buffer | ||
142 | * This must follow the same math as buffer_append_space | ||
143 | */ | ||
144 | int | 47 | int |
145 | buffer_check_alloc(Buffer *buffer, u_int len) | 48 | buffer_check_alloc(Buffer *buffer, u_int len) |
146 | { | 49 | { |
147 | if (buffer->offset == buffer->end) { | 50 | int ret = sshbuf_check_reserve(buffer, len); |
148 | buffer->offset = 0; | ||
149 | buffer->end = 0; | ||
150 | } | ||
151 | restart: | ||
152 | if (buffer->end + len < buffer->alloc) | ||
153 | return (1); | ||
154 | if (buffer_compact(buffer)) | ||
155 | goto restart; | ||
156 | if (roundup(buffer->alloc + len, BUFFER_ALLOCSZ) <= BUFFER_MAX_LEN) | ||
157 | return (1); | ||
158 | return (0); | ||
159 | } | ||
160 | |||
161 | /* Returns the number of bytes of data in the buffer. */ | ||
162 | 51 | ||
163 | u_int | 52 | if (ret == 0) |
164 | buffer_len(const Buffer *buffer) | 53 | return 1; |
165 | { | 54 | if (ret == SSH_ERR_NO_BUFFER_SPACE) |
166 | return buffer->end - buffer->offset; | 55 | return 0; |
56 | fatal("%s: %s", __func__, ssh_err(ret)); | ||
167 | } | 57 | } |
168 | 58 | ||
169 | /* Gets data from the beginning of the buffer. */ | ||
170 | |||
171 | int | 59 | int |
172 | buffer_get_ret(Buffer *buffer, void *buf, u_int len) | 60 | buffer_get_ret(Buffer *buffer, void *buf, u_int len) |
173 | { | 61 | { |
174 | if (len > buffer->end - buffer->offset) { | 62 | int ret; |
175 | error("buffer_get_ret: trying to get more bytes %d than in buffer %d", | 63 | |
176 | len, buffer->end - buffer->offset); | 64 | if ((ret = sshbuf_get(buffer, buf, len)) != 0) { |
177 | return (-1); | 65 | error("%s: %s", __func__, ssh_err(ret)); |
66 | return -1; | ||
178 | } | 67 | } |
179 | memcpy(buf, buffer->buf + buffer->offset, len); | 68 | return 0; |
180 | buffer->offset += len; | ||
181 | return (0); | ||
182 | } | 69 | } |
183 | 70 | ||
184 | void | 71 | void |
185 | buffer_get(Buffer *buffer, void *buf, u_int len) | 72 | buffer_get(Buffer *buffer, void *buf, u_int len) |
186 | { | 73 | { |
187 | if (buffer_get_ret(buffer, buf, len) == -1) | 74 | if (buffer_get_ret(buffer, buf, len) == -1) |
188 | fatal("buffer_get: buffer error"); | 75 | fatal("%s: buffer error", __func__); |
189 | } | 76 | } |
190 | 77 | ||
191 | /* Consumes the given number of bytes from the beginning of the buffer. */ | ||
192 | |||
193 | int | 78 | int |
194 | buffer_consume_ret(Buffer *buffer, u_int bytes) | 79 | buffer_consume_ret(Buffer *buffer, u_int bytes) |
195 | { | 80 | { |
196 | if (bytes > buffer->end - buffer->offset) { | 81 | int ret = sshbuf_consume(buffer, bytes); |
197 | error("buffer_consume_ret: trying to get more bytes than in buffer"); | 82 | |
198 | return (-1); | 83 | if (ret == 0) |
199 | } | 84 | return 0; |
200 | buffer->offset += bytes; | 85 | if (ret == SSH_ERR_MESSAGE_INCOMPLETE) |
201 | return (0); | 86 | return -1; |
87 | fatal("%s: %s", __func__, ssh_err(ret)); | ||
202 | } | 88 | } |
203 | 89 | ||
204 | void | 90 | void |
205 | buffer_consume(Buffer *buffer, u_int bytes) | 91 | buffer_consume(Buffer *buffer, u_int bytes) |
206 | { | 92 | { |
207 | if (buffer_consume_ret(buffer, bytes) == -1) | 93 | if (buffer_consume_ret(buffer, bytes) == -1) |
208 | fatal("buffer_consume: buffer error"); | 94 | fatal("%s: buffer error", __func__); |
209 | } | 95 | } |
210 | 96 | ||
211 | /* Consumes the given number of bytes from the end of the buffer. */ | ||
212 | |||
213 | int | 97 | int |
214 | buffer_consume_end_ret(Buffer *buffer, u_int bytes) | 98 | buffer_consume_end_ret(Buffer *buffer, u_int bytes) |
215 | { | 99 | { |
216 | if (bytes > buffer->end - buffer->offset) | 100 | int ret = sshbuf_consume_end(buffer, bytes); |
217 | return (-1); | 101 | |
218 | buffer->end -= bytes; | 102 | if (ret == 0) |
219 | return (0); | 103 | return 0; |
104 | if (ret == SSH_ERR_MESSAGE_INCOMPLETE) | ||
105 | return -1; | ||
106 | fatal("%s: %s", __func__, ssh_err(ret)); | ||
220 | } | 107 | } |
221 | 108 | ||
222 | void | 109 | void |
223 | buffer_consume_end(Buffer *buffer, u_int bytes) | 110 | buffer_consume_end(Buffer *buffer, u_int bytes) |
224 | { | 111 | { |
225 | if (buffer_consume_end_ret(buffer, bytes) == -1) | 112 | if (buffer_consume_end_ret(buffer, bytes) == -1) |
226 | fatal("buffer_consume_end: trying to get more bytes than in buffer"); | 113 | fatal("%s: buffer error", __func__); |
227 | } | ||
228 | |||
229 | /* Returns a pointer to the first used byte in the buffer. */ | ||
230 | |||
231 | void * | ||
232 | buffer_ptr(const Buffer *buffer) | ||
233 | { | ||
234 | return buffer->buf + buffer->offset; | ||
235 | } | 114 | } |
236 | 115 | ||
237 | /* Dumps the contents of the buffer to stderr. */ | ||
238 | 116 | ||
239 | void | ||
240 | buffer_dump(const Buffer *buffer) | ||
241 | { | ||
242 | u_int i; | ||
243 | u_char *ucp = buffer->buf; | ||
244 | |||
245 | for (i = buffer->offset; i < buffer->end; i++) { | ||
246 | fprintf(stderr, "%02x", ucp[i]); | ||
247 | if ((i-buffer->offset)%16==15) | ||
248 | fprintf(stderr, "\r\n"); | ||
249 | else if ((i-buffer->offset)%2==1) | ||
250 | fprintf(stderr, " "); | ||
251 | } | ||
252 | fprintf(stderr, "\r\n"); | ||
253 | } | ||
@@ -1,57 +1,58 @@ | |||
1 | /* $OpenBSD: buffer.h,v 1.24 2014/04/28 03:09:18 djm Exp $ */ | 1 | /* $OpenBSD: buffer.h,v 1.25 2014/04/30 05:29:56 djm Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 4 | * Copyright (c) 2012 Damien Miller <djm@mindrot.org> |
5 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | ||
6 | * All rights reserved | ||
7 | * Code for manipulating FIFO buffers. | ||
8 | * | 5 | * |
9 | * As far as I am concerned, the code I have written for this software | 6 | * Permission to use, copy, modify, and distribute this software for any |
10 | * can be used freely for any purpose. Any derived versions of this | 7 | * purpose with or without fee is hereby granted, provided that the above |
11 | * software must be clearly marked as such, and if the derived work is | 8 | * copyright notice and this permission notice appear in all copies. |
12 | * incompatible with the protocol description in the RFC file, it must be | 9 | * |
13 | * called by a name other than "ssh" or "Secure Shell". | 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
14 | */ | 17 | */ |
15 | 18 | ||
19 | /* Emulation wrappers for legacy OpenSSH buffer API atop sshbuf */ | ||
20 | |||
16 | #ifndef BUFFER_H | 21 | #ifndef BUFFER_H |
17 | #define BUFFER_H | 22 | #define BUFFER_H |
18 | 23 | ||
19 | typedef struct { | 24 | #include "sshbuf.h" |
20 | u_char *buf; /* Buffer for data. */ | 25 | |
21 | u_int alloc; /* Number of bytes allocated for data. */ | 26 | typedef struct sshbuf Buffer; |
22 | u_int offset; /* Offset of first byte containing data. */ | ||
23 | u_int end; /* Offset of last byte containing data. */ | ||
24 | } Buffer; | ||
25 | 27 | ||
26 | void buffer_init(Buffer *); | 28 | #define buffer_init(b) sshbuf_init(b) |
27 | void buffer_clear(Buffer *); | 29 | #define buffer_clear(b) sshbuf_reset(b) |
28 | void buffer_free(Buffer *); | 30 | #define buffer_free(b) sshbuf_free(b) |
31 | #define buffer_dump(b) sshbuf_dump(b, stderr) | ||
29 | 32 | ||
30 | u_int buffer_len(const Buffer *); | 33 | /* XXX cast is safe: sshbuf never stores more than len 2^31 */ |
31 | void *buffer_ptr(const Buffer *); | 34 | #define buffer_len(b) ((u_int) sshbuf_len(b)) |
35 | #define buffer_ptr(b) sshbuf_mutable_ptr(b) | ||
32 | 36 | ||
33 | void buffer_append(Buffer *, const void *, u_int); | 37 | void buffer_append(Buffer *, const void *, u_int); |
34 | void *buffer_append_space(Buffer *, u_int); | 38 | void *buffer_append_space(Buffer *, u_int); |
35 | |||
36 | int buffer_check_alloc(Buffer *, u_int); | 39 | int buffer_check_alloc(Buffer *, u_int); |
37 | |||
38 | void buffer_get(Buffer *, void *, u_int); | 40 | void buffer_get(Buffer *, void *, u_int); |
39 | 41 | ||
40 | void buffer_consume(Buffer *, u_int); | 42 | void buffer_consume(Buffer *, u_int); |
41 | void buffer_consume_end(Buffer *, u_int); | 43 | void buffer_consume_end(Buffer *, u_int); |
42 | 44 | ||
43 | void buffer_dump(const Buffer *); | ||
44 | 45 | ||
45 | int buffer_get_ret(Buffer *, void *, u_int); | 46 | int buffer_get_ret(Buffer *, void *, u_int); |
46 | int buffer_consume_ret(Buffer *, u_int); | 47 | int buffer_consume_ret(Buffer *, u_int); |
47 | int buffer_consume_end_ret(Buffer *, u_int); | 48 | int buffer_consume_end_ret(Buffer *, u_int); |
48 | 49 | ||
49 | #include <openssl/bn.h> | 50 | #include <openssl/bn.h> |
50 | |||
51 | void buffer_put_bignum(Buffer *, const BIGNUM *); | 51 | void buffer_put_bignum(Buffer *, const BIGNUM *); |
52 | void buffer_put_bignum2(Buffer *, const BIGNUM *); | 52 | void buffer_put_bignum2(Buffer *, const BIGNUM *); |
53 | void buffer_get_bignum(Buffer *, BIGNUM *); | 53 | void buffer_get_bignum(Buffer *, BIGNUM *); |
54 | void buffer_get_bignum2(Buffer *, BIGNUM *); | 54 | void buffer_get_bignum2(Buffer *, BIGNUM *); |
55 | void buffer_put_bignum2_from_string(Buffer *, const u_char *, u_int); | ||
55 | 56 | ||
56 | u_short buffer_get_short(Buffer *); | 57 | u_short buffer_get_short(Buffer *); |
57 | void buffer_put_short(Buffer *, u_short); | 58 | void buffer_put_short(Buffer *, u_short); |
@@ -71,8 +72,7 @@ void buffer_put_string(Buffer *, const void *, u_int); | |||
71 | char *buffer_get_cstring(Buffer *, u_int *); | 72 | char *buffer_get_cstring(Buffer *, u_int *); |
72 | void buffer_put_cstring(Buffer *, const char *); | 73 | void buffer_put_cstring(Buffer *, const char *); |
73 | 74 | ||
74 | #define buffer_skip_string(b) \ | 75 | #define buffer_skip_string(b) (void)buffer_get_string_ptr(b, NULL); |
75 | do { u_int l = buffer_get_int(b); buffer_consume(b, l); } while (0) | ||
76 | 76 | ||
77 | int buffer_put_bignum_ret(Buffer *, const BIGNUM *); | 77 | int buffer_put_bignum_ret(Buffer *, const BIGNUM *); |
78 | int buffer_get_bignum_ret(Buffer *, BIGNUM *); | 78 | int buffer_get_bignum_ret(Buffer *, BIGNUM *); |
@@ -84,19 +84,15 @@ int buffer_get_int64_ret(u_int64_t *, Buffer *); | |||
84 | void *buffer_get_string_ret(Buffer *, u_int *); | 84 | void *buffer_get_string_ret(Buffer *, u_int *); |
85 | char *buffer_get_cstring_ret(Buffer *, u_int *); | 85 | char *buffer_get_cstring_ret(Buffer *, u_int *); |
86 | const void *buffer_get_string_ptr_ret(Buffer *, u_int *); | 86 | const void *buffer_get_string_ptr_ret(Buffer *, u_int *); |
87 | int buffer_get_char_ret(u_char *, Buffer *); | 87 | int buffer_get_char_ret(char *, Buffer *); |
88 | |||
89 | void *buffer_get_bignum2_as_string_ret(Buffer *, u_int *); | ||
90 | void *buffer_get_bignum2_as_string(Buffer *, u_int *); | ||
91 | void buffer_put_bignum2_from_string(Buffer *, const u_char *, u_int); | ||
92 | 88 | ||
93 | #ifdef OPENSSL_HAS_ECC | 89 | #ifdef OPENSSL_HAS_ECC |
94 | #include <openssl/ec.h> | 90 | #include <openssl/ec.h> |
95 | |||
96 | int buffer_put_ecpoint_ret(Buffer *, const EC_GROUP *, const EC_POINT *); | 91 | int buffer_put_ecpoint_ret(Buffer *, const EC_GROUP *, const EC_POINT *); |
97 | void buffer_put_ecpoint(Buffer *, const EC_GROUP *, const EC_POINT *); | 92 | void buffer_put_ecpoint(Buffer *, const EC_GROUP *, const EC_POINT *); |
98 | int buffer_get_ecpoint_ret(Buffer *, const EC_GROUP *, EC_POINT *); | 93 | int buffer_get_ecpoint_ret(Buffer *, const EC_GROUP *, EC_POINT *); |
99 | void buffer_get_ecpoint(Buffer *, const EC_GROUP *, EC_POINT *); | 94 | void buffer_get_ecpoint(Buffer *, const EC_GROUP *, EC_POINT *); |
100 | #endif | 95 | #endif |
101 | 96 | ||
102 | #endif /* BUFFER_H */ | 97 | #endif /* BUFFER_H */ |
98 | |||
diff --git a/sshbuf-getput-basic.c b/sshbuf-getput-basic.c new file mode 100644 index 000000000..6b16b214d --- /dev/null +++ b/sshbuf-getput-basic.c | |||
@@ -0,0 +1,421 @@ | |||
1 | /* $OpenBSD: sshbuf-getput-basic.c,v 1.1 2014/04/30 05:29:56 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 "includes.h" | ||
19 | |||
20 | #include <sys/types.h> | ||
21 | #include <stdlib.h> | ||
22 | #include <stdio.h> | ||
23 | #include <string.h> | ||
24 | |||
25 | #include "ssherr.h" | ||
26 | #define SSHBUF_INTERNAL | ||
27 | #include "sshbuf.h" | ||
28 | |||
29 | int | ||
30 | sshbuf_get(struct sshbuf *buf, void *v, size_t len) | ||
31 | { | ||
32 | const u_char *p = sshbuf_ptr(buf); | ||
33 | int r; | ||
34 | |||
35 | if ((r = sshbuf_consume(buf, len)) < 0) | ||
36 | return r; | ||
37 | if (v != NULL) | ||
38 | memcpy(v, p, len); | ||
39 | return 0; | ||
40 | } | ||
41 | |||
42 | int | ||
43 | sshbuf_get_u64(struct sshbuf *buf, u_int64_t *valp) | ||
44 | { | ||
45 | const u_char *p = sshbuf_ptr(buf); | ||
46 | int r; | ||
47 | |||
48 | if ((r = sshbuf_consume(buf, 8)) < 0) | ||
49 | return r; | ||
50 | if (valp != NULL) | ||
51 | *valp = PEEK_U64(p); | ||
52 | return 0; | ||
53 | } | ||
54 | |||
55 | int | ||
56 | sshbuf_get_u32(struct sshbuf *buf, u_int32_t *valp) | ||
57 | { | ||
58 | const u_char *p = sshbuf_ptr(buf); | ||
59 | int r; | ||
60 | |||
61 | if ((r = sshbuf_consume(buf, 4)) < 0) | ||
62 | return r; | ||
63 | if (valp != NULL) | ||
64 | *valp = PEEK_U32(p); | ||
65 | return 0; | ||
66 | } | ||
67 | |||
68 | int | ||
69 | sshbuf_get_u16(struct sshbuf *buf, u_int16_t *valp) | ||
70 | { | ||
71 | const u_char *p = sshbuf_ptr(buf); | ||
72 | int r; | ||
73 | |||
74 | if ((r = sshbuf_consume(buf, 2)) < 0) | ||
75 | return r; | ||
76 | if (valp != NULL) | ||
77 | *valp = PEEK_U16(p); | ||
78 | return 0; | ||
79 | } | ||
80 | |||
81 | int | ||
82 | sshbuf_get_u8(struct sshbuf *buf, u_char *valp) | ||
83 | { | ||
84 | const u_char *p = sshbuf_ptr(buf); | ||
85 | int r; | ||
86 | |||
87 | if ((r = sshbuf_consume(buf, 1)) < 0) | ||
88 | return r; | ||
89 | if (valp != NULL) | ||
90 | *valp = (u_int8_t)*p; | ||
91 | return 0; | ||
92 | } | ||
93 | |||
94 | int | ||
95 | sshbuf_get_string(struct sshbuf *buf, u_char **valp, size_t *lenp) | ||
96 | { | ||
97 | const u_char *val; | ||
98 | size_t len; | ||
99 | int r; | ||
100 | |||
101 | if (valp != NULL) | ||
102 | *valp = NULL; | ||
103 | if (lenp != NULL) | ||
104 | *lenp = 0; | ||
105 | if ((r = sshbuf_get_string_direct(buf, &val, &len)) < 0) | ||
106 | return r; | ||
107 | if (valp != NULL) { | ||
108 | if ((*valp = malloc(len + 1)) == NULL) { | ||
109 | SSHBUF_DBG(("SSH_ERR_ALLOC_FAIL")); | ||
110 | return SSH_ERR_ALLOC_FAIL; | ||
111 | } | ||
112 | memcpy(*valp, val, len); | ||
113 | (*valp)[len] = '\0'; | ||
114 | } | ||
115 | if (lenp != NULL) | ||
116 | *lenp = len; | ||
117 | return 0; | ||
118 | } | ||
119 | |||
120 | int | ||
121 | sshbuf_get_string_direct(struct sshbuf *buf, const u_char **valp, size_t *lenp) | ||
122 | { | ||
123 | size_t len; | ||
124 | const u_char *p; | ||
125 | int r; | ||
126 | |||
127 | if (valp != NULL) | ||
128 | *valp = NULL; | ||
129 | if (lenp != NULL) | ||
130 | *lenp = 0; | ||
131 | if ((r = sshbuf_peek_string_direct(buf, &p, &len)) < 0) | ||
132 | return r; | ||
133 | if (valp != 0) | ||
134 | *valp = p; | ||
135 | if (lenp != NULL) | ||
136 | *lenp = len; | ||
137 | if (sshbuf_consume(buf, len + 4) != 0) { | ||
138 | /* Shouldn't happen */ | ||
139 | SSHBUF_DBG(("SSH_ERR_INTERNAL_ERROR")); | ||
140 | SSHBUF_ABORT(); | ||
141 | return SSH_ERR_INTERNAL_ERROR; | ||
142 | } | ||
143 | return 0; | ||
144 | } | ||
145 | |||
146 | int | ||
147 | sshbuf_peek_string_direct(const struct sshbuf *buf, const u_char **valp, | ||
148 | size_t *lenp) | ||
149 | { | ||
150 | u_int32_t len; | ||
151 | const u_char *p = sshbuf_ptr(buf); | ||
152 | |||
153 | if (valp != NULL) | ||
154 | *valp = NULL; | ||
155 | if (lenp != NULL) | ||
156 | *lenp = 0; | ||
157 | if (sshbuf_len(buf) < 4) { | ||
158 | SSHBUF_DBG(("SSH_ERR_MESSAGE_INCOMPLETE")); | ||
159 | return SSH_ERR_MESSAGE_INCOMPLETE; | ||
160 | } | ||
161 | len = PEEK_U32(p); | ||
162 | if (len > SSHBUF_SIZE_MAX - 4) { | ||
163 | SSHBUF_DBG(("SSH_ERR_STRING_TOO_LARGE")); | ||
164 | return SSH_ERR_STRING_TOO_LARGE; | ||
165 | } | ||
166 | if (sshbuf_len(buf) - 4 < len) { | ||
167 | SSHBUF_DBG(("SSH_ERR_MESSAGE_INCOMPLETE")); | ||
168 | return SSH_ERR_MESSAGE_INCOMPLETE; | ||
169 | } | ||
170 | if (valp != 0) | ||
171 | *valp = p + 4; | ||
172 | if (lenp != NULL) | ||
173 | *lenp = len; | ||
174 | return 0; | ||
175 | } | ||
176 | |||
177 | int | ||
178 | sshbuf_get_cstring(struct sshbuf *buf, char **valp, size_t *lenp) | ||
179 | { | ||
180 | size_t len; | ||
181 | const u_char *p, *z; | ||
182 | int r; | ||
183 | |||
184 | if (valp != NULL) | ||
185 | *valp = NULL; | ||
186 | if (lenp != NULL) | ||
187 | *lenp = 0; | ||
188 | if ((r = sshbuf_peek_string_direct(buf, &p, &len)) != 0) | ||
189 | return r; | ||
190 | /* Allow a \0 only at the end of the string */ | ||
191 | if (len > 0 && | ||
192 | (z = memchr(p , '\0', len)) != NULL && z < p + len - 1) { | ||
193 | SSHBUF_DBG(("SSH_ERR_INVALID_FORMAT")); | ||
194 | return SSH_ERR_INVALID_FORMAT; | ||
195 | } | ||
196 | if ((r = sshbuf_skip_string(buf)) != 0) | ||
197 | return -1; | ||
198 | if (valp != NULL) { | ||
199 | if ((*valp = malloc(len + 1)) == NULL) { | ||
200 | SSHBUF_DBG(("SSH_ERR_ALLOC_FAIL")); | ||
201 | return SSH_ERR_ALLOC_FAIL; | ||
202 | } | ||
203 | memcpy(*valp, p, len); | ||
204 | (*valp)[len] = '\0'; | ||
205 | } | ||
206 | if (lenp != NULL) | ||
207 | *lenp = (size_t)len; | ||
208 | return 0; | ||
209 | } | ||
210 | |||
211 | int | ||
212 | sshbuf_get_stringb(struct sshbuf *buf, struct sshbuf *v) | ||
213 | { | ||
214 | u_int32_t len; | ||
215 | u_char *p; | ||
216 | int r; | ||
217 | |||
218 | /* | ||
219 | * Use sshbuf_peek_string_direct() to figure out if there is | ||
220 | * a complete string in 'buf' and copy the string directly | ||
221 | * into 'v'. | ||
222 | */ | ||
223 | if ((r = sshbuf_peek_string_direct(buf, NULL, NULL)) != 0 || | ||
224 | (r = sshbuf_get_u32(buf, &len)) != 0 || | ||
225 | (r = sshbuf_reserve(v, len, &p)) != 0 || | ||
226 | (r = sshbuf_get(buf, p, len)) != 0) | ||
227 | return r; | ||
228 | return 0; | ||
229 | } | ||
230 | |||
231 | int | ||
232 | sshbuf_put(struct sshbuf *buf, const void *v, size_t len) | ||
233 | { | ||
234 | u_char *p; | ||
235 | int r; | ||
236 | |||
237 | if ((r = sshbuf_reserve(buf, len, &p)) < 0) | ||
238 | return r; | ||
239 | memcpy(p, v, len); | ||
240 | return 0; | ||
241 | } | ||
242 | |||
243 | int | ||
244 | sshbuf_putb(struct sshbuf *buf, const struct sshbuf *v) | ||
245 | { | ||
246 | return sshbuf_put(buf, sshbuf_ptr(v), sshbuf_len(v)); | ||
247 | } | ||
248 | |||
249 | int | ||
250 | sshbuf_putf(struct sshbuf *buf, const char *fmt, ...) | ||
251 | { | ||
252 | va_list ap; | ||
253 | int r; | ||
254 | |||
255 | va_start(ap, fmt); | ||
256 | r = sshbuf_putfv(buf, fmt, ap); | ||
257 | va_end(ap); | ||
258 | return r; | ||
259 | } | ||
260 | |||
261 | int | ||
262 | sshbuf_putfv(struct sshbuf *buf, const char *fmt, va_list ap) | ||
263 | { | ||
264 | va_list ap2; | ||
265 | int r, len; | ||
266 | u_char *p; | ||
267 | |||
268 | va_copy(ap2, ap); | ||
269 | if ((len = vsnprintf(NULL, 0, fmt, ap2)) < 0) { | ||
270 | r = SSH_ERR_INVALID_ARGUMENT; | ||
271 | goto out; | ||
272 | } | ||
273 | if (len == 0) { | ||
274 | r = 0; | ||
275 | goto out; /* Nothing to do */ | ||
276 | } | ||
277 | va_end(ap2); | ||
278 | va_copy(ap2, ap); | ||
279 | if ((r = sshbuf_reserve(buf, (size_t)len + 1, &p)) < 0) | ||
280 | goto out; | ||
281 | if ((r = vsnprintf((char *)p, len + 1, fmt, ap2)) != len) { | ||
282 | r = SSH_ERR_INTERNAL_ERROR; | ||
283 | goto out; /* Shouldn't happen */ | ||
284 | } | ||
285 | /* Consume terminating \0 */ | ||
286 | if ((r = sshbuf_consume_end(buf, 1)) != 0) | ||
287 | goto out; | ||
288 | r = 0; | ||
289 | out: | ||
290 | va_end(ap2); | ||
291 | return r; | ||
292 | } | ||
293 | |||
294 | int | ||
295 | sshbuf_put_u64(struct sshbuf *buf, u_int64_t val) | ||
296 | { | ||
297 | u_char *p; | ||
298 | int r; | ||
299 | |||
300 | if ((r = sshbuf_reserve(buf, 8, &p)) < 0) | ||
301 | return r; | ||
302 | POKE_U64(p, val); | ||
303 | return 0; | ||
304 | } | ||
305 | |||
306 | int | ||
307 | sshbuf_put_u32(struct sshbuf *buf, u_int32_t val) | ||
308 | { | ||
309 | u_char *p; | ||
310 | int r; | ||
311 | |||
312 | if ((r = sshbuf_reserve(buf, 4, &p)) < 0) | ||
313 | return r; | ||
314 | POKE_U32(p, val); | ||
315 | return 0; | ||
316 | } | ||
317 | |||
318 | int | ||
319 | sshbuf_put_u16(struct sshbuf *buf, u_int16_t val) | ||
320 | { | ||
321 | u_char *p; | ||
322 | int r; | ||
323 | |||
324 | if ((r = sshbuf_reserve(buf, 2, &p)) < 0) | ||
325 | return r; | ||
326 | POKE_U16(p, val); | ||
327 | return 0; | ||
328 | } | ||
329 | |||
330 | int | ||
331 | sshbuf_put_u8(struct sshbuf *buf, u_char val) | ||
332 | { | ||
333 | u_char *p; | ||
334 | int r; | ||
335 | |||
336 | if ((r = sshbuf_reserve(buf, 1, &p)) < 0) | ||
337 | return r; | ||
338 | p[0] = val; | ||
339 | return 0; | ||
340 | } | ||
341 | |||
342 | int | ||
343 | sshbuf_put_string(struct sshbuf *buf, const void *v, size_t len) | ||
344 | { | ||
345 | u_char *d; | ||
346 | int r; | ||
347 | |||
348 | if (len > SSHBUF_SIZE_MAX - 4) { | ||
349 | SSHBUF_DBG(("SSH_ERR_NO_BUFFER_SPACE")); | ||
350 | return SSH_ERR_NO_BUFFER_SPACE; | ||
351 | } | ||
352 | if ((r = sshbuf_reserve(buf, len + 4, &d)) < 0) | ||
353 | return r; | ||
354 | POKE_U32(d, len); | ||
355 | memcpy(d + 4, v, len); | ||
356 | return 0; | ||
357 | } | ||
358 | |||
359 | int | ||
360 | sshbuf_put_cstring(struct sshbuf *buf, const char *v) | ||
361 | { | ||
362 | return sshbuf_put_string(buf, (u_char *)v, strlen(v)); | ||
363 | } | ||
364 | |||
365 | int | ||
366 | sshbuf_put_stringb(struct sshbuf *buf, const struct sshbuf *v) | ||
367 | { | ||
368 | return sshbuf_put_string(buf, sshbuf_ptr(v), sshbuf_len(v)); | ||
369 | } | ||
370 | |||
371 | int | ||
372 | sshbuf_froms(struct sshbuf *buf, struct sshbuf **bufp) | ||
373 | { | ||
374 | const u_char *p; | ||
375 | size_t len; | ||
376 | struct sshbuf *ret; | ||
377 | int r; | ||
378 | |||
379 | if (buf == NULL || bufp == NULL) | ||
380 | return SSH_ERR_INVALID_ARGUMENT; | ||
381 | *bufp = NULL; | ||
382 | if ((r = sshbuf_peek_string_direct(buf, &p, &len)) != 0) | ||
383 | return r; | ||
384 | if ((ret = sshbuf_from(p, len)) == NULL) | ||
385 | return SSH_ERR_ALLOC_FAIL; | ||
386 | if ((r = sshbuf_consume(buf, len + 4)) != 0 || /* Shouldn't happen */ | ||
387 | (r = sshbuf_set_parent(ret, buf)) != 0) { | ||
388 | sshbuf_free(ret); | ||
389 | return r; | ||
390 | } | ||
391 | *bufp = ret; | ||
392 | return 0; | ||
393 | } | ||
394 | |||
395 | int | ||
396 | sshbuf_put_bignum2_bytes(struct sshbuf *buf, const void *v, size_t len) | ||
397 | { | ||
398 | u_char *d; | ||
399 | const u_char *s = (const u_char *)v; | ||
400 | int r, prepend; | ||
401 | |||
402 | if (len > SSHBUF_SIZE_MAX - 5) { | ||
403 | SSHBUF_DBG(("SSH_ERR_NO_BUFFER_SPACE")); | ||
404 | return SSH_ERR_NO_BUFFER_SPACE; | ||
405 | } | ||
406 | /* Skip leading zero bytes */ | ||
407 | for (; len > 0 && *s == 0; len--, s++) | ||
408 | ; | ||
409 | /* | ||
410 | * If most significant bit is set then prepend a zero byte to | ||
411 | * avoid interpretation as a negative number. | ||
412 | */ | ||
413 | prepend = len > 0 && (s[0] & 0x80) != 0; | ||
414 | if ((r = sshbuf_reserve(buf, len + 4 + prepend, &d)) < 0) | ||
415 | return r; | ||
416 | POKE_U32(d, len + prepend); | ||
417 | if (prepend) | ||
418 | d[4] = 0; | ||
419 | memcpy(d + 4 + prepend, s, len); | ||
420 | return 0; | ||
421 | } | ||
diff --git a/sshbuf-getput-crypto.c b/sshbuf-getput-crypto.c new file mode 100644 index 000000000..9c801a45f --- /dev/null +++ b/sshbuf-getput-crypto.c | |||
@@ -0,0 +1,233 @@ | |||
1 | /* $OpenBSD: sshbuf-getput-crypto.c,v 1.1 2014/04/30 05:29:56 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 "includes.h" | ||
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_peek_string_direct(buf, &d, &len)) < 0) | ||
40 | return r; | ||
41 | /* Refuse negative (MSB set) and overlong bignums */ | ||
42 | if ((len != 0 && (*d & 0x80) != 0)) | ||
43 | return SSH_ERR_BIGNUM_IS_NEGATIVE; | ||
44 | if (len > SSHBUF_MAX_BIGNUM) | ||
45 | return SSH_ERR_BIGNUM_TOO_LARGE; | ||
46 | if (v != NULL && BN_bin2bn(d, len, v) == NULL) | ||
47 | return SSH_ERR_ALLOC_FAIL; | ||
48 | /* Consume the string */ | ||
49 | if (sshbuf_get_string_direct(buf, NULL, NULL) != 0) { | ||
50 | /* Shouldn't happen */ | ||
51 | SSHBUF_DBG(("SSH_ERR_INTERNAL_ERROR")); | ||
52 | SSHBUF_ABORT(); | ||
53 | return SSH_ERR_INTERNAL_ERROR; | ||
54 | } | ||
55 | return 0; | ||
56 | } | ||
57 | |||
58 | int | ||
59 | sshbuf_get_bignum1(struct sshbuf *buf, BIGNUM *v) | ||
60 | { | ||
61 | const u_char *d = sshbuf_ptr(buf); | ||
62 | u_int16_t len_bits; | ||
63 | size_t len_bytes; | ||
64 | |||
65 | /* Length in bits */ | ||
66 | if (sshbuf_len(buf) < 2) | ||
67 | return SSH_ERR_MESSAGE_INCOMPLETE; | ||
68 | len_bits = PEEK_U16(d); | ||
69 | len_bytes = (len_bits + 7) >> 3; | ||
70 | if (len_bytes > SSHBUF_MAX_BIGNUM + 1) | ||
71 | return SSH_ERR_BIGNUM_TOO_LARGE; | ||
72 | if (sshbuf_len(buf) < 2 + len_bytes) | ||
73 | return SSH_ERR_MESSAGE_INCOMPLETE; | ||
74 | if (v != NULL && BN_bin2bn(d + 2, len_bytes, v) == NULL) | ||
75 | return SSH_ERR_ALLOC_FAIL; | ||
76 | if (sshbuf_consume(buf, 2 + len_bytes) != 0) { | ||
77 | SSHBUF_DBG(("SSH_ERR_INTERNAL_ERROR")); | ||
78 | SSHBUF_ABORT(); | ||
79 | return SSH_ERR_INTERNAL_ERROR; | ||
80 | } | ||
81 | return 0; | ||
82 | } | ||
83 | |||
84 | #ifdef OPENSSL_HAS_ECC | ||
85 | static int | ||
86 | get_ec(const u_char *d, size_t len, EC_POINT *v, const EC_GROUP *g) | ||
87 | { | ||
88 | /* Refuse overlong bignums */ | ||
89 | if (len == 0 || len > SSHBUF_MAX_ECPOINT) | ||
90 | return SSH_ERR_ECPOINT_TOO_LARGE; | ||
91 | /* Only handle uncompressed points */ | ||
92 | if (*d != POINT_CONVERSION_UNCOMPRESSED) | ||
93 | return SSH_ERR_INVALID_FORMAT; | ||
94 | if (v != NULL && EC_POINT_oct2point(g, v, d, len, NULL) != 1) | ||
95 | return SSH_ERR_INVALID_FORMAT; /* XXX assumption */ | ||
96 | return 0; | ||
97 | } | ||
98 | |||
99 | int | ||
100 | sshbuf_get_ec(struct sshbuf *buf, EC_POINT *v, const EC_GROUP *g) | ||
101 | { | ||
102 | const u_char *d; | ||
103 | size_t len; | ||
104 | int r; | ||
105 | |||
106 | if ((r = sshbuf_peek_string_direct(buf, &d, &len)) < 0) | ||
107 | return r; | ||
108 | if ((r = get_ec(d, len, v, g)) != 0) | ||
109 | return r; | ||
110 | /* Skip string */ | ||
111 | if (sshbuf_get_string_direct(buf, NULL, NULL) != 0) { | ||
112 | /* Shouldn't happen */ | ||
113 | SSHBUF_DBG(("SSH_ERR_INTERNAL_ERROR")); | ||
114 | SSHBUF_ABORT(); | ||
115 | return SSH_ERR_INTERNAL_ERROR; | ||
116 | } | ||
117 | return 0; | ||
118 | } | ||
119 | |||
120 | int | ||
121 | sshbuf_get_eckey(struct sshbuf *buf, EC_KEY *v) | ||
122 | { | ||
123 | EC_POINT *pt = EC_POINT_new(EC_KEY_get0_group(v)); | ||
124 | int r; | ||
125 | const u_char *d; | ||
126 | size_t len; | ||
127 | |||
128 | if (pt == NULL) { | ||
129 | SSHBUF_DBG(("SSH_ERR_ALLOC_FAIL")); | ||
130 | return SSH_ERR_ALLOC_FAIL; | ||
131 | } | ||
132 | if ((r = sshbuf_peek_string_direct(buf, &d, &len)) < 0) { | ||
133 | EC_POINT_free(pt); | ||
134 | return r; | ||
135 | } | ||
136 | if ((r = get_ec(d, len, pt, EC_KEY_get0_group(v))) != 0) { | ||
137 | EC_POINT_free(pt); | ||
138 | return r; | ||
139 | } | ||
140 | if (EC_KEY_set_public_key(v, pt) != 1) { | ||
141 | EC_POINT_free(pt); | ||
142 | return SSH_ERR_ALLOC_FAIL; /* XXX assumption */ | ||
143 | } | ||
144 | EC_POINT_free(pt); | ||
145 | /* Skip string */ | ||
146 | if (sshbuf_get_string_direct(buf, NULL, NULL) != 0) { | ||
147 | /* Shouldn't happen */ | ||
148 | SSHBUF_DBG(("SSH_ERR_INTERNAL_ERROR")); | ||
149 | SSHBUF_ABORT(); | ||
150 | return SSH_ERR_INTERNAL_ERROR; | ||
151 | } | ||
152 | return 0; | ||
153 | } | ||
154 | #endif /* OPENSSL_HAS_ECC */ | ||
155 | |||
156 | int | ||
157 | sshbuf_put_bignum2(struct sshbuf *buf, const BIGNUM *v) | ||
158 | { | ||
159 | u_char d[SSHBUF_MAX_BIGNUM + 1]; | ||
160 | int len = BN_num_bytes(v), prepend = 0, r; | ||
161 | |||
162 | if (len < 0 || len > SSHBUF_MAX_BIGNUM) | ||
163 | return SSH_ERR_INVALID_ARGUMENT; | ||
164 | *d = '\0'; | ||
165 | if (BN_bn2bin(v, d + 1) != len) | ||
166 | return SSH_ERR_INTERNAL_ERROR; /* Shouldn't happen */ | ||
167 | /* If MSB is set, prepend a \0 */ | ||
168 | if (len > 0 && (d[1] & 0x80) != 0) | ||
169 | prepend = 1; | ||
170 | if ((r = sshbuf_put_string(buf, d + 1 - prepend, len + prepend)) < 0) { | ||
171 | bzero(d, sizeof(d)); | ||
172 | return r; | ||
173 | } | ||
174 | bzero(d, sizeof(d)); | ||
175 | return 0; | ||
176 | } | ||
177 | |||
178 | int | ||
179 | sshbuf_put_bignum1(struct sshbuf *buf, const BIGNUM *v) | ||
180 | { | ||
181 | int r, len_bits = BN_num_bits(v); | ||
182 | size_t len_bytes = (len_bits + 7) / 8; | ||
183 | u_char d[SSHBUF_MAX_BIGNUM], *dp; | ||
184 | |||
185 | if (len_bits < 0 || len_bytes > SSHBUF_MAX_BIGNUM) | ||
186 | return SSH_ERR_INVALID_ARGUMENT; | ||
187 | if (BN_bn2bin(v, d) != (int)len_bytes) | ||
188 | return SSH_ERR_INTERNAL_ERROR; /* Shouldn't happen */ | ||
189 | if ((r = sshbuf_reserve(buf, len_bytes + 2, &dp)) < 0) { | ||
190 | bzero(d, sizeof(d)); | ||
191 | return r; | ||
192 | } | ||
193 | POKE_U16(dp, len_bits); | ||
194 | memcpy(dp + 2, d, len_bytes); | ||
195 | bzero(d, sizeof(d)); | ||
196 | return 0; | ||
197 | } | ||
198 | |||
199 | #ifdef OPENSSL_HAS_ECC | ||
200 | int | ||
201 | sshbuf_put_ec(struct sshbuf *buf, const EC_POINT *v, const EC_GROUP *g) | ||
202 | { | ||
203 | u_char d[SSHBUF_MAX_ECPOINT]; | ||
204 | BN_CTX *bn_ctx; | ||
205 | size_t len; | ||
206 | int ret; | ||
207 | |||
208 | if ((bn_ctx = BN_CTX_new()) == NULL) | ||
209 | return SSH_ERR_ALLOC_FAIL; | ||
210 | if ((len = EC_POINT_point2oct(g, v, POINT_CONVERSION_UNCOMPRESSED, | ||
211 | NULL, 0, bn_ctx)) > SSHBUF_MAX_ECPOINT) { | ||
212 | BN_CTX_free(bn_ctx); | ||
213 | return SSH_ERR_INVALID_ARGUMENT; | ||
214 | } | ||
215 | if (EC_POINT_point2oct(g, v, POINT_CONVERSION_UNCOMPRESSED, | ||
216 | d, len, bn_ctx) != len) { | ||
217 | BN_CTX_free(bn_ctx); | ||
218 | return SSH_ERR_INTERNAL_ERROR; /* Shouldn't happen */ | ||
219 | } | ||
220 | BN_CTX_free(bn_ctx); | ||
221 | ret = sshbuf_put_string(buf, d, len); | ||
222 | bzero(d, len); | ||
223 | return ret; | ||
224 | } | ||
225 | |||
226 | int | ||
227 | sshbuf_put_eckey(struct sshbuf *buf, const EC_KEY *v) | ||
228 | { | ||
229 | return sshbuf_put_ec(buf, EC_KEY_get0_public_key(v), | ||
230 | EC_KEY_get0_group(v)); | ||
231 | } | ||
232 | #endif /* OPENSSL_HAS_ECC */ | ||
233 | |||
diff --git a/sshbuf-misc.c b/sshbuf-misc.c new file mode 100644 index 000000000..22dbfd5a4 --- /dev/null +++ b/sshbuf-misc.c | |||
@@ -0,0 +1,129 @@ | |||
1 | /* $OpenBSD: sshbuf-misc.c,v 1.1 2014/04/30 05:29:56 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 "includes.h" | ||
19 | |||
20 | #include <sys/types.h> | ||
21 | #include <sys/socket.h> | ||
22 | #include <netinet/in.h> | ||
23 | #include <errno.h> | ||
24 | #include <stdlib.h> | ||
25 | #include <stdio.h> | ||
26 | #include <limits.h> | ||
27 | #include <string.h> | ||
28 | #include <resolv.h> | ||
29 | #include <ctype.h> | ||
30 | |||
31 | #include "ssherr.h" | ||
32 | #define SSHBUF_INTERNAL | ||
33 | #include "sshbuf.h" | ||
34 | |||
35 | void | ||
36 | sshbuf_dump(struct sshbuf *buf, FILE *f) | ||
37 | { | ||
38 | const u_char *p = sshbuf_ptr(buf); | ||
39 | size_t i, j, len = sshbuf_len(buf); | ||
40 | |||
41 | fprintf(f, "buffer %p len = %zu\n", buf, len); | ||
42 | for (i = 0; i < len; i += 16) { | ||
43 | fprintf(f, "%.4zd: ", i); | ||
44 | for (j = i; j < i + 16; j++) { | ||
45 | if (j < len) | ||
46 | fprintf(f, "%02x ", p[j]); | ||
47 | else | ||
48 | fprintf(f, " "); | ||
49 | } | ||
50 | fprintf(f, " "); | ||
51 | for (j = i; j < i + 16; j++) { | ||
52 | if (j < len) { | ||
53 | if (isascii(p[j]) && isprint(p[j])) | ||
54 | fprintf(f, "%c", p[j]); | ||
55 | else | ||
56 | fprintf(f, "."); | ||
57 | } | ||
58 | } | ||
59 | fprintf(f, "\n"); | ||
60 | } | ||
61 | } | ||
62 | |||
63 | char * | ||
64 | sshbuf_dtob16(struct sshbuf *buf) | ||
65 | { | ||
66 | size_t i, j, len = sshbuf_len(buf); | ||
67 | const u_char *p = sshbuf_ptr(buf); | ||
68 | char *ret; | ||
69 | const char hex[] = "0123456789abcdef"; | ||
70 | |||
71 | if (len == 0) | ||
72 | return strdup(""); | ||
73 | if (SIZE_MAX / 2 <= len || (ret = malloc(len * 2 + 1)) == NULL) | ||
74 | return NULL; | ||
75 | for (i = j = 0; i < len; i++) { | ||
76 | ret[j++] = hex[(p[i] >> 4) & 0xf]; | ||
77 | ret[j++] = hex[p[i] & 0xf]; | ||
78 | } | ||
79 | ret[j] = '\0'; | ||
80 | return ret; | ||
81 | } | ||
82 | |||
83 | char * | ||
84 | sshbuf_dtob64(struct sshbuf *buf) | ||
85 | { | ||
86 | size_t len = sshbuf_len(buf), plen; | ||
87 | const u_char *p = sshbuf_ptr(buf); | ||
88 | char *ret; | ||
89 | int r; | ||
90 | |||
91 | if (len == 0) | ||
92 | return strdup(""); | ||
93 | plen = ((len + 2) / 3) * 4 + 1; | ||
94 | if (SIZE_MAX / 2 <= len || (ret = malloc(plen)) == NULL) | ||
95 | return NULL; | ||
96 | if ((r = b64_ntop(p, len, ret, plen)) == -1) { | ||
97 | bzero(ret, plen); | ||
98 | free(ret); | ||
99 | return NULL; | ||
100 | } | ||
101 | return ret; | ||
102 | } | ||
103 | |||
104 | int | ||
105 | sshbuf_b64tod(struct sshbuf *buf, const char *b64) | ||
106 | { | ||
107 | size_t plen = strlen(b64); | ||
108 | int nlen, r; | ||
109 | u_char *p; | ||
110 | |||
111 | if (plen == 0) | ||
112 | return 0; | ||
113 | if ((p = malloc(plen)) == NULL) | ||
114 | return SSH_ERR_ALLOC_FAIL; | ||
115 | if ((nlen = b64_pton(b64, p, plen)) < 0) { | ||
116 | bzero(p, plen); | ||
117 | free(p); | ||
118 | return SSH_ERR_INVALID_FORMAT; | ||
119 | } | ||
120 | if ((r = sshbuf_put(buf, p, nlen)) < 0) { | ||
121 | bzero(p, plen); | ||
122 | free(p); | ||
123 | return r; | ||
124 | } | ||
125 | bzero(p, plen); | ||
126 | free(p); | ||
127 | return 0; | ||
128 | } | ||
129 | |||
diff --git a/sshbuf.c b/sshbuf.c new file mode 100644 index 000000000..11d8d41df --- /dev/null +++ b/sshbuf.c | |||
@@ -0,0 +1,405 @@ | |||
1 | /* $OpenBSD: sshbuf.c,v 1.1 2014/04/30 05:29:56 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 "includes.h" | ||
19 | |||
20 | #include <sys/types.h> | ||
21 | #include <sys/param.h> | ||
22 | #include <signal.h> | ||
23 | #include <stdlib.h> | ||
24 | #include <stdio.h> | ||
25 | #include <string.h> | ||
26 | |||
27 | #include "ssherr.h" | ||
28 | #define SSHBUF_INTERNAL | ||
29 | #include "sshbuf.h" | ||
30 | |||
31 | static inline int | ||
32 | sshbuf_check_sanity(const struct sshbuf *buf) | ||
33 | { | ||
34 | SSHBUF_TELL("sanity"); | ||
35 | if (__predict_false(buf == NULL || | ||
36 | (!buf->readonly && buf->d != buf->cd) || | ||
37 | buf->refcount < 1 || buf->refcount > SSHBUF_REFS_MAX || | ||
38 | buf->cd == NULL || | ||
39 | (buf->dont_free && (buf->readonly || buf->parent != NULL)) || | ||
40 | buf->max_size > SSHBUF_SIZE_MAX || | ||
41 | buf->alloc > buf->max_size || | ||
42 | buf->size > buf->alloc || | ||
43 | buf->off > buf->size)) { | ||
44 | /* Do not try to recover from corrupted buffer internals */ | ||
45 | SSHBUF_DBG(("SSH_ERR_INTERNAL_ERROR")); | ||
46 | raise(SIGSEGV); | ||
47 | return SSH_ERR_INTERNAL_ERROR; | ||
48 | } | ||
49 | return 0; | ||
50 | } | ||
51 | |||
52 | static void | ||
53 | sshbuf_maybe_pack(struct sshbuf *buf, int force) | ||
54 | { | ||
55 | SSHBUF_DBG(("force %d", force)); | ||
56 | SSHBUF_TELL("pre-pack"); | ||
57 | if (buf->off == 0 || buf->readonly || buf->refcount > 1) | ||
58 | return; | ||
59 | if (force || | ||
60 | (buf->off >= SSHBUF_PACK_MIN && buf->off >= buf->size / 2)) { | ||
61 | memmove(buf->d, buf->d + buf->off, buf->size - buf->off); | ||
62 | buf->size -= buf->off; | ||
63 | buf->off = 0; | ||
64 | SSHBUF_TELL("packed"); | ||
65 | } | ||
66 | } | ||
67 | |||
68 | struct sshbuf * | ||
69 | sshbuf_new(void) | ||
70 | { | ||
71 | struct sshbuf *ret; | ||
72 | |||
73 | if ((ret = calloc(sizeof(*ret), 1)) == NULL) | ||
74 | return NULL; | ||
75 | ret->alloc = SSHBUF_SIZE_INIT; | ||
76 | ret->max_size = SSHBUF_SIZE_MAX; | ||
77 | ret->readonly = 0; | ||
78 | ret->refcount = 1; | ||
79 | ret->parent = NULL; | ||
80 | if ((ret->cd = ret->d = calloc(1, ret->alloc)) == NULL) { | ||
81 | free(ret); | ||
82 | return NULL; | ||
83 | } | ||
84 | return ret; | ||
85 | } | ||
86 | |||
87 | struct sshbuf * | ||
88 | sshbuf_from(const void *blob, size_t len) | ||
89 | { | ||
90 | struct sshbuf *ret; | ||
91 | |||
92 | if (blob == NULL || len > SSHBUF_SIZE_MAX || | ||
93 | (ret = calloc(sizeof(*ret), 1)) == NULL) | ||
94 | return NULL; | ||
95 | ret->alloc = ret->size = ret->max_size = len; | ||
96 | ret->readonly = 1; | ||
97 | ret->refcount = 1; | ||
98 | ret->parent = NULL; | ||
99 | ret->cd = blob; | ||
100 | ret->d = NULL; | ||
101 | return ret; | ||
102 | } | ||
103 | |||
104 | int | ||
105 | sshbuf_set_parent(struct sshbuf *child, struct sshbuf *parent) | ||
106 | { | ||
107 | int r; | ||
108 | |||
109 | if ((r = sshbuf_check_sanity(child)) != 0 || | ||
110 | (r = sshbuf_check_sanity(parent)) != 0) | ||
111 | return r; | ||
112 | child->parent = parent; | ||
113 | child->parent->refcount++; | ||
114 | return 0; | ||
115 | } | ||
116 | |||
117 | struct sshbuf * | ||
118 | sshbuf_fromb(struct sshbuf *buf) | ||
119 | { | ||
120 | struct sshbuf *ret; | ||
121 | |||
122 | if (sshbuf_check_sanity(buf) != 0) | ||
123 | return NULL; | ||
124 | if ((ret = sshbuf_from(sshbuf_ptr(buf), sshbuf_len(buf))) == NULL) | ||
125 | return NULL; | ||
126 | if (sshbuf_set_parent(ret, buf) != 0) { | ||
127 | sshbuf_free(ret); | ||
128 | return NULL; | ||
129 | } | ||
130 | return ret; | ||
131 | } | ||
132 | |||
133 | void | ||
134 | sshbuf_init(struct sshbuf *ret) | ||
135 | { | ||
136 | bzero(ret, sizeof(*ret)); | ||
137 | ret->alloc = SSHBUF_SIZE_INIT; | ||
138 | ret->max_size = SSHBUF_SIZE_MAX; | ||
139 | ret->readonly = 0; | ||
140 | ret->dont_free = 1; | ||
141 | ret->refcount = 1; | ||
142 | if ((ret->cd = ret->d = calloc(1, ret->alloc)) == NULL) | ||
143 | ret->alloc = 0; | ||
144 | } | ||
145 | |||
146 | void | ||
147 | sshbuf_free(struct sshbuf *buf) | ||
148 | { | ||
149 | int dont_free = 0; | ||
150 | |||
151 | if (buf == NULL) | ||
152 | return; | ||
153 | /* | ||
154 | * The following will leak on insane buffers, but this is the safest | ||
155 | * course of action - an invalid pointer or already-freed pointer may | ||
156 | * have been passed to us and continuing to scribble over memory would | ||
157 | * be bad. | ||
158 | */ | ||
159 | if (sshbuf_check_sanity(buf) != 0) | ||
160 | return; | ||
161 | /* | ||
162 | * If we are a child, the free our parent to decrement its reference | ||
163 | * count and possibly free it. | ||
164 | */ | ||
165 | if (buf->parent != NULL) { | ||
166 | sshbuf_free(buf->parent); | ||
167 | buf->parent = NULL; | ||
168 | } | ||
169 | /* | ||
170 | * If we are a parent with still-extant children, then don't free just | ||
171 | * yet. The last child's call to sshbuf_free should decrement our | ||
172 | * refcount to 0 and trigger the actual free. | ||
173 | */ | ||
174 | buf->refcount--; | ||
175 | if (buf->refcount > 0) | ||
176 | return; | ||
177 | dont_free = buf->dont_free; | ||
178 | if (!buf->readonly) { | ||
179 | bzero(buf->d, buf->alloc); | ||
180 | free(buf->d); | ||
181 | } | ||
182 | bzero(buf, sizeof(*buf)); | ||
183 | if (!dont_free) | ||
184 | free(buf); | ||
185 | } | ||
186 | |||
187 | void | ||
188 | sshbuf_reset(struct sshbuf *buf) | ||
189 | { | ||
190 | u_char *d; | ||
191 | |||
192 | if (buf->readonly || buf->refcount > 1) { | ||
193 | /* Nonsensical. Just make buffer appear empty */ | ||
194 | buf->off = buf->size; | ||
195 | return; | ||
196 | } | ||
197 | if (sshbuf_check_sanity(buf) == 0) | ||
198 | bzero(buf->d, buf->alloc); | ||
199 | buf->off = buf->size = 0; | ||
200 | if (buf->alloc != SSHBUF_SIZE_INIT) { | ||
201 | if ((d = realloc(buf->d, SSHBUF_SIZE_INIT)) != NULL) { | ||
202 | buf->cd = buf->d = d; | ||
203 | buf->alloc = SSHBUF_SIZE_INIT; | ||
204 | } | ||
205 | } | ||
206 | } | ||
207 | |||
208 | size_t | ||
209 | sshbuf_max_size(const struct sshbuf *buf) | ||
210 | { | ||
211 | return buf->max_size; | ||
212 | } | ||
213 | |||
214 | size_t | ||
215 | sshbuf_alloc(const struct sshbuf *buf) | ||
216 | { | ||
217 | return buf->alloc; | ||
218 | } | ||
219 | |||
220 | const struct sshbuf * | ||
221 | sshbuf_parent(const struct sshbuf *buf) | ||
222 | { | ||
223 | return buf->parent; | ||
224 | } | ||
225 | |||
226 | u_int | ||
227 | sshbuf_refcount(const struct sshbuf *buf) | ||
228 | { | ||
229 | return buf->refcount; | ||
230 | } | ||
231 | |||
232 | int | ||
233 | sshbuf_set_max_size(struct sshbuf *buf, size_t max_size) | ||
234 | { | ||
235 | size_t rlen; | ||
236 | u_char *dp; | ||
237 | int r; | ||
238 | |||
239 | SSHBUF_DBG(("set max buf = %p len = %zu", buf, max_size)); | ||
240 | if ((r = sshbuf_check_sanity(buf)) != 0) | ||
241 | return r; | ||
242 | if (max_size == buf->max_size) | ||
243 | return 0; | ||
244 | if (buf->readonly || buf->refcount > 1) | ||
245 | return SSH_ERR_BUFFER_READ_ONLY; | ||
246 | if (max_size > SSHBUF_SIZE_MAX) | ||
247 | return SSH_ERR_NO_BUFFER_SPACE; | ||
248 | /* pack and realloc if necessary */ | ||
249 | sshbuf_maybe_pack(buf, max_size < buf->size); | ||
250 | if (max_size < buf->alloc && max_size > buf->size) { | ||
251 | if (buf->size < SSHBUF_SIZE_INIT) | ||
252 | rlen = SSHBUF_SIZE_INIT; | ||
253 | else | ||
254 | rlen = roundup(buf->size, SSHBUF_SIZE_INC); | ||
255 | if (rlen > max_size) | ||
256 | rlen = max_size; | ||
257 | bzero(buf->d + buf->size, buf->alloc - buf->size); | ||
258 | SSHBUF_DBG(("new alloc = %zu", rlen)); | ||
259 | if ((dp = realloc(buf->d, rlen)) == NULL) | ||
260 | return SSH_ERR_ALLOC_FAIL; | ||
261 | buf->cd = buf->d = dp; | ||
262 | buf->alloc = rlen; | ||
263 | } | ||
264 | SSHBUF_TELL("new-max"); | ||
265 | if (max_size < buf->alloc) | ||
266 | return SSH_ERR_NO_BUFFER_SPACE; | ||
267 | buf->max_size = max_size; | ||
268 | return 0; | ||
269 | } | ||
270 | |||
271 | size_t | ||
272 | sshbuf_len(const struct sshbuf *buf) | ||
273 | { | ||
274 | if (sshbuf_check_sanity(buf) != 0) | ||
275 | return 0; | ||
276 | return buf->size - buf->off; | ||
277 | } | ||
278 | |||
279 | size_t | ||
280 | sshbuf_avail(const struct sshbuf *buf) | ||
281 | { | ||
282 | if (sshbuf_check_sanity(buf) != 0 || buf->readonly || buf->refcount > 1) | ||
283 | return 0; | ||
284 | return buf->max_size - (buf->size - buf->off); | ||
285 | } | ||
286 | |||
287 | const u_char * | ||
288 | sshbuf_ptr(const struct sshbuf *buf) | ||
289 | { | ||
290 | if (sshbuf_check_sanity(buf) != 0) | ||
291 | return NULL; | ||
292 | return buf->cd + buf->off; | ||
293 | } | ||
294 | |||
295 | u_char * | ||
296 | sshbuf_mutable_ptr(const struct sshbuf *buf) | ||
297 | { | ||
298 | if (sshbuf_check_sanity(buf) != 0 || buf->readonly || buf->refcount > 1) | ||
299 | return NULL; | ||
300 | return buf->d + buf->off; | ||
301 | } | ||
302 | |||
303 | int | ||
304 | sshbuf_check_reserve(const struct sshbuf *buf, size_t len) | ||
305 | { | ||
306 | int r; | ||
307 | |||
308 | if ((r = sshbuf_check_sanity(buf)) != 0) | ||
309 | return r; | ||
310 | if (buf->readonly || buf->refcount > 1) | ||
311 | return SSH_ERR_BUFFER_READ_ONLY; | ||
312 | SSHBUF_TELL("check"); | ||
313 | /* Check that len is reasonable and that max_size + available < len */ | ||
314 | if (len > buf->max_size || buf->max_size - len < buf->size - buf->off) | ||
315 | return SSH_ERR_NO_BUFFER_SPACE; | ||
316 | return 0; | ||
317 | } | ||
318 | |||
319 | int | ||
320 | sshbuf_reserve(struct sshbuf *buf, size_t len, u_char **dpp) | ||
321 | { | ||
322 | size_t rlen, need; | ||
323 | u_char *dp; | ||
324 | int r; | ||
325 | |||
326 | if (dpp != NULL) | ||
327 | *dpp = NULL; | ||
328 | |||
329 | SSHBUF_DBG(("reserve buf = %p len = %zu", buf, len)); | ||
330 | if ((r = sshbuf_check_reserve(buf, len)) != 0) | ||
331 | return r; | ||
332 | /* | ||
333 | * If the requested allocation appended would push us past max_size | ||
334 | * then pack the buffer, zeroing buf->off. | ||
335 | */ | ||
336 | sshbuf_maybe_pack(buf, buf->size + len > buf->max_size); | ||
337 | SSHBUF_TELL("reserve"); | ||
338 | if (len + buf->size > buf->alloc) { | ||
339 | /* | ||
340 | * Prefer to alloc in SSHBUF_SIZE_INC units, but | ||
341 | * allocate less if doing so would overflow max_size. | ||
342 | */ | ||
343 | need = len + buf->size - buf->alloc; | ||
344 | rlen = roundup(buf->alloc + need, SSHBUF_SIZE_INC); | ||
345 | SSHBUF_DBG(("need %zu initial rlen %zu", need, rlen)); | ||
346 | if (rlen > buf->max_size) | ||
347 | rlen = buf->alloc + need; | ||
348 | SSHBUF_DBG(("adjusted rlen %zu", rlen)); | ||
349 | if ((dp = realloc(buf->d, rlen)) == NULL) { | ||
350 | SSHBUF_DBG(("realloc fail")); | ||
351 | if (dpp != NULL) | ||
352 | *dpp = NULL; | ||
353 | return SSH_ERR_ALLOC_FAIL; | ||
354 | } | ||
355 | buf->alloc = rlen; | ||
356 | buf->cd = buf->d = dp; | ||
357 | if ((r = sshbuf_check_reserve(buf, len)) < 0) { | ||
358 | /* shouldn't fail */ | ||
359 | if (dpp != NULL) | ||
360 | *dpp = NULL; | ||
361 | return r; | ||
362 | } | ||
363 | } | ||
364 | dp = buf->d + buf->size; | ||
365 | buf->size += len; | ||
366 | SSHBUF_TELL("done"); | ||
367 | if (dpp != NULL) | ||
368 | *dpp = dp; | ||
369 | return 0; | ||
370 | } | ||
371 | |||
372 | int | ||
373 | sshbuf_consume(struct sshbuf *buf, size_t len) | ||
374 | { | ||
375 | int r; | ||
376 | |||
377 | SSHBUF_DBG(("len = %zu", len)); | ||
378 | if ((r = sshbuf_check_sanity(buf)) != 0) | ||
379 | return r; | ||
380 | if (len == 0) | ||
381 | return 0; | ||
382 | if (len > sshbuf_len(buf)) | ||
383 | return SSH_ERR_MESSAGE_INCOMPLETE; | ||
384 | buf->off += len; | ||
385 | SSHBUF_TELL("done"); | ||
386 | return 0; | ||
387 | } | ||
388 | |||
389 | int | ||
390 | sshbuf_consume_end(struct sshbuf *buf, size_t len) | ||
391 | { | ||
392 | int r; | ||
393 | |||
394 | SSHBUF_DBG(("len = %zu", len)); | ||
395 | if ((r = sshbuf_check_sanity(buf)) != 0) | ||
396 | return r; | ||
397 | if (len == 0) | ||
398 | return 0; | ||
399 | if (len > sshbuf_len(buf)) | ||
400 | return SSH_ERR_MESSAGE_INCOMPLETE; | ||
401 | buf->size -= len; | ||
402 | SSHBUF_TELL("done"); | ||
403 | return 0; | ||
404 | } | ||
405 | |||
diff --git a/sshbuf.h b/sshbuf.h new file mode 100644 index 000000000..1d7da31c7 --- /dev/null +++ b/sshbuf.h | |||
@@ -0,0 +1,325 @@ | |||
1 | /* $OpenBSD: sshbuf.h,v 1.1 2014/04/30 05:29:56 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 | #ifndef _SSHBUF_H | ||
19 | #define _SSHBUF_H | ||
20 | |||
21 | #include <sys/types.h> | ||
22 | #include <stdarg.h> | ||
23 | #include <stdio.h> | ||
24 | #include <openssl/bn.h> | ||
25 | #include <openssl/ec.h> | ||
26 | |||
27 | #define SSHBUF_SIZE_MAX 0x8000000 /* Hard maximum size */ | ||
28 | #define SSHBUF_REFS_MAX 0x100000 /* Max child buffers */ | ||
29 | #define SSHBUF_MAX_BIGNUM (16384 / 8) /* Max bignum *bytes* */ | ||
30 | #define SSHBUF_MAX_ECPOINT ((528 * 2 / 8) + 1) /* Max EC point *bytes* */ | ||
31 | |||
32 | /* | ||
33 | * NB. do not depend on the internals of this. It will be made opaque | ||
34 | * one day. | ||
35 | */ | ||
36 | struct sshbuf { | ||
37 | u_char *d; /* Data */ | ||
38 | const u_char *cd; /* Const data */ | ||
39 | size_t off; /* First available byte is buf->d + buf->off */ | ||
40 | size_t size; /* Last byte is buf->d + buf->size - 1 */ | ||
41 | size_t max_size; /* Maximum size of buffer */ | ||
42 | size_t alloc; /* Total bytes allocated to buf->d */ | ||
43 | int readonly; /* Refers to external, const data */ | ||
44 | int dont_free; /* Kludge to support sshbuf_init */ | ||
45 | u_int refcount; /* Tracks self and number of child buffers */ | ||
46 | struct sshbuf *parent; /* If child, pointer to parent */ | ||
47 | }; | ||
48 | |||
49 | #ifndef SSHBUF_NO_DEPREACTED | ||
50 | /* | ||
51 | * NB. Please do not use sshbuf_init() in new code. Please use sshbuf_new() | ||
52 | * instead. sshbuf_init() is deprectated and will go away soon (it is | ||
53 | * only included to allow compat with buffer_* in OpenSSH) | ||
54 | */ | ||
55 | void sshbuf_init(struct sshbuf *buf); | ||
56 | #endif | ||
57 | |||
58 | /* | ||
59 | * Create a new sshbuf buffer. | ||
60 | * Returns pointer to buffer on success, or NULL on allocation failure. | ||
61 | */ | ||
62 | struct sshbuf *sshbuf_new(void); | ||
63 | |||
64 | /* | ||
65 | * Create a new, read-only sshbuf buffer from existing data. | ||
66 | * Returns pointer to buffer on success, or NULL on allocation failure. | ||
67 | */ | ||
68 | struct sshbuf *sshbuf_from(const void *blob, size_t len); | ||
69 | |||
70 | /* | ||
71 | * Create a new, read-only sshbuf buffer from the contents of an existing | ||
72 | * buffer. The contents of "buf" must not change in the lifetime of the | ||
73 | * resultant buffer. | ||
74 | * Returns pointer to buffer on success, or NULL on allocation failure. | ||
75 | */ | ||
76 | struct sshbuf *sshbuf_fromb(struct sshbuf *buf); | ||
77 | |||
78 | /* | ||
79 | * Create a new, read-only sshbuf buffer from the contents of a string in | ||
80 | * an existing buffer (the string is consumed in the process). | ||
81 | * The contents of "buf" must not change in the lifetime of the resultant | ||
82 | * buffer. | ||
83 | * Returns pointer to buffer on success, or NULL on allocation failure. | ||
84 | */ | ||
85 | int sshbuf_froms(struct sshbuf *buf, struct sshbuf **bufp); | ||
86 | |||
87 | /* | ||
88 | * Clear and free buf | ||
89 | */ | ||
90 | void sshbuf_free(struct sshbuf *buf); | ||
91 | |||
92 | /* | ||
93 | * Reset buf, clearing its contents. NB. max_size is preserved. | ||
94 | */ | ||
95 | void sshbuf_reset(struct sshbuf *buf); | ||
96 | |||
97 | /* | ||
98 | * Return the maximum size of buf | ||
99 | */ | ||
100 | size_t sshbuf_max_size(const struct sshbuf *buf); | ||
101 | |||
102 | /* | ||
103 | * Set the maximum size of buf | ||
104 | * Returns 0 on success, or a negative SSH_ERR_* error code on failure. | ||
105 | */ | ||
106 | int sshbuf_set_max_size(struct sshbuf *buf, size_t max_size); | ||
107 | |||
108 | /* | ||
109 | * Returns the length of data in buf | ||
110 | */ | ||
111 | size_t sshbuf_len(const struct sshbuf *buf); | ||
112 | |||
113 | /* | ||
114 | * Returns number of bytes left in buffer before hitting max_size. | ||
115 | */ | ||
116 | size_t sshbuf_avail(const struct sshbuf *buf); | ||
117 | |||
118 | /* | ||
119 | * Returns a read-only pointer to the start of the the data in buf | ||
120 | */ | ||
121 | const u_char *sshbuf_ptr(const struct sshbuf *buf); | ||
122 | |||
123 | /* | ||
124 | * Returns a mutable pointer to the start of the the data in buf, or | ||
125 | * NULL if the buffer is read-only. | ||
126 | */ | ||
127 | u_char *sshbuf_mutable_ptr(const struct sshbuf *buf); | ||
128 | |||
129 | /* | ||
130 | * Check whether a reservation of size len will succeed in buf | ||
131 | * Safer to use than direct comparisons again sshbuf_avail as it copes | ||
132 | * with unsigned overflows correctly. | ||
133 | * Returns 0 on success, or a negative SSH_ERR_* error code on failure. | ||
134 | */ | ||
135 | int sshbuf_check_reserve(const struct sshbuf *buf, size_t len); | ||
136 | |||
137 | /* | ||
138 | * Reserve len bytes in buf. | ||
139 | * Returns 0 on success and a pointer to the first reserved byte via the | ||
140 | * optional dpp parameter or a negative * SSH_ERR_* error code on failure. | ||
141 | */ | ||
142 | int sshbuf_reserve(struct sshbuf *buf, size_t len, u_char **dpp); | ||
143 | |||
144 | /* | ||
145 | * Consume len bytes from the start of buf | ||
146 | * Returns 0 on success, or a negative SSH_ERR_* error code on failure. | ||
147 | */ | ||
148 | int sshbuf_consume(struct sshbuf *buf, size_t len); | ||
149 | |||
150 | /* | ||
151 | * Consume len bytes from the end of buf | ||
152 | * Returns 0 on success, or a negative SSH_ERR_* error code on failure. | ||
153 | */ | ||
154 | int sshbuf_consume_end(struct sshbuf *buf, size_t len); | ||
155 | |||
156 | /* Extract or deposit some bytes */ | ||
157 | int sshbuf_get(struct sshbuf *buf, void *v, size_t len); | ||
158 | int sshbuf_put(struct sshbuf *buf, const void *v, size_t len); | ||
159 | int sshbuf_putb(struct sshbuf *buf, const struct sshbuf *v); | ||
160 | |||
161 | /* Append using a printf(3) format */ | ||
162 | int sshbuf_putf(struct sshbuf *buf, const char *fmt, ...) | ||
163 | __attribute__((format(printf, 2, 3))); | ||
164 | int sshbuf_putfv(struct sshbuf *buf, const char *fmt, va_list ap); | ||
165 | |||
166 | /* Functions to extract or store big-endian words of various sizes */ | ||
167 | int sshbuf_get_u64(struct sshbuf *buf, u_int64_t *valp); | ||
168 | int sshbuf_get_u32(struct sshbuf *buf, u_int32_t *valp); | ||
169 | int sshbuf_get_u16(struct sshbuf *buf, u_int16_t *valp); | ||
170 | int sshbuf_get_u8(struct sshbuf *buf, u_char *valp); | ||
171 | int sshbuf_put_u64(struct sshbuf *buf, u_int64_t val); | ||
172 | int sshbuf_put_u32(struct sshbuf *buf, u_int32_t val); | ||
173 | int sshbuf_put_u16(struct sshbuf *buf, u_int16_t val); | ||
174 | int sshbuf_put_u8(struct sshbuf *buf, u_char val); | ||
175 | |||
176 | /* | ||
177 | * Functions to extract or store SSH wire encoded strings (u32 len || data) | ||
178 | * The "cstring" variants admit no \0 characters in the string contents. | ||
179 | * Caller must free *valp. | ||
180 | */ | ||
181 | int sshbuf_get_string(struct sshbuf *buf, u_char **valp, size_t *lenp); | ||
182 | int sshbuf_get_cstring(struct sshbuf *buf, char **valp, size_t *lenp); | ||
183 | int sshbuf_get_stringb(struct sshbuf *buf, struct sshbuf *v); | ||
184 | int sshbuf_put_string(struct sshbuf *buf, const void *v, size_t len); | ||
185 | int sshbuf_put_cstring(struct sshbuf *buf, const char *v); | ||
186 | int sshbuf_put_stringb(struct sshbuf *buf, const struct sshbuf *v); | ||
187 | |||
188 | /* | ||
189 | * "Direct" variant of sshbuf_get_string, returns pointer into the sshbuf to | ||
190 | * avoid an malloc+memcpy. The pointer is guaranteed to be valid until the | ||
191 | * next sshbuf-modifying function call. Caller does not free. | ||
192 | */ | ||
193 | int sshbuf_get_string_direct(struct sshbuf *buf, const u_char **valp, | ||
194 | size_t *lenp); | ||
195 | |||
196 | /* Skip past a string */ | ||
197 | #define sshbuf_skip_string(buf) sshbuf_get_string_direct(buf, NULL, NULL) | ||
198 | |||
199 | /* Another variant: "peeks" into the buffer without modifying it */ | ||
200 | int sshbuf_peek_string_direct(const struct sshbuf *buf, const u_char **valp, | ||
201 | size_t *lenp); | ||
202 | |||
203 | /* | ||
204 | * Functions to extract or store SSH wire encoded bignums and elliptic | ||
205 | * curve points. | ||
206 | */ | ||
207 | int sshbuf_get_bignum2(struct sshbuf *buf, BIGNUM *v); | ||
208 | int sshbuf_get_bignum1(struct sshbuf *buf, BIGNUM *v); | ||
209 | int sshbuf_get_ec(struct sshbuf *buf, EC_POINT *v, const EC_GROUP *g); | ||
210 | int sshbuf_get_eckey(struct sshbuf *buf, EC_KEY *v); | ||
211 | int sshbuf_put_bignum2(struct sshbuf *buf, const BIGNUM *v); | ||
212 | int sshbuf_put_bignum1(struct sshbuf *buf, const BIGNUM *v); | ||
213 | int sshbuf_put_ec(struct sshbuf *buf, const EC_POINT *v, const EC_GROUP *g); | ||
214 | int sshbuf_put_eckey(struct sshbuf *buf, const EC_KEY *v); | ||
215 | int sshbuf_put_bignum2_bytes(struct sshbuf *buf, const void *v, size_t len); | ||
216 | |||
217 | /* Dump the contents of the buffer to stderr in a human-readable format */ | ||
218 | void sshbuf_dump(struct sshbuf *buf, FILE *f); | ||
219 | |||
220 | /* Return the hexadecimal representation of the contents of the buffer */ | ||
221 | char *sshbuf_dtob16(struct sshbuf *buf); | ||
222 | |||
223 | /* Encode the contents of the buffer as base64 */ | ||
224 | char *sshbuf_dtob64(struct sshbuf *buf); | ||
225 | |||
226 | /* Decode base64 data and append it to the buffer */ | ||
227 | int sshbuf_b64tod(struct sshbuf *buf, const char *b64); | ||
228 | |||
229 | /* Macros for decoding/encoding integers */ | ||
230 | #define PEEK_U64(p) \ | ||
231 | (((u_int64_t)(((u_char *)(p))[0]) << 56) | \ | ||
232 | ((u_int64_t)(((u_char *)(p))[1]) << 48) | \ | ||
233 | ((u_int64_t)(((u_char *)(p))[2]) << 40) | \ | ||
234 | ((u_int64_t)(((u_char *)(p))[3]) << 32) | \ | ||
235 | ((u_int64_t)(((u_char *)(p))[4]) << 24) | \ | ||
236 | ((u_int64_t)(((u_char *)(p))[5]) << 16) | \ | ||
237 | ((u_int64_t)(((u_char *)(p))[6]) << 8) | \ | ||
238 | (u_int64_t)(((u_char *)(p))[7])) | ||
239 | #define PEEK_U32(p) \ | ||
240 | (((u_int32_t)(((u_char *)(p))[0]) << 24) | \ | ||
241 | ((u_int32_t)(((u_char *)(p))[1]) << 16) | \ | ||
242 | ((u_int32_t)(((u_char *)(p))[2]) << 8) | \ | ||
243 | (u_int32_t)(((u_char *)(p))[3])) | ||
244 | #define PEEK_U16(p) \ | ||
245 | (((u_int16_t)(((u_char *)(p))[0]) << 8) | \ | ||
246 | (u_int16_t)(((u_char *)(p))[1])) | ||
247 | |||
248 | #define POKE_U64(p, v) \ | ||
249 | do { \ | ||
250 | ((u_char *)(p))[0] = (((u_int64_t)(v)) >> 56) & 0xff; \ | ||
251 | ((u_char *)(p))[1] = (((u_int64_t)(v)) >> 48) & 0xff; \ | ||
252 | ((u_char *)(p))[2] = (((u_int64_t)(v)) >> 40) & 0xff; \ | ||
253 | ((u_char *)(p))[3] = (((u_int64_t)(v)) >> 32) & 0xff; \ | ||
254 | ((u_char *)(p))[4] = (((u_int64_t)(v)) >> 24) & 0xff; \ | ||
255 | ((u_char *)(p))[5] = (((u_int64_t)(v)) >> 16) & 0xff; \ | ||
256 | ((u_char *)(p))[6] = (((u_int64_t)(v)) >> 8) & 0xff; \ | ||
257 | ((u_char *)(p))[7] = ((u_int64_t)(v)) & 0xff; \ | ||
258 | } while (0) | ||
259 | #define POKE_U32(p, v) \ | ||
260 | do { \ | ||
261 | ((u_char *)(p))[0] = (((u_int64_t)(v)) >> 24) & 0xff; \ | ||
262 | ((u_char *)(p))[1] = (((u_int64_t)(v)) >> 16) & 0xff; \ | ||
263 | ((u_char *)(p))[2] = (((u_int64_t)(v)) >> 8) & 0xff; \ | ||
264 | ((u_char *)(p))[3] = ((u_int64_t)(v)) & 0xff; \ | ||
265 | } while (0) | ||
266 | #define POKE_U16(p, v) \ | ||
267 | do { \ | ||
268 | ((u_char *)(p))[0] = (((u_int64_t)(v)) >> 8) & 0xff; \ | ||
269 | ((u_char *)(p))[1] = ((u_int64_t)(v)) & 0xff; \ | ||
270 | } while (0) | ||
271 | |||
272 | /* Internal definitions follow. Exposed for regress tests */ | ||
273 | #ifdef SSHBUF_INTERNAL | ||
274 | |||
275 | /* | ||
276 | * Return the allocation size of buf | ||
277 | */ | ||
278 | size_t sshbuf_alloc(const struct sshbuf *buf); | ||
279 | |||
280 | /* | ||
281 | * Increment the reference count of buf. | ||
282 | */ | ||
283 | int sshbuf_set_parent(struct sshbuf *child, struct sshbuf *parent); | ||
284 | |||
285 | /* | ||
286 | * Return the parent buffer of buf, or NULL if it has no parent. | ||
287 | */ | ||
288 | const struct sshbuf *sshbuf_parent(const struct sshbuf *buf); | ||
289 | |||
290 | /* | ||
291 | * Return the reference count of buf | ||
292 | */ | ||
293 | u_int sshbuf_refcount(const struct sshbuf *buf); | ||
294 | |||
295 | # define SSHBUF_SIZE_INIT 256 /* Initial allocation */ | ||
296 | # define SSHBUF_SIZE_INC 256 /* Preferred increment length */ | ||
297 | # define SSHBUF_PACK_MIN 8192 /* Minimim packable offset */ | ||
298 | |||
299 | /* # define SSHBUF_ABORT abort */ | ||
300 | /* # define SSHBUF_DEBUG */ | ||
301 | |||
302 | # ifndef SSHBUF_ABORT | ||
303 | # define SSHBUF_ABORT() | ||
304 | # endif | ||
305 | |||
306 | # ifdef SSHBUF_DEBUG | ||
307 | # define SSHBUF_TELL(what) do { \ | ||
308 | printf("%s:%d %s: %s size %zu alloc %zu off %zu max %zu\n", \ | ||
309 | __FILE__, __LINE__, __func__, what, \ | ||
310 | buf->size, buf->alloc, buf->off, buf->max_size); \ | ||
311 | fflush(stdout); \ | ||
312 | } while (0) | ||
313 | # define SSHBUF_DBG(x) do { \ | ||
314 | printf("%s:%d %s: ", __FILE__, __LINE__, __func__); \ | ||
315 | printf x; \ | ||
316 | printf("\n"); \ | ||
317 | fflush(stdout); \ | ||
318 | } while (0) | ||
319 | # else | ||
320 | # define SSHBUF_TELL(what) | ||
321 | # define SSHBUF_DBG(x) | ||
322 | # endif | ||
323 | #endif /* SSHBUF_INTERNAL */ | ||
324 | |||
325 | #endif /* _SSHBUF_H */ | ||
diff --git a/ssherr.c b/ssherr.c new file mode 100644 index 000000000..49fbb71de --- /dev/null +++ b/ssherr.c | |||
@@ -0,0 +1,131 @@ | |||
1 | /* $OpenBSD: ssherr.c,v 1.1 2014/04/30 05:29:56 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 <errno.h> | ||
19 | #include <string.h> | ||
20 | #include "ssherr.h" | ||
21 | |||
22 | const char * | ||
23 | ssh_err(int n) | ||
24 | { | ||
25 | switch (n) { | ||
26 | case SSH_ERR_SUCCESS: | ||
27 | return "success"; | ||
28 | case SSH_ERR_INTERNAL_ERROR: | ||
29 | return "unexpected internal error"; | ||
30 | case SSH_ERR_ALLOC_FAIL: | ||
31 | return "memory allocation failed"; | ||
32 | case SSH_ERR_MESSAGE_INCOMPLETE: | ||
33 | return "incomplete message"; | ||
34 | case SSH_ERR_INVALID_FORMAT: | ||
35 | return "invalid format"; | ||
36 | case SSH_ERR_BIGNUM_IS_NEGATIVE: | ||
37 | return "bignum is negative"; | ||
38 | case SSH_ERR_STRING_TOO_LARGE: | ||
39 | return "string is too large"; | ||
40 | case SSH_ERR_BIGNUM_TOO_LARGE: | ||
41 | return "bignum is too large"; | ||
42 | case SSH_ERR_ECPOINT_TOO_LARGE: | ||
43 | return "elliptic curve point is too large"; | ||
44 | case SSH_ERR_NO_BUFFER_SPACE: | ||
45 | return "insufficient buffer space"; | ||
46 | case SSH_ERR_INVALID_ARGUMENT: | ||
47 | return "invalid argument"; | ||
48 | case SSH_ERR_KEY_BITS_MISMATCH: | ||
49 | return "key bits do not match"; | ||
50 | case SSH_ERR_EC_CURVE_INVALID: | ||
51 | return "invalid elliptic curve"; | ||
52 | case SSH_ERR_KEY_TYPE_MISMATCH: | ||
53 | return "key type does not match"; | ||
54 | case SSH_ERR_KEY_TYPE_UNKNOWN: | ||
55 | return "unknown or unsupported key type"; | ||
56 | case SSH_ERR_EC_CURVE_MISMATCH: | ||
57 | return "elliptic curve does not match"; | ||
58 | case SSH_ERR_EXPECTED_CERT: | ||
59 | return "plain key provided where certificate required"; | ||
60 | case SSH_ERR_KEY_LACKS_CERTBLOB: | ||
61 | return "key lacks certificate data"; | ||
62 | case SSH_ERR_KEY_CERT_UNKNOWN_TYPE: | ||
63 | return "unknown/unsupported certificate type"; | ||
64 | case SSH_ERR_KEY_CERT_INVALID_SIGN_KEY: | ||
65 | return "invalid certificate signing key"; | ||
66 | case SSH_ERR_KEY_INVALID_EC_VALUE: | ||
67 | return "invalid elliptic curve value"; | ||
68 | case SSH_ERR_SIGNATURE_INVALID: | ||
69 | return "incorrect signature"; | ||
70 | case SSH_ERR_LIBCRYPTO_ERROR: | ||
71 | return "error in libcrypto"; /* XXX fetch and return */ | ||
72 | case SSH_ERR_UNEXPECTED_TRAILING_DATA: | ||
73 | return "unexpected bytes remain after decoding"; | ||
74 | case SSH_ERR_SYSTEM_ERROR: | ||
75 | return strerror(errno); | ||
76 | case SSH_ERR_KEY_CERT_INVALID: | ||
77 | return "invalid certificate"; | ||
78 | case SSH_ERR_AGENT_COMMUNICATION: | ||
79 | return "communication with agent failed"; | ||
80 | case SSH_ERR_AGENT_FAILURE: | ||
81 | return "agent refused operation"; | ||
82 | case SSH_ERR_DH_GEX_OUT_OF_RANGE: | ||
83 | return "DH GEX group out of range"; | ||
84 | case SSH_ERR_DISCONNECTED: | ||
85 | return "disconnected"; | ||
86 | case SSH_ERR_MAC_INVALID: | ||
87 | return "message authentication code incorrect"; | ||
88 | case SSH_ERR_NO_CIPHER_ALG_MATCH: | ||
89 | return "no matching cipher found"; | ||
90 | case SSH_ERR_NO_MAC_ALG_MATCH: | ||
91 | return "no matching MAC found"; | ||
92 | case SSH_ERR_NO_COMPRESS_ALG_MATCH: | ||
93 | return "no matching compression method found"; | ||
94 | case SSH_ERR_NO_KEX_ALG_MATCH: | ||
95 | return "no matching key exchange method found"; | ||
96 | case SSH_ERR_NO_HOSTKEY_ALG_MATCH: | ||
97 | return "no matching host key type found"; | ||
98 | case SSH_ERR_PROTOCOL_MISMATCH: | ||
99 | return "protocol version mismatch"; | ||
100 | case SSH_ERR_NO_PROTOCOL_VERSION: | ||
101 | return "could not read protocol version"; | ||
102 | case SSH_ERR_NO_HOSTKEY_LOADED: | ||
103 | return "could not load host key"; | ||
104 | case SSH_ERR_NEED_REKEY: | ||
105 | return "rekeying not supported by peer"; | ||
106 | case SSH_ERR_PASSPHRASE_TOO_SHORT: | ||
107 | return "passphrase is too short (minimum four characters)"; | ||
108 | case SSH_ERR_FILE_CHANGED: | ||
109 | return "file changed while reading"; | ||
110 | case SSH_ERR_KEY_UNKNOWN_CIPHER: | ||
111 | return "key encrypted using unsupported cipher"; | ||
112 | case SSH_ERR_KEY_WRONG_PASSPHRASE: | ||
113 | return "incorrect passphrase supplied to decrypt private key"; | ||
114 | case SSH_ERR_KEY_BAD_PERMISSIONS: | ||
115 | return "bad permissions"; | ||
116 | case SSH_ERR_KEY_CERT_MISMATCH: | ||
117 | return "certificate does not match key"; | ||
118 | case SSH_ERR_KEY_NOT_FOUND: | ||
119 | return "key not found"; | ||
120 | case SSH_ERR_AGENT_NOT_PRESENT: | ||
121 | return "agent not present"; | ||
122 | case SSH_ERR_AGENT_NO_IDENTITIES: | ||
123 | return "agent contains no identities"; | ||
124 | case SSH_ERR_KRL_BAD_MAGIC: | ||
125 | return "KRL file has invalid magic number"; | ||
126 | case SSH_ERR_KEY_REVOKED: | ||
127 | return "Key is revoked"; | ||
128 | default: | ||
129 | return "unknown error"; | ||
130 | } | ||
131 | } | ||
diff --git a/ssherr.h b/ssherr.h new file mode 100644 index 000000000..106f786ea --- /dev/null +++ b/ssherr.h | |||
@@ -0,0 +1,80 @@ | |||
1 | /* $OpenBSD: ssherr.h,v 1.1 2014/04/30 05:29:56 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 | #ifndef _SSHERR_H | ||
19 | #define _SSHERR_H | ||
20 | |||
21 | /* XXX are these too granular? not granular enough? I can't decide - djm */ | ||
22 | |||
23 | /* Error codes */ | ||
24 | #define SSH_ERR_SUCCESS 0 | ||
25 | #define SSH_ERR_INTERNAL_ERROR -1 | ||
26 | #define SSH_ERR_ALLOC_FAIL -2 | ||
27 | #define SSH_ERR_MESSAGE_INCOMPLETE -3 | ||
28 | #define SSH_ERR_INVALID_FORMAT -4 | ||
29 | #define SSH_ERR_BIGNUM_IS_NEGATIVE -5 | ||
30 | #define SSH_ERR_STRING_TOO_LARGE -6 | ||
31 | #define SSH_ERR_BIGNUM_TOO_LARGE -7 | ||
32 | #define SSH_ERR_ECPOINT_TOO_LARGE -8 | ||
33 | #define SSH_ERR_NO_BUFFER_SPACE -9 | ||
34 | #define SSH_ERR_INVALID_ARGUMENT -10 | ||
35 | #define SSH_ERR_KEY_BITS_MISMATCH -11 | ||
36 | #define SSH_ERR_EC_CURVE_INVALID -12 | ||
37 | #define SSH_ERR_KEY_TYPE_MISMATCH -13 | ||
38 | #define SSH_ERR_KEY_TYPE_UNKNOWN -14 /* XXX UNSUPPORTED? */ | ||
39 | #define SSH_ERR_EC_CURVE_MISMATCH -15 | ||
40 | #define SSH_ERR_EXPECTED_CERT -16 | ||
41 | #define SSH_ERR_KEY_LACKS_CERTBLOB -17 | ||
42 | #define SSH_ERR_KEY_CERT_UNKNOWN_TYPE -18 | ||
43 | #define SSH_ERR_KEY_CERT_INVALID_SIGN_KEY -19 | ||
44 | #define SSH_ERR_KEY_INVALID_EC_VALUE -20 | ||
45 | #define SSH_ERR_SIGNATURE_INVALID -21 | ||
46 | #define SSH_ERR_LIBCRYPTO_ERROR -22 | ||
47 | #define SSH_ERR_UNEXPECTED_TRAILING_DATA -23 | ||
48 | #define SSH_ERR_SYSTEM_ERROR -24 | ||
49 | #define SSH_ERR_KEY_CERT_INVALID -25 | ||
50 | #define SSH_ERR_AGENT_COMMUNICATION -26 | ||
51 | #define SSH_ERR_AGENT_FAILURE -27 | ||
52 | #define SSH_ERR_DH_GEX_OUT_OF_RANGE -28 | ||
53 | #define SSH_ERR_DISCONNECTED -29 | ||
54 | #define SSH_ERR_MAC_INVALID -30 | ||
55 | #define SSH_ERR_NO_CIPHER_ALG_MATCH -31 | ||
56 | #define SSH_ERR_NO_MAC_ALG_MATCH -32 | ||
57 | #define SSH_ERR_NO_COMPRESS_ALG_MATCH -33 | ||
58 | #define SSH_ERR_NO_KEX_ALG_MATCH -34 | ||
59 | #define SSH_ERR_NO_HOSTKEY_ALG_MATCH -35 | ||
60 | #define SSH_ERR_NO_HOSTKEY_LOADED -36 | ||
61 | #define SSH_ERR_PROTOCOL_MISMATCH -37 | ||
62 | #define SSH_ERR_NO_PROTOCOL_VERSION -38 | ||
63 | #define SSH_ERR_NEED_REKEY -39 | ||
64 | #define SSH_ERR_PASSPHRASE_TOO_SHORT -40 | ||
65 | #define SSH_ERR_FILE_CHANGED -41 | ||
66 | #define SSH_ERR_KEY_UNKNOWN_CIPHER -42 | ||
67 | #define SSH_ERR_KEY_WRONG_PASSPHRASE -43 | ||
68 | #define SSH_ERR_KEY_BAD_PERMISSIONS -44 | ||
69 | #define SSH_ERR_KEY_CERT_MISMATCH -45 | ||
70 | #define SSH_ERR_KEY_NOT_FOUND -46 | ||
71 | #define SSH_ERR_AGENT_NOT_PRESENT -47 | ||
72 | #define SSH_ERR_AGENT_NO_IDENTITIES -48 | ||
73 | #define SSH_ERR_BUFFER_READ_ONLY -49 | ||
74 | #define SSH_ERR_KRL_BAD_MAGIC -50 | ||
75 | #define SSH_ERR_KEY_REVOKED -51 | ||
76 | |||
77 | /* Translate a numeric error code to a human-readable error string */ | ||
78 | const char *ssh_err(int n); | ||
79 | |||
80 | #endif /* _SSHERR_H */ | ||