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