bufaux.c revision 98941
11556Srgrimes/*
21556Srgrimes * Author: Tatu Ylonen <ylo@cs.hut.fi>
31556Srgrimes * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
41556Srgrimes *                    All rights reserved
51556Srgrimes * Auxiliary functions for storing and retrieving various data types to/from
61556Srgrimes * Buffers.
71556Srgrimes *
81556Srgrimes * As far as I am concerned, the code I have written for this software
91556Srgrimes * can be used freely for any purpose.  Any derived versions of this
101556Srgrimes * software must be clearly marked as such, and if the derived work is
111556Srgrimes * incompatible with the protocol description in the RFC file, it must be
121556Srgrimes * called by a name other than "ssh" or "Secure Shell".
131556Srgrimes *
141556Srgrimes *
151556Srgrimes * SSH2 packet format added by Markus Friedl
161556Srgrimes * Copyright (c) 2000 Markus Friedl.  All rights reserved.
171556Srgrimes *
181556Srgrimes * Redistribution and use in source and binary forms, with or without
191556Srgrimes * modification, are permitted provided that the following conditions
201556Srgrimes * are met:
211556Srgrimes * 1. Redistributions of source code must retain the above copyright
221556Srgrimes *    notice, this list of conditions and the following disclaimer.
231556Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
241556Srgrimes *    notice, this list of conditions and the following disclaimer in the
251556Srgrimes *    documentation and/or other materials provided with the distribution.
261556Srgrimes *
271556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
281556Srgrimes * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
291556Srgrimes * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
301556Srgrimes * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
311556Srgrimes * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
321556Srgrimes * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3390153Smarkm * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
341556Srgrimes * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3527967Ssteve * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
3690153Smarkm * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3727967Ssteve */
38114583Smarkm
3999109Sobrien#include "includes.h"
401556SrgrimesRCSID("$OpenBSD: bufaux.c,v 1.25 2002/04/20 09:14:58 markus Exp $");
411556Srgrimes
421556Srgrimes#include <openssl/bn.h>
431556Srgrimes#include "bufaux.h"
441556Srgrimes#include "xmalloc.h"
4535373Sdes#include "getput.h"
461556Srgrimes#include "log.h"
47128823Stjr
481556Srgrimes/*
491556Srgrimes * Stores an BIGNUM in the buffer with a 2-byte msb first bit count, followed
501556Srgrimes * by (bits+7)/8 bytes of binary data, msb first.
51128823Stjr */
52128823Stjrvoid
531556Srgrimesbuffer_put_bignum(Buffer *buffer, BIGNUM *value)
541556Srgrimes{
551556Srgrimes	int bits = BN_num_bits(value);
561556Srgrimes	int bin_size = (bits + 7) / 8;
5762597Sassar	u_char *buf = xmalloc(bin_size);
58128823Stjr	int oi;
59128823Stjr	char msg[2];
60128823Stjr
61128823Stjr	/* Get the value of in binary */
62128823Stjr	oi = BN_bn2bin(value, buf);
63128823Stjr	if (oi != bin_size)
64128823Stjr		fatal("buffer_put_bignum: BN_bn2bin() failed: oi %d != bin_size %d",
65128823Stjr		    oi, bin_size);
66128823Stjr
67128823Stjr	/* Store the number of bits in the buffer in two bytes, msb first. */
68128823Stjr	PUT_16BIT(msg, bits);
69128823Stjr	buffer_append(buffer, msg, 2);
70128823Stjr	/* Store the binary data. */
71128823Stjr	buffer_append(buffer, (char *)buf, oi);
72128823Stjr
73128823Stjr	memset(buf, 0, bin_size);
74128823Stjr	xfree(buf);
75128823Stjr}
76128823Stjr
77128823Stjr/*
78128823Stjr * Retrieves an BIGNUM from the buffer.
79128823Stjr */
80128823Stjrvoid
81128823Stjrbuffer_get_bignum(Buffer *buffer, BIGNUM *value)
82128823Stjr{
83128823Stjr	int bits, bytes;
84128823Stjr	u_char buf[2], *bin;
85128823Stjr
86128823Stjr	/* Get the number for bits. */
87128823Stjr	buffer_get(buffer, (char *) buf, 2);
8890110Simp	bits = GET_16BIT(buf);
891556Srgrimes	/* Compute the number of binary bytes that follow. */
90128823Stjr	bytes = (bits + 7) / 8;
91128823Stjr	if (buffer_len(buffer) < bytes)
92128823Stjr		fatal("buffer_get_bignum: input buffer too small");
93128823Stjr	bin = buffer_ptr(buffer);
941556Srgrimes	BN_bin2bn(bin, bytes, value);
95128823Stjr	buffer_consume(buffer, bytes);
96128823Stjr}
97128823Stjr
98128823Stjr/*
9962597Sassar * Stores an BIGNUM in the buffer in SSH2 format.
100128823Stjr */
101128823Stjrvoid
102128823Stjrbuffer_put_bignum2(Buffer *buffer, BIGNUM *value)
103128823Stjr{
104128823Stjr	int bytes = BN_num_bytes(value) + 1;
105128823Stjr	u_char *buf = xmalloc(bytes);
106128823Stjr	int oi;
107128823Stjr	int hasnohigh = 0;
108128823Stjr	buf[0] = '\0';
109128823Stjr	/* Get the value of in binary */
110128823Stjr	oi = BN_bn2bin(value, buf+1);
111128823Stjr	if (oi != bytes-1)
112128823Stjr		fatal("buffer_put_bignum: BN_bn2bin() failed: oi %d != bin_size %d",
113128823Stjr		    oi, bytes);
114128823Stjr	hasnohigh = (buf[1] & 0x80) ? 0 : 1;
115128823Stjr	if (value->neg) {
116128823Stjr		/**XXX should be two's-complement */
117128823Stjr		int i, carry;
118128823Stjr		u_char *uc = buf;
119128823Stjr		log("negativ!");
120128823Stjr		for (i = bytes-1, carry = 1; i>=0; i--) {
121128823Stjr			uc[i] ^= 0xff;
1221556Srgrimes			if (carry)
1231556Srgrimes				carry = !++uc[i];
12435373Sdes		}
12535373Sdes	}
12635373Sdes	buffer_put_string(buffer, buf+hasnohigh, bytes-hasnohigh);
12735373Sdes	memset(buf, 0, bytes);
12835417Sdes	xfree(buf);
12935417Sdes}
13035417Sdes
13135417Sdesvoid
13235417Sdesbuffer_get_bignum2(Buffer *buffer, BIGNUM *value)
13335417Sdes{
13435417Sdes	/**XXX should be two's-complement */
13535373Sdes	int len;
13635417Sdes	u_char *bin = buffer_get_string(buffer, (u_int *)&len);
13790150Smarkm	BN_bin2bn(bin, len, value);
13890110Simp	xfree(bin);
13935373Sdes}
140128823Stjr/*
141128823Stjr * Returns integers from the buffer (msb first).
142128823Stjr */
14335373Sdes
144128823Stjru_short
145128823Stjrbuffer_get_short(Buffer *buffer)
146128823Stjr{
147128823Stjr	u_char buf[2];
148128823Stjr	buffer_get(buffer, (char *) buf, 2);
149128823Stjr	return GET_16BIT(buf);
150128823Stjr}
151128823Stjr
152128823Stjru_int
153128823Stjrbuffer_get_int(Buffer *buffer)
154128823Stjr{
155128823Stjr	u_char buf[4];
156128823Stjr	buffer_get(buffer, (char *) buf, 4);
157128823Stjr	return GET_32BIT(buf);
158128823Stjr}
159128823Stjr
160128823Stjr#ifdef HAVE_U_INT64_T
161128823Stjru_int64_t
162128823Stjrbuffer_get_int64(Buffer *buffer)
163128823Stjr{
164128823Stjr	u_char buf[8];
16535373Sdes	buffer_get(buffer, (char *) buf, 8);
16635373Sdes	return GET_64BIT(buf);
16735373Sdes}
16890110Simp#endif
16935373Sdes
170128823Stjr/*
171128823Stjr * Stores integers in the buffer, msb first.
172128823Stjr */
173128823Stjrvoid
174128823Stjrbuffer_put_short(Buffer *buffer, u_short value)
175128823Stjr{
176128823Stjr	char buf[2];
17735373Sdes	PUT_16BIT(buf, value);
178128823Stjr	buffer_append(buffer, buf, 2);
179128823Stjr}
180128823Stjr
181128823Stjrvoid
182128823Stjrbuffer_put_int(Buffer *buffer, u_int value)
183128823Stjr{
184128823Stjr	char buf[4];
185128823Stjr	PUT_32BIT(buf, value);
186128823Stjr	buffer_append(buffer, buf, 4);
187128823Stjr}
188128823Stjr
189128823Stjr#ifdef HAVE_U_INT64_T
190128823Stjrvoid
191128823Stjrbuffer_put_int64(Buffer *buffer, u_int64_t value)
192128823Stjr{
193128823Stjr	char buf[8];
194128823Stjr	PUT_64BIT(buf, value);
195128823Stjr	buffer_append(buffer, buf, 8);
196128823Stjr}
197128823Stjr#endif
198128823Stjr
199128823Stjr/*
200128823Stjr * Returns an arbitrary binary string from the buffer.  The string cannot
201128823Stjr * be longer than 256k.  The returned value points to memory allocated
20235417Sdes * with xmalloc; it is the responsibility of the calling function to free
20340300Sdes * the data.  If length_ptr is non-NULL, the length of the returned data
20440300Sdes * will be stored there.  A null character will be automatically appended
205128823Stjr * to the returned string, and is not counted in length.
206128823Stjr */
20735417Sdesvoid *
208128823Stjrbuffer_get_string(Buffer *buffer, u_int *length_ptr)
209128823Stjr{
210128823Stjr	u_int len;
211128823Stjr	u_char *value;
212128823Stjr	/* Get the length. */
213128823Stjr	len = buffer_get_int(buffer);
214128823Stjr	if (len > 256 * 1024)
21535373Sdes		fatal("buffer_get_string: bad string length %d", len);
216128823Stjr	/* Allocate space for the string.  Add one byte for a null character. */
21735373Sdes	value = xmalloc(len + 1);
21835373Sdes	/* Get the string. */
2191556Srgrimes	buffer_get(buffer, value, len);
22090110Simp	/* Append a null character to make processing easier. */
2211556Srgrimes	value[len] = 0;
22261324Sache	/* Optionally return the length of the string. */
22361324Sache	if (length_ptr)
224119914Stjr		*length_ptr = len;
22561324Sache	return value;
226119914Stjr}
22761324Sache
22835426Sdes/*
2291556Srgrimes * Stores and arbitrary binary string in the buffer.
2301556Srgrimes */
231void
232buffer_put_string(Buffer *buffer, const void *buf, u_int len)
233{
234	buffer_put_int(buffer, len);
235	buffer_append(buffer, buf, len);
236}
237void
238buffer_put_cstring(Buffer *buffer, const char *s)
239{
240	if (s == NULL)
241		fatal("buffer_put_cstring: s == NULL");
242	buffer_put_string(buffer, s, strlen(s));
243}
244
245/*
246 * Returns a character from the buffer (0 - 255).
247 */
248int
249buffer_get_char(Buffer *buffer)
250{
251	char ch;
252	buffer_get(buffer, &ch, 1);
253	return (u_char) ch;
254}
255
256/*
257 * Stores a character in the buffer.
258 */
259void
260buffer_put_char(Buffer *buffer, int value)
261{
262	char ch = value;
263	buffer_append(buffer, &ch, 1);
264}
265