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 }