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