1*ea547eb0Sdjm@openbsd.org /*	$OpenBSD: sshbuf-getput-basic.c,v 1.11 2020/06/05 03:25:35 djm Exp $	*/
205e82c3bSDamien Miller /*
305e82c3bSDamien Miller  * Copyright (c) 2011 Damien Miller
405e82c3bSDamien Miller  *
505e82c3bSDamien Miller  * Permission to use, copy, modify, and distribute this software for any
605e82c3bSDamien Miller  * purpose with or without fee is hereby granted, provided that the above
705e82c3bSDamien Miller  * copyright notice and this permission notice appear in all copies.
805e82c3bSDamien Miller  *
905e82c3bSDamien Miller  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1005e82c3bSDamien Miller  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1105e82c3bSDamien Miller  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1205e82c3bSDamien Miller  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1305e82c3bSDamien Miller  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1405e82c3bSDamien Miller  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1505e82c3bSDamien Miller  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1605e82c3bSDamien Miller  */
1705e82c3bSDamien Miller 
18e5b9f0f2SDamien Miller #define SSHBUF_INTERNAL
1905e82c3bSDamien Miller #include "includes.h"
2005e82c3bSDamien Miller 
2105e82c3bSDamien Miller #include <sys/types.h>
229816fc5dSdtucker@openbsd.org 
239816fc5dSdtucker@openbsd.org #include <stdarg.h>
2405e82c3bSDamien Miller #include <stdlib.h>
2505e82c3bSDamien Miller #include <stdio.h>
2605e82c3bSDamien Miller #include <string.h>
27cfc1897aSDamien Miller #ifdef HAVE_STDINT_H
28be02d7cbSdjm@openbsd.org # include <stdint.h>
29cfc1897aSDamien Miller #endif
3005e82c3bSDamien Miller 
3105e82c3bSDamien Miller #include "ssherr.h"
3205e82c3bSDamien Miller #include "sshbuf.h"
3305e82c3bSDamien Miller 
3405e82c3bSDamien Miller int
sshbuf_get(struct sshbuf * buf,void * v,size_t len)3505e82c3bSDamien Miller sshbuf_get(struct sshbuf *buf, void *v, size_t len)
3605e82c3bSDamien Miller {
3705e82c3bSDamien Miller 	const u_char *p = sshbuf_ptr(buf);
3805e82c3bSDamien Miller 	int r;
3905e82c3bSDamien Miller 
4005e82c3bSDamien Miller 	if ((r = sshbuf_consume(buf, len)) < 0)
4105e82c3bSDamien Miller 		return r;
42a7f49dcbSdjm@openbsd.org 	if (v != NULL && len != 0)
4305e82c3bSDamien Miller 		memcpy(v, p, len);
4405e82c3bSDamien Miller 	return 0;
4505e82c3bSDamien Miller }
4605e82c3bSDamien Miller 
4705e82c3bSDamien Miller int
sshbuf_get_u64(struct sshbuf * buf,u_int64_t * valp)4805e82c3bSDamien Miller sshbuf_get_u64(struct sshbuf *buf, u_int64_t *valp)
4905e82c3bSDamien Miller {
5005e82c3bSDamien Miller 	const u_char *p = sshbuf_ptr(buf);
5105e82c3bSDamien Miller 	int r;
5205e82c3bSDamien Miller 
5305e82c3bSDamien Miller 	if ((r = sshbuf_consume(buf, 8)) < 0)
5405e82c3bSDamien Miller 		return r;
5505e82c3bSDamien Miller 	if (valp != NULL)
5605e82c3bSDamien Miller 		*valp = PEEK_U64(p);
5705e82c3bSDamien Miller 	return 0;
5805e82c3bSDamien Miller }
5905e82c3bSDamien Miller 
6005e82c3bSDamien Miller int
sshbuf_get_u32(struct sshbuf * buf,u_int32_t * valp)6105e82c3bSDamien Miller sshbuf_get_u32(struct sshbuf *buf, u_int32_t *valp)
6205e82c3bSDamien Miller {
6305e82c3bSDamien Miller 	const u_char *p = sshbuf_ptr(buf);
6405e82c3bSDamien Miller 	int r;
6505e82c3bSDamien Miller 
6605e82c3bSDamien Miller 	if ((r = sshbuf_consume(buf, 4)) < 0)
6705e82c3bSDamien Miller 		return r;
6805e82c3bSDamien Miller 	if (valp != NULL)
6905e82c3bSDamien Miller 		*valp = PEEK_U32(p);
7005e82c3bSDamien Miller 	return 0;
7105e82c3bSDamien Miller }
7205e82c3bSDamien Miller 
7305e82c3bSDamien Miller int
sshbuf_get_u16(struct sshbuf * buf,u_int16_t * valp)7405e82c3bSDamien Miller sshbuf_get_u16(struct sshbuf *buf, u_int16_t *valp)
7505e82c3bSDamien Miller {
7605e82c3bSDamien Miller 	const u_char *p = sshbuf_ptr(buf);
7705e82c3bSDamien Miller 	int r;
7805e82c3bSDamien Miller 
7905e82c3bSDamien Miller 	if ((r = sshbuf_consume(buf, 2)) < 0)
8005e82c3bSDamien Miller 		return r;
8105e82c3bSDamien Miller 	if (valp != NULL)
8205e82c3bSDamien Miller 		*valp = PEEK_U16(p);
8305e82c3bSDamien Miller 	return 0;
8405e82c3bSDamien Miller }
8505e82c3bSDamien Miller 
8605e82c3bSDamien Miller int
sshbuf_get_u8(struct sshbuf * buf,u_char * valp)8705e82c3bSDamien Miller sshbuf_get_u8(struct sshbuf *buf, u_char *valp)
8805e82c3bSDamien Miller {
8905e82c3bSDamien Miller 	const u_char *p = sshbuf_ptr(buf);
9005e82c3bSDamien Miller 	int r;
9105e82c3bSDamien Miller 
9205e82c3bSDamien Miller 	if ((r = sshbuf_consume(buf, 1)) < 0)
9305e82c3bSDamien Miller 		return r;
9405e82c3bSDamien Miller 	if (valp != NULL)
9505e82c3bSDamien Miller 		*valp = (u_int8_t)*p;
9605e82c3bSDamien Miller 	return 0;
9705e82c3bSDamien Miller }
9805e82c3bSDamien Miller 
99101d1647Sdjm@openbsd.org static int
check_offset(const struct sshbuf * buf,int wr,size_t offset,size_t len)100101d1647Sdjm@openbsd.org check_offset(const struct sshbuf *buf, int wr, size_t offset, size_t len)
101101d1647Sdjm@openbsd.org {
102101d1647Sdjm@openbsd.org 	if (sshbuf_ptr(buf) == NULL) /* calls sshbuf_check_sanity() */
103101d1647Sdjm@openbsd.org 		return SSH_ERR_INTERNAL_ERROR;
104101d1647Sdjm@openbsd.org 	if (offset >= SIZE_MAX - len)
105101d1647Sdjm@openbsd.org 		return SSH_ERR_INVALID_ARGUMENT;
106101d1647Sdjm@openbsd.org 	if (offset + len > sshbuf_len(buf)) {
107101d1647Sdjm@openbsd.org 		return wr ?
108101d1647Sdjm@openbsd.org 		    SSH_ERR_NO_BUFFER_SPACE : SSH_ERR_MESSAGE_INCOMPLETE;
109101d1647Sdjm@openbsd.org 	}
110101d1647Sdjm@openbsd.org 	return 0;
111101d1647Sdjm@openbsd.org }
112101d1647Sdjm@openbsd.org 
113101d1647Sdjm@openbsd.org static int
check_roffset(const struct sshbuf * buf,size_t offset,size_t len,const u_char ** p)114101d1647Sdjm@openbsd.org check_roffset(const struct sshbuf *buf, size_t offset, size_t len,
115101d1647Sdjm@openbsd.org     const u_char **p)
116101d1647Sdjm@openbsd.org {
117101d1647Sdjm@openbsd.org 	int r;
118101d1647Sdjm@openbsd.org 
119101d1647Sdjm@openbsd.org 	*p = NULL;
120101d1647Sdjm@openbsd.org 	if ((r = check_offset(buf, 0, offset, len)) != 0)
121101d1647Sdjm@openbsd.org 		return r;
122101d1647Sdjm@openbsd.org 	*p = sshbuf_ptr(buf) + offset;
123101d1647Sdjm@openbsd.org 	return 0;
124101d1647Sdjm@openbsd.org }
125101d1647Sdjm@openbsd.org 
126101d1647Sdjm@openbsd.org int
sshbuf_peek_u64(const struct sshbuf * buf,size_t offset,u_int64_t * valp)127101d1647Sdjm@openbsd.org sshbuf_peek_u64(const struct sshbuf *buf, size_t offset, u_int64_t *valp)
128101d1647Sdjm@openbsd.org {
129101d1647Sdjm@openbsd.org 	const u_char *p = NULL;
130101d1647Sdjm@openbsd.org 	int r;
131101d1647Sdjm@openbsd.org 
132101d1647Sdjm@openbsd.org 	if (valp != NULL)
133101d1647Sdjm@openbsd.org 		*valp = 0;
134101d1647Sdjm@openbsd.org 	if ((r = check_roffset(buf, offset, 8, &p)) != 0)
135101d1647Sdjm@openbsd.org 		return r;
136101d1647Sdjm@openbsd.org 	if (valp != NULL)
137101d1647Sdjm@openbsd.org 		*valp = PEEK_U64(p);
138101d1647Sdjm@openbsd.org 	return 0;
139101d1647Sdjm@openbsd.org }
140101d1647Sdjm@openbsd.org 
141101d1647Sdjm@openbsd.org int
sshbuf_peek_u32(const struct sshbuf * buf,size_t offset,u_int32_t * valp)142101d1647Sdjm@openbsd.org sshbuf_peek_u32(const struct sshbuf *buf, size_t offset, u_int32_t *valp)
143101d1647Sdjm@openbsd.org {
144101d1647Sdjm@openbsd.org 	const u_char *p = NULL;
145101d1647Sdjm@openbsd.org 	int r;
146101d1647Sdjm@openbsd.org 
147101d1647Sdjm@openbsd.org 	if (valp != NULL)
148101d1647Sdjm@openbsd.org 		*valp = 0;
149101d1647Sdjm@openbsd.org 	if ((r = check_roffset(buf, offset, 4, &p)) != 0)
150101d1647Sdjm@openbsd.org 		return r;
151101d1647Sdjm@openbsd.org 	if (valp != NULL)
152101d1647Sdjm@openbsd.org 		*valp = PEEK_U32(p);
153101d1647Sdjm@openbsd.org 	return 0;
154101d1647Sdjm@openbsd.org }
155101d1647Sdjm@openbsd.org 
156101d1647Sdjm@openbsd.org int
sshbuf_peek_u16(const struct sshbuf * buf,size_t offset,u_int16_t * valp)157101d1647Sdjm@openbsd.org sshbuf_peek_u16(const struct sshbuf *buf, size_t offset, u_int16_t *valp)
158101d1647Sdjm@openbsd.org {
159101d1647Sdjm@openbsd.org 	const u_char *p = NULL;
160101d1647Sdjm@openbsd.org 	int r;
161101d1647Sdjm@openbsd.org 
162101d1647Sdjm@openbsd.org 	if (valp != NULL)
163101d1647Sdjm@openbsd.org 		*valp = 0;
164101d1647Sdjm@openbsd.org 	if ((r = check_roffset(buf, offset, 2, &p)) != 0)
165101d1647Sdjm@openbsd.org 		return r;
166101d1647Sdjm@openbsd.org 	if (valp != NULL)
167101d1647Sdjm@openbsd.org 		*valp = PEEK_U16(p);
168101d1647Sdjm@openbsd.org 	return 0;
169101d1647Sdjm@openbsd.org }
170101d1647Sdjm@openbsd.org 
171101d1647Sdjm@openbsd.org int
sshbuf_peek_u8(const struct sshbuf * buf,size_t offset,u_char * valp)172101d1647Sdjm@openbsd.org sshbuf_peek_u8(const struct sshbuf *buf, size_t offset, u_char *valp)
173101d1647Sdjm@openbsd.org {
174101d1647Sdjm@openbsd.org 	const u_char *p = NULL;
175101d1647Sdjm@openbsd.org 	int r;
176101d1647Sdjm@openbsd.org 
177101d1647Sdjm@openbsd.org 	if (valp != NULL)
178101d1647Sdjm@openbsd.org 		*valp = 0;
179101d1647Sdjm@openbsd.org 	if ((r = check_roffset(buf, offset, 1, &p)) != 0)
180101d1647Sdjm@openbsd.org 		return r;
181101d1647Sdjm@openbsd.org 	if (valp != NULL)
182101d1647Sdjm@openbsd.org 		*valp = *p;
183101d1647Sdjm@openbsd.org 	return 0;
184101d1647Sdjm@openbsd.org }
185101d1647Sdjm@openbsd.org 
18605e82c3bSDamien Miller int
sshbuf_get_string(struct sshbuf * buf,u_char ** valp,size_t * lenp)18705e82c3bSDamien Miller sshbuf_get_string(struct sshbuf *buf, u_char **valp, size_t *lenp)
18805e82c3bSDamien Miller {
18905e82c3bSDamien Miller 	const u_char *val;
19005e82c3bSDamien Miller 	size_t len;
19105e82c3bSDamien Miller 	int r;
19205e82c3bSDamien Miller 
19305e82c3bSDamien Miller 	if (valp != NULL)
19405e82c3bSDamien Miller 		*valp = NULL;
19505e82c3bSDamien Miller 	if (lenp != NULL)
19605e82c3bSDamien Miller 		*lenp = 0;
19705e82c3bSDamien Miller 	if ((r = sshbuf_get_string_direct(buf, &val, &len)) < 0)
19805e82c3bSDamien Miller 		return r;
19905e82c3bSDamien Miller 	if (valp != NULL) {
20005e82c3bSDamien Miller 		if ((*valp = malloc(len + 1)) == NULL) {
20105e82c3bSDamien Miller 			SSHBUF_DBG(("SSH_ERR_ALLOC_FAIL"));
20205e82c3bSDamien Miller 			return SSH_ERR_ALLOC_FAIL;
20305e82c3bSDamien Miller 		}
204a7f49dcbSdjm@openbsd.org 		if (len != 0)
20505e82c3bSDamien Miller 			memcpy(*valp, val, len);
20605e82c3bSDamien Miller 		(*valp)[len] = '\0';
20705e82c3bSDamien Miller 	}
20805e82c3bSDamien Miller 	if (lenp != NULL)
20905e82c3bSDamien Miller 		*lenp = len;
21005e82c3bSDamien Miller 	return 0;
21105e82c3bSDamien Miller }
21205e82c3bSDamien Miller 
21305e82c3bSDamien Miller int
sshbuf_get_string_direct(struct sshbuf * buf,const u_char ** valp,size_t * lenp)21405e82c3bSDamien Miller sshbuf_get_string_direct(struct sshbuf *buf, const u_char **valp, size_t *lenp)
21505e82c3bSDamien Miller {
21605e82c3bSDamien Miller 	size_t len;
21705e82c3bSDamien Miller 	const u_char *p;
21805e82c3bSDamien Miller 	int r;
21905e82c3bSDamien Miller 
22005e82c3bSDamien Miller 	if (valp != NULL)
22105e82c3bSDamien Miller 		*valp = NULL;
22205e82c3bSDamien Miller 	if (lenp != NULL)
22305e82c3bSDamien Miller 		*lenp = 0;
22405e82c3bSDamien Miller 	if ((r = sshbuf_peek_string_direct(buf, &p, &len)) < 0)
22505e82c3bSDamien Miller 		return r;
2267d6c0362Smmcc@openbsd.org 	if (valp != NULL)
22705e82c3bSDamien Miller 		*valp = p;
22805e82c3bSDamien Miller 	if (lenp != NULL)
22905e82c3bSDamien Miller 		*lenp = len;
23005e82c3bSDamien Miller 	if (sshbuf_consume(buf, len + 4) != 0) {
23105e82c3bSDamien Miller 		/* Shouldn't happen */
23205e82c3bSDamien Miller 		SSHBUF_DBG(("SSH_ERR_INTERNAL_ERROR"));
23305e82c3bSDamien Miller 		SSHBUF_ABORT();
23405e82c3bSDamien Miller 		return SSH_ERR_INTERNAL_ERROR;
23505e82c3bSDamien Miller 	}
23605e82c3bSDamien Miller 	return 0;
23705e82c3bSDamien Miller }
23805e82c3bSDamien Miller 
23905e82c3bSDamien Miller int
sshbuf_peek_string_direct(const struct sshbuf * buf,const u_char ** valp,size_t * lenp)24005e82c3bSDamien Miller sshbuf_peek_string_direct(const struct sshbuf *buf, const u_char **valp,
24105e82c3bSDamien Miller     size_t *lenp)
24205e82c3bSDamien Miller {
24305e82c3bSDamien Miller 	u_int32_t len;
24405e82c3bSDamien Miller 	const u_char *p = sshbuf_ptr(buf);
24505e82c3bSDamien Miller 
24605e82c3bSDamien Miller 	if (valp != NULL)
24705e82c3bSDamien Miller 		*valp = NULL;
24805e82c3bSDamien Miller 	if (lenp != NULL)
24905e82c3bSDamien Miller 		*lenp = 0;
25005e82c3bSDamien Miller 	if (sshbuf_len(buf) < 4) {
25105e82c3bSDamien Miller 		SSHBUF_DBG(("SSH_ERR_MESSAGE_INCOMPLETE"));
25205e82c3bSDamien Miller 		return SSH_ERR_MESSAGE_INCOMPLETE;
25305e82c3bSDamien Miller 	}
25405e82c3bSDamien Miller 	len = PEEK_U32(p);
25505e82c3bSDamien Miller 	if (len > SSHBUF_SIZE_MAX - 4) {
25605e82c3bSDamien Miller 		SSHBUF_DBG(("SSH_ERR_STRING_TOO_LARGE"));
25705e82c3bSDamien Miller 		return SSH_ERR_STRING_TOO_LARGE;
25805e82c3bSDamien Miller 	}
25905e82c3bSDamien Miller 	if (sshbuf_len(buf) - 4 < len) {
26005e82c3bSDamien Miller 		SSHBUF_DBG(("SSH_ERR_MESSAGE_INCOMPLETE"));
26105e82c3bSDamien Miller 		return SSH_ERR_MESSAGE_INCOMPLETE;
26205e82c3bSDamien Miller 	}
2637d6c0362Smmcc@openbsd.org 	if (valp != NULL)
26405e82c3bSDamien Miller 		*valp = p + 4;
26505e82c3bSDamien Miller 	if (lenp != NULL)
26605e82c3bSDamien Miller 		*lenp = len;
26705e82c3bSDamien Miller 	return 0;
26805e82c3bSDamien Miller }
26905e82c3bSDamien Miller 
27005e82c3bSDamien Miller int
sshbuf_get_cstring(struct sshbuf * buf,char ** valp,size_t * lenp)27105e82c3bSDamien Miller sshbuf_get_cstring(struct sshbuf *buf, char **valp, size_t *lenp)
27205e82c3bSDamien Miller {
27305e82c3bSDamien Miller 	size_t len;
27405e82c3bSDamien Miller 	const u_char *p, *z;
27505e82c3bSDamien Miller 	int r;
27605e82c3bSDamien Miller 
27705e82c3bSDamien Miller 	if (valp != NULL)
27805e82c3bSDamien Miller 		*valp = NULL;
27905e82c3bSDamien Miller 	if (lenp != NULL)
28005e82c3bSDamien Miller 		*lenp = 0;
28105e82c3bSDamien Miller 	if ((r = sshbuf_peek_string_direct(buf, &p, &len)) != 0)
28205e82c3bSDamien Miller 		return r;
28305e82c3bSDamien Miller 	/* Allow a \0 only at the end of the string */
28405e82c3bSDamien Miller 	if (len > 0 &&
28505e82c3bSDamien Miller 	    (z = memchr(p , '\0', len)) != NULL && z < p + len - 1) {
28605e82c3bSDamien Miller 		SSHBUF_DBG(("SSH_ERR_INVALID_FORMAT"));
28705e82c3bSDamien Miller 		return SSH_ERR_INVALID_FORMAT;
28805e82c3bSDamien Miller 	}
28905e82c3bSDamien Miller 	if ((r = sshbuf_skip_string(buf)) != 0)
29005e82c3bSDamien Miller 		return -1;
29105e82c3bSDamien Miller 	if (valp != NULL) {
29205e82c3bSDamien Miller 		if ((*valp = malloc(len + 1)) == NULL) {
29305e82c3bSDamien Miller 			SSHBUF_DBG(("SSH_ERR_ALLOC_FAIL"));
29405e82c3bSDamien Miller 			return SSH_ERR_ALLOC_FAIL;
29505e82c3bSDamien Miller 		}
296a7f49dcbSdjm@openbsd.org 		if (len != 0)
29705e82c3bSDamien Miller 			memcpy(*valp, p, len);
29805e82c3bSDamien Miller 		(*valp)[len] = '\0';
29905e82c3bSDamien Miller 	}
30005e82c3bSDamien Miller 	if (lenp != NULL)
30105e82c3bSDamien Miller 		*lenp = (size_t)len;
30205e82c3bSDamien Miller 	return 0;
30305e82c3bSDamien Miller }
30405e82c3bSDamien Miller 
30505e82c3bSDamien Miller int
sshbuf_get_stringb(struct sshbuf * buf,struct sshbuf * v)30605e82c3bSDamien Miller sshbuf_get_stringb(struct sshbuf *buf, struct sshbuf *v)
30705e82c3bSDamien Miller {
30805e82c3bSDamien Miller 	u_int32_t len;
30905e82c3bSDamien Miller 	u_char *p;
31005e82c3bSDamien Miller 	int r;
31105e82c3bSDamien Miller 
31205e82c3bSDamien Miller 	/*
31305e82c3bSDamien Miller 	 * Use sshbuf_peek_string_direct() to figure out if there is
31405e82c3bSDamien Miller 	 * a complete string in 'buf' and copy the string directly
31505e82c3bSDamien Miller 	 * into 'v'.
31605e82c3bSDamien Miller 	 */
31705e82c3bSDamien Miller 	if ((r = sshbuf_peek_string_direct(buf, NULL, NULL)) != 0 ||
31805e82c3bSDamien Miller 	    (r = sshbuf_get_u32(buf, &len)) != 0 ||
31905e82c3bSDamien Miller 	    (r = sshbuf_reserve(v, len, &p)) != 0 ||
32005e82c3bSDamien Miller 	    (r = sshbuf_get(buf, p, len)) != 0)
32105e82c3bSDamien Miller 		return r;
32205e82c3bSDamien Miller 	return 0;
32305e82c3bSDamien Miller }
32405e82c3bSDamien Miller 
32505e82c3bSDamien Miller int
sshbuf_put(struct sshbuf * buf,const void * v,size_t len)32605e82c3bSDamien Miller sshbuf_put(struct sshbuf *buf, const void *v, size_t len)
32705e82c3bSDamien Miller {
32805e82c3bSDamien Miller 	u_char *p;
32905e82c3bSDamien Miller 	int r;
33005e82c3bSDamien Miller 
33105e82c3bSDamien Miller 	if ((r = sshbuf_reserve(buf, len, &p)) < 0)
33205e82c3bSDamien Miller 		return r;
333a7f49dcbSdjm@openbsd.org 	if (len != 0)
33405e82c3bSDamien Miller 		memcpy(p, v, len);
33505e82c3bSDamien Miller 	return 0;
33605e82c3bSDamien Miller }
33705e82c3bSDamien Miller 
33805e82c3bSDamien Miller int
sshbuf_putb(struct sshbuf * buf,const struct sshbuf * v)33905e82c3bSDamien Miller sshbuf_putb(struct sshbuf *buf, const struct sshbuf *v)
34005e82c3bSDamien Miller {
341*ea547eb0Sdjm@openbsd.org 	if (v == NULL)
342*ea547eb0Sdjm@openbsd.org 		return 0;
34305e82c3bSDamien Miller 	return sshbuf_put(buf, sshbuf_ptr(v), sshbuf_len(v));
34405e82c3bSDamien Miller }
34505e82c3bSDamien Miller 
34605e82c3bSDamien Miller int
sshbuf_putf(struct sshbuf * buf,const char * fmt,...)34705e82c3bSDamien Miller sshbuf_putf(struct sshbuf *buf, const char *fmt, ...)
34805e82c3bSDamien Miller {
34905e82c3bSDamien Miller 	va_list ap;
35005e82c3bSDamien Miller 	int r;
35105e82c3bSDamien Miller 
35205e82c3bSDamien Miller 	va_start(ap, fmt);
35305e82c3bSDamien Miller 	r = sshbuf_putfv(buf, fmt, ap);
35405e82c3bSDamien Miller 	va_end(ap);
35505e82c3bSDamien Miller 	return r;
35605e82c3bSDamien Miller }
35705e82c3bSDamien Miller 
35805e82c3bSDamien Miller int
sshbuf_putfv(struct sshbuf * buf,const char * fmt,va_list ap)35905e82c3bSDamien Miller sshbuf_putfv(struct sshbuf *buf, const char *fmt, va_list ap)
36005e82c3bSDamien Miller {
36105e82c3bSDamien Miller 	va_list ap2;
36205e82c3bSDamien Miller 	int r, len;
36305e82c3bSDamien Miller 	u_char *p;
36405e82c3bSDamien Miller 
3655abfb15cSDarren Tucker 	VA_COPY(ap2, ap);
36605e82c3bSDamien Miller 	if ((len = vsnprintf(NULL, 0, fmt, ap2)) < 0) {
36705e82c3bSDamien Miller 		r = SSH_ERR_INVALID_ARGUMENT;
36805e82c3bSDamien Miller 		goto out;
36905e82c3bSDamien Miller 	}
37005e82c3bSDamien Miller 	if (len == 0) {
37105e82c3bSDamien Miller 		r = 0;
37205e82c3bSDamien Miller 		goto out; /* Nothing to do */
37305e82c3bSDamien Miller 	}
37405e82c3bSDamien Miller 	va_end(ap2);
3755abfb15cSDarren Tucker 	VA_COPY(ap2, ap);
37605e82c3bSDamien Miller 	if ((r = sshbuf_reserve(buf, (size_t)len + 1, &p)) < 0)
37705e82c3bSDamien Miller 		goto out;
37805e82c3bSDamien Miller 	if ((r = vsnprintf((char *)p, len + 1, fmt, ap2)) != len) {
37905e82c3bSDamien Miller 		r = SSH_ERR_INTERNAL_ERROR;
38005e82c3bSDamien Miller 		goto out; /* Shouldn't happen */
38105e82c3bSDamien Miller 	}
38205e82c3bSDamien Miller 	/* Consume terminating \0 */
38305e82c3bSDamien Miller 	if ((r = sshbuf_consume_end(buf, 1)) != 0)
38405e82c3bSDamien Miller 		goto out;
38505e82c3bSDamien Miller 	r = 0;
38605e82c3bSDamien Miller  out:
38705e82c3bSDamien Miller 	va_end(ap2);
38805e82c3bSDamien Miller 	return r;
38905e82c3bSDamien Miller }
39005e82c3bSDamien Miller 
39105e82c3bSDamien Miller int
sshbuf_put_u64(struct sshbuf * buf,u_int64_t val)39205e82c3bSDamien Miller sshbuf_put_u64(struct sshbuf *buf, u_int64_t val)
39305e82c3bSDamien Miller {
39405e82c3bSDamien Miller 	u_char *p;
39505e82c3bSDamien Miller 	int r;
39605e82c3bSDamien Miller 
39705e82c3bSDamien Miller 	if ((r = sshbuf_reserve(buf, 8, &p)) < 0)
39805e82c3bSDamien Miller 		return r;
39905e82c3bSDamien Miller 	POKE_U64(p, val);
40005e82c3bSDamien Miller 	return 0;
40105e82c3bSDamien Miller }
40205e82c3bSDamien Miller 
40305e82c3bSDamien Miller int
sshbuf_put_u32(struct sshbuf * buf,u_int32_t val)40405e82c3bSDamien Miller sshbuf_put_u32(struct sshbuf *buf, u_int32_t val)
40505e82c3bSDamien Miller {
40605e82c3bSDamien Miller 	u_char *p;
40705e82c3bSDamien Miller 	int r;
40805e82c3bSDamien Miller 
40905e82c3bSDamien Miller 	if ((r = sshbuf_reserve(buf, 4, &p)) < 0)
41005e82c3bSDamien Miller 		return r;
41105e82c3bSDamien Miller 	POKE_U32(p, val);
41205e82c3bSDamien Miller 	return 0;
41305e82c3bSDamien Miller }
41405e82c3bSDamien Miller 
41505e82c3bSDamien Miller int
sshbuf_put_u16(struct sshbuf * buf,u_int16_t val)41605e82c3bSDamien Miller sshbuf_put_u16(struct sshbuf *buf, u_int16_t val)
41705e82c3bSDamien Miller {
41805e82c3bSDamien Miller 	u_char *p;
41905e82c3bSDamien Miller 	int r;
42005e82c3bSDamien Miller 
42105e82c3bSDamien Miller 	if ((r = sshbuf_reserve(buf, 2, &p)) < 0)
42205e82c3bSDamien Miller 		return r;
42305e82c3bSDamien Miller 	POKE_U16(p, val);
42405e82c3bSDamien Miller 	return 0;
42505e82c3bSDamien Miller }
42605e82c3bSDamien Miller 
42705e82c3bSDamien Miller int
sshbuf_put_u8(struct sshbuf * buf,u_char val)42805e82c3bSDamien Miller sshbuf_put_u8(struct sshbuf *buf, u_char val)
42905e82c3bSDamien Miller {
43005e82c3bSDamien Miller 	u_char *p;
43105e82c3bSDamien Miller 	int r;
43205e82c3bSDamien Miller 
43305e82c3bSDamien Miller 	if ((r = sshbuf_reserve(buf, 1, &p)) < 0)
43405e82c3bSDamien Miller 		return r;
43505e82c3bSDamien Miller 	p[0] = val;
43605e82c3bSDamien Miller 	return 0;
43705e82c3bSDamien Miller }
43805e82c3bSDamien Miller 
439101d1647Sdjm@openbsd.org static int
check_woffset(struct sshbuf * buf,size_t offset,size_t len,u_char ** p)440101d1647Sdjm@openbsd.org check_woffset(struct sshbuf *buf, size_t offset, size_t len, u_char **p)
441101d1647Sdjm@openbsd.org {
442101d1647Sdjm@openbsd.org 	int r;
443101d1647Sdjm@openbsd.org 
444101d1647Sdjm@openbsd.org 	*p = NULL;
445101d1647Sdjm@openbsd.org 	if ((r = check_offset(buf, 1, offset, len)) != 0)
446101d1647Sdjm@openbsd.org 		return r;
447101d1647Sdjm@openbsd.org 	if (sshbuf_mutable_ptr(buf) == NULL)
448101d1647Sdjm@openbsd.org 		return SSH_ERR_BUFFER_READ_ONLY;
449101d1647Sdjm@openbsd.org 	*p = sshbuf_mutable_ptr(buf) + offset;
450101d1647Sdjm@openbsd.org 	return 0;
451101d1647Sdjm@openbsd.org }
452101d1647Sdjm@openbsd.org 
453101d1647Sdjm@openbsd.org int
sshbuf_poke_u64(struct sshbuf * buf,size_t offset,u_int64_t val)454101d1647Sdjm@openbsd.org sshbuf_poke_u64(struct sshbuf *buf, size_t offset, u_int64_t val)
455101d1647Sdjm@openbsd.org {
456101d1647Sdjm@openbsd.org 	u_char *p = NULL;
457101d1647Sdjm@openbsd.org 	int r;
458101d1647Sdjm@openbsd.org 
459101d1647Sdjm@openbsd.org 	if ((r = check_woffset(buf, offset, 8, &p)) != 0)
460101d1647Sdjm@openbsd.org 		return r;
461101d1647Sdjm@openbsd.org 	POKE_U64(p, val);
462101d1647Sdjm@openbsd.org 	return 0;
463101d1647Sdjm@openbsd.org }
464101d1647Sdjm@openbsd.org 
465101d1647Sdjm@openbsd.org int
sshbuf_poke_u32(struct sshbuf * buf,size_t offset,u_int32_t val)466101d1647Sdjm@openbsd.org sshbuf_poke_u32(struct sshbuf *buf, size_t offset, u_int32_t val)
467101d1647Sdjm@openbsd.org {
468101d1647Sdjm@openbsd.org 	u_char *p = NULL;
469101d1647Sdjm@openbsd.org 	int r;
470101d1647Sdjm@openbsd.org 
471101d1647Sdjm@openbsd.org 	if ((r = check_woffset(buf, offset, 4, &p)) != 0)
472101d1647Sdjm@openbsd.org 		return r;
473101d1647Sdjm@openbsd.org 	POKE_U32(p, val);
474101d1647Sdjm@openbsd.org 	return 0;
475101d1647Sdjm@openbsd.org }
476101d1647Sdjm@openbsd.org 
477101d1647Sdjm@openbsd.org int
sshbuf_poke_u16(struct sshbuf * buf,size_t offset,u_int16_t val)478101d1647Sdjm@openbsd.org sshbuf_poke_u16(struct sshbuf *buf, size_t offset, u_int16_t val)
479101d1647Sdjm@openbsd.org {
480101d1647Sdjm@openbsd.org 	u_char *p = NULL;
481101d1647Sdjm@openbsd.org 	int r;
482101d1647Sdjm@openbsd.org 
483101d1647Sdjm@openbsd.org 	if ((r = check_woffset(buf, offset, 2, &p)) != 0)
484101d1647Sdjm@openbsd.org 		return r;
485101d1647Sdjm@openbsd.org 	POKE_U16(p, val);
486101d1647Sdjm@openbsd.org 	return 0;
487101d1647Sdjm@openbsd.org }
488101d1647Sdjm@openbsd.org 
489101d1647Sdjm@openbsd.org int
sshbuf_poke_u8(struct sshbuf * buf,size_t offset,u_char val)490101d1647Sdjm@openbsd.org sshbuf_poke_u8(struct sshbuf *buf, size_t offset, u_char val)
491101d1647Sdjm@openbsd.org {
492101d1647Sdjm@openbsd.org 	u_char *p = NULL;
493101d1647Sdjm@openbsd.org 	int r;
494101d1647Sdjm@openbsd.org 
495101d1647Sdjm@openbsd.org 	if ((r = check_woffset(buf, offset, 1, &p)) != 0)
496101d1647Sdjm@openbsd.org 		return r;
497101d1647Sdjm@openbsd.org 	*p = val;
498101d1647Sdjm@openbsd.org 	return 0;
499101d1647Sdjm@openbsd.org }
500101d1647Sdjm@openbsd.org 
501101d1647Sdjm@openbsd.org int
sshbuf_poke(struct sshbuf * buf,size_t offset,void * v,size_t len)502101d1647Sdjm@openbsd.org sshbuf_poke(struct sshbuf *buf, size_t offset, void *v, size_t len)
503101d1647Sdjm@openbsd.org {
504101d1647Sdjm@openbsd.org 	u_char *p = NULL;
505101d1647Sdjm@openbsd.org 	int r;
506101d1647Sdjm@openbsd.org 
507101d1647Sdjm@openbsd.org 	if ((r = check_woffset(buf, offset, len, &p)) != 0)
508101d1647Sdjm@openbsd.org 		return r;
509101d1647Sdjm@openbsd.org 	memcpy(p, v, len);
510101d1647Sdjm@openbsd.org 	return 0;
511101d1647Sdjm@openbsd.org }
512101d1647Sdjm@openbsd.org 
51305e82c3bSDamien Miller int
sshbuf_put_string(struct sshbuf * buf,const void * v,size_t len)51405e82c3bSDamien Miller sshbuf_put_string(struct sshbuf *buf, const void *v, size_t len)
51505e82c3bSDamien Miller {
51605e82c3bSDamien Miller 	u_char *d;
51705e82c3bSDamien Miller 	int r;
51805e82c3bSDamien Miller 
51905e82c3bSDamien Miller 	if (len > SSHBUF_SIZE_MAX - 4) {
52005e82c3bSDamien Miller 		SSHBUF_DBG(("SSH_ERR_NO_BUFFER_SPACE"));
52105e82c3bSDamien Miller 		return SSH_ERR_NO_BUFFER_SPACE;
52205e82c3bSDamien Miller 	}
52305e82c3bSDamien Miller 	if ((r = sshbuf_reserve(buf, len + 4, &d)) < 0)
52405e82c3bSDamien Miller 		return r;
52505e82c3bSDamien Miller 	POKE_U32(d, len);
526a7f49dcbSdjm@openbsd.org 	if (len != 0)
52705e82c3bSDamien Miller 		memcpy(d + 4, v, len);
52805e82c3bSDamien Miller 	return 0;
52905e82c3bSDamien Miller }
53005e82c3bSDamien Miller 
53105e82c3bSDamien Miller int
sshbuf_put_cstring(struct sshbuf * buf,const char * v)532