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