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 }