xref: /dragonfly/crypto/openssh/sshbuf.c (revision ee116499)
1*ee116499SAntonio Huete Jimenez /*	$OpenBSD: sshbuf.c,v 1.18 2022/05/25 06:03:44 djm Exp $	*/
236e94dc5SPeter Avalos /*
336e94dc5SPeter Avalos  * Copyright (c) 2011 Damien Miller
436e94dc5SPeter Avalos  *
536e94dc5SPeter Avalos  * Permission to use, copy, modify, and distribute this software for any
636e94dc5SPeter Avalos  * purpose with or without fee is hereby granted, provided that the above
736e94dc5SPeter Avalos  * copyright notice and this permission notice appear in all copies.
836e94dc5SPeter Avalos  *
936e94dc5SPeter Avalos  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1036e94dc5SPeter Avalos  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1136e94dc5SPeter Avalos  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1236e94dc5SPeter Avalos  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1336e94dc5SPeter Avalos  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1436e94dc5SPeter Avalos  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1536e94dc5SPeter Avalos  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1636e94dc5SPeter Avalos  */
1736e94dc5SPeter Avalos 
1836e94dc5SPeter Avalos #define SSHBUF_INTERNAL
1936e94dc5SPeter Avalos #include "includes.h"
2036e94dc5SPeter Avalos 
2136e94dc5SPeter Avalos #include <sys/types.h>
2236e94dc5SPeter Avalos #include <signal.h>
2336e94dc5SPeter Avalos #include <stdlib.h>
2436e94dc5SPeter Avalos #include <stdio.h>
2536e94dc5SPeter Avalos #include <string.h>
2636e94dc5SPeter Avalos 
2736e94dc5SPeter Avalos #include "ssherr.h"
2836e94dc5SPeter Avalos #include "sshbuf.h"
29ce74bacaSMatthew Dillon #include "misc.h"
3036e94dc5SPeter Avalos 
3136e94dc5SPeter Avalos static inline int
sshbuf_check_sanity(const struct sshbuf * buf)3236e94dc5SPeter Avalos sshbuf_check_sanity(const struct sshbuf *buf)
3336e94dc5SPeter Avalos {
3436e94dc5SPeter Avalos 	SSHBUF_TELL("sanity");
3536e94dc5SPeter Avalos 	if (__predict_false(buf == NULL ||
3636e94dc5SPeter Avalos 	    (!buf->readonly && buf->d != buf->cd) ||
3736e94dc5SPeter Avalos 	    buf->refcount < 1 || buf->refcount > SSHBUF_REFS_MAX ||
3836e94dc5SPeter Avalos 	    buf->cd == NULL ||
3936e94dc5SPeter Avalos 	    buf->max_size > SSHBUF_SIZE_MAX ||
4036e94dc5SPeter Avalos 	    buf->alloc > buf->max_size ||
4136e94dc5SPeter Avalos 	    buf->size > buf->alloc ||
4236e94dc5SPeter Avalos 	    buf->off > buf->size)) {
4336e94dc5SPeter Avalos 		/* Do not try to recover from corrupted buffer internals */
4436e94dc5SPeter Avalos 		SSHBUF_DBG(("SSH_ERR_INTERNAL_ERROR"));
450cbfa66cSDaniel Fojt 		ssh_signal(SIGSEGV, SIG_DFL);
4636e94dc5SPeter Avalos 		raise(SIGSEGV);
4736e94dc5SPeter Avalos 		return SSH_ERR_INTERNAL_ERROR;
4836e94dc5SPeter Avalos 	}
4936e94dc5SPeter Avalos 	return 0;
5036e94dc5SPeter Avalos }
5136e94dc5SPeter Avalos 
5236e94dc5SPeter Avalos static void
sshbuf_maybe_pack(struct sshbuf * buf,int force)5336e94dc5SPeter Avalos sshbuf_maybe_pack(struct sshbuf *buf, int force)
5436e94dc5SPeter Avalos {
5536e94dc5SPeter Avalos 	SSHBUF_DBG(("force %d", force));
5636e94dc5SPeter Avalos 	SSHBUF_TELL("pre-pack");
5736e94dc5SPeter Avalos 	if (buf->off == 0 || buf->readonly || buf->refcount > 1)
5836e94dc5SPeter Avalos 		return;
5936e94dc5SPeter Avalos 	if (force ||
6036e94dc5SPeter Avalos 	    (buf->off >= SSHBUF_PACK_MIN && buf->off >= buf->size / 2)) {
6136e94dc5SPeter Avalos 		memmove(buf->d, buf->d + buf->off, buf->size - buf->off);
6236e94dc5SPeter Avalos 		buf->size -= buf->off;
6336e94dc5SPeter Avalos 		buf->off = 0;
6436e94dc5SPeter Avalos 		SSHBUF_TELL("packed");
6536e94dc5SPeter Avalos 	}
6636e94dc5SPeter Avalos }
6736e94dc5SPeter Avalos 
6836e94dc5SPeter Avalos struct sshbuf *
sshbuf_new(void)6936e94dc5SPeter Avalos sshbuf_new(void)
7036e94dc5SPeter Avalos {
7136e94dc5SPeter Avalos 	struct sshbuf *ret;
7236e94dc5SPeter Avalos 
7336e94dc5SPeter Avalos 	if ((ret = calloc(sizeof(*ret), 1)) == NULL)
7436e94dc5SPeter Avalos 		return NULL;
7536e94dc5SPeter Avalos 	ret->alloc = SSHBUF_SIZE_INIT;
7636e94dc5SPeter Avalos 	ret->max_size = SSHBUF_SIZE_MAX;
7736e94dc5SPeter Avalos 	ret->readonly = 0;
7836e94dc5SPeter Avalos 	ret->refcount = 1;
7936e94dc5SPeter Avalos 	ret->parent = NULL;
8036e94dc5SPeter Avalos 	if ((ret->cd = ret->d = calloc(1, ret->alloc)) == NULL) {
8136e94dc5SPeter Avalos 		free(ret);
8236e94dc5SPeter Avalos 		return NULL;
8336e94dc5SPeter Avalos 	}
8436e94dc5SPeter Avalos 	return ret;
8536e94dc5SPeter Avalos }
8636e94dc5SPeter Avalos 
8736e94dc5SPeter Avalos struct sshbuf *
sshbuf_from(const void * blob,size_t len)8836e94dc5SPeter Avalos sshbuf_from(const void *blob, size_t len)
8936e94dc5SPeter Avalos {
9036e94dc5SPeter Avalos 	struct sshbuf *ret;
9136e94dc5SPeter Avalos 
9236e94dc5SPeter Avalos 	if (blob == NULL || len > SSHBUF_SIZE_MAX ||
9336e94dc5SPeter Avalos 	    (ret = calloc(sizeof(*ret), 1)) == NULL)
9436e94dc5SPeter Avalos 		return NULL;
9536e94dc5SPeter Avalos 	ret->alloc = ret->size = ret->max_size = len;
9636e94dc5SPeter Avalos 	ret->readonly = 1;
9736e94dc5SPeter Avalos 	ret->refcount = 1;
9836e94dc5SPeter Avalos 	ret->parent = NULL;
9936e94dc5SPeter Avalos 	ret->cd = blob;
10036e94dc5SPeter Avalos 	ret->d = NULL;
10136e94dc5SPeter Avalos 	return ret;
10236e94dc5SPeter Avalos }
10336e94dc5SPeter Avalos 
10436e94dc5SPeter Avalos int
sshbuf_set_parent(struct sshbuf * child,struct sshbuf * parent)10536e94dc5SPeter Avalos sshbuf_set_parent(struct sshbuf *child, struct sshbuf *parent)
10636e94dc5SPeter Avalos {
10736e94dc5SPeter Avalos 	int r;
10836e94dc5SPeter Avalos 
10936e94dc5SPeter Avalos 	if ((r = sshbuf_check_sanity(child)) != 0 ||
11036e94dc5SPeter Avalos 	    (r = sshbuf_check_sanity(parent)) != 0)
11136e94dc5SPeter Avalos 		return r;
112*ee116499SAntonio Huete Jimenez 	if (child->parent != NULL && child->parent != parent)
113*ee116499SAntonio Huete Jimenez 		return SSH_ERR_INTERNAL_ERROR;
11436e94dc5SPeter Avalos 	child->parent = parent;
11536e94dc5SPeter Avalos 	child->parent->refcount++;
11636e94dc5SPeter Avalos 	return 0;
11736e94dc5SPeter Avalos }
11836e94dc5SPeter Avalos 
11936e94dc5SPeter Avalos struct sshbuf *
sshbuf_fromb(struct sshbuf * buf)12036e94dc5SPeter Avalos sshbuf_fromb(struct sshbuf *buf)
12136e94dc5SPeter Avalos {
12236e94dc5SPeter Avalos 	struct sshbuf *ret;
12336e94dc5SPeter Avalos 
12436e94dc5SPeter Avalos 	if (sshbuf_check_sanity(buf) != 0)
12536e94dc5SPeter Avalos 		return NULL;
12636e94dc5SPeter Avalos 	if ((ret = sshbuf_from(sshbuf_ptr(buf), sshbuf_len(buf))) == NULL)
12736e94dc5SPeter Avalos 		return NULL;
12836e94dc5SPeter Avalos 	if (sshbuf_set_parent(ret, buf) != 0) {
12936e94dc5SPeter Avalos 		sshbuf_free(ret);
13036e94dc5SPeter Avalos 		return NULL;
13136e94dc5SPeter Avalos 	}
13236e94dc5SPeter Avalos 	return ret;
13336e94dc5SPeter Avalos }
13436e94dc5SPeter Avalos 
13536e94dc5SPeter Avalos void
sshbuf_free(struct sshbuf * buf)13636e94dc5SPeter Avalos sshbuf_free(struct sshbuf *buf)
13736e94dc5SPeter Avalos {
13836e94dc5SPeter Avalos 	if (buf == NULL)
13936e94dc5SPeter Avalos 		return;
14036e94dc5SPeter Avalos 	/*
14136e94dc5SPeter Avalos 	 * The following will leak on insane buffers, but this is the safest
14236e94dc5SPeter Avalos 	 * course of action - an invalid pointer or already-freed pointer may
14336e94dc5SPeter Avalos 	 * have been passed to us and continuing to scribble over memory would
14436e94dc5SPeter Avalos 	 * be bad.
14536e94dc5SPeter Avalos 	 */
14636e94dc5SPeter Avalos 	if (sshbuf_check_sanity(buf) != 0)
14736e94dc5SPeter Avalos 		return;
148664f4763Szrj 
14936e94dc5SPeter Avalos 	/*
15036e94dc5SPeter Avalos 	 * If we are a parent with still-extant children, then don't free just
15136e94dc5SPeter Avalos 	 * yet. The last child's call to sshbuf_free should decrement our
15236e94dc5SPeter Avalos 	 * refcount to 0 and trigger the actual free.
15336e94dc5SPeter Avalos 	 */
15436e94dc5SPeter Avalos 	buf->refcount--;
15536e94dc5SPeter Avalos 	if (buf->refcount > 0)
15636e94dc5SPeter Avalos 		return;
157664f4763Szrj 
158664f4763Szrj 	/*
159664f4763Szrj 	 * If we are a child, the free our parent to decrement its reference
160664f4763Szrj 	 * count and possibly free it.
161664f4763Szrj 	 */
162664f4763Szrj 	sshbuf_free(buf->parent);
163664f4763Szrj 	buf->parent = NULL;
164664f4763Szrj 
16536e94dc5SPeter Avalos 	if (!buf->readonly) {
166e9778795SPeter Avalos 		explicit_bzero(buf->d, buf->alloc);
16736e94dc5SPeter Avalos 		free(buf->d);
16836e94dc5SPeter Avalos 	}
1690cbfa66cSDaniel Fojt 	freezero(buf, sizeof(*buf));
17036e94dc5SPeter Avalos }
17136e94dc5SPeter Avalos 
17236e94dc5SPeter Avalos void
sshbuf_reset(struct sshbuf * buf)17336e94dc5SPeter Avalos sshbuf_reset(struct sshbuf *buf)
17436e94dc5SPeter Avalos {
17536e94dc5SPeter Avalos 	u_char *d;
17636e94dc5SPeter Avalos 
17736e94dc5SPeter Avalos 	if (buf->readonly || buf->refcount > 1) {
17836e94dc5SPeter Avalos 		/* Nonsensical. Just make buffer appear empty */
17936e94dc5SPeter Avalos 		buf->off = buf->size;
18036e94dc5SPeter Avalos 		return;
18136e94dc5SPeter Avalos 	}
182*ee116499SAntonio Huete Jimenez 	if (sshbuf_check_sanity(buf) != 0)
183*ee116499SAntonio Huete Jimenez 		return;
18436e94dc5SPeter Avalos 	buf->off = buf->size = 0;
18536e94dc5SPeter Avalos 	if (buf->alloc != SSHBUF_SIZE_INIT) {
186ce74bacaSMatthew Dillon 		if ((d = recallocarray(buf->d, buf->alloc, SSHBUF_SIZE_INIT,
187ce74bacaSMatthew Dillon 		    1)) != NULL) {
18836e94dc5SPeter Avalos 			buf->cd = buf->d = d;
18936e94dc5SPeter Avalos 			buf->alloc = SSHBUF_SIZE_INIT;
19036e94dc5SPeter Avalos 		}
19136e94dc5SPeter Avalos 	}
192*ee116499SAntonio Huete Jimenez 	explicit_bzero(buf->d, buf->alloc);
19336e94dc5SPeter Avalos }
19436e94dc5SPeter Avalos 
19536e94dc5SPeter Avalos size_t
sshbuf_max_size(const struct sshbuf * buf)19636e94dc5SPeter Avalos sshbuf_max_size(const struct sshbuf *buf)
19736e94dc5SPeter Avalos {
19836e94dc5SPeter Avalos 	return buf->max_size;
19936e94dc5SPeter Avalos }
20036e94dc5SPeter Avalos 
20136e94dc5SPeter Avalos size_t
sshbuf_alloc(const struct sshbuf * buf)20236e94dc5SPeter Avalos sshbuf_alloc(const struct sshbuf *buf)
20336e94dc5SPeter Avalos {
20436e94dc5SPeter Avalos 	return buf->alloc;
20536e94dc5SPeter Avalos }
20636e94dc5SPeter Avalos 
20736e94dc5SPeter Avalos const struct sshbuf *
sshbuf_parent(const struct sshbuf * buf)20836e94dc5SPeter Avalos sshbuf_parent(const struct sshbuf *buf)
20936e94dc5SPeter Avalos {
21036e94dc5SPeter Avalos 	return buf->parent;
21136e94dc5SPeter Avalos }
21236e94dc5SPeter Avalos 
21336e94dc5SPeter Avalos u_int
sshbuf_refcount(const struct sshbuf * buf)21436e94dc5SPeter Avalos sshbuf_refcount(const struct sshbuf *buf)
21536e94dc5SPeter Avalos {
21636e94dc5SPeter Avalos 	return buf->refcount;
21736e94dc5SPeter Avalos }
21836e94dc5SPeter Avalos 
21936e94dc5SPeter Avalos int
sshbuf_set_max_size(struct sshbuf * buf,size_t max_size)22036e94dc5SPeter Avalos sshbuf_set_max_size(struct sshbuf *buf, size_t max_size)
22136e94dc5SPeter Avalos {
22236e94dc5SPeter Avalos 	size_t rlen;
22336e94dc5SPeter Avalos 	u_char *dp;
22436e94dc5SPeter Avalos 	int r;
22536e94dc5SPeter Avalos 
22636e94dc5SPeter Avalos 	SSHBUF_DBG(("set max buf = %p len = %zu", buf, max_size));
22736e94dc5SPeter Avalos 	if ((r = sshbuf_check_sanity(buf)) != 0)
22836e94dc5SPeter Avalos 		return r;
22936e94dc5SPeter Avalos 	if (max_size == buf->max_size)
23036e94dc5SPeter Avalos 		return 0;
23136e94dc5SPeter Avalos 	if (buf->readonly || buf->refcount > 1)
23236e94dc5SPeter Avalos 		return SSH_ERR_BUFFER_READ_ONLY;
23336e94dc5SPeter Avalos 	if (max_size > SSHBUF_SIZE_MAX)
23436e94dc5SPeter Avalos 		return SSH_ERR_NO_BUFFER_SPACE;
23536e94dc5SPeter Avalos 	/* pack and realloc if necessary */
23636e94dc5SPeter Avalos 	sshbuf_maybe_pack(buf, max_size < buf->size);
23736e94dc5SPeter Avalos 	if (max_size < buf->alloc && max_size > buf->size) {
23836e94dc5SPeter Avalos 		if (buf->size < SSHBUF_SIZE_INIT)
23936e94dc5SPeter Avalos 			rlen = SSHBUF_SIZE_INIT;
24036e94dc5SPeter Avalos 		else
241ce74bacaSMatthew Dillon 			rlen = ROUNDUP(buf->size, SSHBUF_SIZE_INC);
24236e94dc5SPeter Avalos 		if (rlen > max_size)
24336e94dc5SPeter Avalos 			rlen = max_size;
24436e94dc5SPeter Avalos 		SSHBUF_DBG(("new alloc = %zu", rlen));
245ce74bacaSMatthew Dillon 		if ((dp = recallocarray(buf->d, buf->alloc, rlen, 1)) == NULL)
24636e94dc5SPeter Avalos 			return SSH_ERR_ALLOC_FAIL;
24736e94dc5SPeter Avalos 		buf->cd = buf->d = dp;
24836e94dc5SPeter Avalos 		buf->alloc = rlen;
24936e94dc5SPeter Avalos 	}
25036e94dc5SPeter Avalos 	SSHBUF_TELL("new-max");
25136e94dc5SPeter Avalos 	if (max_size < buf->alloc)
25236e94dc5SPeter Avalos 		return SSH_ERR_NO_BUFFER_SPACE;
25336e94dc5SPeter Avalos 	buf->max_size = max_size;
25436e94dc5SPeter Avalos 	return 0;
25536e94dc5SPeter Avalos }
25636e94dc5SPeter Avalos 
25736e94dc5SPeter Avalos size_t
sshbuf_len(const struct sshbuf * buf)25836e94dc5SPeter Avalos sshbuf_len(const struct sshbuf *buf)
25936e94dc5SPeter Avalos {
26036e94dc5SPeter Avalos 	if (sshbuf_check_sanity(buf) != 0)
26136e94dc5SPeter Avalos 		return 0;
26236e94dc5SPeter Avalos 	return buf->size - buf->off;
26336e94dc5SPeter Avalos }
26436e94dc5SPeter Avalos 
26536e94dc5SPeter Avalos size_t
sshbuf_avail(const struct sshbuf * buf)26636e94dc5SPeter Avalos sshbuf_avail(const struct sshbuf *buf)
26736e94dc5SPeter Avalos {
26836e94dc5SPeter Avalos 	if (sshbuf_check_sanity(buf) != 0 || buf->readonly || buf->refcount > 1)
26936e94dc5SPeter Avalos 		return 0;
27036e94dc5SPeter Avalos 	return buf->max_size - (buf->size - buf->off);
27136e94dc5SPeter Avalos }
27236e94dc5SPeter Avalos 
27336e94dc5SPeter Avalos const u_char *
sshbuf_ptr(const struct sshbuf * buf)27436e94dc5SPeter Avalos sshbuf_ptr(const struct sshbuf *buf)
27536e94dc5SPeter Avalos {
27636e94dc5SPeter Avalos 	if (sshbuf_check_sanity(buf) != 0)
27736e94dc5SPeter Avalos 		return NULL;
27836e94dc5SPeter Avalos 	return buf->cd + buf->off;
27936e94dc5SPeter Avalos }
28036e94dc5SPeter Avalos 
28136e94dc5SPeter Avalos u_char *
sshbuf_mutable_ptr(const struct sshbuf * buf)28236e94dc5SPeter Avalos sshbuf_mutable_ptr(const struct sshbuf *buf)
28336e94dc5SPeter Avalos {
28436e94dc5SPeter Avalos 	if (sshbuf_check_sanity(buf) != 0 || buf->readonly || buf->refcount > 1)
28536e94dc5SPeter Avalos 		return NULL;
28636e94dc5SPeter Avalos 	return buf->d + buf->off;
28736e94dc5SPeter Avalos }
28836e94dc5SPeter Avalos 
28936e94dc5SPeter Avalos int
sshbuf_check_reserve(const struct sshbuf * buf,size_t len)29036e94dc5SPeter Avalos sshbuf_check_reserve(const struct sshbuf *buf, size_t len)
29136e94dc5SPeter Avalos {
29236e94dc5SPeter Avalos 	int r;
29336e94dc5SPeter Avalos 
29436e94dc5SPeter Avalos 	if ((r = sshbuf_check_sanity(buf)) != 0)
29536e94dc5SPeter Avalos 		return r;
29636e94dc5SPeter Avalos 	if (buf->readonly || buf->refcount > 1)
29736e94dc5SPeter Avalos 		return SSH_ERR_BUFFER_READ_ONLY;
29836e94dc5SPeter Avalos 	SSHBUF_TELL("check");
29936e94dc5SPeter Avalos 	/* Check that len is reasonable and that max_size + available < len */
30036e94dc5SPeter Avalos 	if (len > buf->max_size || buf->max_size - len < buf->size - buf->off)
30136e94dc5SPeter Avalos 		return SSH_ERR_NO_BUFFER_SPACE;
30236e94dc5SPeter Avalos 	return 0;
30336e94dc5SPeter Avalos }
30436e94dc5SPeter Avalos 
30536e94dc5SPeter Avalos int
sshbuf_allocate(struct sshbuf * buf,size_t len)306ce74bacaSMatthew Dillon sshbuf_allocate(struct sshbuf *buf, size_t len)
30736e94dc5SPeter Avalos {
30836e94dc5SPeter Avalos 	size_t rlen, need;
30936e94dc5SPeter Avalos 	u_char *dp;
31036e94dc5SPeter Avalos 	int r;
31136e94dc5SPeter Avalos 
312ce74bacaSMatthew Dillon 	SSHBUF_DBG(("allocate buf = %p len = %zu", buf, len));
31336e94dc5SPeter Avalos 	if ((r = sshbuf_check_reserve(buf, len)) != 0)
31436e94dc5SPeter Avalos 		return r;
31536e94dc5SPeter Avalos 	/*
31636e94dc5SPeter Avalos 	 * If the requested allocation appended would push us past max_size
31736e94dc5SPeter Avalos 	 * then pack the buffer, zeroing buf->off.
31836e94dc5SPeter Avalos 	 */
31936e94dc5SPeter Avalos 	sshbuf_maybe_pack(buf, buf->size + len > buf->max_size);
320ce74bacaSMatthew Dillon 	SSHBUF_TELL("allocate");
321ce74bacaSMatthew Dillon 	if (len + buf->size <= buf->alloc)
322ce74bacaSMatthew Dillon 		return 0; /* already have it. */
323ce74bacaSMatthew Dillon 
32436e94dc5SPeter Avalos 	/*
32536e94dc5SPeter Avalos 	 * Prefer to alloc in SSHBUF_SIZE_INC units, but
32636e94dc5SPeter Avalos 	 * allocate less if doing so would overflow max_size.
32736e94dc5SPeter Avalos 	 */
32836e94dc5SPeter Avalos 	need = len + buf->size - buf->alloc;
329ce74bacaSMatthew Dillon 	rlen = ROUNDUP(buf->alloc + need, SSHBUF_SIZE_INC);
33036e94dc5SPeter Avalos 	SSHBUF_DBG(("need %zu initial rlen %zu", need, rlen));
33136e94dc5SPeter Avalos 	if (rlen > buf->max_size)
33236e94dc5SPeter Avalos 		rlen = buf->alloc + need;
33336e94dc5SPeter Avalos 	SSHBUF_DBG(("adjusted rlen %zu", rlen));
334ce74bacaSMatthew Dillon 	if ((dp = recallocarray(buf->d, buf->alloc, rlen, 1)) == NULL) {
33536e94dc5SPeter Avalos 		SSHBUF_DBG(("realloc fail"));
33636e94dc5SPeter Avalos 		return SSH_ERR_ALLOC_FAIL;
33736e94dc5SPeter Avalos 	}
33836e94dc5SPeter Avalos 	buf->alloc = rlen;
33936e94dc5SPeter Avalos 	buf->cd = buf->d = dp;
34036e94dc5SPeter Avalos 	if ((r = sshbuf_check_reserve(buf, len)) < 0) {
34136e94dc5SPeter Avalos 		/* shouldn't fail */
34236e94dc5SPeter Avalos 		return r;
34336e94dc5SPeter Avalos 	}
344ce74bacaSMatthew Dillon 	SSHBUF_TELL("done");
345ce74bacaSMatthew Dillon 	return 0;
34636e94dc5SPeter Avalos }
347ce74bacaSMatthew Dillon 
348ce74bacaSMatthew Dillon int
sshbuf_reserve(struct sshbuf * buf,size_t len,u_char ** dpp)349ce74bacaSMatthew Dillon sshbuf_reserve(struct sshbuf *buf, size_t len, u_char **dpp)
350ce74bacaSMatthew Dillon {
351ce74bacaSMatthew Dillon 	u_char *dp;
352ce74bacaSMatthew Dillon 	int r;
353ce74bacaSMatthew Dillon 
354ce74bacaSMatthew Dillon 	if (dpp != NULL)
355ce74bacaSMatthew Dillon 		*dpp = NULL;
356ce74bacaSMatthew Dillon 
357ce74bacaSMatthew Dillon 	SSHBUF_DBG(("reserve buf = %p len = %zu", buf, len));
358ce74bacaSMatthew Dillon 	if ((r = sshbuf_allocate(buf, len)) != 0)
359ce74bacaSMatthew Dillon 		return r;
360ce74bacaSMatthew Dillon 
36136e94dc5SPeter Avalos 	dp = buf->d + buf->size;
36236e94dc5SPeter Avalos 	buf->size += len;
36336e94dc5SPeter Avalos 	if (dpp != NULL)
36436e94dc5SPeter Avalos 		*dpp = dp;
36536e94dc5SPeter Avalos 	return 0;
36636e94dc5SPeter Avalos }
36736e94dc5SPeter Avalos 
36836e94dc5SPeter Avalos int
sshbuf_consume(struct sshbuf * buf,size_t len)36936e94dc5SPeter Avalos sshbuf_consume(struct sshbuf *buf, size_t len)
37036e94dc5SPeter Avalos {
37136e94dc5SPeter Avalos 	int r;
37236e94dc5SPeter Avalos 
37336e94dc5SPeter Avalos 	SSHBUF_DBG(("len = %zu", len));
37436e94dc5SPeter Avalos 	if ((r = sshbuf_check_sanity(buf)) != 0)
37536e94dc5SPeter Avalos 		return r;
37636e94dc5SPeter Avalos 	if (len == 0)
37736e94dc5SPeter Avalos 		return 0;
37836e94dc5SPeter Avalos 	if (len > sshbuf_len(buf))
37936e94dc5SPeter Avalos 		return SSH_ERR_MESSAGE_INCOMPLETE;
38036e94dc5SPeter Avalos 	buf->off += len;
381ce74bacaSMatthew Dillon 	/* deal with empty buffer */
382ce74bacaSMatthew Dillon 	if (buf->off == buf->size)
383ce74bacaSMatthew Dillon 		buf->off = buf->size = 0;
38436e94dc5SPeter Avalos 	SSHBUF_TELL("done");
38536e94dc5SPeter Avalos 	return 0;
38636e94dc5SPeter Avalos }
38736e94dc5SPeter Avalos 
38836e94dc5SPeter Avalos int
sshbuf_consume_end(struct sshbuf * buf,size_t len)38936e94dc5SPeter Avalos sshbuf_consume_end(struct sshbuf *buf, size_t len)
39036e94dc5SPeter Avalos {
39136e94dc5SPeter Avalos 	int r;
39236e94dc5SPeter Avalos 
39336e94dc5SPeter Avalos 	SSHBUF_DBG(("len = %zu", len));
39436e94dc5SPeter Avalos 	if ((r = sshbuf_check_sanity(buf)) != 0)
39536e94dc5SPeter Avalos 		return r;
39636e94dc5SPeter Avalos 	if (len == 0)
39736e94dc5SPeter Avalos 		return 0;
39836e94dc5SPeter Avalos 	if (len > sshbuf_len(buf))
39936e94dc5SPeter Avalos 		return SSH_ERR_MESSAGE_INCOMPLETE;
40036e94dc5SPeter Avalos 	buf->size -= len;
40136e94dc5SPeter Avalos 	SSHBUF_TELL("done");
40236e94dc5SPeter Avalos 	return 0;
40336e94dc5SPeter Avalos }
40436e94dc5SPeter Avalos 
405