1264692Sdes/* $OpenBSD: bufaux.c,v 1.57 2014/04/16 23:22:45 djm Exp $ */ 257429Smarkm/* 357429Smarkm * Author: Tatu Ylonen <ylo@cs.hut.fi> 457429Smarkm * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 557429Smarkm * All rights reserved 657429Smarkm * Auxiliary functions for storing and retrieving various data types to/from 757429Smarkm * Buffers. 857429Smarkm * 965674Skris * As far as I am concerned, the code I have written for this software 1065674Skris * can be used freely for any purpose. Any derived versions of this 1165674Skris * software must be clearly marked as such, and if the derived work is 1265674Skris * incompatible with the protocol description in the RFC file, it must be 1365674Skris * called by a name other than "ssh" or "Secure Shell". 1465674Skris * 1565674Skris * 1660576Skris * SSH2 packet format added by Markus Friedl 1765674Skris * Copyright (c) 2000 Markus Friedl. All rights reserved. 1860576Skris * 1965674Skris * Redistribution and use in source and binary forms, with or without 2065674Skris * modification, are permitted provided that the following conditions 2165674Skris * are met: 2265674Skris * 1. Redistributions of source code must retain the above copyright 2365674Skris * notice, this list of conditions and the following disclaimer. 2465674Skris * 2. Redistributions in binary form must reproduce the above copyright 2565674Skris * notice, this list of conditions and the following disclaimer in the 2665674Skris * documentation and/or other materials provided with the distribution. 2765674Skris * 2865674Skris * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 2965674Skris * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 3065674Skris * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 3165674Skris * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 3265674Skris * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 3365674Skris * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 3465674Skris * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 3565674Skris * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3665674Skris * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 3765674Skris * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3857429Smarkm */ 3957429Smarkm 4057429Smarkm#include "includes.h" 4157429Smarkm 42162856Sdes#include <sys/types.h> 43162856Sdes 4457464Sgreen#include <openssl/bn.h> 45162856Sdes 46162856Sdes#include <string.h> 47162856Sdes#include <stdarg.h> 48262566Sdes#include <stdlib.h> 49162856Sdes 5057429Smarkm#include "xmalloc.h" 51162856Sdes#include "buffer.h" 5276262Sgreen#include "log.h" 53162856Sdes#include "misc.h" 5457429Smarkm 5557429Smarkm/* 5698684Sdes * Returns integers from the buffer (msb first). 5757429Smarkm */ 5898684Sdes 59147005Sdesint 60147005Sdesbuffer_get_short_ret(u_short *ret, Buffer *buffer) 61147005Sdes{ 62147005Sdes u_char buf[2]; 63147005Sdes 64147005Sdes if (buffer_get_ret(buffer, (char *) buf, 2) == -1) 65147005Sdes return (-1); 66162856Sdes *ret = get_u16(buf); 67147005Sdes return (0); 68147005Sdes} 69147005Sdes 7098684Sdesu_short 7198684Sdesbuffer_get_short(Buffer *buffer) 7298684Sdes{ 73147005Sdes u_short ret; 7499063Sdes 75147005Sdes if (buffer_get_short_ret(&ret, buffer) == -1) 76147005Sdes fatal("buffer_get_short: buffer error"); 77147005Sdes 78147005Sdes return (ret); 7998684Sdes} 8098684Sdes 81147005Sdesint 82147005Sdesbuffer_get_int_ret(u_int *ret, Buffer *buffer) 83147005Sdes{ 84147005Sdes u_char buf[4]; 85147005Sdes 86147005Sdes if (buffer_get_ret(buffer, (char *) buf, 4) == -1) 87147005Sdes return (-1); 88215116Sdes if (ret != NULL) 89215116Sdes *ret = get_u32(buf); 90147005Sdes return (0); 91147005Sdes} 92147005Sdes 9376262Sgreenu_int 9457429Smarkmbuffer_get_int(Buffer *buffer) 9557429Smarkm{ 96147005Sdes u_int ret; 9799063Sdes 98147005Sdes if (buffer_get_int_ret(&ret, buffer) == -1) 99147005Sdes fatal("buffer_get_int: buffer error"); 100147005Sdes 101147005Sdes return (ret); 10257429Smarkm} 10357429Smarkm 104147005Sdesint 105147005Sdesbuffer_get_int64_ret(u_int64_t *ret, Buffer *buffer) 106147005Sdes{ 107147005Sdes u_char buf[8]; 108147005Sdes 109147005Sdes if (buffer_get_ret(buffer, (char *) buf, 8) == -1) 110147005Sdes return (-1); 111215116Sdes if (ret != NULL) 112215116Sdes *ret = get_u64(buf); 113147005Sdes return (0); 114147005Sdes} 115147005Sdes 11676262Sgreenu_int64_t 11776262Sgreenbuffer_get_int64(Buffer *buffer) 11876262Sgreen{ 119147005Sdes u_int64_t ret; 12099063Sdes 121147005Sdes if (buffer_get_int64_ret(&ret, buffer) == -1) 122147005Sdes fatal("buffer_get_int: buffer error"); 123147005Sdes 124147005Sdes return (ret); 12576262Sgreen} 12676262Sgreen 12757429Smarkm/* 12898684Sdes * Stores integers in the buffer, msb first. 12957429Smarkm */ 13060576Skrisvoid 13198684Sdesbuffer_put_short(Buffer *buffer, u_short value) 13298684Sdes{ 13398684Sdes char buf[2]; 13499063Sdes 135162856Sdes put_u16(buf, value); 13698684Sdes buffer_append(buffer, buf, 2); 13798684Sdes} 13898684Sdes 13998684Sdesvoid 14076262Sgreenbuffer_put_int(Buffer *buffer, u_int value) 14157429Smarkm{ 14257429Smarkm char buf[4]; 14399063Sdes 144162856Sdes put_u32(buf, value); 14557429Smarkm buffer_append(buffer, buf, 4); 14657429Smarkm} 14757429Smarkm 14876262Sgreenvoid 14976262Sgreenbuffer_put_int64(Buffer *buffer, u_int64_t value) 15076262Sgreen{ 15176262Sgreen char buf[8]; 15299063Sdes 153162856Sdes put_u64(buf, value); 15476262Sgreen buffer_append(buffer, buf, 8); 15576262Sgreen} 15676262Sgreen 15757429Smarkm/* 15857429Smarkm * Returns an arbitrary binary string from the buffer. The string cannot 15957429Smarkm * be longer than 256k. The returned value points to memory allocated 16057429Smarkm * with xmalloc; it is the responsibility of the calling function to free 16157429Smarkm * the data. If length_ptr is non-NULL, the length of the returned data 16257429Smarkm * will be stored there. A null character will be automatically appended 16357429Smarkm * to the returned string, and is not counted in length. 16457429Smarkm */ 16592559Sdesvoid * 166147005Sdesbuffer_get_string_ret(Buffer *buffer, u_int *length_ptr) 16757429Smarkm{ 16899063Sdes u_char *value; 16976262Sgreen u_int len; 17099063Sdes 17157429Smarkm /* Get the length. */ 172204917Sdes if (buffer_get_int_ret(&len, buffer) != 0) { 173204917Sdes error("buffer_get_string_ret: cannot extract length"); 174204917Sdes return (NULL); 175204917Sdes } 176147005Sdes if (len > 256 * 1024) { 177147005Sdes error("buffer_get_string_ret: bad string length %u", len); 178147005Sdes return (NULL); 179147005Sdes } 18057429Smarkm /* Allocate space for the string. Add one byte for a null character. */ 18157429Smarkm value = xmalloc(len + 1); 18257429Smarkm /* Get the string. */ 183147005Sdes if (buffer_get_ret(buffer, value, len) == -1) { 184147005Sdes error("buffer_get_string_ret: buffer_get failed"); 185255767Sdes free(value); 186147005Sdes return (NULL); 187147005Sdes } 18857429Smarkm /* Append a null character to make processing easier. */ 189181111Sdes value[len] = '\0'; 19057429Smarkm /* Optionally return the length of the string. */ 19157429Smarkm if (length_ptr) 19257429Smarkm *length_ptr = len; 193147005Sdes return (value); 19457429Smarkm} 19557429Smarkm 196147005Sdesvoid * 197147005Sdesbuffer_get_string(Buffer *buffer, u_int *length_ptr) 198147005Sdes{ 199147005Sdes void *ret; 200147005Sdes 201147005Sdes if ((ret = buffer_get_string_ret(buffer, length_ptr)) == NULL) 202147005Sdes fatal("buffer_get_string: buffer error"); 203147005Sdes return (ret); 204147005Sdes} 205147005Sdes 206221420Sdeschar * 207221420Sdesbuffer_get_cstring_ret(Buffer *buffer, u_int *length_ptr) 208221420Sdes{ 209221420Sdes u_int length; 210221420Sdes char *cp, *ret = buffer_get_string_ret(buffer, &length); 211221420Sdes 212221420Sdes if (ret == NULL) 213221420Sdes return NULL; 214221420Sdes if ((cp = memchr(ret, '\0', length)) != NULL) { 215221420Sdes /* XXX allow \0 at end-of-string for a while, remove later */ 216221420Sdes if (cp == ret + length - 1) 217221420Sdes error("buffer_get_cstring_ret: string contains \\0"); 218221420Sdes else { 219264377Sdes explicit_bzero(ret, length); 220255767Sdes free(ret); 221221420Sdes return NULL; 222221420Sdes } 223221420Sdes } 224221420Sdes if (length_ptr != NULL) 225221420Sdes *length_ptr = length; 226221420Sdes return ret; 227221420Sdes} 228221420Sdes 229221420Sdeschar * 230221420Sdesbuffer_get_cstring(Buffer *buffer, u_int *length_ptr) 231221420Sdes{ 232221420Sdes char *ret; 233221420Sdes 234221420Sdes if ((ret = buffer_get_cstring_ret(buffer, length_ptr)) == NULL) 235221420Sdes fatal("buffer_get_cstring: buffer error"); 236221420Sdes return ret; 237221420Sdes} 238221420Sdes 239181111Sdesvoid * 240204917Sdesbuffer_get_string_ptr_ret(Buffer *buffer, u_int *length_ptr) 241181111Sdes{ 242181111Sdes void *ptr; 243181111Sdes u_int len; 244181111Sdes 245204917Sdes if (buffer_get_int_ret(&len, buffer) != 0) 246204917Sdes return NULL; 247204917Sdes if (len > 256 * 1024) { 248204917Sdes error("buffer_get_string_ptr: bad string length %u", len); 249204917Sdes return NULL; 250204917Sdes } 251181111Sdes ptr = buffer_ptr(buffer); 252181111Sdes buffer_consume(buffer, len); 253181111Sdes if (length_ptr) 254181111Sdes *length_ptr = len; 255181111Sdes return (ptr); 256181111Sdes} 257181111Sdes 258204917Sdesvoid * 259204917Sdesbuffer_get_string_ptr(Buffer *buffer, u_int *length_ptr) 260204917Sdes{ 261204917Sdes void *ret; 262204917Sdes 263204917Sdes if ((ret = buffer_get_string_ptr_ret(buffer, length_ptr)) == NULL) 264204917Sdes fatal("buffer_get_string_ptr: buffer error"); 265204917Sdes return (ret); 266204917Sdes} 267204917Sdes 26857429Smarkm/* 26957429Smarkm * Stores and arbitrary binary string in the buffer. 27057429Smarkm */ 27160576Skrisvoid 27276262Sgreenbuffer_put_string(Buffer *buffer, const void *buf, u_int len) 27357429Smarkm{ 27457429Smarkm buffer_put_int(buffer, len); 27557429Smarkm buffer_append(buffer, buf, len); 27657429Smarkm} 27760576Skrisvoid 27860576Skrisbuffer_put_cstring(Buffer *buffer, const char *s) 27960576Skris{ 28098684Sdes if (s == NULL) 28198684Sdes fatal("buffer_put_cstring: s == NULL"); 28260576Skris buffer_put_string(buffer, s, strlen(s)); 28360576Skris} 28457429Smarkm 28557429Smarkm/* 28657429Smarkm * Returns a character from the buffer (0 - 255). 28757429Smarkm */ 28860576Skrisint 289255767Sdesbuffer_get_char_ret(u_char *ret, Buffer *buffer) 290147005Sdes{ 291147005Sdes if (buffer_get_ret(buffer, ret, 1) == -1) { 292147005Sdes error("buffer_get_char_ret: buffer_get_ret failed"); 293147005Sdes return (-1); 294147005Sdes } 295147005Sdes return (0); 296147005Sdes} 297147005Sdes 298147005Sdesint 29957429Smarkmbuffer_get_char(Buffer *buffer) 30057429Smarkm{ 301255767Sdes u_char ch; 30299063Sdes 303147005Sdes if (buffer_get_char_ret(&ch, buffer) == -1) 304147005Sdes fatal("buffer_get_char: buffer error"); 305255767Sdes return ch; 30657429Smarkm} 30757429Smarkm 30857429Smarkm/* 30957429Smarkm * Stores a character in the buffer. 31057429Smarkm */ 31160576Skrisvoid 31257429Smarkmbuffer_put_char(Buffer *buffer, int value) 31357429Smarkm{ 31457429Smarkm char ch = value; 31599063Sdes 31657429Smarkm buffer_append(buffer, &ch, 1); 31757429Smarkm} 318262566Sdes 319262566Sdes/* Pseudo bignum functions */ 320262566Sdes 321262566Sdesvoid * 322262566Sdesbuffer_get_bignum2_as_string_ret(Buffer *buffer, u_int *length_ptr) 323262566Sdes{ 324262566Sdes u_int len; 325262566Sdes u_char *bin, *p, *ret; 326262566Sdes 327262566Sdes if ((p = bin = buffer_get_string_ret(buffer, &len)) == NULL) { 328262566Sdes error("%s: invalid bignum", __func__); 329262566Sdes return NULL; 330262566Sdes } 331262566Sdes 332262566Sdes if (len > 0 && (bin[0] & 0x80)) { 333262566Sdes error("%s: negative numbers not supported", __func__); 334262566Sdes free(bin); 335262566Sdes return NULL; 336262566Sdes } 337262566Sdes if (len > 8 * 1024) { 338262566Sdes error("%s: cannot handle BN of size %d", __func__, len); 339262566Sdes free(bin); 340262566Sdes return NULL; 341262566Sdes } 342262566Sdes /* Skip zero prefix on numbers with the MSB set */ 343262566Sdes if (len > 1 && bin[0] == 0x00 && (bin[1] & 0x80) != 0) { 344262566Sdes p++; 345262566Sdes len--; 346262566Sdes } 347262566Sdes ret = xmalloc(len); 348262566Sdes memcpy(ret, p, len); 349264377Sdes explicit_bzero(p, len); 350262566Sdes free(bin); 351262566Sdes return ret; 352262566Sdes} 353262566Sdes 354262566Sdesvoid * 355262566Sdesbuffer_get_bignum2_as_string(Buffer *buffer, u_int *l) 356262566Sdes{ 357262566Sdes void *ret = buffer_get_bignum2_as_string_ret(buffer, l); 358262566Sdes 359262566Sdes if (ret == NULL) 360262566Sdes fatal("%s: buffer error", __func__); 361262566Sdes return ret; 362262566Sdes} 363262566Sdes 364262566Sdes/* 365262566Sdes * Stores a string using the bignum encoding rules (\0 pad if MSB set). 366262566Sdes */ 367262566Sdesvoid 368262566Sdesbuffer_put_bignum2_from_string(Buffer *buffer, const u_char *s, u_int l) 369262566Sdes{ 370262566Sdes u_char *buf, *p; 371262566Sdes int pad = 0; 372262566Sdes 373262566Sdes if (l > 8 * 1024) 374262566Sdes fatal("%s: length %u too long", __func__, l); 375264692Sdes /* Skip leading zero bytes */ 376264692Sdes for (; l > 0 && *s == 0; l--, s++) 377264692Sdes ; 378262566Sdes p = buf = xmalloc(l + 1); 379262566Sdes /* 380262566Sdes * If most significant bit is set then prepend a zero byte to 381262566Sdes * avoid interpretation as a negative number. 382262566Sdes */ 383262566Sdes if (l > 0 && (s[0] & 0x80) != 0) { 384262566Sdes *p++ = '\0'; 385262566Sdes pad = 1; 386262566Sdes } 387262566Sdes memcpy(p, s, l); 388262566Sdes buffer_put_string(buffer, buf, l + pad); 389264377Sdes explicit_bzero(buf, l + pad); 390262566Sdes free(buf); 391262566Sdes} 392262566Sdes 393262566Sdes 394