1 /* 2 * Copyright 2006 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 #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