1264693Sdes/* $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>
48263970Sdes#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");
185263970Sdes		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 {
219263970Sdes			explicit_bzero(ret, length);
220263970Sdes			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
289263970Sdesbuffer_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{
301263970Sdes	u_char ch;
30299063Sdes
303147005Sdes	if (buffer_get_char_ret(&ch, buffer) == -1)
304147005Sdes		fatal("buffer_get_char: buffer error");
305263970Sdes	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}
318263970Sdes
319263970Sdes/* Pseudo bignum functions */
320263970Sdes
321263970Sdesvoid *
322263970Sdesbuffer_get_bignum2_as_string_ret(Buffer *buffer, u_int *length_ptr)
323263970Sdes{
324263970Sdes	u_int len;
325263970Sdes	u_char *bin, *p, *ret;
326263970Sdes
327263970Sdes	if ((p = bin = buffer_get_string_ret(buffer, &len)) == NULL) {
328263970Sdes		error("%s: invalid bignum", __func__);
329263970Sdes		return NULL;
330263970Sdes	}
331263970Sdes
332263970Sdes	if (len > 0 && (bin[0] & 0x80)) {
333263970Sdes		error("%s: negative numbers not supported", __func__);
334263970Sdes		free(bin);
335263970Sdes		return NULL;
336263970Sdes	}
337263970Sdes	if (len > 8 * 1024) {
338263970Sdes		error("%s: cannot handle BN of size %d", __func__, len);
339263970Sdes		free(bin);
340263970Sdes		return NULL;
341263970Sdes	}
342263970Sdes	/* Skip zero prefix on numbers with the MSB set */
343263970Sdes	if (len > 1 && bin[0] == 0x00 && (bin[1] & 0x80) != 0) {
344263970Sdes		p++;
345263970Sdes		len--;
346263970Sdes	}
347263970Sdes	ret = xmalloc(len);
348263970Sdes	memcpy(ret, p, len);
349263970Sdes	explicit_bzero(p, len);
350263970Sdes	free(bin);
351263970Sdes	return ret;
352263970Sdes}
353263970Sdes
354263970Sdesvoid *
355263970Sdesbuffer_get_bignum2_as_string(Buffer *buffer, u_int *l)
356263970Sdes{
357263970Sdes	void *ret = buffer_get_bignum2_as_string_ret(buffer, l);
358263970Sdes
359263970Sdes	if (ret == NULL)
360263970Sdes		fatal("%s: buffer error", __func__);
361263970Sdes	return ret;
362263970Sdes}
363263970Sdes
364263970Sdes/*
365263970Sdes * Stores a string using the bignum encoding rules (\0 pad if MSB set).
366263970Sdes */
367263970Sdesvoid
368263970Sdesbuffer_put_bignum2_from_string(Buffer *buffer, const u_char *s, u_int l)
369263970Sdes{
370263970Sdes	u_char *buf, *p;
371263970Sdes	int pad = 0;
372263970Sdes
373263970Sdes	if (l > 8 * 1024)
374263970Sdes		fatal("%s: length %u too long", __func__, l);
375264693Sdes	/* Skip leading zero bytes */
376264693Sdes	for (; l > 0 && *s == 0; l--, s++)
377264693Sdes		;
378263970Sdes	p = buf = xmalloc(l + 1);
379263970Sdes	/*
380263970Sdes	 * If most significant bit is set then prepend a zero byte to
381263970Sdes	 * avoid interpretation as a negative number.
382263970Sdes	 */
383263970Sdes	if (l > 0 && (s[0] & 0x80) != 0) {
384263970Sdes		*p++ = '\0';
385263970Sdes		pad = 1;
386263970Sdes	}
387263970Sdes	memcpy(p, s, l);
388263970Sdes	buffer_put_string(buffer, buf, l + pad);
389263970Sdes	explicit_bzero(buf, l + pad);
390263970Sdes	free(buf);
391263970Sdes}
392263970Sdes
393263970Sdes
394