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