summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDamien Miller <djm@mindrot.org>2014-05-15 14:33:43 +1000
committerDamien Miller <djm@mindrot.org>2014-05-15 14:33:43 +1000
commit05e82c3b963c33048128baf72a6f6b3a1c10b4c1 (patch)
treecb238452459af2f8311d54ca509722497e799517
parent380948180f847a26f2d0c85b4dad3dca2ed2fd8b (diff)
- djm@cvs.openbsd.org 2014/04/30 05:29:56
[bufaux.c bufbn.c bufec.c buffer.c buffer.h sshbuf-getput-basic.c] [sshbuf-getput-crypto.c sshbuf-misc.c sshbuf.c sshbuf.h ssherr.c] [ssherr.h] New buffer API; the first installment of the conversion/replacement of OpenSSH's internals to make them usable as a standalone library. This includes a set of wrappers to make it compatible with the existing buffer API so replacement can occur incrementally. With and ok markus@ Thanks also to Ben Hawkes, David Tomaschik, Ivan Fratric, Matthew Dempsky and Ron Bowes for a detailed review.
-rw-r--r--ChangeLog14
-rw-r--r--bufaux.c332
-rw-r--r--bufbn.c210
-rw-r--r--bufec.c107
-rw-r--r--buffer.c245
-rw-r--r--buffer.h64
-rw-r--r--sshbuf-getput-basic.c421
-rw-r--r--sshbuf-getput-crypto.c233
-rw-r--r--sshbuf-misc.c129
-rw-r--r--sshbuf.c405
-rw-r--r--sshbuf.h325
-rw-r--r--ssherr.c131
-rw-r--r--ssherr.h80
13 files changed, 1977 insertions, 719 deletions
diff --git a/ChangeLog b/ChangeLog
index 50c83e64b..5ffe464e3 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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
5620140430 7020140430
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
diff --git a/bufaux.c b/bufaux.c
index 320bc2cb6..aa9b892d9 100644
--- a/bufaux.c
+++ b/bufaux.c
@@ -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
57int 26int
58buffer_get_short_ret(u_short *ret, Buffer *buffer) 27buffer_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
68u_short 38u_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
79int 49int
80buffer_get_int_ret(u_int *ret, Buffer *buffer) 50buffer_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
91u_int 61u_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
102int 72int
103buffer_get_int64_ret(u_int64_t *ret, Buffer *buffer) 73buffer_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
114u_int64_t 84u_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 */
128void 95void
129buffer_put_short(Buffer *buffer, u_short value) 96buffer_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
137void 104void
138buffer_put_int(Buffer *buffer, u_int value) 105buffer_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
146void 113void
147buffer_put_int64(Buffer *buffer, u_int64_t value) 114buffer_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 */
163void * 122void *
164buffer_get_string_ret(Buffer *buffer, u_int *length_ptr) 123buffer_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
194void * 138void *
@@ -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
204char * 148char *
205buffer_get_cstring_ret(Buffer *buffer, u_int *length_ptr) 149buffer_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
227char * 164char *
@@ -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
237const void * 174const void *
238buffer_get_string_ptr_ret(Buffer *buffer, u_int *length_ptr) 175buffer_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
256const void * 190const 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 */
269void 200void
270buffer_put_string(Buffer *buffer, const void *buf, u_int len) 201buffer_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
275void 209void
276buffer_put_cstring(Buffer *buffer, const char *s) 210buffer_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 */
286int 218int
287buffer_get_char_ret(u_char *ret, Buffer *buffer) 219buffer_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
296int 230int
297buffer_get_char(Buffer *buffer) 231buffer_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 */
309void 240void
310buffer_put_char(Buffer *buffer, int value) 241buffer_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
319void *
320buffer_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
352void *
353buffer_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 */
365void 249void
366buffer_put_bignum2_from_string(Buffer *buffer, const u_char *s, u_int l) 250buffer_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
diff --git a/bufbn.c b/bufbn.c
index 1d2e01266..0a519ed2d 100644
--- a/bufbn.c
+++ b/bufbn.c
@@ -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 */
59int 27int
60buffer_put_bignum_ret(Buffer *buffer, const BIGNUM *value) 28buffer_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
89void 39void
90buffer_put_bignum(Buffer *buffer, const BIGNUM *value) 40buffer_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 */
99int 46int
100buffer_get_bignum_ret(Buffer *buffer, BIGNUM *value) 47buffer_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
138void 58void
139buffer_get_bignum(Buffer *buffer, BIGNUM *value) 59buffer_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 */
148int 65int
149buffer_put_bignum2_ret(Buffer *buffer, const BIGNUM *value) 66buffer_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
186void 77void
187buffer_put_bignum2(Buffer *buffer, const BIGNUM *value) 78buffer_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
193int 84int
194buffer_get_bignum2_ret(Buffer *buffer, BIGNUM *value) 85buffer_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
224void 96void
225buffer_get_bignum2(Buffer *buffer, BIGNUM *value) 97buffer_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}
diff --git a/bufec.c b/bufec.c
index 89482b906..b33ede385 100644
--- a/bufec.c
+++ b/bufec.c
@@ -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 */
49int 27int
50buffer_put_ecpoint_ret(Buffer *buffer, const EC_GROUP *curve, 28buffer_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
87void 40void
@@ -96,43 +49,13 @@ int
96buffer_get_ecpoint_ret(Buffer *buffer, const EC_GROUP *curve, 49buffer_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
138void 61void
@@ -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
diff --git a/buffer.c b/buffer.c
index d240f6753..07bc186d0 100644
--- a/buffer.c
+++ b/buffer.c
@@ -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
34void
35buffer_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
48void
49buffer_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
63void
64buffer_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
72void 27void
73buffer_append(Buffer *buffer, const void *data, u_int len) 28buffer_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
80static int 32 if ((ret = sshbuf_put(buffer, data, len)) != 0)
81buffer_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
103void * 36void *
104buffer_append_space(Buffer *buffer, u_int len) 37buffer_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 }
117restart:
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 */
144int 47int
145buffer_check_alloc(Buffer *buffer, u_int len) 48buffer_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
163u_int 52 if (ret == 0)
164buffer_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
171int 59int
172buffer_get_ret(Buffer *buffer, void *buf, u_int len) 60buffer_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
184void 71void
185buffer_get(Buffer *buffer, void *buf, u_int len) 72buffer_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
193int 78int
194buffer_consume_ret(Buffer *buffer, u_int bytes) 79buffer_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
204void 90void
205buffer_consume(Buffer *buffer, u_int bytes) 91buffer_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
213int 97int
214buffer_consume_end_ret(Buffer *buffer, u_int bytes) 98buffer_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
222void 109void
223buffer_consume_end(Buffer *buffer, u_int bytes) 110buffer_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
231void *
232buffer_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
239void
240buffer_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}
diff --git a/buffer.h b/buffer.h
index 74a7b8149..9d853edf2 100644
--- a/buffer.h
+++ b/buffer.h
@@ -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
19typedef struct { 24#include "sshbuf.h"
20 u_char *buf; /* Buffer for data. */ 25
21 u_int alloc; /* Number of bytes allocated for data. */ 26typedef 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
26void buffer_init(Buffer *); 28#define buffer_init(b) sshbuf_init(b)
27void buffer_clear(Buffer *); 29#define buffer_clear(b) sshbuf_reset(b)
28void buffer_free(Buffer *); 30#define buffer_free(b) sshbuf_free(b)
31#define buffer_dump(b) sshbuf_dump(b, stderr)
29 32
30u_int buffer_len(const Buffer *); 33/* XXX cast is safe: sshbuf never stores more than len 2^31 */
31void *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
33void buffer_append(Buffer *, const void *, u_int); 37void buffer_append(Buffer *, const void *, u_int);
34void *buffer_append_space(Buffer *, u_int); 38void *buffer_append_space(Buffer *, u_int);
35
36int buffer_check_alloc(Buffer *, u_int); 39int buffer_check_alloc(Buffer *, u_int);
37
38void buffer_get(Buffer *, void *, u_int); 40void buffer_get(Buffer *, void *, u_int);
39 41
40void buffer_consume(Buffer *, u_int); 42void buffer_consume(Buffer *, u_int);
41void buffer_consume_end(Buffer *, u_int); 43void buffer_consume_end(Buffer *, u_int);
42 44
43void buffer_dump(const Buffer *);
44 45
45int buffer_get_ret(Buffer *, void *, u_int); 46int buffer_get_ret(Buffer *, void *, u_int);
46int buffer_consume_ret(Buffer *, u_int); 47int buffer_consume_ret(Buffer *, u_int);
47int buffer_consume_end_ret(Buffer *, u_int); 48int buffer_consume_end_ret(Buffer *, u_int);
48 49
49#include <openssl/bn.h> 50#include <openssl/bn.h>
50
51void buffer_put_bignum(Buffer *, const BIGNUM *); 51void buffer_put_bignum(Buffer *, const BIGNUM *);
52void buffer_put_bignum2(Buffer *, const BIGNUM *); 52void buffer_put_bignum2(Buffer *, const BIGNUM *);
53void buffer_get_bignum(Buffer *, BIGNUM *); 53void buffer_get_bignum(Buffer *, BIGNUM *);
54void buffer_get_bignum2(Buffer *, BIGNUM *); 54void buffer_get_bignum2(Buffer *, BIGNUM *);
55void buffer_put_bignum2_from_string(Buffer *, const u_char *, u_int);
55 56
56u_short buffer_get_short(Buffer *); 57u_short buffer_get_short(Buffer *);
57void buffer_put_short(Buffer *, u_short); 58void buffer_put_short(Buffer *, u_short);
@@ -71,8 +72,7 @@ void buffer_put_string(Buffer *, const void *, u_int);
71char *buffer_get_cstring(Buffer *, u_int *); 72char *buffer_get_cstring(Buffer *, u_int *);
72void buffer_put_cstring(Buffer *, const char *); 73void 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
77int buffer_put_bignum_ret(Buffer *, const BIGNUM *); 77int buffer_put_bignum_ret(Buffer *, const BIGNUM *);
78int buffer_get_bignum_ret(Buffer *, BIGNUM *); 78int buffer_get_bignum_ret(Buffer *, BIGNUM *);
@@ -84,19 +84,15 @@ int buffer_get_int64_ret(u_int64_t *, Buffer *);
84void *buffer_get_string_ret(Buffer *, u_int *); 84void *buffer_get_string_ret(Buffer *, u_int *);
85char *buffer_get_cstring_ret(Buffer *, u_int *); 85char *buffer_get_cstring_ret(Buffer *, u_int *);
86const void *buffer_get_string_ptr_ret(Buffer *, u_int *); 86const void *buffer_get_string_ptr_ret(Buffer *, u_int *);
87int buffer_get_char_ret(u_char *, Buffer *); 87int buffer_get_char_ret(char *, Buffer *);
88
89void *buffer_get_bignum2_as_string_ret(Buffer *, u_int *);
90void *buffer_get_bignum2_as_string(Buffer *, u_int *);
91void 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
96int buffer_put_ecpoint_ret(Buffer *, const EC_GROUP *, const EC_POINT *); 91int buffer_put_ecpoint_ret(Buffer *, const EC_GROUP *, const EC_POINT *);
97void buffer_put_ecpoint(Buffer *, const EC_GROUP *, const EC_POINT *); 92void buffer_put_ecpoint(Buffer *, const EC_GROUP *, const EC_POINT *);
98int buffer_get_ecpoint_ret(Buffer *, const EC_GROUP *, EC_POINT *); 93int buffer_get_ecpoint_ret(Buffer *, const EC_GROUP *, EC_POINT *);
99void buffer_get_ecpoint(Buffer *, const EC_GROUP *, EC_POINT *); 94void 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
29int
30sshbuf_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
42int
43sshbuf_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
55int
56sshbuf_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
68int
69sshbuf_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
81int
82sshbuf_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
94int
95sshbuf_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
120int
121sshbuf_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
146int
147sshbuf_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
177int
178sshbuf_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
211int
212sshbuf_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
231int
232sshbuf_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
243int
244sshbuf_putb(struct sshbuf *buf, const struct sshbuf *v)
245{
246 return sshbuf_put(buf, sshbuf_ptr(v), sshbuf_len(v));
247}
248
249int
250sshbuf_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
261int
262sshbuf_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
294int
295sshbuf_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
306int
307sshbuf_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
318int
319sshbuf_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
330int
331sshbuf_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
342int
343sshbuf_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
359int
360sshbuf_put_cstring(struct sshbuf *buf, const char *v)
361{
362 return sshbuf_put_string(buf, (u_char *)v, strlen(v));
363}
364
365int
366sshbuf_put_stringb(struct sshbuf *buf, const struct sshbuf *v)
367{
368 return sshbuf_put_string(buf, sshbuf_ptr(v), sshbuf_len(v));
369}
370
371int
372sshbuf_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
395int
396sshbuf_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
32int
33sshbuf_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
58int
59sshbuf_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
85static int
86get_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
99int
100sshbuf_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
120int
121sshbuf_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
156int
157sshbuf_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
178int
179sshbuf_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
200int
201sshbuf_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
226int
227sshbuf_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
35void
36sshbuf_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
63char *
64sshbuf_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
83char *
84sshbuf_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
104int
105sshbuf_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
31static inline int
32sshbuf_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
52static void
53sshbuf_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
68struct sshbuf *
69sshbuf_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
87struct sshbuf *
88sshbuf_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
104int
105sshbuf_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
117struct sshbuf *
118sshbuf_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
133void
134sshbuf_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
146void
147sshbuf_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
187void
188sshbuf_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
208size_t
209sshbuf_max_size(const struct sshbuf *buf)
210{
211 return buf->max_size;
212}
213
214size_t
215sshbuf_alloc(const struct sshbuf *buf)
216{
217 return buf->alloc;
218}
219
220const struct sshbuf *
221sshbuf_parent(const struct sshbuf *buf)
222{
223 return buf->parent;
224}
225
226u_int
227sshbuf_refcount(const struct sshbuf *buf)
228{
229 return buf->refcount;
230}
231
232int
233sshbuf_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
271size_t
272sshbuf_len(const struct sshbuf *buf)
273{
274 if (sshbuf_check_sanity(buf) != 0)
275 return 0;
276 return buf->size - buf->off;
277}
278
279size_t
280sshbuf_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
287const u_char *
288sshbuf_ptr(const struct sshbuf *buf)
289{
290 if (sshbuf_check_sanity(buf) != 0)
291 return NULL;
292 return buf->cd + buf->off;
293}
294
295u_char *
296sshbuf_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
303int
304sshbuf_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
319int
320sshbuf_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
372int
373sshbuf_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
389int
390sshbuf_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 */
36struct 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 */
55void 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 */
62struct 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 */
68struct 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 */
76struct 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 */
85int sshbuf_froms(struct sshbuf *buf, struct sshbuf **bufp);
86
87/*
88 * Clear and free buf
89 */
90void sshbuf_free(struct sshbuf *buf);
91
92/*
93 * Reset buf, clearing its contents. NB. max_size is preserved.
94 */
95void sshbuf_reset(struct sshbuf *buf);
96
97/*
98 * Return the maximum size of buf
99 */
100size_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 */
106int sshbuf_set_max_size(struct sshbuf *buf, size_t max_size);
107
108/*
109 * Returns the length of data in buf
110 */
111size_t sshbuf_len(const struct sshbuf *buf);
112
113/*
114 * Returns number of bytes left in buffer before hitting max_size.
115 */
116size_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 */
121const 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 */
127u_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 */
135int 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 */
142int 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 */
148int 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 */
154int sshbuf_consume_end(struct sshbuf *buf, size_t len);
155
156/* Extract or deposit some bytes */
157int sshbuf_get(struct sshbuf *buf, void *v, size_t len);
158int sshbuf_put(struct sshbuf *buf, const void *v, size_t len);
159int sshbuf_putb(struct sshbuf *buf, const struct sshbuf *v);
160
161/* Append using a printf(3) format */
162int sshbuf_putf(struct sshbuf *buf, const char *fmt, ...)
163 __attribute__((format(printf, 2, 3)));
164int sshbuf_putfv(struct sshbuf *buf, const char *fmt, va_list ap);
165
166/* Functions to extract or store big-endian words of various sizes */
167int sshbuf_get_u64(struct sshbuf *buf, u_int64_t *valp);
168int sshbuf_get_u32(struct sshbuf *buf, u_int32_t *valp);
169int sshbuf_get_u16(struct sshbuf *buf, u_int16_t *valp);
170int sshbuf_get_u8(struct sshbuf *buf, u_char *valp);
171int sshbuf_put_u64(struct sshbuf *buf, u_int64_t val);
172int sshbuf_put_u32(struct sshbuf *buf, u_int32_t val);
173int sshbuf_put_u16(struct sshbuf *buf, u_int16_t val);
174int 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 */
181int sshbuf_get_string(struct sshbuf *buf, u_char **valp, size_t *lenp);
182int sshbuf_get_cstring(struct sshbuf *buf, char **valp, size_t *lenp);
183int sshbuf_get_stringb(struct sshbuf *buf, struct sshbuf *v);
184int sshbuf_put_string(struct sshbuf *buf, const void *v, size_t len);
185int sshbuf_put_cstring(struct sshbuf *buf, const char *v);
186int 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 */
193int 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 */
200int 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 */
207int sshbuf_get_bignum2(struct sshbuf *buf, BIGNUM *v);
208int sshbuf_get_bignum1(struct sshbuf *buf, BIGNUM *v);
209int sshbuf_get_ec(struct sshbuf *buf, EC_POINT *v, const EC_GROUP *g);
210int sshbuf_get_eckey(struct sshbuf *buf, EC_KEY *v);
211int sshbuf_put_bignum2(struct sshbuf *buf, const BIGNUM *v);
212int sshbuf_put_bignum1(struct sshbuf *buf, const BIGNUM *v);
213int sshbuf_put_ec(struct sshbuf *buf, const EC_POINT *v, const EC_GROUP *g);
214int sshbuf_put_eckey(struct sshbuf *buf, const EC_KEY *v);
215int 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 */
218void sshbuf_dump(struct sshbuf *buf, FILE *f);
219
220/* Return the hexadecimal representation of the contents of the buffer */
221char *sshbuf_dtob16(struct sshbuf *buf);
222
223/* Encode the contents of the buffer as base64 */
224char *sshbuf_dtob64(struct sshbuf *buf);
225
226/* Decode base64 data and append it to the buffer */
227int 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 */
278size_t sshbuf_alloc(const struct sshbuf *buf);
279
280/*
281 * Increment the reference count of buf.
282 */
283int 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 */
288const struct sshbuf *sshbuf_parent(const struct sshbuf *buf);
289
290/*
291 * Return the reference count of buf
292 */
293u_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
22const char *
23ssh_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 */
78const char *ssh_err(int n);
79
80#endif /* _SSHERR_H */