Home | History | Annotate | Download | only in common
      1 /*
      2  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
      3  * Use is subject to license terms.
      4  */
      5 /*
      6  * Author: Tatu Ylonen <ylo (at) cs.hut.fi>
      7  * Copyright (c) 1995 Tatu Ylonen <ylo (at) 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 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     47 
     48 #include <langinfo.h>
     49 #include <openssl/bn.h>
     50 #include "bufaux.h"
     51 #include "xmalloc.h"
     52 #include "getput.h"
     53 #include "log.h"
     54 #include "g11n.h"
     55 
     56 /*
     57  * Stores an BIGNUM in the buffer with a 2-byte msb first bit count, followed
     58  * by (bits+7)/8 bytes of binary data, msb first.
     59  */
     60 int
     61 buffer_put_bignum_ret(Buffer *buffer, const BIGNUM *value)
     62 {
     63 	int bits = BN_num_bits(value);
     64 	int bin_size = (bits + 7) / 8;
     65 	u_char *buf = xmalloc(bin_size);
     66 	int oi;
     67 	char msg[2];
     68 
     69 	/* Get the value of in binary */
     70 	oi = BN_bn2bin(value, buf);
     71 	if (oi != bin_size) {
     72 		error("buffer_put_bignum_ret: BN_bn2bin() failed: oi %d != bin_size %d",
     73 		    oi, bin_size);
     74 		xfree(buf);
     75 		return (-1);
     76 	}
     77 
     78 	/* Store the number of bits in the buffer in two bytes, msb first. */
     79 	PUT_16BIT(msg, bits);
     80 	buffer_append(buffer, msg, 2);
     81 	/* Store the binary data. */
     82 	buffer_append(buffer, (char *)buf, oi);
     83 
     84 	memset(buf, 0, bin_size);
     85 	xfree(buf);
     86 
     87 	return (0);
     88 }
     89 
     90 void
     91 buffer_put_bignum(Buffer *buffer, const BIGNUM *value)
     92 {
     93 	if (buffer_put_bignum_ret(buffer, value) == -1)
     94 		fatal("buffer_put_bignum: buffer error");
     95 }
     96 
     97 /*
     98  * Retrieves an BIGNUM from the buffer.
     99  */
    100 int
    101 buffer_get_bignum_ret(Buffer *buffer, BIGNUM *value)
    102 {
    103 	u_int bits, bytes;
    104 	u_char buf[2], *bin;
    105 
    106 	/* Get the number for bits. */
    107 	if (buffer_get_ret(buffer, (char *) buf, 2) == -1) {
    108 		error("buffer_get_bignum_ret: invalid length");
    109 		return (-1);
    110 	}
    111 	bits = GET_16BIT(buf);
    112 	/* Compute the number of binary bytes that follow. */
    113 	bytes = (bits + 7) / 8;
    114 	if (bytes > 8 * 1024) {
    115 		error("buffer_get_bignum_ret: cannot handle BN of size %d", bytes);
    116 		return (-1);
    117 	}
    118 	if (buffer_len(buffer) < bytes) {
    119 		error("buffer_get_bignum_ret: input buffer too small");
    120 		return (-1);
    121 	}
    122 	bin = buffer_ptr(buffer);
    123 	BN_bin2bn(bin, bytes, value);
    124 	if (buffer_consume_ret(buffer, bytes) == -1) {
    125 		error("buffer_get_bignum_ret: buffer_consume failed");
    126 		return (-1);
    127 	}
    128 	return (0);
    129 }
    130 
    131 void
    132 buffer_get_bignum(Buffer *buffer, BIGNUM *value)
    133 {
    134 	if (buffer_get_bignum_ret(buffer, value) == -1)
    135 		fatal("buffer_get_bignum: buffer error");
    136 }
    137 
    138 /*
    139  * Stores an BIGNUM in the buffer in SSH2 format.
    140  */
    141 int
    142 buffer_put_bignum2_ret(Buffer *buffer, const BIGNUM *value)
    143 {
    144 	u_int bytes;
    145 	u_char *buf;
    146 	int oi;
    147 	u_int hasnohigh = 0;
    148 
    149 	if (BN_is_zero(value)) {
    150 		buffer_put_int(buffer, 0);
    151 		return 0;
    152 	}
    153 	if (value->neg) {
    154 		error("buffer_put_bignum2_ret: negative numbers not supported");
    155 		return (-1);
    156 	}
    157 	bytes = BN_num_bytes(value) + 1; /* extra padding byte */
    158 	if (bytes < 2) {
    159 		error("buffer_put_bignum2_ret: BN too small");
    160 		return (-1);
    161 	}
    162 	buf = xmalloc(bytes);
    163 	buf[0] = 0x00;
    164 	/* Get the value of in binary */
    165 	oi = BN_bn2bin(value, buf+1);
    166 	if (oi < 0 || (u_int)oi != bytes - 1) {
    167 		error("buffer_put_bignum2_ret: BN_bn2bin() failed: "
    168 		    "oi %d != bin_size %d", oi, bytes);
    169 		xfree(buf);
    170 		return (-1);
    171 	}
    172 	hasnohigh = (buf[1] & 0x80) ? 0 : 1;
    173 	buffer_put_string(buffer, buf+hasnohigh, bytes-hasnohigh);
    174 	memset(buf, 0, bytes);
    175 	xfree(buf);
    176 	return (0);
    177 }
    178 
    179 void
    180 buffer_put_bignum2(Buffer *buffer, const BIGNUM *value)
    181 {
    182 	if (buffer_put_bignum2_ret(buffer, value) == -1)
    183 		fatal("buffer_put_bignum2: buffer error");
    184 }
    185 
    186 /* XXX does not handle negative BNs */
    187 int
    188 buffer_get_bignum2_ret(Buffer *buffer, BIGNUM *value)
    189 {
    190 	u_int len;
    191 	u_char *bin;
    192 
    193 	if ((bin = buffer_get_string_ret(buffer, &len)) == NULL) {
    194 		error("buffer_get_bignum2_ret: invalid bignum");
    195 		return (-1);
    196 	}
    197 
    198 	if (len > 0 && (bin[0] & 0x80)) {
    199 		error("buffer_get_bignum2_ret: negative numbers not supported");
    200 		xfree(bin);
    201 		return (-1);
    202 	}
    203 	if (len > 8 * 1024) {
    204 		error("buffer_get_bignum2_ret: cannot handle BN of size %d", len);
    205 		xfree(bin);
    206 		return (-1);
    207 	}
    208 	BN_bin2bn(bin, len, value);
    209 	xfree(bin);
    210 	return (0);
    211 }
    212 
    213 void
    214 buffer_get_bignum2(Buffer *buffer, BIGNUM *value)
    215 {
    216 	if (buffer_get_bignum2_ret(buffer, value) == -1)
    217 		fatal("buffer_get_bignum2: buffer error");
    218 }
    219 
    220 /*
    221  * Returns integers from the buffer (msb first).
    222  */
    223 
    224 int
    225 buffer_get_short_ret(u_short *ret, Buffer *buffer)
    226 {
    227 	u_char buf[2];
    228 
    229 	if (buffer_get_ret(buffer, (char *) buf, 2) == -1)
    230 		return (-1);
    231 	*ret = GET_16BIT(buf);
    232 	return (0);
    233 }
    234 
    235 u_short
    236 buffer_get_short(Buffer *buffer)
    237 {
    238 	u_short ret;
    239 
    240 	if (buffer_get_short_ret(&ret, buffer) == -1)
    241 		fatal("buffer_get_short: buffer error");
    242 
    243 	return (ret);
    244 }
    245 
    246 int
    247 buffer_get_int_ret(u_int *ret, Buffer *buffer)
    248 {
    249 	u_char buf[4];
    250 
    251 	if (buffer_get_ret(buffer, (char *) buf, 4) == -1)
    252 		return (-1);
    253 	*ret = GET_32BIT(buf);
    254 	return (0);
    255 }
    256 
    257 u_int
    258 buffer_get_int(Buffer *buffer)
    259 {
    260 	u_int ret;
    261 
    262 	if (buffer_get_int_ret(&ret, buffer) == -1)
    263 		fatal("buffer_get_int: buffer error");
    264 
    265 	return (ret);
    266 }
    267 
    268 #ifdef HAVE_U_INT64_T
    269 int
    270 buffer_get_int64_ret(u_int64_t *ret, Buffer *buffer)
    271 {
    272 	u_char buf[8];
    273 
    274 	if (buffer_get_ret(buffer, (char *) buf, 8) == -1)
    275 		return (-1);
    276 	*ret = GET_64BIT(buf);
    277 	return (0);
    278 }
    279 
    280 u_int64_t
    281 buffer_get_int64(Buffer *buffer)
    282 {
    283 	u_int64_t ret;
    284 
    285 	if (buffer_get_int64_ret(&ret, buffer) == -1)
    286 		fatal("buffer_get_int: buffer error");
    287 
    288 	return (ret);
    289 }
    290 #endif
    291 
    292 /*
    293  * Stores integers in the buffer, msb first.
    294  */
    295 void
    296 buffer_put_short(Buffer *buffer, u_short value)
    297 {
    298 	char buf[2];
    299 
    300 	PUT_16BIT(buf, value);
    301 	buffer_append(buffer, buf, 2);
    302 }
    303 
    304 void
    305 buffer_put_int(Buffer *buffer, u_int value)
    306 {
    307 	char buf[4];
    308 
    309 	PUT_32BIT(buf, value);
    310 	buffer_append(buffer, buf, 4);
    311 }
    312 
    313 #ifdef HAVE_U_INT64_T
    314 void
    315 buffer_put_int64(Buffer *buffer, u_int64_t value)
    316 {
    317 	char buf[8];
    318 
    319 	PUT_64BIT(buf, value);
    320 	buffer_append(buffer, buf, 8);
    321 }
    322 #endif
    323 
    324 /*
    325  * Returns an arbitrary binary string from the buffer.  The string cannot
    326  * be longer than 256k.  The returned value points to memory allocated
    327  * with xmalloc; it is the responsibility of the calling function to free
    328  * the data.  If length_ptr is non-NULL, the length of the returned data
    329  * will be stored there.  A null character will be automatically appended
    330  * to the returned string, and is not counted in length.
    331  */
    332 void *
    333 buffer_get_string_ret(Buffer *buffer, u_int *length_ptr)
    334 {
    335 	u_char *value;
    336 	u_int len;
    337 
    338 	/* Get the length. */
    339 	len = buffer_get_int(buffer);
    340 	if (len > 256 * 1024) {
    341 		error("buffer_get_string_ret: bad string length %u", len);
    342 		return (NULL);
    343 	}
    344 	/* Allocate space for the string.  Add one byte for a null character. */
    345 	value = xmalloc(len + 1);
    346 	/* Get the string. */
    347 	if (buffer_get_ret(buffer, value, len) == -1) {
    348 		error("buffer_get_string_ret: buffer_get failed");
    349 		xfree(value);
    350 		return (NULL);
    351 	}
    352 	/* Append a null character to make processing easier. */
    353 	value[len] = 0;
    354 	/* Optionally return the length of the string. */
    355 	if (length_ptr)
    356 		*length_ptr = len;
    357 	return (value);
    358 }
    359 
    360 void *
    361 buffer_get_string(Buffer *buffer, u_int *length_ptr)
    362 {
    363 	void *ret;
    364 
    365 	if ((ret = buffer_get_string_ret(buffer, length_ptr)) == NULL)
    366 		fatal("buffer_get_string: buffer error");
    367 	return (ret);
    368 }
    369 
    370 char *
    371 buffer_get_ascii_cstring(Buffer *buffer)
    372 {
    373 	char *value;
    374 	u_char *p;
    375 	u_int len;
    376 	value = buffer_get_string(buffer, &len);
    377 
    378 	/* Look for NULL or high-bit set bytes */
    379 	for (p = (u_char *) value ;
    380 	     p && *p && (!(*p & 0x80)) && (p - (u_char *) value) < len ;
    381 	     p++) ;
    382 
    383 	/* If there were any, bomb */
    384 	if ((p - (u_char *) value) != len) {
    385 	    xfree(value);
    386 	    errno = EILSEQ;
    387 	    return NULL;
    388 	}
    389 	return value;
    390 }
    391 u_char *
    392 buffer_get_utf8_cstring(Buffer *buffer)
    393 {
    394 	u_char	*value, *converted, *estr;
    395 	u_int	len;
    396 	int	err;
    397 
    398 	if ((value = buffer_get_string(buffer, &len)) == NULL) {
    399 		return value;
    400 	}
    401 
    402 	converted = g11n_convert_from_utf8(value, &err, &estr);
    403 
    404 	if (converted != value) xfree(value);
    405 
    406 	if (err)
    407 	    fatal("invalid UTF-8 sequence; %s", estr);
    408 
    409 	return converted;
    410 }
    411 
    412 /*
    413  * Stores and arbitrary binary string in the buffer.
    414  */
    415 void
    416 buffer_put_string(Buffer *buffer, const void *buf, u_int len)
    417 {
    418 	buffer_put_int(buffer, len);
    419 	buffer_append(buffer, buf, len);
    420 }
    421 void
    422 buffer_put_cstring(Buffer *buffer, const char *s)
    423 {
    424 	if (s == NULL)
    425 		fatal("buffer_put_cstring: s == NULL");
    426 	buffer_put_string(buffer, s, strlen(s));
    427 }
    428 
    429 /*
    430  * ASCII versions of the above
    431  */
    432 #if 0
    433 void
    434 buffer_put_ascii_string(Buffer *buffer, const void *buf, u_int len)
    435 {
    436 	u_char *p;
    437 	for (p = (u_char *) buf ;
    438 	     p && ((p - (u_char *) buf) < len) && *p && (!(*p & 0x80)) ;
    439 	     p++) ;
    440 
    441 	if ((p - (u_char *) buf) != len)
    442 		verbose("buffer_put_ascii_string: storing a non-ASCII string");
    443 	buffer_put_int(buffer, len);
    444 	buffer_append(buffer, buf, len);
    445 }
    446 #endif
    447 void
    448 buffer_put_ascii_cstring(Buffer *buffer, const char *s)
    449 {
    450 	u_char *estr;
    451 	if (s == NULL)
    452 		fatal("buffer_put_cstring: s == NULL");
    453 
    454 	if (!g11n_validate_ascii(s, strlen(s), &estr))
    455 	    verbose("buffer_put_ascii_cstring: non-ASCII string; %s", estr);
    456 
    457 	buffer_put_cstring(buffer, s);
    458 }
    459 
    460 /*
    461  * UTF-8 versions of the above.
    462  */
    463 
    464 #if 0
    465 void
    466 buffer_put_utf8_string(Buffer *buffer, const void *buf, u_int len)
    467 {
    468 	char *converted *estr;
    469 
    470 	converted = g11n_convert_to_utf8(buf, &err, &estr);
    471 
    472 	if (!converted && err)
    473 		fatal("buffer_put_utf8_string: input not a valid UTF-8 encoding; %s", estr);
    474 
    475 	if (err)
    476 		verbose("buffer_put_utf8_string: input not a valid UTF-8 encoding; %s", estr);
    477 
    478 	buffer_put_string(buffer, converted, strlen(converted));
    479 
    480 	if (converted != bug) xfree(converted);
    481 
    482 	return;
    483 }
    484 #endif
    485 void
    486 buffer_put_utf8_cstring(Buffer *buffer, const u_char *s)
    487 {
    488 	u_char *converted, *estr;
    489 	int err;
    490 
    491 	if (s == NULL)
    492 		fatal("buffer_put_cstring: s == NULL");
    493 
    494 	converted = g11n_convert_to_utf8(s, &err, &estr);
    495 
    496 	if (!converted && err)
    497 		fatal("buffer_put_utf8_string: input not a valid UTF-8 encoding; %s", estr);
    498 
    499 	if (err)
    500 		verbose("buffer_put_utf8_string: input not a valid UTF-8 encoding; %s", estr);
    501 
    502 	buffer_put_cstring(buffer, (const char *) converted);
    503 
    504 	if (converted != s) xfree(converted);
    505 
    506 	return;
    507 }
    508 
    509 
    510 /*
    511  * Returns a character from the buffer (0 - 255).
    512  */
    513 int
    514 buffer_get_char_ret(char *ret, Buffer *buffer)
    515 {
    516 	if (buffer_get_ret(buffer, ret, 1) == -1) {
    517 		error("buffer_get_char_ret: buffer_get_ret failed");
    518 		return (-1);
    519 	}
    520 	return (0);
    521 }
    522 
    523 int
    524 buffer_get_char(Buffer *buffer)
    525 {
    526 	char ch;
    527 
    528 	if (buffer_get_char_ret(&ch, buffer) == -1)
    529 		fatal("buffer_get_char: buffer error");
    530 	return (u_char) ch;
    531 }
    532 
    533 /*
    534  * Stores a character in the buffer.
    535  */
    536 void
    537 buffer_put_char(Buffer *buffer, int value)
    538 {
    539 	char ch = value;
    540 
    541 	buffer_append(buffer, &ch, 1);
    542 }
    543