summaryrefslogtreecommitdiff
path: root/bufaux.c
diff options
context:
space:
mode:
Diffstat (limited to 'bufaux.c')
-rw-r--r--bufaux.c332
1 files changed, 99 insertions, 233 deletions
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