1*ee116499SAntonio Huete Jimenez /* $OpenBSD: sshbuf-getput-basic.c,v 1.13 2022/05/25 06:03:44 djm Exp $ */
236e94dc5SPeter Avalos /*
336e94dc5SPeter Avalos * Copyright (c) 2011 Damien Miller
436e94dc5SPeter Avalos *
536e94dc5SPeter Avalos * Permission to use, copy, modify, and distribute this software for any
636e94dc5SPeter Avalos * purpose with or without fee is hereby granted, provided that the above
736e94dc5SPeter Avalos * copyright notice and this permission notice appear in all copies.
836e94dc5SPeter Avalos *
936e94dc5SPeter Avalos * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1036e94dc5SPeter Avalos * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1136e94dc5SPeter Avalos * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1236e94dc5SPeter Avalos * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1336e94dc5SPeter Avalos * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1436e94dc5SPeter Avalos * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1536e94dc5SPeter Avalos * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1636e94dc5SPeter Avalos */
1736e94dc5SPeter Avalos
1836e94dc5SPeter Avalos #define SSHBUF_INTERNAL
1936e94dc5SPeter Avalos #include "includes.h"
2036e94dc5SPeter Avalos
2136e94dc5SPeter Avalos #include <sys/types.h>
22e9778795SPeter Avalos
23e9778795SPeter Avalos #include <stdarg.h>
2436e94dc5SPeter Avalos #include <stdlib.h>
2536e94dc5SPeter Avalos #include <stdio.h>
2636e94dc5SPeter Avalos #include <string.h>
270cbfa66cSDaniel Fojt #ifdef HAVE_STDINT_H
280cbfa66cSDaniel Fojt # include <stdint.h>
290cbfa66cSDaniel Fojt #endif
3036e94dc5SPeter Avalos
3136e94dc5SPeter Avalos #include "ssherr.h"
3236e94dc5SPeter Avalos #include "sshbuf.h"
3336e94dc5SPeter Avalos
3436e94dc5SPeter Avalos int
sshbuf_get(struct sshbuf * buf,void * v,size_t len)3536e94dc5SPeter Avalos sshbuf_get(struct sshbuf *buf, void *v, size_t len)
3636e94dc5SPeter Avalos {
3736e94dc5SPeter Avalos const u_char *p = sshbuf_ptr(buf);
3836e94dc5SPeter Avalos int r;
3936e94dc5SPeter Avalos
4036e94dc5SPeter Avalos if ((r = sshbuf_consume(buf, len)) < 0)
4136e94dc5SPeter Avalos return r;
42e9778795SPeter Avalos if (v != NULL && len != 0)
4336e94dc5SPeter Avalos memcpy(v, p, len);
4436e94dc5SPeter Avalos return 0;
4536e94dc5SPeter Avalos }
4636e94dc5SPeter Avalos
4736e94dc5SPeter Avalos int
sshbuf_get_u64(struct sshbuf * buf,u_int64_t * valp)4836e94dc5SPeter Avalos sshbuf_get_u64(struct sshbuf *buf, u_int64_t *valp)
4936e94dc5SPeter Avalos {
5036e94dc5SPeter Avalos const u_char *p = sshbuf_ptr(buf);
5136e94dc5SPeter Avalos int r;
5236e94dc5SPeter Avalos
5336e94dc5SPeter Avalos if ((r = sshbuf_consume(buf, 8)) < 0)
5436e94dc5SPeter Avalos return r;
5536e94dc5SPeter Avalos if (valp != NULL)
5636e94dc5SPeter Avalos *valp = PEEK_U64(p);
5736e94dc5SPeter Avalos return 0;
5836e94dc5SPeter Avalos }
5936e94dc5SPeter Avalos
6036e94dc5SPeter Avalos int
sshbuf_get_u32(struct sshbuf * buf,u_int32_t * valp)6136e94dc5SPeter Avalos sshbuf_get_u32(struct sshbuf *buf, u_int32_t *valp)
6236e94dc5SPeter Avalos {
6336e94dc5SPeter Avalos const u_char *p = sshbuf_ptr(buf);
6436e94dc5SPeter Avalos int r;
6536e94dc5SPeter Avalos
6636e94dc5SPeter Avalos if ((r = sshbuf_consume(buf, 4)) < 0)
6736e94dc5SPeter Avalos return r;
6836e94dc5SPeter Avalos if (valp != NULL)
6936e94dc5SPeter Avalos *valp = PEEK_U32(p);
7036e94dc5SPeter Avalos return 0;
7136e94dc5SPeter Avalos }
7236e94dc5SPeter Avalos
7336e94dc5SPeter Avalos int
sshbuf_get_u16(struct sshbuf * buf,u_int16_t * valp)7436e94dc5SPeter Avalos sshbuf_get_u16(struct sshbuf *buf, u_int16_t *valp)
7536e94dc5SPeter Avalos {
7636e94dc5SPeter Avalos const u_char *p = sshbuf_ptr(buf);
7736e94dc5SPeter Avalos int r;
7836e94dc5SPeter Avalos
7936e94dc5SPeter Avalos if ((r = sshbuf_consume(buf, 2)) < 0)
8036e94dc5SPeter Avalos return r;
8136e94dc5SPeter Avalos if (valp != NULL)
8236e94dc5SPeter Avalos *valp = PEEK_U16(p);
8336e94dc5SPeter Avalos return 0;
8436e94dc5SPeter Avalos }
8536e94dc5SPeter Avalos
8636e94dc5SPeter Avalos int
sshbuf_get_u8(struct sshbuf * buf,u_char * valp)8736e94dc5SPeter Avalos sshbuf_get_u8(struct sshbuf *buf, u_char *valp)
8836e94dc5SPeter Avalos {
8936e94dc5SPeter Avalos const u_char *p = sshbuf_ptr(buf);
9036e94dc5SPeter Avalos int r;
9136e94dc5SPeter Avalos
9236e94dc5SPeter Avalos if ((r = sshbuf_consume(buf, 1)) < 0)
9336e94dc5SPeter Avalos return r;
9436e94dc5SPeter Avalos if (valp != NULL)
9536e94dc5SPeter Avalos *valp = (u_int8_t)*p;
9636e94dc5SPeter Avalos return 0;
9736e94dc5SPeter Avalos }
9836e94dc5SPeter Avalos
990cbfa66cSDaniel Fojt static int
check_offset(const struct sshbuf * buf,int wr,size_t offset,size_t len)1000cbfa66cSDaniel Fojt check_offset(const struct sshbuf *buf, int wr, size_t offset, size_t len)
1010cbfa66cSDaniel Fojt {
1020cbfa66cSDaniel Fojt if (sshbuf_ptr(buf) == NULL) /* calls sshbuf_check_sanity() */
1030cbfa66cSDaniel Fojt return SSH_ERR_INTERNAL_ERROR;
1040cbfa66cSDaniel Fojt if (offset >= SIZE_MAX - len)
1050cbfa66cSDaniel Fojt return SSH_ERR_INVALID_ARGUMENT;
1060cbfa66cSDaniel Fojt if (offset + len > sshbuf_len(buf)) {
1070cbfa66cSDaniel Fojt return wr ?
1080cbfa66cSDaniel Fojt SSH_ERR_NO_BUFFER_SPACE : SSH_ERR_MESSAGE_INCOMPLETE;
1090cbfa66cSDaniel Fojt }
1100cbfa66cSDaniel Fojt return 0;
1110cbfa66cSDaniel Fojt }
1120cbfa66cSDaniel Fojt
1130cbfa66cSDaniel Fojt static int
check_roffset(const struct sshbuf * buf,size_t offset,size_t len,const u_char ** p)1140cbfa66cSDaniel Fojt check_roffset(const struct sshbuf *buf, size_t offset, size_t len,
1150cbfa66cSDaniel Fojt const u_char **p)
1160cbfa66cSDaniel Fojt {
1170cbfa66cSDaniel Fojt int r;
1180cbfa66cSDaniel Fojt
1190cbfa66cSDaniel Fojt *p = NULL;
1200cbfa66cSDaniel Fojt if ((r = check_offset(buf, 0, offset, len)) != 0)
1210cbfa66cSDaniel Fojt return r;
1220cbfa66cSDaniel Fojt *p = sshbuf_ptr(buf) + offset;
1230cbfa66cSDaniel Fojt return 0;
1240cbfa66cSDaniel Fojt }
1250cbfa66cSDaniel Fojt
1260cbfa66cSDaniel Fojt int
sshbuf_peek_u64(const struct sshbuf * buf,size_t offset,u_int64_t * valp)1270cbfa66cSDaniel Fojt sshbuf_peek_u64(const struct sshbuf *buf, size_t offset, u_int64_t *valp)
1280cbfa66cSDaniel Fojt {
1290cbfa66cSDaniel Fojt const u_char *p = NULL;
1300cbfa66cSDaniel Fojt int r;
1310cbfa66cSDaniel Fojt
1320cbfa66cSDaniel Fojt if (valp != NULL)
1330cbfa66cSDaniel Fojt *valp = 0;
1340cbfa66cSDaniel Fojt if ((r = check_roffset(buf, offset, 8, &p)) != 0)
1350cbfa66cSDaniel Fojt return r;
1360cbfa66cSDaniel Fojt if (valp != NULL)
1370cbfa66cSDaniel Fojt *valp = PEEK_U64(p);
1380cbfa66cSDaniel Fojt return 0;
1390cbfa66cSDaniel Fojt }
1400cbfa66cSDaniel Fojt
1410cbfa66cSDaniel Fojt int
sshbuf_peek_u32(const struct sshbuf * buf,size_t offset,u_int32_t * valp)1420cbfa66cSDaniel Fojt sshbuf_peek_u32(const struct sshbuf *buf, size_t offset, u_int32_t *valp)
1430cbfa66cSDaniel Fojt {
1440cbfa66cSDaniel Fojt const u_char *p = NULL;
1450cbfa66cSDaniel Fojt int r;
1460cbfa66cSDaniel Fojt
1470cbfa66cSDaniel Fojt if (valp != NULL)
1480cbfa66cSDaniel Fojt *valp = 0;
1490cbfa66cSDaniel Fojt if ((r = check_roffset(buf, offset, 4, &p)) != 0)
1500cbfa66cSDaniel Fojt return r;
1510cbfa66cSDaniel Fojt if (valp != NULL)
1520cbfa66cSDaniel Fojt *valp = PEEK_U32(p);
1530cbfa66cSDaniel Fojt return 0;
1540cbfa66cSDaniel Fojt }
1550cbfa66cSDaniel Fojt
1560cbfa66cSDaniel Fojt int
sshbuf_peek_u16(const struct sshbuf * buf,size_t offset,u_int16_t * valp)1570cbfa66cSDaniel Fojt sshbuf_peek_u16(const struct sshbuf *buf, size_t offset, u_int16_t *valp)
1580cbfa66cSDaniel Fojt {
1590cbfa66cSDaniel Fojt const u_char *p = NULL;
1600cbfa66cSDaniel Fojt int r;
1610cbfa66cSDaniel Fojt
1620cbfa66cSDaniel Fojt if (valp != NULL)
1630cbfa66cSDaniel Fojt *valp = 0;
1640cbfa66cSDaniel Fojt if ((r = check_roffset(buf, offset, 2, &p)) != 0)
1650cbfa66cSDaniel Fojt return r;
1660cbfa66cSDaniel Fojt if (valp != NULL)
1670cbfa66cSDaniel Fojt *valp = PEEK_U16(p);
1680cbfa66cSDaniel Fojt return 0;
1690cbfa66cSDaniel Fojt }
1700cbfa66cSDaniel Fojt
1710cbfa66cSDaniel Fojt int
sshbuf_peek_u8(const struct sshbuf * buf,size_t offset,u_char * valp)1720cbfa66cSDaniel Fojt sshbuf_peek_u8(const struct sshbuf *buf, size_t offset, u_char *valp)
1730cbfa66cSDaniel Fojt {
1740cbfa66cSDaniel Fojt const u_char *p = NULL;
1750cbfa66cSDaniel Fojt int r;
1760cbfa66cSDaniel Fojt
1770cbfa66cSDaniel Fojt if (valp != NULL)
1780cbfa66cSDaniel Fojt *valp = 0;
1790cbfa66cSDaniel Fojt if ((r = check_roffset(buf, offset, 1, &p)) != 0)
1800cbfa66cSDaniel Fojt return r;
1810cbfa66cSDaniel Fojt if (valp != NULL)
1820cbfa66cSDaniel Fojt *valp = *p;
1830cbfa66cSDaniel Fojt return 0;
1840cbfa66cSDaniel Fojt }
1850cbfa66cSDaniel Fojt
18636e94dc5SPeter Avalos int
sshbuf_get_string(struct sshbuf * buf,u_char ** valp,size_t * lenp)18736e94dc5SPeter Avalos sshbuf_get_string(struct sshbuf *buf, u_char **valp, size_t *lenp)
18836e94dc5SPeter Avalos {
18936e94dc5SPeter Avalos const u_char *val;
19036e94dc5SPeter Avalos size_t len;
19136e94dc5SPeter Avalos int r;
19236e94dc5SPeter Avalos
19336e94dc5SPeter Avalos if (valp != NULL)
19436e94dc5SPeter Avalos *valp = NULL;
19536e94dc5SPeter Avalos if (lenp != NULL)
19636e94dc5SPeter Avalos *lenp = 0;
19736e94dc5SPeter Avalos if ((r = sshbuf_get_string_direct(buf, &val, &len)) < 0)
19836e94dc5SPeter Avalos return r;
19936e94dc5SPeter Avalos if (valp != NULL) {
20036e94dc5SPeter Avalos if ((*valp = malloc(len + 1)) == NULL) {
20136e94dc5SPeter Avalos SSHBUF_DBG(("SSH_ERR_ALLOC_FAIL"));
20236e94dc5SPeter Avalos return SSH_ERR_ALLOC_FAIL;
20336e94dc5SPeter Avalos }
204e9778795SPeter Avalos if (len != 0)
20536e94dc5SPeter Avalos memcpy(*valp, val, len);
20636e94dc5SPeter Avalos (*valp)[len] = '\0';
20736e94dc5SPeter Avalos }
20836e94dc5SPeter Avalos if (lenp != NULL)
20936e94dc5SPeter Avalos *lenp = len;
21036e94dc5SPeter Avalos return 0;
21136e94dc5SPeter Avalos }
21236e94dc5SPeter Avalos
21336e94dc5SPeter Avalos int
sshbuf_get_string_direct(struct sshbuf * buf,const u_char ** valp,size_t * lenp)21436e94dc5SPeter Avalos sshbuf_get_string_direct(struct sshbuf *buf, const u_char **valp, size_t *lenp)
21536e94dc5SPeter Avalos {
21636e94dc5SPeter Avalos size_t len;
21736e94dc5SPeter Avalos const u_char *p;
21836e94dc5SPeter Avalos int r;
21936e94dc5SPeter Avalos
22036e94dc5SPeter Avalos if (valp != NULL)
22136e94dc5SPeter Avalos *valp = NULL;
22236e94dc5SPeter Avalos if (lenp != NULL)
22336e94dc5SPeter Avalos *lenp = 0;
22436e94dc5SPeter Avalos if ((r = sshbuf_peek_string_direct(buf, &p, &len)) < 0)
22536e94dc5SPeter Avalos return r;
226e9778795SPeter Avalos if (valp != NULL)
22736e94dc5SPeter Avalos *valp = p;
22836e94dc5SPeter Avalos if (lenp != NULL)
22936e94dc5SPeter Avalos *lenp = len;
23036e94dc5SPeter Avalos if (sshbuf_consume(buf, len + 4) != 0) {
23136e94dc5SPeter Avalos /* Shouldn't happen */
23236e94dc5SPeter Avalos SSHBUF_DBG(("SSH_ERR_INTERNAL_ERROR"));
23336e94dc5SPeter Avalos SSHBUF_ABORT();
23436e94dc5SPeter Avalos return SSH_ERR_INTERNAL_ERROR;
23536e94dc5SPeter Avalos }
23636e94dc5SPeter Avalos return 0;
23736e94dc5SPeter Avalos }
23836e94dc5SPeter Avalos
23936e94dc5SPeter Avalos int
sshbuf_peek_string_direct(const struct sshbuf * buf,const u_char ** valp,size_t * lenp)24036e94dc5SPeter Avalos sshbuf_peek_string_direct(const struct sshbuf *buf, const u_char **valp,
24136e94dc5SPeter Avalos size_t *lenp)
24236e94dc5SPeter Avalos {
24336e94dc5SPeter Avalos u_int32_t len;
24436e94dc5SPeter Avalos const u_char *p = sshbuf_ptr(buf);
24536e94dc5SPeter Avalos
24636e94dc5SPeter Avalos if (valp != NULL)
24736e94dc5SPeter Avalos *valp = NULL;
24836e94dc5SPeter Avalos if (lenp != NULL)
24936e94dc5SPeter Avalos *lenp = 0;
25036e94dc5SPeter Avalos if (sshbuf_len(buf) < 4) {
25136e94dc5SPeter Avalos SSHBUF_DBG(("SSH_ERR_MESSAGE_INCOMPLETE"));
25236e94dc5SPeter Avalos return SSH_ERR_MESSAGE_INCOMPLETE;
25336e94dc5SPeter Avalos }
25436e94dc5SPeter Avalos len = PEEK_U32(p);
25536e94dc5SPeter Avalos if (len > SSHBUF_SIZE_MAX - 4) {
25636e94dc5SPeter Avalos SSHBUF_DBG(("SSH_ERR_STRING_TOO_LARGE"));
25736e94dc5SPeter Avalos return SSH_ERR_STRING_TOO_LARGE;
25836e94dc5SPeter Avalos }
25936e94dc5SPeter Avalos if (sshbuf_len(buf) - 4 < len) {
26036e94dc5SPeter Avalos SSHBUF_DBG(("SSH_ERR_MESSAGE_INCOMPLETE"));
26136e94dc5SPeter Avalos return SSH_ERR_MESSAGE_INCOMPLETE;
26236e94dc5SPeter Avalos }
263e9778795SPeter Avalos if (valp != NULL)
26436e94dc5SPeter Avalos *valp = p + 4;
26536e94dc5SPeter Avalos if (lenp != NULL)
26636e94dc5SPeter Avalos *lenp = len;
26736e94dc5SPeter Avalos return 0;
26836e94dc5SPeter Avalos }
26936e94dc5SPeter Avalos
27036e94dc5SPeter Avalos int
sshbuf_get_cstring(struct sshbuf * buf,char ** valp,size_t * lenp)27136e94dc5SPeter Avalos sshbuf_get_cstring(struct sshbuf *buf, char **valp, size_t *lenp)
27236e94dc5SPeter Avalos {
27336e94dc5SPeter Avalos size_t len;
27436e94dc5SPeter Avalos const u_char *p, *z;
27536e94dc5SPeter Avalos int r;
27636e94dc5SPeter Avalos
27736e94dc5SPeter Avalos if (valp != NULL)
27836e94dc5SPeter Avalos *valp = NULL;
27936e94dc5SPeter Avalos if (lenp != NULL)
28036e94dc5SPeter Avalos *lenp = 0;
28136e94dc5SPeter Avalos if ((r = sshbuf_peek_string_direct(buf, &p, &len)) != 0)
28236e94dc5SPeter Avalos return r;
28336e94dc5SPeter Avalos /* Allow a \0 only at the end of the string */
28436e94dc5SPeter Avalos if (len > 0 &&
28536e94dc5SPeter Avalos (z = memchr(p , '\0', len)) != NULL && z < p + len - 1) {
28636e94dc5SPeter Avalos SSHBUF_DBG(("SSH_ERR_INVALID_FORMAT"));
28736e94dc5SPeter Avalos return SSH_ERR_INVALID_FORMAT;
28836e94dc5SPeter Avalos }
28936e94dc5SPeter Avalos if ((r = sshbuf_skip_string(buf)) != 0)
29036e94dc5SPeter Avalos return -1;
29136e94dc5SPeter Avalos if (valp != NULL) {
29236e94dc5SPeter Avalos if ((*valp = malloc(len + 1)) == NULL) {
29336e94dc5SPeter Avalos SSHBUF_DBG(("SSH_ERR_ALLOC_FAIL"));
29436e94dc5SPeter Avalos return SSH_ERR_ALLOC_FAIL;
29536e94dc5SPeter Avalos }
296e9778795SPeter Avalos if (len != 0)
29736e94dc5SPeter Avalos memcpy(*valp, p, len);
29836e94dc5SPeter Avalos (*valp)[len] = '\0';
29936e94dc5SPeter Avalos }
30036e94dc5SPeter Avalos if (lenp != NULL)
30136e94dc5SPeter Avalos *lenp = (size_t)len;
30236e94dc5SPeter Avalos return 0;
30336e94dc5SPeter Avalos }
30436e94dc5SPeter Avalos
30536e94dc5SPeter Avalos int
sshbuf_get_stringb(struct sshbuf * buf,struct sshbuf * v)30636e94dc5SPeter Avalos sshbuf_get_stringb(struct sshbuf *buf, struct sshbuf *v)
30736e94dc5SPeter Avalos {
30836e94dc5SPeter Avalos u_int32_t len;
30936e94dc5SPeter Avalos u_char *p;
31036e94dc5SPeter Avalos int r;
31136e94dc5SPeter Avalos
31236e94dc5SPeter Avalos /*
31336e94dc5SPeter Avalos * Use sshbuf_peek_string_direct() to figure out if there is
31436e94dc5SPeter Avalos * a complete string in 'buf' and copy the string directly
31536e94dc5SPeter Avalos * into 'v'.
31636e94dc5SPeter Avalos */
31736e94dc5SPeter Avalos if ((r = sshbuf_peek_string_direct(buf, NULL, NULL)) != 0 ||
31836e94dc5SPeter Avalos (r = sshbuf_get_u32(buf, &len)) != 0 ||
31936e94dc5SPeter Avalos (r = sshbuf_reserve(v, len, &p)) != 0 ||
32036e94dc5SPeter Avalos (r = sshbuf_get(buf, p, len)) != 0)
32136e94dc5SPeter Avalos return r;
32236e94dc5SPeter Avalos return 0;
32336e94dc5SPeter Avalos }
32436e94dc5SPeter Avalos
32536e94dc5SPeter Avalos int
sshbuf_put(struct sshbuf * buf,const void * v,size_t len)32636e94dc5SPeter Avalos sshbuf_put(struct sshbuf *buf, const void *v, size_t len)
32736e94dc5SPeter Avalos {
32836e94dc5SPeter Avalos u_char *p;
32936e94dc5SPeter Avalos int r;
33036e94dc5SPeter Avalos
33136e94dc5SPeter Avalos if ((r = sshbuf_reserve(buf, len, &p)) < 0)
33236e94dc5SPeter Avalos return r;
333e9778795SPeter Avalos if (len != 0)
33436e94dc5SPeter Avalos memcpy(p, v, len);
33536e94dc5SPeter Avalos return 0;
33636e94dc5SPeter Avalos }
33736e94dc5SPeter Avalos
33836e94dc5SPeter Avalos int
sshbuf_putb(struct sshbuf * buf,const struct sshbuf * v)33936e94dc5SPeter Avalos sshbuf_putb(struct sshbuf *buf, const struct sshbuf *v)
34036e94dc5SPeter Avalos {
34150a69bb5SSascha Wildner if (v == NULL)
34250a69bb5SSascha Wildner return 0;
34336e94dc5SPeter Avalos return sshbuf_put(buf, sshbuf_ptr(v), sshbuf_len(v));
34436e94dc5SPeter Avalos }
34536e94dc5SPeter Avalos
34636e94dc5SPeter Avalos int
sshbuf_putf(struct sshbuf * buf,const char * fmt,...)34736e94dc5SPeter Avalos sshbuf_putf(struct sshbuf *buf, const char *fmt, ...)
34836e94dc5SPeter Avalos {
34936e94dc5SPeter Avalos va_list ap;
35036e94dc5SPeter Avalos int r;
35136e94dc5SPeter Avalos
35236e94dc5SPeter Avalos va_start(ap, fmt);
35336e94dc5SPeter Avalos r = sshbuf_putfv(buf, fmt, ap);
35436e94dc5SPeter Avalos va_end(ap);
35536e94dc5SPeter Avalos return r;
35636e94dc5SPeter Avalos }
35736e94dc5SPeter Avalos
35836e94dc5SPeter Avalos int
sshbuf_putfv(struct sshbuf * buf,const char * fmt,va_list ap)35936e94dc5SPeter Avalos sshbuf_putfv(struct sshbuf *buf, const char *fmt, va_list ap)
36036e94dc5SPeter Avalos {
36136e94dc5SPeter Avalos va_list ap2;
36236e94dc5SPeter Avalos int r, len;
36336e94dc5SPeter Avalos u_char *p;
36436e94dc5SPeter Avalos
365e9778795SPeter Avalos VA_COPY(ap2, ap);
36636e94dc5SPeter Avalos if ((len = vsnprintf(NULL, 0, fmt, ap2)) < 0) {
36736e94dc5SPeter Avalos r = SSH_ERR_INVALID_ARGUMENT;
36836e94dc5SPeter Avalos goto out;
36936e94dc5SPeter Avalos }
37036e94dc5SPeter Avalos if (len == 0) {
37136e94dc5SPeter Avalos r = 0;
37236e94dc5SPeter Avalos goto out; /* Nothing to do */
37336e94dc5SPeter Avalos }
37436e94dc5SPeter Avalos va_end(ap2);
375e9778795SPeter Avalos VA_COPY(ap2, ap);
37636e94dc5SPeter Avalos if ((r = sshbuf_reserve(buf, (size_t)len + 1, &p)) < 0)
37736e94dc5SPeter Avalos goto out;
37836e94dc5SPeter Avalos if ((r = vsnprintf((char *)p, len + 1, fmt, ap2)) != len) {
37936e94dc5SPeter Avalos r = SSH_ERR_INTERNAL_ERROR;
38036e94dc5SPeter Avalos goto out; /* Shouldn't happen */
38136e94dc5SPeter Avalos }
38236e94dc5SPeter Avalos /* Consume terminating \0 */
38336e94dc5SPeter Avalos if ((r = sshbuf_consume_end(buf, 1)) != 0)
38436e94dc5SPeter Avalos goto out;
38536e94dc5SPeter Avalos r = 0;
38636e94dc5SPeter Avalos out:
38736e94dc5SPeter Avalos va_end(ap2);
38836e94dc5SPeter Avalos return r;
38936e94dc5SPeter Avalos }
39036e94dc5SPeter Avalos
39136e94dc5SPeter Avalos int
sshbuf_put_u64(struct sshbuf * buf,u_int64_t val)39236e94dc5SPeter Avalos sshbuf_put_u64(struct sshbuf *buf, u_int64_t val)
39336e94dc5SPeter Avalos {
39436e94dc5SPeter Avalos u_char *p;
39536e94dc5SPeter Avalos int r;
39636e94dc5SPeter Avalos
39736e94dc5SPeter Avalos if ((r = sshbuf_reserve(buf, 8, &p)) < 0)
39836e94dc5SPeter Avalos return r;
39936e94dc5SPeter Avalos POKE_U64(p, val);
40036e94dc5SPeter Avalos return 0;
40136e94dc5SPeter Avalos }
40236e94dc5SPeter Avalos
40336e94dc5SPeter Avalos int
sshbuf_put_u32(struct sshbuf * buf,u_int32_t val)40436e94dc5SPeter Avalos sshbuf_put_u32(struct sshbuf *buf, u_int32_t val)
40536e94dc5SPeter Avalos {
40636e94dc5SPeter Avalos u_char *p;
40736e94dc5SPeter Avalos int r;
40836e94dc5SPeter Avalos
40936e94dc5SPeter Avalos if ((r = sshbuf_reserve(buf, 4, &p)) < 0)
41036e94dc5SPeter Avalos return r;
41136e94dc5SPeter Avalos POKE_U32(p, val);
41236e94dc5SPeter Avalos return 0;
41336e94dc5SPeter Avalos }
41436e94dc5SPeter Avalos
41536e94dc5SPeter Avalos int
sshbuf_put_u16(struct sshbuf * buf,u_int16_t val)41636e94dc5SPeter Avalos sshbuf_put_u16(struct sshbuf *buf, u_int16_t val)
41736e94dc5SPeter Avalos {
41836e94dc5SPeter Avalos u_char *p;
41936e94dc5SPeter Avalos int r;
42036e94dc5SPeter Avalos
42136e94dc5SPeter Avalos if ((r = sshbuf_reserve(buf, 2, &p)) < 0)
42236e94dc5SPeter Avalos return r;
42336e94dc5SPeter Avalos POKE_U16(p, val);
42436e94dc5SPeter Avalos return 0;
42536e94dc5SPeter Avalos }
42636e94dc5SPeter Avalos
42736e94dc5SPeter Avalos int
sshbuf_put_u8(struct sshbuf * buf,u_char val)42836e94dc5SPeter Avalos sshbuf_put_u8(struct sshbuf *buf, u_char val)
42936e94dc5SPeter Avalos {
43036e94dc5SPeter Avalos u_char *p;
43136e94dc5SPeter Avalos int r;
43236e94dc5SPeter Avalos
43336e94dc5SPeter Avalos if ((r = sshbuf_reserve(buf, 1, &p)) < 0)
43436e94dc5SPeter Avalos return r;
43536e94dc5SPeter Avalos p[0] = val;
43636e94dc5SPeter Avalos return 0;
43736e94dc5SPeter Avalos }
43836e94dc5SPeter Avalos
4390cbfa66cSDaniel Fojt static int
check_woffset(struct sshbuf * buf,size_t offset,size_t len,u_char ** p)4400cbfa66cSDaniel Fojt check_woffset(struct sshbuf *buf, size_t offset, size_t len, u_char **p)
4410cbfa66cSDaniel Fojt {
4420cbfa66cSDaniel Fojt int r;
4430cbfa66cSDaniel Fojt
4440cbfa66cSDaniel Fojt *p = NULL;
4450cbfa66cSDaniel Fojt if ((r = check_offset(buf, 1, offset, len)) != 0)
4460cbfa66cSDaniel Fojt return r;
4470cbfa66cSDaniel Fojt if (sshbuf_mutable_ptr(buf) == NULL)
4480cbfa66cSDaniel Fojt return SSH_ERR_BUFFER_READ_ONLY;
4490cbfa66cSDaniel Fojt *p = sshbuf_mutable_ptr(buf) + offset;
4500cbfa66cSDaniel Fojt return 0;
4510cbfa66cSDaniel Fojt }
4520cbfa66cSDaniel Fojt
4530cbfa66cSDaniel Fojt int
sshbuf_poke_u64(struct sshbuf * buf,size_t offset,u_int64_t val)4540cbfa66cSDaniel Fojt sshbuf_poke_u64(struct sshbuf *buf, size_t offset, u_int64_t val)
4550cbfa66cSDaniel Fojt {
4560cbfa66cSDaniel Fojt u_char *p = NULL;
4570cbfa66cSDaniel Fojt int r;
4580cbfa66cSDaniel Fojt
4590cbfa66cSDaniel Fojt if ((r = check_woffset(buf, offset, 8, &p)) != 0)
4600cbfa66cSDaniel Fojt return r;
4610cbfa66cSDaniel Fojt POKE_U64(p, val);
4620cbfa66cSDaniel Fojt return 0;
4630cbfa66cSDaniel Fojt }
4640cbfa66cSDaniel Fojt
4650cbfa66cSDaniel Fojt int
sshbuf_poke_u32(struct sshbuf * buf,size_t offset,u_int32_t val)4660cbfa66cSDaniel Fojt sshbuf_poke_u32(struct sshbuf *buf, size_t offset, u_int32_t val)
4670cbfa66cSDaniel Fojt {
4680cbfa66cSDaniel Fojt u_char *p = NULL;
4690cbfa66cSDaniel Fojt int r;
4700cbfa66cSDaniel Fojt
4710cbfa66cSDaniel Fojt if ((r = check_woffset(buf, offset, 4, &p)) != 0)
4720cbfa66cSDaniel Fojt return r;
4730cbfa66cSDaniel Fojt POKE_U32(p, val);
4740cbfa66cSDaniel Fojt return 0;
4750cbfa66cSDaniel Fojt }
4760cbfa66cSDaniel Fojt
4770cbfa66cSDaniel Fojt int
sshbuf_poke_u16(struct sshbuf * buf,size_t offset,u_int16_t val)4780cbfa66cSDaniel Fojt sshbuf_poke_u16(struct sshbuf *buf, size_t offset, u_int16_t val)
4790cbfa66cSDaniel Fojt {
4800cbfa66cSDaniel Fojt u_char *p = NULL;
4810cbfa66cSDaniel Fojt int r;
4820cbfa66cSDaniel Fojt
4830cbfa66cSDaniel Fojt if ((r = check_woffset(buf, offset, 2, &p)) != 0)
4840cbfa66cSDaniel Fojt return r;
4850cbfa66cSDaniel Fojt POKE_U16(p, val);
4860cbfa66cSDaniel Fojt return 0;
4870cbfa66cSDaniel Fojt }
4880cbfa66cSDaniel Fojt
4890cbfa66cSDaniel Fojt int
sshbuf_poke_u8(struct sshbuf * buf,size_t offset,u_char val)4900cbfa66cSDaniel Fojt sshbuf_poke_u8(struct sshbuf *buf, size_t offset, u_char val)
4910cbfa66cSDaniel Fojt {
4920cbfa66cSDaniel Fojt u_char *p = NULL;
4930cbfa66cSDaniel Fojt int r;
4940cbfa66cSDaniel Fojt
4950cbfa66cSDaniel Fojt if ((r = check_woffset(buf, offset, 1, &p)) != 0)
4960cbfa66cSDaniel Fojt return r;
4970cbfa66cSDaniel Fojt *p = val;
4980cbfa66cSDaniel Fojt return 0;
4990cbfa66cSDaniel Fojt }
5000cbfa66cSDaniel Fojt
5010cbfa66cSDaniel Fojt int
sshbuf_poke(struct sshbuf * buf,size_t offset,void * v,size_t len)5020cbfa66cSDaniel Fojt sshbuf_poke(struct sshbuf *buf, size_t offset, void *v, size_t len)
5030cbfa66cSDaniel Fojt {
5040cbfa66cSDaniel Fojt u_char *p = NULL;
5050cbfa66cSDaniel Fojt int r;
5060cbfa66cSDaniel Fojt
5070cbfa66cSDaniel Fojt if ((r = check_woffset(buf, offset, len, &p)) != 0)
5080cbfa66cSDaniel Fojt return r;
5090cbfa66cSDaniel Fojt memcpy(p, v, len);
5100cbfa66cSDaniel Fojt return 0;
5110cbfa66cSDaniel Fojt }
5120cbfa66cSDaniel Fojt
51336e94dc5SPeter Avalos int
sshbuf_put_string(struct sshbuf * buf,const void * v,size_t len)51436e94dc5SPeter Avalos sshbuf_put_string(struct sshbuf *buf, const void *v, size_t len)
51536e94dc5SPeter Avalos {
51636e94dc5SPeter Avalos u_char *d;
51736e94dc5SPeter Avalos int r;
51836e94dc5SPeter Avalos
51936e94dc5SPeter Avalos if (len > SSHBUF_SIZE_MAX - 4) {
52036e94dc5SPeter Avalos SSHBUF_DBG(("SSH_ERR_NO_BUFFER_SPACE"));
52136e94dc5SPeter Avalos return SSH_ERR_NO_BUFFER_SPACE;
52236e94dc5SPeter Avalos }
52336e94dc5SPeter Avalos if ((r = sshbuf_reserve(buf, len + 4, &d)) < 0)
52436e94dc5SPeter Avalos return r;
52536e94dc5SPeter Avalos POKE_U32(d, len);
526e9778795SPeter Avalos if (len != 0)
52736e94dc5SPeter Avalos memcpy(d + 4, v, len);
52836e94dc5SPeter Avalos return 0;
52936e94dc5SPeter Avalos }
53036e94dc5SPeter Avalos
53136e94dc5SPeter Avalos int
sshbuf_put_cstring(struct sshbuf * buf,const char * v)53236e94dc5SPeter Avalos sshbuf_put_cstring(struct sshbuf *buf, const char *v)
53336e94dc5SPeter Avalos {
534ce74bacaSMatthew Dillon return sshbuf_put_string(buf, v, v == NULL ? 0 : strlen(v));
53536e94dc5SPeter Avalos }
53636e94dc5SPeter Avalos
53736e94dc5SPeter Avalos int
sshbuf_put_stringb(struct sshbuf * buf,const struct sshbuf * v)53836e94dc5SPeter Avalos sshbuf_put_stringb(struct sshbuf *buf, const struct sshbuf *v)
53936e94dc5SPeter Avalos {
5400cbfa66cSDaniel Fojt if (v == NULL)
5410cbfa66cSDaniel Fojt return sshbuf_put_string(buf, NULL, 0);
5420cbfa66cSDaniel Fojt
54336e94dc5SPeter Avalos return sshbuf_put_string(buf, sshbuf_ptr(v), sshbuf_len(v));
54436e94dc5SPeter Avalos }
54536e94dc5SPeter Avalos
54636e94dc5SPeter Avalos int
sshbuf_froms(struct sshbuf * buf,struct sshbuf ** bufp)54736e94dc5SPeter Avalos sshbuf_froms(struct sshbuf *buf, struct sshbuf **bufp)
54836e94dc5SPeter Avalos {
54936e94dc5SPeter Avalos const u_char *p;
55036e94dc5SPeter Avalos size_t len;
55136e94dc5SPeter Avalos struct sshbuf *ret;
55236e94dc5SPeter Avalos int r;
55336e94dc5SPeter Avalos
55436e94dc5SPeter Avalos if (buf == NULL || bufp == NULL)
55536e94dc5SPeter Avalos return SSH_ERR_INVALID_ARGUMENT;
55636e94dc5SPeter Avalos *bufp = NULL;
55736e94dc5SPeter Avalos if ((r = sshbuf_peek_string_direct(buf, &p, &len)) != 0)
55836e94dc5SPeter Avalos return r;
55936e94dc5SPeter Avalos if ((ret = sshbuf_from(p, len)) == NULL)
56036e94dc5SPeter Avalos return SSH_ERR_ALLOC_FAIL;
56136e94dc5SPeter Avalos if ((r = sshbuf_consume(buf, len + 4)) != 0 || /* Shouldn't happen */
56236e94dc5SPeter Avalos (r = sshbuf_set_parent(ret, buf)) != 0) {
56336e94dc5SPeter Avalos sshbuf_free(ret);
56436e94dc5SPeter Avalos return r;
56536e94dc5SPeter Avalos }
56636e94dc5SPeter Avalos *bufp = ret;
56736e94dc5SPeter Avalos return 0;
56836e94dc5SPeter Avalos }
56936e94dc5SPeter Avalos
57036e94dc5SPeter Avalos int
sshbuf_put_bignum2_bytes(struct sshbuf * buf,const void * v,size_t len)57136e94dc5SPeter Avalos sshbuf_put_bignum2_bytes(struct sshbuf *buf, const void *v, size_t len)
57236e94dc5SPeter Avalos {
57336e94dc5SPeter Avalos u_char *d;
57436e94dc5SPeter Avalos const u_char *s = (const u_char *)v;
57536e94dc5SPeter Avalos int r, prepend;
57636e94dc5SPeter Avalos
57736e94dc5SPeter Avalos if (len > SSHBUF_SIZE_MAX - 5) {
57836e94dc5SPeter Avalos SSHBUF_DBG(("SSH_ERR_NO_BUFFER_SPACE"));
57936e94dc5SPeter Avalos return SSH_ERR_NO_BUFFER_SPACE;
58036e94dc5SPeter Avalos }
58136e94dc5SPeter Avalos /* Skip leading zero bytes */
58236e94dc5SPeter Avalos for (; len > 0 && *s == 0; len--, s++)
58336e94dc5SPeter Avalos ;
58436e94dc5SPeter Avalos /*
58536e94dc5SPeter Avalos * If most significant bit is set then prepend a zero byte to
58636e94dc5SPeter Avalos * avoid interpretation as a negative number.
58736e94dc5SPeter Avalos */
58836e94dc5SPeter Avalos prepend = len > 0 && (s[0] & 0x80) != 0;
58936e94dc5SPeter Avalos if ((r = sshbuf_reserve(buf, len + 4 + prepend, &d)) < 0)
59036e94dc5SPeter Avalos return r;
59136e94dc5SPeter Avalos POKE_U32(d, len + prepend);
59236e94dc5SPeter Avalos if (prepend)
59336e94dc5SPeter Avalos d[4] = 0;
594e9778795SPeter Avalos if (len != 0)
59536e94dc5SPeter Avalos memcpy(d + 4 + prepend, s, len);
59636e94dc5SPeter Avalos return 0;
59736e94dc5SPeter Avalos }
598e9778795SPeter Avalos
599e9778795SPeter Avalos int
sshbuf_get_bignum2_bytes_direct(struct sshbuf * buf,const u_char ** valp,size_t * lenp)600e9778795SPeter Avalos sshbuf_get_bignum2_bytes_direct(struct sshbuf *buf,
601e9778795SPeter Avalos const u_char **valp, size_t *lenp)
602e9778795SPeter Avalos {
603e9778795SPeter Avalos const u_char *d;
604e9778795SPeter Avalos size_t len, olen;
605e9778795SPeter Avalos int r;
606e9778795SPeter Avalos
607e9778795SPeter Avalos if ((r = sshbuf_peek_string_direct(buf, &d, &olen)) < 0)
608e9778795SPeter Avalos return r;
609e9778795SPeter Avalos len = olen;
610e9778795SPeter Avalos /* Refuse negative (MSB set) bignums */
611e9778795SPeter Avalos if ((len != 0 && (*d & 0x80) != 0))
612e9778795SPeter Avalos return SSH_ERR_BIGNUM_IS_NEGATIVE;
613e9778795SPeter Avalos /* Refuse overlong bignums, allow prepended \0 to avoid MSB set */
614e9778795SPeter Avalos if (len > SSHBUF_MAX_BIGNUM + 1 ||
615e9778795SPeter Avalos (len == SSHBUF_MAX_BIGNUM + 1 && *d != 0))
616e9778795SPeter Avalos return SSH_ERR_BIGNUM_TOO_LARGE;
617e9778795SPeter Avalos /* Trim leading zeros */
618e9778795SPeter Avalos while (len > 0 && *d == 0x00) {
619e9778795SPeter Avalos d++;
620e9778795SPeter Avalos len--;
621e9778795SPeter Avalos }
622e9778795SPeter Avalos if (valp != NULL)
623e9778795SPeter Avalos *valp = d;
624e9778795SPeter Avalos if (lenp != NULL)
625e9778795SPeter Avalos *lenp = len;
626e9778795SPeter Avalos if (sshbuf_consume(buf, olen + 4) != 0) {
627e9778795SPeter Avalos /* Shouldn't happen */
628e9778795SPeter Avalos SSHBUF_DBG(("SSH_ERR_INTERNAL_ERROR"));
629e9778795SPeter Avalos SSHBUF_ABORT();
630e9778795SPeter Avalos return SSH_ERR_INTERNAL_ERROR;
631e9778795SPeter Avalos }
632e9778795SPeter Avalos return 0;
633e9778795SPeter Avalos }
634