xref: /dragonfly/crypto/openssh/sshbuf.c (revision e9778795)
1*e9778795SPeter Avalos /*	$OpenBSD: sshbuf.c,v 1.6 2016/01/12 23:42:54 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 
21*e9778795SPeter Avalos #include <sys/param.h>	/* roundup */
2236e94dc5SPeter Avalos #include <sys/types.h>
2336e94dc5SPeter Avalos #include <signal.h>
2436e94dc5SPeter Avalos #include <stdlib.h>
2536e94dc5SPeter Avalos #include <stdio.h>
2636e94dc5SPeter Avalos #include <string.h>
2736e94dc5SPeter Avalos 
2836e94dc5SPeter Avalos #include "ssherr.h"
2936e94dc5SPeter Avalos #include "sshbuf.h"
3036e94dc5SPeter Avalos 
3136e94dc5SPeter Avalos static inline int
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->dont_free && (buf->readonly || buf->parent != NULL)) ||
4036e94dc5SPeter Avalos 	    buf->max_size > SSHBUF_SIZE_MAX ||
4136e94dc5SPeter Avalos 	    buf->alloc > buf->max_size ||
4236e94dc5SPeter Avalos 	    buf->size > buf->alloc ||
4336e94dc5SPeter Avalos 	    buf->off > buf->size)) {
4436e94dc5SPeter Avalos 		/* Do not try to recover from corrupted buffer internals */
4536e94dc5SPeter Avalos 		SSHBUF_DBG(("SSH_ERR_INTERNAL_ERROR"));
4636e94dc5SPeter Avalos 		signal(SIGSEGV, SIG_DFL);
4736e94dc5SPeter Avalos 		raise(SIGSEGV);
4836e94dc5SPeter Avalos 		return SSH_ERR_INTERNAL_ERROR;
4936e94dc5SPeter Avalos 	}
5036e94dc5SPeter Avalos 	return 0;
5136e94dc5SPeter Avalos }
5236e94dc5SPeter Avalos 
5336e94dc5SPeter Avalos static void
5436e94dc5SPeter Avalos sshbuf_maybe_pack(struct sshbuf *buf, int force)
5536e94dc5SPeter Avalos {
5636e94dc5SPeter Avalos 	SSHBUF_DBG(("force %d", force));
5736e94dc5SPeter Avalos 	SSHBUF_TELL("pre-pack");
5836e94dc5SPeter Avalos 	if (buf->off == 0 || buf->readonly || buf->refcount > 1)
5936e94dc5SPeter Avalos 		return;
6036e94dc5SPeter Avalos 	if (force ||
6136e94dc5SPeter Avalos 	    (buf->off >= SSHBUF_PACK_MIN && buf->off >= buf->size / 2)) {
6236e94dc5SPeter Avalos 		memmove(buf->d, buf->d + buf->off, buf->size - buf->off);
6336e94dc5SPeter Avalos 		buf->size -= buf->off;
6436e94dc5SPeter Avalos 		buf->off = 0;
6536e94dc5SPeter Avalos 		SSHBUF_TELL("packed");
6636e94dc5SPeter Avalos 	}
6736e94dc5SPeter Avalos }
6836e94dc5SPeter Avalos 
6936e94dc5SPeter Avalos struct sshbuf *
7036e94dc5SPeter Avalos sshbuf_new(void)
7136e94dc5SPeter Avalos {
7236e94dc5SPeter Avalos 	struct sshbuf *ret;
7336e94dc5SPeter Avalos 
7436e94dc5SPeter Avalos 	if ((ret = calloc(sizeof(*ret), 1)) == NULL)
7536e94dc5SPeter Avalos 		return NULL;
7636e94dc5SPeter Avalos 	ret->alloc = SSHBUF_SIZE_INIT;
7736e94dc5SPeter Avalos 	ret->max_size = SSHBUF_SIZE_MAX;
7836e94dc5SPeter Avalos 	ret->readonly = 0;
7936e94dc5SPeter Avalos 	ret->refcount = 1;
8036e94dc5SPeter Avalos 	ret->parent = NULL;
8136e94dc5SPeter Avalos 	if ((ret->cd = ret->d = calloc(1, ret->alloc)) == NULL) {
8236e94dc5SPeter Avalos 		free(ret);
8336e94dc5SPeter Avalos 		return NULL;
8436e94dc5SPeter Avalos 	}
8536e94dc5SPeter Avalos 	return ret;
8636e94dc5SPeter Avalos }
8736e94dc5SPeter Avalos 
8836e94dc5SPeter Avalos struct sshbuf *
8936e94dc5SPeter Avalos sshbuf_from(const void *blob, size_t len)
9036e94dc5SPeter Avalos {
9136e94dc5SPeter Avalos 	struct sshbuf *ret;
9236e94dc5SPeter Avalos 
9336e94dc5SPeter Avalos 	if (blob == NULL || len > SSHBUF_SIZE_MAX ||
9436e94dc5SPeter Avalos 	    (ret = calloc(sizeof(*ret), 1)) == NULL)
9536e94dc5SPeter Avalos 		return NULL;
9636e94dc5SPeter Avalos 	ret->alloc = ret->size = ret->max_size = len;
9736e94dc5SPeter Avalos 	ret->readonly = 1;
9836e94dc5SPeter Avalos 	ret->refcount = 1;
9936e94dc5SPeter Avalos 	ret->parent = NULL;
10036e94dc5SPeter Avalos 	ret->cd = blob;
10136e94dc5SPeter Avalos 	ret->d = NULL;
10236e94dc5SPeter Avalos 	return ret;
10336e94dc5SPeter Avalos }
10436e94dc5SPeter Avalos 
10536e94dc5SPeter Avalos int
10636e94dc5SPeter Avalos sshbuf_set_parent(struct sshbuf *child, struct sshbuf *parent)
10736e94dc5SPeter Avalos {
10836e94dc5SPeter Avalos 	int r;
10936e94dc5SPeter Avalos 
11036e94dc5SPeter Avalos 	if ((r = sshbuf_check_sanity(child)) != 0 ||
11136e94dc5SPeter Avalos 	    (r = sshbuf_check_sanity(parent)) != 0)
11236e94dc5SPeter Avalos 		return r;
11336e94dc5SPeter Avalos 	child->parent = parent;
11436e94dc5SPeter Avalos 	child->parent->refcount++;
11536e94dc5SPeter Avalos 	return 0;
11636e94dc5SPeter Avalos }
11736e94dc5SPeter Avalos 
11836e94dc5SPeter Avalos struct sshbuf *
11936e94dc5SPeter Avalos sshbuf_fromb(struct sshbuf *buf)
12036e94dc5SPeter Avalos {
12136e94dc5SPeter Avalos 	struct sshbuf *ret;
12236e94dc5SPeter Avalos 
12336e94dc5SPeter Avalos 	if (sshbuf_check_sanity(buf) != 0)
12436e94dc5SPeter Avalos 		return NULL;
12536e94dc5SPeter Avalos 	if ((ret = sshbuf_from(sshbuf_ptr(buf), sshbuf_len(buf))) == NULL)
12636e94dc5SPeter Avalos 		return NULL;
12736e94dc5SPeter Avalos 	if (sshbuf_set_parent(ret, buf) != 0) {
12836e94dc5SPeter Avalos 		sshbuf_free(ret);
12936e94dc5SPeter Avalos 		return NULL;
13036e94dc5SPeter Avalos 	}
13136e94dc5SPeter Avalos 	return ret;
13236e94dc5SPeter Avalos }
13336e94dc5SPeter Avalos 
13436e94dc5SPeter Avalos void
13536e94dc5SPeter Avalos sshbuf_init(struct sshbuf *ret)
13636e94dc5SPeter Avalos {
137*e9778795SPeter Avalos 	explicit_bzero(ret, sizeof(*ret));
13836e94dc5SPeter Avalos 	ret->alloc = SSHBUF_SIZE_INIT;
13936e94dc5SPeter Avalos 	ret->max_size = SSHBUF_SIZE_MAX;
14036e94dc5SPeter Avalos 	ret->readonly = 0;
14136e94dc5SPeter Avalos 	ret->dont_free = 1;
14236e94dc5SPeter Avalos 	ret->refcount = 1;
14336e94dc5SPeter Avalos 	if ((ret->cd = ret->d = calloc(1, ret->alloc)) == NULL)
14436e94dc5SPeter Avalos 		ret->alloc = 0;
14536e94dc5SPeter Avalos }
14636e94dc5SPeter Avalos 
14736e94dc5SPeter Avalos void
14836e94dc5SPeter Avalos sshbuf_free(struct sshbuf *buf)
14936e94dc5SPeter Avalos {
15036e94dc5SPeter Avalos 	int dont_free = 0;
15136e94dc5SPeter Avalos 
15236e94dc5SPeter Avalos 	if (buf == NULL)
15336e94dc5SPeter Avalos 		return;
15436e94dc5SPeter Avalos 	/*
15536e94dc5SPeter Avalos 	 * The following will leak on insane buffers, but this is the safest
15636e94dc5SPeter Avalos 	 * course of action - an invalid pointer or already-freed pointer may
15736e94dc5SPeter Avalos 	 * have been passed to us and continuing to scribble over memory would
15836e94dc5SPeter Avalos 	 * be bad.
15936e94dc5SPeter Avalos 	 */
16036e94dc5SPeter Avalos 	if (sshbuf_check_sanity(buf) != 0)
16136e94dc5SPeter Avalos 		return;
16236e94dc5SPeter Avalos 	/*
16336e94dc5SPeter Avalos 	 * If we are a child, the free our parent to decrement its reference
16436e94dc5SPeter Avalos 	 * count and possibly free it.
16536e94dc5SPeter Avalos 	 */
16636e94dc5SPeter Avalos 	sshbuf_free(buf->parent);
16736e94dc5SPeter Avalos 	buf->parent = NULL;
16836e94dc5SPeter Avalos 	/*
16936e94dc5SPeter Avalos 	 * If we are a parent with still-extant children, then don't free just
17036e94dc5SPeter Avalos 	 * yet. The last child's call to sshbuf_free should decrement our
17136e94dc5SPeter Avalos 	 * refcount to 0 and trigger the actual free.
17236e94dc5SPeter Avalos 	 */
17336e94dc5SPeter Avalos 	buf->refcount--;
17436e94dc5SPeter Avalos 	if (buf->refcount > 0)
17536e94dc5SPeter Avalos 		return;
17636e94dc5SPeter Avalos 	dont_free = buf->dont_free;
17736e94dc5SPeter Avalos 	if (!buf->readonly) {
178*e9778795SPeter Avalos 		explicit_bzero(buf->d, buf->alloc);
17936e94dc5SPeter Avalos 		free(buf->d);
18036e94dc5SPeter Avalos 	}
181*e9778795SPeter Avalos 	explicit_bzero(buf, sizeof(*buf));
18236e94dc5SPeter Avalos 	if (!dont_free)
18336e94dc5SPeter Avalos 		free(buf);
18436e94dc5SPeter Avalos }
18536e94dc5SPeter Avalos 
18636e94dc5SPeter Avalos void
18736e94dc5SPeter Avalos sshbuf_reset(struct sshbuf *buf)
18836e94dc5SPeter Avalos {
18936e94dc5SPeter Avalos 	u_char *d;
19036e94dc5SPeter Avalos 
19136e94dc5SPeter Avalos 	if (buf->readonly || buf->refcount > 1) {
19236e94dc5SPeter Avalos 		/* Nonsensical. Just make buffer appear empty */
19336e94dc5SPeter Avalos 		buf->off = buf->size;
19436e94dc5SPeter Avalos 		return;
19536e94dc5SPeter Avalos 	}
19636e94dc5SPeter Avalos 	if (sshbuf_check_sanity(buf) == 0)
197*e9778795SPeter Avalos 		explicit_bzero(buf->d, buf->alloc);
19836e94dc5SPeter Avalos 	buf->off = buf->size = 0;
19936e94dc5SPeter Avalos 	if (buf->alloc != SSHBUF_SIZE_INIT) {
20036e94dc5SPeter Avalos 		if ((d = realloc(buf->d, SSHBUF_SIZE_INIT)) != NULL) {
20136e94dc5SPeter Avalos 			buf->cd = buf->d = d;
20236e94dc5SPeter Avalos 			buf->alloc = SSHBUF_SIZE_INIT;
20336e94dc5SPeter Avalos 		}
20436e94dc5SPeter Avalos 	}
20536e94dc5SPeter Avalos }
20636e94dc5SPeter Avalos 
20736e94dc5SPeter Avalos size_t
20836e94dc5SPeter Avalos sshbuf_max_size(const struct sshbuf *buf)
20936e94dc5SPeter Avalos {
21036e94dc5SPeter Avalos 	return buf->max_size;
21136e94dc5SPeter Avalos }
21236e94dc5SPeter Avalos 
21336e94dc5SPeter Avalos size_t
21436e94dc5SPeter Avalos sshbuf_alloc(const struct sshbuf *buf)
21536e94dc5SPeter Avalos {
21636e94dc5SPeter Avalos 	return buf->alloc;
21736e94dc5SPeter Avalos }
21836e94dc5SPeter Avalos 
21936e94dc5SPeter Avalos const struct sshbuf *
22036e94dc5SPeter Avalos sshbuf_parent(const struct sshbuf *buf)
22136e94dc5SPeter Avalos {
22236e94dc5SPeter Avalos 	return buf->parent;
22336e94dc5SPeter Avalos }
22436e94dc5SPeter Avalos 
22536e94dc5SPeter Avalos u_int
22636e94dc5SPeter Avalos sshbuf_refcount(const struct sshbuf *buf)
22736e94dc5SPeter Avalos {
22836e94dc5SPeter Avalos 	return buf->refcount;
22936e94dc5SPeter Avalos }
23036e94dc5SPeter Avalos 
23136e94dc5SPeter Avalos int
23236e94dc5SPeter Avalos sshbuf_set_max_size(struct sshbuf *buf, size_t max_size)
23336e94dc5SPeter Avalos {
23436e94dc5SPeter Avalos 	size_t rlen;
23536e94dc5SPeter Avalos 	u_char *dp;
23636e94dc5SPeter Avalos 	int r;
23736e94dc5SPeter Avalos 
23836e94dc5SPeter Avalos 	SSHBUF_DBG(("set max buf = %p len = %zu", buf, max_size));
23936e94dc5SPeter Avalos 	if ((r = sshbuf_check_sanity(buf)) != 0)
24036e94dc5SPeter Avalos 		return r;
24136e94dc5SPeter Avalos 	if (max_size == buf->max_size)
24236e94dc5SPeter Avalos 		return 0;
24336e94dc5SPeter Avalos 	if (buf->readonly || buf->refcount > 1)
24436e94dc5SPeter Avalos 		return SSH_ERR_BUFFER_READ_ONLY;
24536e94dc5SPeter Avalos 	if (max_size > SSHBUF_SIZE_MAX)
24636e94dc5SPeter Avalos 		return SSH_ERR_NO_BUFFER_SPACE;
24736e94dc5SPeter Avalos 	/* pack and realloc if necessary */
24836e94dc5SPeter Avalos 	sshbuf_maybe_pack(buf, max_size < buf->size);
24936e94dc5SPeter Avalos 	if (max_size < buf->alloc && max_size > buf->size) {
25036e94dc5SPeter Avalos 		if (buf->size < SSHBUF_SIZE_INIT)
25136e94dc5SPeter Avalos 			rlen = SSHBUF_SIZE_INIT;
25236e94dc5SPeter Avalos 		else
25336e94dc5SPeter Avalos 			rlen = roundup(buf->size, SSHBUF_SIZE_INC);
25436e94dc5SPeter Avalos 		if (rlen > max_size)
25536e94dc5SPeter Avalos 			rlen = max_size;
256*e9778795SPeter Avalos 		explicit_bzero(buf->d + buf->size, buf->alloc - buf->size);
25736e94dc5SPeter Avalos 		SSHBUF_DBG(("new alloc = %zu", rlen));
25836e94dc5SPeter Avalos 		if ((dp = realloc(buf->d, rlen)) == NULL)
25936e94dc5SPeter Avalos 			return SSH_ERR_ALLOC_FAIL;
26036e94dc5SPeter Avalos 		buf->cd = buf->d = dp;
26136e94dc5SPeter Avalos 		buf->alloc = rlen;
26236e94dc5SPeter Avalos 	}
26336e94dc5SPeter Avalos 	SSHBUF_TELL("new-max");
26436e94dc5SPeter Avalos 	if (max_size < buf->alloc)
26536e94dc5SPeter Avalos 		return SSH_ERR_NO_BUFFER_SPACE;
26636e94dc5SPeter Avalos 	buf->max_size = max_size;
26736e94dc5SPeter Avalos 	return 0;
26836e94dc5SPeter Avalos }
26936e94dc5SPeter Avalos 
27036e94dc5SPeter Avalos size_t
27136e94dc5SPeter Avalos sshbuf_len(const struct sshbuf *buf)
27236e94dc5SPeter Avalos {
27336e94dc5SPeter Avalos 	if (sshbuf_check_sanity(buf) != 0)
27436e94dc5SPeter Avalos 		return 0;
27536e94dc5SPeter Avalos 	return buf->size - buf->off;
27636e94dc5SPeter Avalos }
27736e94dc5SPeter Avalos 
27836e94dc5SPeter Avalos size_t
27936e94dc5SPeter Avalos sshbuf_avail(const struct sshbuf *buf)
28036e94dc5SPeter Avalos {
28136e94dc5SPeter Avalos 	if (sshbuf_check_sanity(buf) != 0 || buf->readonly || buf->refcount > 1)
28236e94dc5SPeter Avalos 		return 0;
28336e94dc5SPeter Avalos 	return buf->max_size - (buf->size - buf->off);
28436e94dc5SPeter Avalos }
28536e94dc5SPeter Avalos 
28636e94dc5SPeter Avalos const u_char *
28736e94dc5SPeter Avalos sshbuf_ptr(const struct sshbuf *buf)
28836e94dc5SPeter Avalos {
28936e94dc5SPeter Avalos 	if (sshbuf_check_sanity(buf) != 0)
29036e94dc5SPeter Avalos 		return NULL;
29136e94dc5SPeter Avalos 	return buf->cd + buf->off;
29236e94dc5SPeter Avalos }
29336e94dc5SPeter Avalos 
29436e94dc5SPeter Avalos u_char *
29536e94dc5SPeter Avalos sshbuf_mutable_ptr(const struct sshbuf *buf)
29636e94dc5SPeter Avalos {
29736e94dc5SPeter Avalos 	if (sshbuf_check_sanity(buf) != 0 || buf->readonly || buf->refcount > 1)
29836e94dc5SPeter Avalos 		return NULL;
29936e94dc5SPeter Avalos 	return buf->d + buf->off;
30036e94dc5SPeter Avalos }
30136e94dc5SPeter Avalos 
30236e94dc5SPeter Avalos int
30336e94dc5SPeter Avalos sshbuf_check_reserve(const struct sshbuf *buf, size_t len)
30436e94dc5SPeter Avalos {
30536e94dc5SPeter Avalos 	int r;
30636e94dc5SPeter Avalos 
30736e94dc5SPeter Avalos 	if ((r = sshbuf_check_sanity(buf)) != 0)
30836e94dc5SPeter Avalos 		return r;
30936e94dc5SPeter Avalos 	if (buf->readonly || buf->refcount > 1)
31036e94dc5SPeter Avalos 		return SSH_ERR_BUFFER_READ_ONLY;
31136e94dc5SPeter Avalos 	SSHBUF_TELL("check");
31236e94dc5SPeter Avalos 	/* Check that len is reasonable and that max_size + available < len */
31336e94dc5SPeter Avalos 	if (len > buf->max_size || buf->max_size - len < buf->size - buf->off)
31436e94dc5SPeter Avalos 		return SSH_ERR_NO_BUFFER_SPACE;
31536e94dc5SPeter Avalos 	return 0;
31636e94dc5SPeter Avalos }
31736e94dc5SPeter Avalos 
31836e94dc5SPeter Avalos int
31936e94dc5SPeter Avalos sshbuf_reserve(struct sshbuf *buf, size_t len, u_char **dpp)
32036e94dc5SPeter Avalos {
32136e94dc5SPeter Avalos 	size_t rlen, need;
32236e94dc5SPeter Avalos 	u_char *dp;
32336e94dc5SPeter Avalos 	int r;
32436e94dc5SPeter Avalos 
32536e94dc5SPeter Avalos 	if (dpp != NULL)
32636e94dc5SPeter Avalos 		*dpp = NULL;
32736e94dc5SPeter Avalos 
32836e94dc5SPeter Avalos 	SSHBUF_DBG(("reserve buf = %p len = %zu", buf, len));
32936e94dc5SPeter Avalos 	if ((r = sshbuf_check_reserve(buf, len)) != 0)
33036e94dc5SPeter Avalos 		return r;
33136e94dc5SPeter Avalos 	/*
33236e94dc5SPeter Avalos 	 * If the requested allocation appended would push us past max_size
33336e94dc5SPeter Avalos 	 * then pack the buffer, zeroing buf->off.
33436e94dc5SPeter Avalos 	 */
33536e94dc5SPeter Avalos 	sshbuf_maybe_pack(buf, buf->size + len > buf->max_size);
33636e94dc5SPeter Avalos 	SSHBUF_TELL("reserve");
33736e94dc5SPeter Avalos 	if (len + buf->size > buf->alloc) {
33836e94dc5SPeter Avalos 		/*
33936e94dc5SPeter Avalos 		 * Prefer to alloc in SSHBUF_SIZE_INC units, but
34036e94dc5SPeter Avalos 		 * allocate less if doing so would overflow max_size.
34136e94dc5SPeter Avalos 		 */
34236e94dc5SPeter Avalos 		need = len + buf->size - buf->alloc;
34336e94dc5SPeter Avalos 		rlen = roundup(buf->alloc + need, SSHBUF_SIZE_INC);
34436e94dc5SPeter Avalos 		SSHBUF_DBG(("need %zu initial rlen %zu", need, rlen));
34536e94dc5SPeter Avalos 		if (rlen > buf->max_size)
34636e94dc5SPeter Avalos 			rlen = buf->alloc + need;
34736e94dc5SPeter Avalos 		SSHBUF_DBG(("adjusted rlen %zu", rlen));
34836e94dc5SPeter Avalos 		if ((dp = realloc(buf->d, rlen)) == NULL) {
34936e94dc5SPeter Avalos 			SSHBUF_DBG(("realloc fail"));
35036e94dc5SPeter Avalos 			if (dpp != NULL)
35136e94dc5SPeter Avalos 				*dpp = NULL;
35236e94dc5SPeter Avalos 			return SSH_ERR_ALLOC_FAIL;
35336e94dc5SPeter Avalos 		}
35436e94dc5SPeter Avalos 		buf->alloc = rlen;
35536e94dc5SPeter Avalos 		buf->cd = buf->d = dp;
35636e94dc5SPeter Avalos 		if ((r = sshbuf_check_reserve(buf, len)) < 0) {
35736e94dc5SPeter Avalos 			/* shouldn't fail */
35836e94dc5SPeter Avalos 			if (dpp != NULL)
35936e94dc5SPeter Avalos 				*dpp = NULL;
36036e94dc5SPeter Avalos 			return r;
36136e94dc5SPeter Avalos 		}
36236e94dc5SPeter Avalos 	}
36336e94dc5SPeter Avalos 	dp = buf->d + buf->size;
36436e94dc5SPeter Avalos 	buf->size += len;
36536e94dc5SPeter Avalos 	SSHBUF_TELL("done");
36636e94dc5SPeter Avalos 	if (dpp != NULL)
36736e94dc5SPeter Avalos 		*dpp = dp;
36836e94dc5SPeter Avalos 	return 0;
36936e94dc5SPeter Avalos }
37036e94dc5SPeter Avalos 
37136e94dc5SPeter Avalos int
37236e94dc5SPeter Avalos sshbuf_consume(struct sshbuf *buf, size_t len)
37336e94dc5SPeter Avalos {
37436e94dc5SPeter Avalos 	int r;
37536e94dc5SPeter Avalos 
37636e94dc5SPeter Avalos 	SSHBUF_DBG(("len = %zu", len));
37736e94dc5SPeter Avalos 	if ((r = sshbuf_check_sanity(buf)) != 0)
37836e94dc5SPeter Avalos 		return r;
37936e94dc5SPeter Avalos 	if (len == 0)
38036e94dc5SPeter Avalos 		return 0;
38136e94dc5SPeter Avalos 	if (len > sshbuf_len(buf))
38236e94dc5SPeter Avalos 		return SSH_ERR_MESSAGE_INCOMPLETE;
38336e94dc5SPeter Avalos 	buf->off += len;
38436e94dc5SPeter Avalos 	SSHBUF_TELL("done");
38536e94dc5SPeter Avalos 	return 0;
38636e94dc5SPeter Avalos }
38736e94dc5SPeter Avalos 
38836e94dc5SPeter Avalos int
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