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
  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
  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
  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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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 *
 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 *
 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 *
 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
 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
 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
 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
 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
 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
 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
 464 buffer_put_char(Buffer *buffer, int value)
 465 {
 466         char ch = value;
 467 
 468         buffer_append(buffer, &ch, 1);
 469 }