xref: /openbsd/usr.bin/ssh/sshbuf-getput-basic.c (revision a8cbed27)
1*a8cbed27Sdjm /*	$OpenBSD: sshbuf-getput-basic.c,v 1.13 2022/05/25 06:03:44 djm Exp $	*/
215b55daeSdjm /*
315b55daeSdjm  * Copyright (c) 2011 Damien Miller
415b55daeSdjm  *
515b55daeSdjm  * Permission to use, copy, modify, and distribute this software for any
615b55daeSdjm  * purpose with or without fee is hereby granted, provided that the above
715b55daeSdjm  * copyright notice and this permission notice appear in all copies.
815b55daeSdjm  *
915b55daeSdjm  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1015b55daeSdjm  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1115b55daeSdjm  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1215b55daeSdjm  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1315b55daeSdjm  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1415b55daeSdjm  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1515b55daeSdjm  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1615b55daeSdjm  */
1715b55daeSdjm 
1815b55daeSdjm #include <sys/types.h>
19ae6d6c75Sdtucker 
20ae6d6c75Sdtucker #include <stdarg.h>
2115b55daeSdjm #include <stdlib.h>
2215b55daeSdjm #include <stdio.h>
2315b55daeSdjm #include <string.h>
24d04a6061Sdjm #include <stdint.h>
2515b55daeSdjm 
2615b55daeSdjm #include "ssherr.h"
2715b55daeSdjm #define SSHBUF_INTERNAL
2815b55daeSdjm #include "sshbuf.h"
2915b55daeSdjm 
3015b55daeSdjm int
sshbuf_get(struct sshbuf * buf,void * v,size_t len)3115b55daeSdjm sshbuf_get(struct sshbuf *buf, void *v, size_t len)
3215b55daeSdjm {
3315b55daeSdjm 	const u_char *p = sshbuf_ptr(buf);
3415b55daeSdjm 	int r;
3515b55daeSdjm 
3615b55daeSdjm 	if ((r = sshbuf_consume(buf, len)) < 0)
3715b55daeSdjm 		return r;
3838940dfdSdjm 	if (v != NULL && len != 0)
3915b55daeSdjm 		memcpy(v, p, len);
4015b55daeSdjm 	return 0;
4115b55daeSdjm }
4215b55daeSdjm 
4315b55daeSdjm int
sshbuf_get_u64(struct sshbuf * buf,u_int64_t * valp)4415b55daeSdjm sshbuf_get_u64(struct sshbuf *buf, u_int64_t *valp)
4515b55daeSdjm {
4615b55daeSdjm 	const u_char *p = sshbuf_ptr(buf);
4715b55daeSdjm 	int r;
4815b55daeSdjm 
4915b55daeSdjm 	if ((r = sshbuf_consume(buf, 8)) < 0)
5015b55daeSdjm 		return r;
5115b55daeSdjm 	if (valp != NULL)
5215b55daeSdjm 		*valp = PEEK_U64(p);
5315b55daeSdjm 	return 0;
5415b55daeSdjm }
5515b55daeSdjm 
5615b55daeSdjm int
sshbuf_get_u32(struct sshbuf * buf,u_int32_t * valp)5715b55daeSdjm sshbuf_get_u32(struct sshbuf *buf, u_int32_t *valp)
5815b55daeSdjm {
5915b55daeSdjm 	const u_char *p = sshbuf_ptr(buf);
6015b55daeSdjm 	int r;
6115b55daeSdjm 
6215b55daeSdjm 	if ((r = sshbuf_consume(buf, 4)) < 0)
6315b55daeSdjm 		return r;
6415b55daeSdjm 	if (valp != NULL)
6515b55daeSdjm 		*valp = PEEK_U32(p);
6615b55daeSdjm 	return 0;
6715b55daeSdjm }
6815b55daeSdjm 
6915b55daeSdjm int
sshbuf_get_u16(struct sshbuf * buf,u_int16_t * valp)7015b55daeSdjm sshbuf_get_u16(struct sshbuf *buf, u_int16_t *valp)
7115b55daeSdjm {
7215b55daeSdjm 	const u_char *p = sshbuf_ptr(buf);
7315b55daeSdjm 	int r;
7415b55daeSdjm 
7515b55daeSdjm 	if ((r = sshbuf_consume(buf, 2)) < 0)
7615b55daeSdjm 		return r;
7715b55daeSdjm 	if (valp != NULL)
7815b55daeSdjm 		*valp = PEEK_U16(p);
7915b55daeSdjm 	return 0;
8015b55daeSdjm }
8115b55daeSdjm 
8215b55daeSdjm int
sshbuf_get_u8(struct sshbuf * buf,u_char * valp)8315b55daeSdjm sshbuf_get_u8(struct sshbuf *buf, u_char *valp)
8415b55daeSdjm {
8515b55daeSdjm 	const u_char *p = sshbuf_ptr(buf);
8615b55daeSdjm 	int r;
8715b55daeSdjm 
8815b55daeSdjm 	if ((r = sshbuf_consume(buf, 1)) < 0)
8915b55daeSdjm 		return r;
9015b55daeSdjm 	if (valp != NULL)
9115b55daeSdjm 		*valp = (u_int8_t)*p;
9215b55daeSdjm 	return 0;
9315b55daeSdjm }
9415b55daeSdjm 
9559567923Sdjm static int
check_offset(const struct sshbuf * buf,int wr,size_t offset,size_t len)9659567923Sdjm check_offset(const struct sshbuf *buf, int wr, size_t offset, size_t len)
9759567923Sdjm {
9859567923Sdjm 	if (sshbuf_ptr(buf) == NULL) /* calls sshbuf_check_sanity() */
9959567923Sdjm 		return SSH_ERR_INTERNAL_ERROR;
10059567923Sdjm 	if (offset >= SIZE_MAX - len)
10159567923Sdjm 		return SSH_ERR_INVALID_ARGUMENT;
10259567923Sdjm 	if (offset + len > sshbuf_len(buf)) {
10359567923Sdjm 		return wr ?
10459567923Sdjm 		    SSH_ERR_NO_BUFFER_SPACE : SSH_ERR_MESSAGE_INCOMPLETE;
10559567923Sdjm 	}
10659567923Sdjm 	return 0;
10759567923Sdjm }
10859567923Sdjm 
10959567923Sdjm static int
check_roffset(const struct sshbuf * buf,size_t offset,size_t len,const u_char ** p)11059567923Sdjm check_roffset(const struct sshbuf *buf, size_t offset, size_t len,
11159567923Sdjm     const u_char **p)
11259567923Sdjm {
11359567923Sdjm 	int r;
11459567923Sdjm 
11559567923Sdjm 	*p = NULL;
11659567923Sdjm 	if ((r = check_offset(buf, 0, offset, len)) != 0)
11759567923Sdjm 		return r;
11859567923Sdjm 	*p = sshbuf_ptr(buf) + offset;
11959567923Sdjm 	return 0;
12059567923Sdjm }
12159567923Sdjm 
12259567923Sdjm int
sshbuf_peek_u64(const struct sshbuf * buf,size_t offset,u_int64_t * valp)12359567923Sdjm sshbuf_peek_u64(const struct sshbuf *buf, size_t offset, u_int64_t *valp)
12459567923Sdjm {
12559567923Sdjm 	const u_char *p = NULL;
12659567923Sdjm 	int r;
12759567923Sdjm 
12859567923Sdjm 	if (valp != NULL)
12959567923Sdjm 		*valp = 0;
13059567923Sdjm 	if ((r = check_roffset(buf, offset, 8, &p)) != 0)
13159567923Sdjm 		return r;
13259567923Sdjm 	if (valp != NULL)
13359567923Sdjm 		*valp = PEEK_U64(p);
13459567923Sdjm 	return 0;
13559567923Sdjm }
13659567923Sdjm 
13759567923Sdjm int
sshbuf_peek_u32(const struct sshbuf * buf,size_t offset,u_int32_t * valp)13859567923Sdjm sshbuf_peek_u32(const struct sshbuf *buf, size_t offset, u_int32_t *valp)
13959567923Sdjm {
14059567923Sdjm 	const u_char *p = NULL;
14159567923Sdjm 	int r;
14259567923Sdjm 
14359567923Sdjm 	if (valp != NULL)
14459567923Sdjm 		*valp = 0;
14559567923Sdjm 	if ((r = check_roffset(buf, offset, 4, &p)) != 0)
14659567923Sdjm 		return r;
14759567923Sdjm 	if (valp != NULL)
14859567923Sdjm 		*valp = PEEK_U32(p);
14959567923Sdjm 	return 0;
15059567923Sdjm }
15159567923Sdjm 
15259567923Sdjm int
sshbuf_peek_u16(const struct sshbuf * buf,size_t offset,u_int16_t * valp)15359567923Sdjm sshbuf_peek_u16(const struct sshbuf *buf, size_t offset, u_int16_t *valp)
15459567923Sdjm {
15559567923Sdjm 	const u_char *p = NULL;
15659567923Sdjm 	int r;
15759567923Sdjm 
15859567923Sdjm 	if (valp != NULL)
15959567923Sdjm 		*valp = 0;
16059567923Sdjm 	if ((r = check_roffset(buf, offset, 2, &p)) != 0)
16159567923Sdjm 		return r;
16259567923Sdjm 	if (valp != NULL)
16359567923Sdjm 		*valp = PEEK_U16(p);
16459567923Sdjm 	return 0;
16559567923Sdjm }
16659567923Sdjm 
16759567923Sdjm int
sshbuf_peek_u8(const struct sshbuf * buf,size_t offset,u_char * valp)16859567923Sdjm sshbuf_peek_u8(const struct sshbuf *buf, size_t offset, u_char *valp)
16959567923Sdjm {
17059567923Sdjm 	const u_char *p = NULL;
17159567923Sdjm 	int r;
17259567923Sdjm 
17359567923Sdjm 	if (valp != NULL)
17459567923Sdjm 		*valp = 0;
17559567923Sdjm 	if ((r = check_roffset(buf, offset, 1, &p)) != 0)
17659567923Sdjm 		return r;
17759567923Sdjm 	if (valp != NULL)
17859567923Sdjm 		*valp = *p;
17959567923Sdjm 	return 0;
18059567923Sdjm }
18159567923Sdjm 
18215b55daeSdjm int
sshbuf_get_string(struct sshbuf * buf,u_char ** valp,size_t * lenp)18315b55daeSdjm sshbuf_get_string(struct sshbuf *buf, u_char **valp, size_t *lenp)
18415b55daeSdjm {
18515b55daeSdjm 	const u_char *val;
18615b55daeSdjm 	size_t len;
18715b55daeSdjm 	int r;
18815b55daeSdjm 
18915b55daeSdjm 	if (valp != NULL)
19015b55daeSdjm 		*valp = NULL;
19115b55daeSdjm 	if (lenp != NULL)
19215b55daeSdjm 		*lenp = 0;
19315b55daeSdjm 	if ((r = sshbuf_get_string_direct(buf, &val, &len)) < 0)
19415b55daeSdjm 		return r;
19515b55daeSdjm 	if (valp != NULL) {
19615b55daeSdjm 		if ((*valp = malloc(len + 1)) == NULL) {
197*a8cbed27Sdjm 			SSHBUF_DBG(("SSH_ERR_ALLOC_FAIL"));
19815b55daeSdjm 			return SSH_ERR_ALLOC_FAIL;
19915b55daeSdjm 		}
20038940dfdSdjm 		if (len != 0)
20115b55daeSdjm 			memcpy(*valp, val, len);
20215b55daeSdjm 		(*valp)[len] = '\0';
20315b55daeSdjm 	}
20415b55daeSdjm 	if (lenp != NULL)
20515b55daeSdjm 		*lenp = len;
20615b55daeSdjm 	return 0;
20715b55daeSdjm }
20815b55daeSdjm 
20915b55daeSdjm int
sshbuf_get_string_direct(struct sshbuf * buf,const u_char ** valp,size_t * lenp)21015b55daeSdjm sshbuf_get_string_direct(struct sshbuf *buf, const u_char **valp, size_t *lenp)
21115b55daeSdjm {
21215b55daeSdjm 	size_t len;
21315b55daeSdjm 	const u_char *p;
21415b55daeSdjm 	int r;
21515b55daeSdjm 
21615b55daeSdjm 	if (valp != NULL)
21715b55daeSdjm 		*valp = NULL;
21815b55daeSdjm 	if (lenp != NULL)
21915b55daeSdjm 		*lenp = 0;
22015b55daeSdjm 	if ((r = sshbuf_peek_string_direct(buf, &p, &len)) < 0)
22115b55daeSdjm 		return r;
2222e96fb62Smmcc 	if (valp != NULL)
22315b55daeSdjm 		*valp = p;
22415b55daeSdjm 	if (lenp != NULL)
22515b55daeSdjm 		*lenp = len;
22615b55daeSdjm 	if (sshbuf_consume(buf, len + 4) != 0) {
22715b55daeSdjm 		/* Shouldn't happen */
228*a8cbed27Sdjm 		SSHBUF_DBG(("SSH_ERR_INTERNAL_ERROR"));
22915b55daeSdjm 		SSHBUF_ABORT();
23015b55daeSdjm 		return SSH_ERR_INTERNAL_ERROR;
23115b55daeSdjm 	}
23215b55daeSdjm 	return 0;
23315b55daeSdjm }
23415b55daeSdjm 
23515b55daeSdjm int
sshbuf_peek_string_direct(const struct sshbuf * buf,const u_char ** valp,size_t * lenp)23615b55daeSdjm sshbuf_peek_string_direct(const struct sshbuf *buf, const u_char **valp,
23715b55daeSdjm     size_t *lenp)
23815b55daeSdjm {
23915b55daeSdjm 	u_int32_t len;
24015b55daeSdjm 	const u_char *p = sshbuf_ptr(buf);
24115b55daeSdjm 
24215b55daeSdjm 	if (valp != NULL)
24315b55daeSdjm 		*valp = NULL;
24415b55daeSdjm 	if (lenp != NULL)
24515b55daeSdjm 		*lenp = 0;
24615b55daeSdjm 	if (sshbuf_len(buf) < 4) {
247*a8cbed27Sdjm 		SSHBUF_DBG(("SSH_ERR_MESSAGE_INCOMPLETE"));
24815b55daeSdjm 		return SSH_ERR_MESSAGE_INCOMPLETE;
24915b55daeSdjm 	}
25015b55daeSdjm 	len = PEEK_U32(p);
25115b55daeSdjm 	if (len > SSHBUF_SIZE_MAX - 4) {
252*a8cbed27Sdjm 		SSHBUF_DBG(("SSH_ERR_STRING_TOO_LARGE"));
25315b55daeSdjm 		return SSH_ERR_STRING_TOO_LARGE;
25415b55daeSdjm 	}
25515b55daeSdjm 	if (sshbuf_len(buf) - 4 < len) {
256*a8cbed27Sdjm 		SSHBUF_DBG(("SSH_ERR_MESSAGE_INCOMPLETE"));
25715b55daeSdjm 		return SSH_ERR_MESSAGE_INCOMPLETE;
25815b55daeSdjm 	}
2592e96fb62Smmcc 	if (valp != NULL)
26015b55daeSdjm 		*valp = p + 4;
26115b55daeSdjm 	if (lenp != NULL)
26215b55daeSdjm 		*lenp = len;
26315b55daeSdjm 	return 0;
26415b55daeSdjm }
26515b55daeSdjm 
26615b55daeSdjm int
sshbuf_get_cstring(struct sshbuf * buf,char ** valp,size_t * lenp)26715b55daeSdjm sshbuf_get_cstring(struct sshbuf *buf, char **valp, size_t *lenp)
26815b55daeSdjm {
26915b55daeSdjm 	size_t len;
27015b55daeSdjm 	const u_char *p, *z;
27115b55daeSdjm 	int r;
27215b55daeSdjm 
27315b55daeSdjm 	if (valp != NULL)
27415b55daeSdjm 		*valp = NULL;
27515b55daeSdjm 	if (lenp != NULL)
27615b55daeSdjm 		*lenp = 0;
27715b55daeSdjm 	if ((r = sshbuf_peek_string_direct(buf, &p, &len)) != 0)
27815b55daeSdjm 		return r;
27915b55daeSdjm 	/* Allow a \0 only at the end of the string */
28015b55daeSdjm 	if (len > 0 &&
28115b55daeSdjm 	    (z = memchr(p , '\0', len)) != NULL && z < p + len - 1) {
282*a8cbed27Sdjm 		SSHBUF_DBG(("SSH_ERR_INVALID_FORMAT"));
28315b55daeSdjm 		return SSH_ERR_INVALID_FORMAT;
28415b55daeSdjm 	}
28515b55daeSdjm 	if ((r = sshbuf_skip_string(buf)) != 0)
28615b55daeSdjm 		return -1;
28715b55daeSdjm 	if (valp != NULL) {
28815b55daeSdjm 		if ((*valp = malloc(len + 1)) == NULL) {
289*a8cbed27Sdjm 			SSHBUF_DBG(("SSH_ERR_ALLOC_FAIL"));
29015b55daeSdjm 			return SSH_ERR_ALLOC_FAIL;
29115b55daeSdjm 		}
29238940dfdSdjm 		if (len != 0)
29315b55daeSdjm 			memcpy(*valp, p, len);
29415b55daeSdjm 		(*valp)[len] = '\0';
29515b55daeSdjm 	}
29615b55daeSdjm 	if (lenp != NULL)
29715b55daeSdjm 		*lenp = (size_t)len;
29815b55daeSdjm 	return 0;
29915b55daeSdjm }
30015b55daeSdjm 
30115b55daeSdjm int
sshbuf_get_stringb(struct sshbuf * buf,struct sshbuf * v)30215b55daeSdjm sshbuf_get_stringb(struct sshbuf *buf, struct sshbuf *v)
30315b55daeSdjm {
30415b55daeSdjm 	u_int32_t len;
30515b55daeSdjm 	u_char *p;
30615b55daeSdjm 	int r;
30715b55daeSdjm 
30815b55daeSdjm 	/*
30915b55daeSdjm 	 * Use sshbuf_peek_string_direct() to figure out if there is
31015b55daeSdjm 	 * a complete string in 'buf' and copy the string directly
31115b55daeSdjm 	 * into 'v'.
31215b55daeSdjm 	 */
31315b55daeSdjm 	if ((r = sshbuf_peek_string_direct(buf, NULL, NULL)) != 0 ||
31415b55daeSdjm 	    (r = sshbuf_get_u32(buf, &len)) != 0 ||
31515b55daeSdjm 	    (r = sshbuf_reserve(v, len, &p)) != 0 ||
31615b55daeSdjm 	    (r = sshbuf_get(buf, p, len)) != 0)
31715b55daeSdjm 		return r;
31815b55daeSdjm 	return 0;
31915b55daeSdjm }
32015b55daeSdjm 
32115b55daeSdjm int
sshbuf_put(struct sshbuf * buf,const void * v,size_t len)32215b55daeSdjm sshbuf_put(struct sshbuf *buf, const void *v, size_t len)
32315b55daeSdjm {
32415b55daeSdjm 	u_char *p;
32515b55daeSdjm 	int r;
32615b55daeSdjm 
32715b55daeSdjm 	if ((r = sshbuf_reserve(buf, len, &p)) < 0)
32815b55daeSdjm 		return r;
32938940dfdSdjm 	if (len != 0)
33015b55daeSdjm 		memcpy(p, v, len);
33115b55daeSdjm 	return 0;
33215b55daeSdjm }
33315b55daeSdjm 
33415b55daeSdjm int
sshbuf_putb(struct sshbuf * buf,const struct sshbuf * v)33515b55daeSdjm sshbuf_putb(struct sshbuf *buf, const struct sshbuf *v)
33615b55daeSdjm {
3372916947cSdjm 	if (v == NULL)
3382916947cSdjm 		return 0;
33915b55daeSdjm 	return sshbuf_put(buf, sshbuf_ptr(v), sshbuf_len(v));
34015b55daeSdjm }
34115b55daeSdjm 
34215b55daeSdjm int
sshbuf_putf(struct sshbuf * buf,const char * fmt,...)34315b55daeSdjm sshbuf_putf(struct sshbuf *buf, const char *fmt, ...)
34415b55daeSdjm {
34515b55daeSdjm 	va_list ap;
34615b55daeSdjm 	int r;
34715b55daeSdjm 
34815b55daeSdjm 	va_start(ap, fmt);
34915b55daeSdjm 	r = sshbuf_putfv(buf, fmt, ap);
35015b55daeSdjm 	va_end(ap);
35115b55daeSdjm 	return r;
35215b55daeSdjm }
35315b55daeSdjm 
35415b55daeSdjm int
sshbuf_putfv(struct sshbuf * buf,const char * fmt,va_list ap)35515b55daeSdjm sshbuf_putfv(struct sshbuf *buf, const char *fmt, va_list ap)
35615b55daeSdjm {
35715b55daeSdjm 	va_list ap2;
35815b55daeSdjm 	int r, len;
35915b55daeSdjm 	u_char *p;
36015b55daeSdjm 
36115b55daeSdjm 	va_copy(ap2, ap);
36215b55daeSdjm 	if ((len = vsnprintf(NULL, 0, fmt, ap2)) < 0) {
36315b55daeSdjm 		r = SSH_ERR_INVALID_ARGUMENT;
36415b55daeSdjm 		goto out;
36515b55daeSdjm 	}
36615b55daeSdjm 	if (len == 0) {
36715b55daeSdjm 		r = 0;
36815b55daeSdjm 		goto out; /* Nothing to do */
36915b55daeSdjm 	}
37015b55daeSdjm 	va_end(ap2);
37115b55daeSdjm 	va_copy(ap2, ap);
37215b55daeSdjm 	if ((r = sshbuf_reserve(buf, (size_t)len + 1, &p)) < 0)
37315b55daeSdjm 		goto out;
37415b55daeSdjm 	if ((r = vsnprintf((char *)p, len + 1, fmt, ap2)) != len) {
37515b55daeSdjm 		r = SSH_ERR_INTERNAL_ERROR;
37615b55daeSdjm 		goto out; /* Shouldn't happen */
37715b55daeSdjm 	}
37815b55daeSdjm 	/* Consume terminating \0 */
37915b55daeSdjm 	if ((r = sshbuf_consume_end(buf, 1)) != 0)
38015b55daeSdjm 		goto out;
38115b55daeSdjm 	r = 0;
38215b55daeSdjm  out:
38315b55daeSdjm 	va_end(ap2);
38415b55daeSdjm 	return r;
38515b55daeSdjm }
38615b55daeSdjm 
38715b55daeSdjm int
sshbuf_put_u64(struct sshbuf * buf,u_int64_t val)38815b55daeSdjm sshbuf_put_u64(struct sshbuf *buf, u_int64_t val)
38915b55daeSdjm {
39015b55daeSdjm 	u_char *p;
39115b55daeSdjm 	int r;
39215b55daeSdjm 
39315b55daeSdjm 	if ((r = sshbuf_reserve(buf, 8, &p)) < 0)
39415b55daeSdjm 		return r;
39515b55daeSdjm 	POKE_U64(p, val);
39615b55daeSdjm 	return 0;
39715b55daeSdjm }
39815b55daeSdjm 
39915b55daeSdjm int
sshbuf_put_u32(struct sshbuf * buf,u_int32_t val)40015b55daeSdjm sshbuf_put_u32(struct sshbuf *buf, u_int32_t val)
40115b55daeSdjm {
40215b55daeSdjm 	u_char *p;
40315b55daeSdjm 	int r;
40415b55daeSdjm 
40515b55daeSdjm 	if ((r = sshbuf_reserve(buf, 4, &p)) < 0)
40615b55daeSdjm 		return r;
40715b55daeSdjm 	POKE_U32(p, val);
40815b55daeSdjm 	return 0;
40915b55daeSdjm }
41015b55daeSdjm 
41115b55daeSdjm int
sshbuf_put_u16(struct sshbuf * buf,u_int16_t val)41215b55daeSdjm sshbuf_put_u16(struct sshbuf *buf, u_int16_t val)
41315b55daeSdjm {
41415b55daeSdjm 	u_char *p;
41515b55daeSdjm 	int r;
41615b55daeSdjm 
41715b55daeSdjm 	if ((r = sshbuf_reserve(buf, 2, &p)) < 0)
41815b55daeSdjm 		return r;
41915b55daeSdjm 	POKE_U16(p, val);
42015b55daeSdjm 	return 0;
42115b55daeSdjm }
42215b55daeSdjm 
42315b55daeSdjm int
sshbuf_put_u8(struct sshbuf * buf,u_char val)42415b55daeSdjm sshbuf_put_u8(struct sshbuf *buf, u_char val)
42515b55daeSdjm {
42615b55daeSdjm 	u_char *p;
42715b55daeSdjm 	int r;
42815b55daeSdjm 
42915b55daeSdjm 	if ((r = sshbuf_reserve(buf, 1, &p)) < 0)
43015b55daeSdjm 		return r;
43115b55daeSdjm 	p[0] = val;
43215b55daeSdjm 	return 0;
43315b55daeSdjm }
43415b55daeSdjm 
43559567923Sdjm static int
check_woffset(struct sshbuf * buf,size_t offset,size_t len,u_char ** p)43659567923Sdjm check_woffset(struct sshbuf *buf, size_t offset, size_t len, u_char **p)
43759567923Sdjm {
43859567923Sdjm 	int r;
43959567923Sdjm 
44059567923Sdjm 	*p = NULL;
44159567923Sdjm 	if ((r = check_offset(buf, 1, offset, len)) != 0)
44259567923Sdjm 		return r;
44359567923Sdjm 	if (sshbuf_mutable_ptr(buf) == NULL)
44459567923Sdjm 		return SSH_ERR_BUFFER_READ_ONLY;
44559567923Sdjm 	*p = sshbuf_mutable_ptr(buf) + offset;
44659567923Sdjm 	return 0;
44759567923Sdjm }
44859567923Sdjm 
44959567923Sdjm int
sshbuf_poke_u64(struct sshbuf * buf,size_t offset,u_int64_t val)45059567923Sdjm sshbuf_poke_u64(struct sshbuf *buf, size_t offset, u_int64_t val)
45159567923Sdjm {
45259567923Sdjm 	u_char *p = NULL;
45359567923Sdjm 	int r;
45459567923Sdjm 
45559567923Sdjm 	if ((r = check_woffset(buf, offset, 8, &p)) != 0)
45659567923Sdjm 		return r;
45759567923Sdjm 	POKE_U64(p, val);
45859567923Sdjm 	return 0;
45959567923Sdjm }
46059567923Sdjm 
46159567923Sdjm int
sshbuf_poke_u32(struct sshbuf * buf,size_t offset,u_int32_t val)46259567923Sdjm sshbuf_poke_u32(struct sshbuf *buf, size_t offset, u_int32_t val)
46359567923Sdjm {
46459567923Sdjm 	u_char *p = NULL;
46559567923Sdjm 	int r;
46659567923Sdjm 
46759567923Sdjm 	if ((r = check_woffset(buf, offset, 4, &p)) != 0)
46859567923Sdjm 		return r;
46959567923Sdjm 	POKE_U32(p, val);
47059567923Sdjm 	return 0;
47159567923Sdjm }
47259567923Sdjm 
47359567923Sdjm int
sshbuf_poke_u16(struct sshbuf * buf,size_t offset,u_int16_t val)47459567923Sdjm sshbuf_poke_u16(struct sshbuf *buf, size_t offset, u_int16_t val)
47559567923Sdjm {
47659567923Sdjm 	u_char *p = NULL;
47759567923Sdjm 	int r;
47859567923Sdjm 
47959567923Sdjm 	if ((r = check_woffset(buf, offset, 2, &p)) != 0)
48059567923Sdjm 		return r;
48159567923Sdjm 	POKE_U16(p, val);
48259567923Sdjm 	return 0;
48359567923Sdjm }
48459567923Sdjm 
48559567923Sdjm int
sshbuf_poke_u8(struct sshbuf * buf,size_t offset,u_char val)48659567923Sdjm sshbuf_poke_u8(struct sshbuf *buf, size_t offset, u_char val)
48759567923Sdjm {
48859567923Sdjm 	u_char *p = NULL;
48959567923Sdjm 	int r;
49059567923Sdjm 
49159567923Sdjm 	if ((r = check_woffset(buf, offset, 1, &p)) != 0)
49259567923Sdjm 		return r;
49359567923Sdjm 	*p = val;
49459567923Sdjm 	return 0;
49559567923Sdjm }
49659567923Sdjm 
49759567923Sdjm int
sshbuf_poke(struct sshbuf * buf,size_t offset,void * v,size_t len)49859567923Sdjm sshbuf_poke(struct sshbuf *buf, size_t offset, void *v, size_t len)
49959567923Sdjm {
50059567923Sdjm 	u_char *p = NULL;
50159567923Sdjm 	int r;
50259567923Sdjm 
50359567923Sdjm 	if ((r = check_woffset(buf, offset, len, &p)) != 0)
50459567923Sdjm 		return r;
50559567923Sdjm 	memcpy(p, v, len);
50659567923Sdjm 	return 0;
50759567923Sdjm }
50859567923Sdjm 
50915b55daeSdjm int
sshbuf_put_string(struct sshbuf * buf,const void * v,size_t len)51015b55daeSdjm sshbuf_put_string(struct sshbuf *buf, const void *v, size_t len)
51115b55daeSdjm {
51215b55daeSdjm 	u_char *d;
51315b55daeSdjm 	int r;
51415b55daeSdjm 
51515b55daeSdjm 	if (len > SSHBUF_SIZE_MAX - 4) {
516*a8cbed27Sdjm 		SSHBUF_DBG(("SSH_ERR_NO_BUFFER_SPACE"));
51715b55daeSdjm 		return SSH_ERR_NO_BUFFER_SPACE;
51815b55daeSdjm 	}
51915b55daeSdjm 	if ((r = sshbuf_reserve(buf, len + 4, &d)) < 0)
52015b55daeSdjm 		return r;
52115b55daeSdjm 	POKE_U32(d, len);
52238940dfdSdjm 	if (len != 0)
52315b55daeSdjm 		memcpy(d + 4, v, len);
52415b55daeSdjm 	return 0;
52515b55daeSdjm }
52615b55daeSdjm 
52715b55daeSdjm int
sshbuf_put_cstring(struct sshbuf * buf,const char * v)52815b55daeSdjm sshbuf_put_cstring(struct sshbuf *buf, const char *v)
52915b55daeSdjm {
5307154f74eSdjm 	return sshbuf_put_string(buf, v, v == NULL ? 0 : strlen(v));
53115b55daeSdjm }
53215b55daeSdjm 
53315b55daeSdjm int
sshbuf_put_stringb(struct sshbuf * buf,const struct sshbuf * v)53415b55daeSdjm sshbuf_put_stringb(struct sshbuf *buf, const struct sshbuf *v)
53515b55daeSdjm {
536e62314d4Sdjm 	if (v == NULL)
537e62314d4Sdjm 		return sshbuf_put_string(buf, NULL, 0);
538e62314d4Sdjm 
53915b55daeSdjm 	return sshbuf_put_string(buf, sshbuf_ptr(v), sshbuf_len(v));
54015b55daeSdjm }
54115b55daeSdjm 
54215b55daeSdjm int
sshbuf_froms(struct sshbuf * buf,struct sshbuf ** bufp)54315b55daeSdjm sshbuf_froms(struct sshbuf *buf, struct sshbuf **bufp)
54415b55daeSdjm {
54515b55daeSdjm 	const u_char *p;
54615b55daeSdjm 	size_t len;
54715b55daeSdjm 	struct sshbuf *ret;
54815b55daeSdjm 	int r;
54915b55daeSdjm 
55015b55daeSdjm 	if (buf == NULL || bufp == NULL)
55115b55daeSdjm 		return SSH_ERR_INVALID_ARGUMENT;
55215b55daeSdjm 	*bufp = NULL;
55315b55daeSdjm 	if ((r = sshbuf_peek_string_direct(buf, &p, &len)) != 0)
55415b55daeSdjm 		return r;
55515b55daeSdjm 	if ((ret = sshbuf_from(p, len)) == NULL)
55615b55daeSdjm 		return SSH_ERR_ALLOC_FAIL;
55715b55daeSdjm 	if ((r = sshbuf_consume(buf, len + 4)) != 0 ||  /* Shouldn't happen */
55815b55daeSdjm 	    (r = sshbuf_set_parent(ret, buf)) != 0) {
55915b55daeSdjm 		sshbuf_free(ret);
56015b55daeSdjm 		return r;
56115b55daeSdjm 	}
56215b55daeSdjm 	*bufp = ret;
56315b55daeSdjm 	return 0;
56415b55daeSdjm }
56515b55daeSdjm 
56615b55daeSdjm int
sshbuf_put_bignum2_bytes(struct sshbuf * buf,const void * v,size_t len)56715b55daeSdjm sshbuf_put_bignum2_bytes(struct sshbuf *buf, const void *v, size_t len)
56815b55daeSdjm {
56915b55daeSdjm 	u_char *d;
57015b55daeSdjm 	const u_char *s = (const u_char *)v;
57115b55daeSdjm 	int r, prepend;
57215b55daeSdjm 
57315b55daeSdjm 	if (len > SSHBUF_SIZE_MAX - 5) {
574*a8cbed27Sdjm 		SSHBUF_DBG(("SSH_ERR_NO_BUFFER_SPACE"));
57515b55daeSdjm 		return SSH_ERR_NO_BUFFER_SPACE;
57615b55daeSdjm 	}
57715b55daeSdjm 	/* Skip leading zero bytes */
57815b55daeSdjm 	for (; len > 0 && *s == 0; len--, s++)
57915b55daeSdjm 		;
58015b55daeSdjm 	/*
58115b55daeSdjm 	 * If most significant bit is set then prepend a zero byte to
58215b55daeSdjm 	 * avoid interpretation as a negative number.
58315b55daeSdjm 	 */
58415b55daeSdjm 	prepend = len > 0 && (s[0] & 0x80) != 0;
58515b55daeSdjm 	if ((r = sshbuf_reserve(buf, len + 4 + prepend, &d)) < 0)
58615b55daeSdjm 		return r;
58715b55daeSdjm 	POKE_U32(d, len + prepend);
58815b55daeSdjm 	if (prepend)
58915b55daeSdjm 		d[4] = 0;
59038940dfdSdjm 	if (len != 0)
59115b55daeSdjm 		memcpy(d + 4 + prepend, s, len);
59215b55daeSdjm 	return 0;
59315b55daeSdjm }
59478e9a853Sdjm 
59578e9a853Sdjm int
sshbuf_get_bignum2_bytes_direct(struct sshbuf * buf,const u_char ** valp,size_t * lenp)59678e9a853Sdjm sshbuf_get_bignum2_bytes_direct(struct sshbuf *buf,
59778e9a853Sdjm     const u_char **valp, size_t *lenp)
59878e9a853Sdjm {
59978e9a853Sdjm 	const u_char *d;
60078e9a853Sdjm 	size_t len, olen;
60178e9a853Sdjm 	int r;
60278e9a853Sdjm 
60378e9a853Sdjm 	if ((r = sshbuf_peek_string_direct(buf, &d, &olen)) < 0)
60478e9a853Sdjm 		return r;
60578e9a853Sdjm 	len = olen;
60678e9a853Sdjm 	/* Refuse negative (MSB set) bignums */
60778e9a853Sdjm 	if ((len != 0 && (*d & 0x80) != 0))
60878e9a853Sdjm 		return SSH_ERR_BIGNUM_IS_NEGATIVE;
60978e9a853Sdjm 	/* Refuse overlong bignums, allow prepended \0 to avoid MSB set */
61078e9a853Sdjm 	if (len > SSHBUF_MAX_BIGNUM + 1 ||
61178e9a853Sdjm 	    (len == SSHBUF_MAX_BIGNUM + 1 && *d != 0))
61278e9a853Sdjm 		return SSH_ERR_BIGNUM_TOO_LARGE;
61378e9a853Sdjm 	/* Trim leading zeros */
61478e9a853Sdjm 	while (len > 0 && *d == 0x00) {
61578e9a853Sdjm 		d++;
61678e9a853Sdjm 		len--;
61778e9a853Sdjm 	}
6182e96fb62Smmcc 	if (valp != NULL)
61978e9a853Sdjm 		*valp = d;
62078e9a853Sdjm 	if (lenp != NULL)
62178e9a853Sdjm 		*lenp = len;
62278e9a853Sdjm 	if (sshbuf_consume(buf, olen + 4) != 0) {
62378e9a853Sdjm 		/* Shouldn't happen */
624*a8cbed27Sdjm 		SSHBUF_DBG(("SSH_ERR_INTERNAL_ERROR"));
62578e9a853Sdjm 		SSHBUF_ABORT();
62678e9a853Sdjm 		return SSH_ERR_INTERNAL_ERROR;
62778e9a853Sdjm 	}
62878e9a853Sdjm 	return 0;
62978e9a853Sdjm }
630