bufbn.c revision 164147
162587Sitojun/* $OpenBSD: bufbn.c,v 1.4 2006/11/06 21:25:28 markus Exp $*/ 278064Sume/* 362587Sitojun * Author: Tatu Ylonen <ylo@cs.hut.fi> 4139826Simp * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 553541Sshin * All rights reserved 653541Sshin * Auxiliary functions for storing and retrieving various data types to/from 753541Sshin * Buffers. 853541Sshin * 953541Sshin * As far as I am concerned, the code I have written for this software 1053541Sshin * can be used freely for any purpose. Any derived versions of this 1153541Sshin * software must be clearly marked as such, and if the derived work is 1253541Sshin * incompatible with the protocol description in the RFC file, it must be 1353541Sshin * called by a name other than "ssh" or "Secure Shell". 1453541Sshin * 1553541Sshin * 1653541Sshin * SSH2 packet format added by Markus Friedl 1753541Sshin * Copyright (c) 2000 Markus Friedl. All rights reserved. 1853541Sshin * 1953541Sshin * Redistribution and use in source and binary forms, with or without 2053541Sshin * modification, are permitted provided that the following conditions 2153541Sshin * are met: 2253541Sshin * 1. Redistributions of source code must retain the above copyright 2353541Sshin * notice, this list of conditions and the following disclaimer. 2453541Sshin * 2. Redistributions in binary form must reproduce the above copyright 2553541Sshin * notice, this list of conditions and the following disclaimer in the 2653541Sshin * documentation and/or other materials provided with the distribution. 2753541Sshin * 2853541Sshin * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 2953541Sshin * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 3053541Sshin * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 3153541Sshin * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 3253541Sshin * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 33139826Simp * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 3453541Sshin * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 3553541Sshin * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3653541Sshin * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 3753541Sshin * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3853541Sshin */ 3953541Sshin 4053541Sshin#include "includes.h" 4153541Sshin 4253541Sshin#include <sys/types.h> 4353541Sshin 4453541Sshin#include <openssl/bn.h> 4553541Sshin 4653541Sshin#include <string.h> 4753541Sshin#include <stdarg.h> 4853541Sshin 4953541Sshin#include "xmalloc.h" 5053541Sshin#include "buffer.h" 5153541Sshin#include "log.h" 5253541Sshin#include "misc.h" 5353541Sshin 5453541Sshin/* 5553541Sshin * Stores an BIGNUM in the buffer with a 2-byte msb first bit count, followed 5653541Sshin * by (bits+7)/8 bytes of binary data, msb first. 5753541Sshin */ 5853541Sshinint 5953541Sshinbuffer_put_bignum_ret(Buffer *buffer, const BIGNUM *value) 6053541Sshin{ 6153541Sshin int bits = BN_num_bits(value); 6253541Sshin int bin_size = (bits + 7) / 8; 6353541Sshin u_char *buf = xmalloc(bin_size); 6453541Sshin int oi; 6553541Sshin char msg[2]; 6653541Sshin 6753541Sshin /* Get the value of in binary */ 6862587Sitojun oi = BN_bn2bin(value, buf); 6953541Sshin if (oi != bin_size) { 7053541Sshin error("buffer_put_bignum_ret: BN_bn2bin() failed: oi %d != bin_size %d", 7153541Sshin oi, bin_size); 7253541Sshin xfree(buf); 7353541Sshin return (-1); 7453541Sshin } 7553541Sshin 7653541Sshin /* Store the number of bits in the buffer in two bytes, msb first. */ 7753541Sshin put_u16(msg, bits); 7853541Sshin buffer_append(buffer, msg, 2); 7962587Sitojun /* Store the binary data. */ 8062587Sitojun buffer_append(buffer, buf, oi); 8153541Sshin 8253541Sshin memset(buf, 0, bin_size); 8353541Sshin xfree(buf); 84108533Sschweikh 8553541Sshin return (0); 8653541Sshin} 8753541Sshin 8853541Sshinvoid 8953541Sshinbuffer_put_bignum(Buffer *buffer, const BIGNUM *value) 9053541Sshin{ 9178064Sume if (buffer_put_bignum_ret(buffer, value) == -1) 9253541Sshin fatal("buffer_put_bignum: buffer error"); 9362587Sitojun} 9453541Sshin 9578064Sume/* 9678064Sume * Retrieves an BIGNUM from the buffer. 9778064Sume */ 9853541Sshinint 99114205Ssuzbuffer_get_bignum_ret(Buffer *buffer, BIGNUM *value) 10053541Sshin{ 10165637Sitojun u_int bits, bytes; 10265637Sitojun u_char buf[2], *bin; 10365637Sitojun 10465637Sitojun /* Get the number for bits. */ 10565637Sitojun if (buffer_get_ret(buffer, (char *) buf, 2) == -1) { 106103842Salfred error("buffer_get_bignum_ret: invalid length"); 10765637Sitojun return (-1); 10865637Sitojun } 10953541Sshin bits = get_u16(buf); 11053541Sshin /* Compute the number of binary bytes that follow. */ 11153541Sshin bytes = (bits + 7) / 8; 11253541Sshin if (bytes > 8 * 1024) { 11353541Sshin error("buffer_get_bignum_ret: cannot handle BN of size %d", bytes); 11453541Sshin return (-1); 11553541Sshin } 11653541Sshin if (buffer_len(buffer) < bytes) { 11753541Sshin error("buffer_get_bignum_ret: input buffer too small"); 11853541Sshin return (-1); 119114205Ssuz } 12053541Sshin bin = buffer_ptr(buffer); 12153541Sshin if (BN_bin2bn(bin, bytes, value) == NULL) { 12253541Sshin error("buffer_get_bignum_ret: BN_bin2bn failed"); 12365637Sitojun return (-1); 12465637Sitojun } 12553541Sshin if (buffer_consume_ret(buffer, bytes) == -1) { 12653541Sshin error("buffer_get_bignum_ret: buffer_consume failed"); 12753541Sshin return (-1); 12853541Sshin } 12953541Sshin return (0); 13053541Sshin} 13153541Sshin 13253541Sshinvoid 13353541Sshinbuffer_get_bignum(Buffer *buffer, BIGNUM *value) 13453541Sshin{ 13553541Sshin if (buffer_get_bignum_ret(buffer, value) == -1) 13653541Sshin fatal("buffer_get_bignum: buffer error"); 13753541Sshin} 13853541Sshin 13953541Sshin/* 14053541Sshin * Stores an BIGNUM in the buffer in SSH2 format. 14153541Sshin */ 14253541Sshinint 14353541Sshinbuffer_put_bignum2_ret(Buffer *buffer, const BIGNUM *value) 14453541Sshin{ 14553541Sshin u_int bytes; 14653541Sshin u_char *buf; 14753541Sshin int oi; 14853541Sshin u_int hasnohigh = 0; 14953541Sshin 15053541Sshin if (BN_is_zero(value)) { 15153541Sshin buffer_put_int(buffer, 0); 15253541Sshin return 0; 15353541Sshin } 15453541Sshin if (value->neg) { 15553541Sshin error("buffer_put_bignum2_ret: negative numbers not supported"); 15653541Sshin return (-1); 15753541Sshin } 15853541Sshin bytes = BN_num_bytes(value) + 1; /* extra padding byte */ 15953541Sshin if (bytes < 2) { 16053541Sshin error("buffer_put_bignum2_ret: BN too small"); 16153541Sshin return (-1); 16253541Sshin } 16353541Sshin buf = xmalloc(bytes); 16453541Sshin buf[0] = 0x00; 16553541Sshin /* Get the value of in binary */ 16653541Sshin oi = BN_bn2bin(value, buf+1); 16753541Sshin if (oi < 0 || (u_int)oi != bytes - 1) { 16853541Sshin error("buffer_put_bignum2_ret: BN_bn2bin() failed: " 16953541Sshin "oi %d != bin_size %d", oi, bytes); 17053541Sshin xfree(buf); 17153541Sshin return (-1); 17253541Sshin } 17353541Sshin hasnohigh = (buf[1] & 0x80) ? 0 : 1; 17453541Sshin buffer_put_string(buffer, buf+hasnohigh, bytes-hasnohigh); 17553541Sshin memset(buf, 0, bytes); 17653541Sshin xfree(buf); 17753541Sshin return (0); 17853541Sshin} 17953541Sshin 18053541Sshinvoid 18153541Sshinbuffer_put_bignum2(Buffer *buffer, const BIGNUM *value) 18253541Sshin{ 18353541Sshin if (buffer_put_bignum2_ret(buffer, value) == -1) 18453541Sshin fatal("buffer_put_bignum2: buffer error"); 18553541Sshin} 18653541Sshin 18753541Sshinint 18853541Sshinbuffer_get_bignum2_ret(Buffer *buffer, BIGNUM *value) 18953541Sshin{ 19053541Sshin u_int len; 19153541Sshin u_char *bin; 19253541Sshin 19353541Sshin if ((bin = buffer_get_string_ret(buffer, &len)) == NULL) { 19453541Sshin error("buffer_get_bignum2_ret: invalid bignum"); 19553541Sshin return (-1); 19653541Sshin } 19753541Sshin 19853541Sshin if (len > 0 && (bin[0] & 0x80)) { 19953541Sshin error("buffer_get_bignum2_ret: negative numbers not supported"); 20053541Sshin xfree(bin); 20153541Sshin return (-1); 20253541Sshin } 20353541Sshin if (len > 8 * 1024) { 20453541Sshin error("buffer_get_bignum2_ret: cannot handle BN of size %d", len); 20553541Sshin xfree(bin); 20653541Sshin return (-1); 20753541Sshin } 20853541Sshin if (BN_bin2bn(bin, len, value) == NULL) { 20953541Sshin error("buffer_get_bignum2_ret: BN_bin2bn failed"); 21053541Sshin return (-1); 21153541Sshin } 21253541Sshin xfree(bin); 21353541Sshin return (0); 21453541Sshin} 21553541Sshin 216114205Ssuzvoid 21753541Sshinbuffer_get_bignum2(Buffer *buffer, BIGNUM *value) 21853541Sshin{ 21953541Sshin if (buffer_get_bignum2_ret(buffer, value) == -1) 22053541Sshin fatal("buffer_get_bignum2: buffer error"); 22153541Sshin} 22253541Sshin