1 /*
2 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 */
5 /*
6 * Author: Tatu Ylonen <ylo@cs.hut.fi>
7 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
8 * All rights reserved
9 * Auxiliary functions for storing and retrieving various data types to/from
10 * Buffers.
11 *
12 * As far as I am concerned, the code I have written for this software
13 * can be used freely for any purpose. Any derived versions of this
14 * software must be clearly marked as such, and if the derived work is
15 * incompatible with the protocol description in the RFC file, it must be
16 * called by a name other than "ssh" or "Secure Shell".
17 *
18 *
19 * SSH2 packet format added by Markus Friedl
20 * Copyright (c) 2000 Markus Friedl. All rights reserved.
21 *
22 * Redistribution and use in source and binary forms, with or without
23 * modification, are permitted provided that the following conditions
24 * are met:
25 * 1. Redistributions of source code must retain the above copyright
26 * notice, this list of conditions and the following disclaimer.
27 * 2. Redistributions in binary form must reproduce the above copyright
28 * notice, this list of conditions and the following disclaimer in the
29 * documentation and/or other materials provided with the distribution.
30 *
31 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
32 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
33 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
34 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
35 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
36 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
37 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
38 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
39 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
40 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
41 */
42
43 #include "includes.h"
44 RCSID("$OpenBSD: bufaux.c,v 1.27 2002/06/26 08:53:12 markus Exp $");
45
46 #include <langinfo.h>
47 #include <openssl/bn.h>
48 #include "bufaux.h"
49 #include "xmalloc.h"
50 #include "getput.h"
51 #include "log.h"
52 #include "g11n.h"
53
54 /*
55 * Stores an BIGNUM in the buffer with a 2-byte msb first bit count, followed
56 * by (bits+7)/8 bytes of binary data, msb first.
57 */
58 int
buffer_put_bignum_ret(Buffer * buffer,const BIGNUM * value)59 buffer_put_bignum_ret(Buffer *buffer, const BIGNUM *value)
60 {
61 int bits = BN_num_bits(value);
62 int bin_size = (bits + 7) / 8;
63 u_char *buf = xmalloc(bin_size);
64 int oi;
65 char msg[2];
66
67 /* Get the value of in binary */
68 oi = BN_bn2bin(value, buf);
69 if (oi != bin_size) {
70 error("buffer_put_bignum_ret: BN_bn2bin() failed: oi %d != bin_size %d",
71 oi, bin_size);
72 xfree(buf);
73 return (-1);
74 }
75
76 /* Store the number of bits in the buffer in two bytes, msb first. */
77 PUT_16BIT(msg, bits);
78 buffer_append(buffer, msg, 2);
79 /* Store the binary data. */
80 buffer_append(buffer, (char *)buf, oi);
81
82 memset(buf, 0, bin_size);
83 xfree(buf);
84
85 return (0);
86 }
87
88 void
buffer_put_bignum(Buffer * buffer,const BIGNUM * value)89 buffer_put_bignum(Buffer *buffer, const BIGNUM *value)
90 {
91 if (buffer_put_bignum_ret(buffer, value) == -1)
92 fatal("buffer_put_bignum: buffer error");
93 }
94
95 /*
96 * Retrieves an BIGNUM from the buffer.
97 */
98 int
buffer_get_bignum_ret(Buffer * buffer,BIGNUM * value)99 buffer_get_bignum_ret(Buffer *buffer, BIGNUM *value)
100 {
101 u_int bits, bytes;
102 u_char buf[2], *bin;
103
104 /* Get the number for bits. */
105 if (buffer_get_ret(buffer, (char *) buf, 2) == -1) {
106 error("buffer_get_bignum_ret: invalid length");
107 return (-1);
108 }
109 bits = GET_16BIT(buf);
110 /* Compute the number of binary bytes that follow. */
111 bytes = (bits + 7) / 8;
112 if (bytes > 8 * 1024) {
113 error("buffer_get_bignum_ret: cannot handle BN of size %d", bytes);
114 return (-1);
115 }
116 if (buffer_len(buffer) < bytes) {
117 error("buffer_get_bignum_ret: input buffer too small");
118 return (-1);
119 }
120 bin = buffer_ptr(buffer);
121 BN_bin2bn(bin, bytes, value);
122 if (buffer_consume_ret(buffer, bytes) == -1) {
123 error("buffer_get_bignum_ret: buffer_consume failed");
124 return (-1);
125 }
126 return (0);
127 }
128
129 void
buffer_get_bignum(Buffer * buffer,BIGNUM * value)130 buffer_get_bignum(Buffer *buffer, BIGNUM *value)
131 {
132 if (buffer_get_bignum_ret(buffer, value) == -1)
133 fatal("buffer_get_bignum: buffer error");
134 }
135
136 /*
137 * Stores an BIGNUM in the buffer in SSH2 format.
138 */
139 int
buffer_put_bignum2_ret(Buffer * buffer,const BIGNUM * value)140 buffer_put_bignum2_ret(Buffer *buffer, const BIGNUM *value)
141 {
142 u_int bytes;
143 u_char *buf;
144 int oi;
145 u_int hasnohigh = 0;
146
147 if (BN_is_zero(value)) {
148 buffer_put_int(buffer, 0);
149 return 0;
150 }
151 if (value->neg) {
152 error("buffer_put_bignum2_ret: negative numbers not supported");
153 return (-1);
154 }
155 bytes = BN_num_bytes(value) + 1; /* extra padding byte */
156 if (bytes < 2) {
157 error("buffer_put_bignum2_ret: BN too small");
158 return (-1);
159 }
160 buf = xmalloc(bytes);
161 buf[0] = 0x00;
162 /* Get the value of in binary */
163 oi = BN_bn2bin(value, buf+1);
164 if (oi < 0 || (u_int)oi != bytes - 1) {
165 error("buffer_put_bignum2_ret: BN_bn2bin() failed: "
166 "oi %d != bin_size %d", oi, bytes);
167 xfree(buf);
168 return (-1);
169 }
170 hasnohigh = (buf[1] & 0x80) ? 0 : 1;
171 buffer_put_string(buffer, buf+hasnohigh, bytes-hasnohigh);
172 memset(buf, 0, bytes);
173 xfree(buf);
174 return (0);
175 }
176
177 void
buffer_put_bignum2(Buffer * buffer,const BIGNUM * value)178 buffer_put_bignum2(Buffer *buffer, const BIGNUM *value)
179 {
180 if (buffer_put_bignum2_ret(buffer, value) == -1)
181 fatal("buffer_put_bignum2: buffer error");
182 }
183
184 /* XXX does not handle negative BNs */
185 int
buffer_get_bignum2_ret(Buffer * buffer,BIGNUM * value)186 buffer_get_bignum2_ret(Buffer *buffer, BIGNUM *value)
187 {
188 u_int len;
189 u_char *bin;
190
191 if ((bin = buffer_get_string_ret(buffer, &len)) == NULL) {
192 error("buffer_get_bignum2_ret: invalid bignum");
193 return (-1);
194 }
195
196 if (len > 0 && (bin[0] & 0x80)) {
197 error("buffer_get_bignum2_ret: negative numbers not supported");
198 xfree(bin);
199 return (-1);
200 }
201 if (len > 8 * 1024) {
202 error("buffer_get_bignum2_ret: cannot handle BN of size %d", len);
203 xfree(bin);
204 return (-1);
205 }
206 BN_bin2bn(bin, len, value);
207 xfree(bin);
208 return (0);
209 }
210
211 void
buffer_get_bignum2(Buffer * buffer,BIGNUM * value)212 buffer_get_bignum2(Buffer *buffer, BIGNUM *value)
213 {
214 if (buffer_get_bignum2_ret(buffer, value) == -1)
215 fatal("buffer_get_bignum2: buffer error");
216 }
217
218 /*
219 * Returns integers from the buffer (msb first).
220 */
221
222 int
buffer_get_short_ret(u_short * ret,Buffer * buffer)223 buffer_get_short_ret(u_short *ret, Buffer *buffer)
224 {
225 u_char buf[2];
226
227 if (buffer_get_ret(buffer, (char *) buf, 2) == -1)
228 return (-1);
229 *ret = GET_16BIT(buf);
230 return (0);
231 }
232
233 u_short
buffer_get_short(Buffer * buffer)234 buffer_get_short(Buffer *buffer)
235 {
236 u_short ret;
237
238 if (buffer_get_short_ret(&ret, buffer) == -1)
239 fatal("buffer_get_short: buffer error");
240
241 return (ret);
242 }
243
244 int
buffer_get_int_ret(u_int * ret,Buffer * buffer)245 buffer_get_int_ret(u_int *ret, Buffer *buffer)
246 {
247 u_char buf[4];
248
249 if (buffer_get_ret(buffer, (char *) buf, 4) == -1)
250 return (-1);
251 *ret = GET_32BIT(buf);
252 return (0);
253 }
254
255 u_int
buffer_get_int(Buffer * buffer)256 buffer_get_int(Buffer *buffer)
257 {
258 u_int ret;
259
260 if (buffer_get_int_ret(&ret, buffer) == -1)
261 fatal("buffer_get_int: buffer error");
262
263 return (ret);
264 }
265
266 #ifdef HAVE_U_INT64_T
267 int
buffer_get_int64_ret(u_int64_t * ret,Buffer * buffer)268 buffer_get_int64_ret(u_int64_t *ret, Buffer *buffer)
269 {
270 u_char buf[8];
271
272 if (buffer_get_ret(buffer, (char *) buf, 8) == -1)
273 return (-1);
274 *ret = GET_64BIT(buf);
275 return (0);
276 }
277
278 u_int64_t
buffer_get_int64(Buffer * buffer)279 buffer_get_int64(Buffer *buffer)
280 {
281 u_int64_t ret;
282
283 if (buffer_get_int64_ret(&ret, buffer) == -1)
284 fatal("buffer_get_int: buffer error");
285
286 return (ret);
287 }
288 #endif
289
290 /*
291 * Stores integers in the buffer, msb first.
292 */
293 void
buffer_put_short(Buffer * buffer,u_short value)294 buffer_put_short(Buffer *buffer, u_short value)
295 {
296 char buf[2];
297
298 PUT_16BIT(buf, value);
299 buffer_append(buffer, buf, 2);
300 }
301
302 void
buffer_put_int(Buffer * buffer,u_int value)303 buffer_put_int(Buffer *buffer, u_int value)
304 {
305 char buf[4];
306
307 PUT_32BIT(buf, value);
308 buffer_append(buffer, buf, 4);
309 }
310
311 #ifdef HAVE_U_INT64_T
312 void
buffer_put_int64(Buffer * buffer,u_int64_t value)313 buffer_put_int64(Buffer *buffer, u_int64_t value)
314 {
315 char buf[8];
316
317 PUT_64BIT(buf, value);
318 buffer_append(buffer, buf, 8);
319 }
320 #endif
321
322 /*
323 * Returns an arbitrary binary string from the buffer. The string cannot
324 * be longer than 256k. The returned value points to memory allocated
325 * with xmalloc; it is the responsibility of the calling function to free
326 * the data. If length_ptr is non-NULL, the length of the returned data
327 * will be stored there. A null character will be automatically appended
328 * to the returned string, and is not counted in length.
329 */
330 void *
buffer_get_string_ret(Buffer * buffer,u_int * length_ptr)331 buffer_get_string_ret(Buffer *buffer, u_int *length_ptr)
332 {
333 u_char *value;
334 u_int len;
335
336 /* Get the length. */
337 len = buffer_get_int(buffer);
338 if (len > 256 * 1024) {
339 error("buffer_get_string_ret: bad string length %u", len);
340 return (NULL);
341 }
342 /* Allocate space for the string. Add one byte for a null character. */
343 value = xmalloc(len + 1);
344 /* Get the string. */
345 if (buffer_get_ret(buffer, value, len) == -1) {
346 error("buffer_get_string_ret: buffer_get failed");
347 xfree(value);
348 return (NULL);
349 }
350 /* Append a null character to make processing easier. */
351 value[len] = 0;
352 /* Optionally return the length of the string. */
353 if (length_ptr)
354 *length_ptr = len;
355 return (value);
356 }
357
358 void *
buffer_get_string(Buffer * buffer,u_int * length_ptr)359 buffer_get_string(Buffer *buffer, u_int *length_ptr)
360 {
361 void *ret;
362
363 if ((ret = buffer_get_string_ret(buffer, length_ptr)) == NULL)
364 fatal("buffer_get_string: buffer error");
365 return (ret);
366 }
367
368 char *
buffer_get_utf8_string(Buffer * buffer,uint_t * length_ptr)369 buffer_get_utf8_string(Buffer *buffer, uint_t *length_ptr)
370 {
371 char *value, *converted, *estr;
372 uint_t len;
373
374 if ((value = buffer_get_string(buffer, &len)) == NULL)
375 return (value);
376
377 converted = g11n_convert_from_utf8(value, &len, &estr);
378 if (converted == NULL) {
379 if (estr != NULL)
380 error("invalid UTF-8 sequence: %s", estr);
381 converted = value;
382 } else {
383 xfree(value);
384 }
385
386 if (length_ptr != NULL)
387 *length_ptr = len;
388
389 return (converted);
390 }
391
392 /*
393 * Stores and arbitrary binary string in the buffer.
394 */
395 void
buffer_put_string(Buffer * buffer,const void * buf,u_int len)396 buffer_put_string(Buffer *buffer, const void *buf, u_int len)
397 {
398 buffer_put_int(buffer, len);
399 buffer_append(buffer, buf, len);
400 }
401 void
buffer_put_cstring(Buffer * buffer,const char * s)402 buffer_put_cstring(Buffer *buffer, const char *s)
403 {
404 if (s == NULL)
405 fatal("buffer_put_cstring: s == NULL");
406 buffer_put_string(buffer, s, strlen(s));
407 }
408
409 /*
410 * UTF-8 versions of the above.
411 */
412 void
buffer_put_utf8_string(Buffer * buffer,const char * s,uint_t len)413 buffer_put_utf8_string(Buffer *buffer, const char *s, uint_t len)
414 {
415 char *converted, *estr;
416 uint_t nlen = len;
417
418 converted = g11n_convert_to_utf8(s, &nlen, 0, &estr);
419 if (converted == NULL) {
420 if (estr != NULL)
421 error("Can't convert to UTF-8: %s", estr);
422 converted = (char *)s;
423 }
424
425 buffer_put_string(buffer, converted, nlen);
426
427 if (converted != s)
428 xfree(converted);
429 }
430
431 void
buffer_put_utf8_cstring(Buffer * buffer,const char * s)432 buffer_put_utf8_cstring(Buffer *buffer, const char *s)
433 {
434 buffer_put_utf8_string(buffer, s, strlen(s));
435 }
436
437 /*
438 * Returns a character from the buffer (0 - 255).
439 */
440 int
buffer_get_char_ret(char * ret,Buffer * buffer)441 buffer_get_char_ret(char *ret, Buffer *buffer)
442 {
443 if (buffer_get_ret(buffer, ret, 1) == -1) {
444 error("buffer_get_char_ret: buffer_get_ret failed");
445 return (-1);
446 }
447 return (0);
448 }
449
450 int
buffer_get_char(Buffer * buffer)451 buffer_get_char(Buffer *buffer)
452 {
453 char ch;
454
455 if (buffer_get_char_ret(&ch, buffer) == -1)
456 fatal("buffer_get_char: buffer error");
457 return (u_char) ch;
458 }
459
460 /*
461 * Stores a character in the buffer.
462 */
463 void
buffer_put_char(Buffer * buffer,int value)464 buffer_put_char(Buffer *buffer, int value)
465 {
466 char ch = value;
467
468 buffer_append(buffer, &ch, 1);
469 }
470