1*e160b4e8Schristos /* $OpenBSD: sshbuf-getput-basic.c,v 1.13 2022/05/25 06:03:44 djm Exp $ */
25484a5efSchristos /*
35484a5efSchristos * Copyright (c) 2011 Damien Miller
45484a5efSchristos *
55484a5efSchristos * Permission to use, copy, modify, and distribute this software for any
65484a5efSchristos * purpose with or without fee is hereby granted, provided that the above
75484a5efSchristos * copyright notice and this permission notice appear in all copies.
85484a5efSchristos *
95484a5efSchristos * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
105484a5efSchristos * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
115484a5efSchristos * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
125484a5efSchristos * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
135484a5efSchristos * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
145484a5efSchristos * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
155484a5efSchristos * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
165484a5efSchristos */
178a4530f9Schristos #include "includes.h"
18*e160b4e8Schristos __RCSID("$NetBSD: sshbuf-getput-basic.c,v 1.12 2022/10/05 22:39:36 christos Exp $");
195484a5efSchristos
205484a5efSchristos #include <sys/types.h>
215101d403Schristos
225101d403Schristos #include <stdarg.h>
235484a5efSchristos #include <stdlib.h>
245484a5efSchristos #include <stdio.h>
255484a5efSchristos #include <string.h>
26cd4ada6aSchristos #include <stdint.h>
275484a5efSchristos
285484a5efSchristos #include "ssherr.h"
295484a5efSchristos #define SSHBUF_INTERNAL
305484a5efSchristos #include "sshbuf.h"
315484a5efSchristos
325484a5efSchristos int
sshbuf_get(struct sshbuf * buf,void * v,size_t len)335484a5efSchristos sshbuf_get(struct sshbuf *buf, void *v, size_t len)
345484a5efSchristos {
355484a5efSchristos const u_char *p = sshbuf_ptr(buf);
365484a5efSchristos int r;
375484a5efSchristos
385484a5efSchristos if ((r = sshbuf_consume(buf, len)) < 0)
395484a5efSchristos return r;
40e4d43b82Schristos if (v != NULL && len != 0)
415484a5efSchristos memcpy(v, p, len);
425484a5efSchristos return 0;
435484a5efSchristos }
445484a5efSchristos
455484a5efSchristos int
sshbuf_get_u64(struct sshbuf * buf,u_int64_t * valp)465484a5efSchristos sshbuf_get_u64(struct sshbuf *buf, u_int64_t *valp)
475484a5efSchristos {
485484a5efSchristos const u_char *p = sshbuf_ptr(buf);
495484a5efSchristos int r;
505484a5efSchristos
515484a5efSchristos if ((r = sshbuf_consume(buf, 8)) < 0)
525484a5efSchristos return r;
535484a5efSchristos if (valp != NULL)
545484a5efSchristos *valp = PEEK_U64(p);
555484a5efSchristos return 0;
565484a5efSchristos }
575484a5efSchristos
585484a5efSchristos int
sshbuf_get_u32(struct sshbuf * buf,u_int32_t * valp)595484a5efSchristos sshbuf_get_u32(struct sshbuf *buf, u_int32_t *valp)
605484a5efSchristos {
615484a5efSchristos const u_char *p = sshbuf_ptr(buf);
625484a5efSchristos int r;
635484a5efSchristos
645484a5efSchristos if ((r = sshbuf_consume(buf, 4)) < 0)
655484a5efSchristos return r;
665484a5efSchristos if (valp != NULL)
675484a5efSchristos *valp = PEEK_U32(p);
685484a5efSchristos return 0;
695484a5efSchristos }
705484a5efSchristos
715484a5efSchristos int
sshbuf_get_u16(struct sshbuf * buf,u_int16_t * valp)725484a5efSchristos sshbuf_get_u16(struct sshbuf *buf, u_int16_t *valp)
735484a5efSchristos {
745484a5efSchristos const u_char *p = sshbuf_ptr(buf);
755484a5efSchristos int r;
765484a5efSchristos
775484a5efSchristos if ((r = sshbuf_consume(buf, 2)) < 0)
785484a5efSchristos return r;
795484a5efSchristos if (valp != NULL)
805484a5efSchristos *valp = PEEK_U16(p);
815484a5efSchristos return 0;
825484a5efSchristos }
835484a5efSchristos
845484a5efSchristos int
sshbuf_get_u8(struct sshbuf * buf,u_char * valp)855484a5efSchristos sshbuf_get_u8(struct sshbuf *buf, u_char *valp)
865484a5efSchristos {
875484a5efSchristos const u_char *p = sshbuf_ptr(buf);
885484a5efSchristos int r;
895484a5efSchristos
905484a5efSchristos if ((r = sshbuf_consume(buf, 1)) < 0)
915484a5efSchristos return r;
925484a5efSchristos if (valp != NULL)
935484a5efSchristos *valp = (u_int8_t)*p;
945484a5efSchristos return 0;
955484a5efSchristos }
965484a5efSchristos
97cd4ada6aSchristos static int
check_offset(const struct sshbuf * buf,int wr,size_t offset,size_t len)98cd4ada6aSchristos check_offset(const struct sshbuf *buf, int wr, size_t offset, size_t len)
99cd4ada6aSchristos {
100cd4ada6aSchristos if (sshbuf_ptr(buf) == NULL) /* calls sshbuf_check_sanity() */
101cd4ada6aSchristos return SSH_ERR_INTERNAL_ERROR;
102cd4ada6aSchristos if (offset >= SIZE_MAX - len)
103cd4ada6aSchristos return SSH_ERR_INVALID_ARGUMENT;
104cd4ada6aSchristos if (offset + len > sshbuf_len(buf)) {
105cd4ada6aSchristos return wr ?
106cd4ada6aSchristos SSH_ERR_NO_BUFFER_SPACE : SSH_ERR_MESSAGE_INCOMPLETE;
107cd4ada6aSchristos }
108cd4ada6aSchristos return 0;
109cd4ada6aSchristos }
110cd4ada6aSchristos
111cd4ada6aSchristos static int
check_roffset(const struct sshbuf * buf,size_t offset,size_t len,const u_char ** p)112cd4ada6aSchristos check_roffset(const struct sshbuf *buf, size_t offset, size_t len,
113cd4ada6aSchristos const u_char **p)
114cd4ada6aSchristos {
115cd4ada6aSchristos int r;
116cd4ada6aSchristos
117cd4ada6aSchristos *p = NULL;
118cd4ada6aSchristos if ((r = check_offset(buf, 0, offset, len)) != 0)
119cd4ada6aSchristos return r;
120cd4ada6aSchristos *p = sshbuf_ptr(buf) + offset;
121cd4ada6aSchristos return 0;
122cd4ada6aSchristos }
123cd4ada6aSchristos
124cd4ada6aSchristos int
sshbuf_peek_u64(const struct sshbuf * buf,size_t offset,u_int64_t * valp)125cd4ada6aSchristos sshbuf_peek_u64(const struct sshbuf *buf, size_t offset, u_int64_t *valp)
126cd4ada6aSchristos {
127cd4ada6aSchristos const u_char *p = NULL;
128cd4ada6aSchristos int r;
129cd4ada6aSchristos
130cd4ada6aSchristos if (valp != NULL)
131cd4ada6aSchristos *valp = 0;
132cd4ada6aSchristos if ((r = check_roffset(buf, offset, 8, &p)) != 0)
133cd4ada6aSchristos return r;
134cd4ada6aSchristos if (valp != NULL)
135cd4ada6aSchristos *valp = PEEK_U64(p);
136cd4ada6aSchristos return 0;
137cd4ada6aSchristos }
138cd4ada6aSchristos
139cd4ada6aSchristos int
sshbuf_peek_u32(const struct sshbuf * buf,size_t offset,u_int32_t * valp)140cd4ada6aSchristos sshbuf_peek_u32(const struct sshbuf *buf, size_t offset, u_int32_t *valp)
141cd4ada6aSchristos {
142cd4ada6aSchristos const u_char *p = NULL;
143cd4ada6aSchristos int r;
144cd4ada6aSchristos
145cd4ada6aSchristos if (valp != NULL)
146cd4ada6aSchristos *valp = 0;
147cd4ada6aSchristos if ((r = check_roffset(buf, offset, 4, &p)) != 0)
148cd4ada6aSchristos return r;
149cd4ada6aSchristos if (valp != NULL)
150cd4ada6aSchristos *valp = PEEK_U32(p);
151cd4ada6aSchristos return 0;
152cd4ada6aSchristos }
153cd4ada6aSchristos
154cd4ada6aSchristos int
sshbuf_peek_u16(const struct sshbuf * buf,size_t offset,u_int16_t * valp)155cd4ada6aSchristos sshbuf_peek_u16(const struct sshbuf *buf, size_t offset, u_int16_t *valp)
156cd4ada6aSchristos {
157cd4ada6aSchristos const u_char *p = NULL;
158cd4ada6aSchristos int r;
159cd4ada6aSchristos
160cd4ada6aSchristos if (valp != NULL)
161cd4ada6aSchristos *valp = 0;
162cd4ada6aSchristos if ((r = check_roffset(buf, offset, 2, &p)) != 0)
163cd4ada6aSchristos return r;
164cd4ada6aSchristos if (valp != NULL)
165cd4ada6aSchristos *valp = PEEK_U16(p);
166cd4ada6aSchristos return 0;
167cd4ada6aSchristos }
168cd4ada6aSchristos
169cd4ada6aSchristos int
sshbuf_peek_u8(const struct sshbuf * buf,size_t offset,u_char * valp)170cd4ada6aSchristos sshbuf_peek_u8(const struct sshbuf *buf, size_t offset, u_char *valp)
171cd4ada6aSchristos {
172cd4ada6aSchristos const u_char *p = NULL;
173cd4ada6aSchristos int r;
174cd4ada6aSchristos
175cd4ada6aSchristos if (valp != NULL)
176cd4ada6aSchristos *valp = 0;
177cd4ada6aSchristos if ((r = check_roffset(buf, offset, 1, &p)) != 0)
178cd4ada6aSchristos return r;
179cd4ada6aSchristos if (valp != NULL)
180cd4ada6aSchristos *valp = *p;
181cd4ada6aSchristos return 0;
182cd4ada6aSchristos }
183cd4ada6aSchristos
1845484a5efSchristos int
sshbuf_get_string(struct sshbuf * buf,u_char ** valp,size_t * lenp)1855484a5efSchristos sshbuf_get_string(struct sshbuf *buf, u_char **valp, size_t *lenp)
1865484a5efSchristos {
1875484a5efSchristos const u_char *val;
1885484a5efSchristos size_t len;
1895484a5efSchristos int r;
1905484a5efSchristos
1915484a5efSchristos if (valp != NULL)
1925484a5efSchristos *valp = NULL;
1935484a5efSchristos if (lenp != NULL)
1945484a5efSchristos *lenp = 0;
1955484a5efSchristos if ((r = sshbuf_get_string_direct(buf, &val, &len)) < 0)
1965484a5efSchristos return r;
1975484a5efSchristos if (valp != NULL) {
1985484a5efSchristos if ((*valp = malloc(len + 1)) == NULL) {
1995484a5efSchristos SSHBUF_DBG(("SSH_ERR_ALLOC_FAIL"));
2005484a5efSchristos return SSH_ERR_ALLOC_FAIL;
2015484a5efSchristos }
202e4d43b82Schristos if (len != 0)
2035484a5efSchristos memcpy(*valp, val, len);
2045484a5efSchristos (*valp)[len] = '\0';
2055484a5efSchristos }
2065484a5efSchristos if (lenp != NULL)
2075484a5efSchristos *lenp = len;
2085484a5efSchristos return 0;
2095484a5efSchristos }
2105484a5efSchristos
2115484a5efSchristos int
sshbuf_get_string_direct(struct sshbuf * buf,const u_char ** valp,size_t * lenp)2125484a5efSchristos sshbuf_get_string_direct(struct sshbuf *buf, const u_char **valp, size_t *lenp)
2135484a5efSchristos {
2145484a5efSchristos size_t len;
2155484a5efSchristos const u_char *p;
2165484a5efSchristos int r;
2175484a5efSchristos
2185484a5efSchristos if (valp != NULL)
2195484a5efSchristos *valp = NULL;
2205484a5efSchristos if (lenp != NULL)
2215484a5efSchristos *lenp = 0;
2225484a5efSchristos if ((r = sshbuf_peek_string_direct(buf, &p, &len)) < 0)
2235484a5efSchristos return r;
22479976551Schristos if (valp != NULL)
2255484a5efSchristos *valp = p;
2265484a5efSchristos if (lenp != NULL)
2275484a5efSchristos *lenp = len;
2285484a5efSchristos if (sshbuf_consume(buf, len + 4) != 0) {
2295484a5efSchristos /* Shouldn't happen */
2305484a5efSchristos SSHBUF_DBG(("SSH_ERR_INTERNAL_ERROR"));
2315484a5efSchristos SSHBUF_ABORT();
2325484a5efSchristos return SSH_ERR_INTERNAL_ERROR;
2335484a5efSchristos }
2345484a5efSchristos return 0;
2355484a5efSchristos }
2365484a5efSchristos
2375484a5efSchristos int
sshbuf_peek_string_direct(const struct sshbuf * buf,const u_char ** valp,size_t * lenp)2385484a5efSchristos sshbuf_peek_string_direct(const struct sshbuf *buf, const u_char **valp,
2395484a5efSchristos size_t *lenp)
2405484a5efSchristos {
2415484a5efSchristos u_int32_t len;
2425484a5efSchristos const u_char *p = sshbuf_ptr(buf);
2435484a5efSchristos
2445484a5efSchristos if (valp != NULL)
2455484a5efSchristos *valp = NULL;
2465484a5efSchristos if (lenp != NULL)
2475484a5efSchristos *lenp = 0;
2485484a5efSchristos if (sshbuf_len(buf) < 4) {
2495484a5efSchristos SSHBUF_DBG(("SSH_ERR_MESSAGE_INCOMPLETE"));
2505484a5efSchristos return SSH_ERR_MESSAGE_INCOMPLETE;
2515484a5efSchristos }
2525484a5efSchristos len = PEEK_U32(p);
2535484a5efSchristos if (len > SSHBUF_SIZE_MAX - 4) {
2545484a5efSchristos SSHBUF_DBG(("SSH_ERR_STRING_TOO_LARGE"));
2555484a5efSchristos return SSH_ERR_STRING_TOO_LARGE;
2565484a5efSchristos }
2575484a5efSchristos if (sshbuf_len(buf) - 4 < len) {
2585484a5efSchristos SSHBUF_DBG(("SSH_ERR_MESSAGE_INCOMPLETE"));
2595484a5efSchristos return SSH_ERR_MESSAGE_INCOMPLETE;
2605484a5efSchristos }
26179976551Schristos if (valp != NULL)
2625484a5efSchristos *valp = p + 4;
2635484a5efSchristos if (lenp != NULL)
2645484a5efSchristos *lenp = len;
2655484a5efSchristos return 0;
2665484a5efSchristos }
2675484a5efSchristos
2685484a5efSchristos int
sshbuf_get_cstring(struct sshbuf * buf,char ** valp,size_t * lenp)2695484a5efSchristos sshbuf_get_cstring(struct sshbuf *buf, char **valp, size_t *lenp)
2705484a5efSchristos {
2715484a5efSchristos size_t len;
2725484a5efSchristos const u_char *p, *z;
2735484a5efSchristos int r;
2745484a5efSchristos
2755484a5efSchristos if (valp != NULL)
2765484a5efSchristos *valp = NULL;
2775484a5efSchristos if (lenp != NULL)
2785484a5efSchristos *lenp = 0;
2795484a5efSchristos if ((r = sshbuf_peek_string_direct(buf, &p, &len)) != 0)
2805484a5efSchristos return r;
2815484a5efSchristos /* Allow a \0 only at the end of the string */
2825484a5efSchristos if (len > 0 &&
2835484a5efSchristos (z = memchr(p , '\0', len)) != NULL && z < p + len - 1) {
2845484a5efSchristos SSHBUF_DBG(("SSH_ERR_INVALID_FORMAT"));
2855484a5efSchristos return SSH_ERR_INVALID_FORMAT;
2865484a5efSchristos }
2875484a5efSchristos if ((r = sshbuf_skip_string(buf)) != 0)
2885484a5efSchristos return -1;
2895484a5efSchristos if (valp != NULL) {
2905484a5efSchristos if ((*valp = malloc(len + 1)) == NULL) {
2915484a5efSchristos SSHBUF_DBG(("SSH_ERR_ALLOC_FAIL"));
2925484a5efSchristos return SSH_ERR_ALLOC_FAIL;
2935484a5efSchristos }
294e4d43b82Schristos if (len != 0)
2955484a5efSchristos memcpy(*valp, p, len);
2965484a5efSchristos (*valp)[len] = '\0';
2975484a5efSchristos }
2985484a5efSchristos if (lenp != NULL)
2995484a5efSchristos *lenp = (size_t)len;
3005484a5efSchristos return 0;
3015484a5efSchristos }
3025484a5efSchristos
3035484a5efSchristos int
sshbuf_get_stringb(struct sshbuf * buf,struct sshbuf * v)3045484a5efSchristos sshbuf_get_stringb(struct sshbuf *buf, struct sshbuf *v)
3055484a5efSchristos {
3065484a5efSchristos u_int32_t len;
3075484a5efSchristos u_char *p;
3085484a5efSchristos int r;
3095484a5efSchristos
3105484a5efSchristos /*
3115484a5efSchristos * Use sshbuf_peek_string_direct() to figure out if there is
3125484a5efSchristos * a complete string in 'buf' and copy the string directly
3135484a5efSchristos * into 'v'.
3145484a5efSchristos */
3155484a5efSchristos if ((r = sshbuf_peek_string_direct(buf, NULL, NULL)) != 0 ||
3165484a5efSchristos (r = sshbuf_get_u32(buf, &len)) != 0 ||
3175484a5efSchristos (r = sshbuf_reserve(v, len, &p)) != 0 ||
3185484a5efSchristos (r = sshbuf_get(buf, p, len)) != 0)
3195484a5efSchristos return r;
3205484a5efSchristos return 0;
3215484a5efSchristos }
3225484a5efSchristos
3235484a5efSchristos int
sshbuf_put(struct sshbuf * buf,const void * v,size_t len)3245484a5efSchristos sshbuf_put(struct sshbuf *buf, const void *v, size_t len)
3255484a5efSchristos {
3265484a5efSchristos u_char *p;
3275484a5efSchristos int r;
3285484a5efSchristos
3295484a5efSchristos if ((r = sshbuf_reserve(buf, len, &p)) < 0)
3305484a5efSchristos return r;
331e4d43b82Schristos if (len != 0)
3325484a5efSchristos memcpy(p, v, len);
3335484a5efSchristos return 0;
3345484a5efSchristos }
3355484a5efSchristos
3365484a5efSchristos int
sshbuf_putb(struct sshbuf * buf,const struct sshbuf * v)3375484a5efSchristos sshbuf_putb(struct sshbuf *buf, const struct sshbuf *v)
3385484a5efSchristos {
3392d3b0f52Schristos if (v == NULL)
3402d3b0f52Schristos return 0;
3415484a5efSchristos return sshbuf_put(buf, sshbuf_ptr(v), sshbuf_len(v));
3425484a5efSchristos }
3435484a5efSchristos
3445484a5efSchristos int
sshbuf_putf(struct sshbuf * buf,const char * fmt,...)3455484a5efSchristos sshbuf_putf(struct sshbuf *buf, const char *fmt, ...)
3465484a5efSchristos {
3475484a5efSchristos va_list ap;
3485484a5efSchristos int r;
3495484a5efSchristos
3505484a5efSchristos va_start(ap, fmt);
3515484a5efSchristos r = sshbuf_putfv(buf, fmt, ap);
3525484a5efSchristos va_end(ap);
3535484a5efSchristos return r;
3545484a5efSchristos }
3555484a5efSchristos
3565484a5efSchristos int
sshbuf_putfv(struct sshbuf * buf,const char * fmt,va_list ap)3575484a5efSchristos sshbuf_putfv(struct sshbuf *buf, const char *fmt, va_list ap)
3585484a5efSchristos {
3595484a5efSchristos va_list ap2;
3605484a5efSchristos int r, len;
3615484a5efSchristos u_char *p;
3625484a5efSchristos
3635484a5efSchristos va_copy(ap2, ap);
3645484a5efSchristos if ((len = vsnprintf(NULL, 0, fmt, ap2)) < 0) {
3655484a5efSchristos r = SSH_ERR_INVALID_ARGUMENT;
3665484a5efSchristos goto out;
3675484a5efSchristos }
3685484a5efSchristos if (len == 0) {
3695484a5efSchristos r = 0;
3705484a5efSchristos goto out; /* Nothing to do */
3715484a5efSchristos }
3725484a5efSchristos va_end(ap2);
3735484a5efSchristos va_copy(ap2, ap);
3745484a5efSchristos if ((r = sshbuf_reserve(buf, (size_t)len + 1, &p)) < 0)
3755484a5efSchristos goto out;
3765484a5efSchristos if ((r = vsnprintf((char *)p, len + 1, fmt, ap2)) != len) {
3775484a5efSchristos r = SSH_ERR_INTERNAL_ERROR;
3785484a5efSchristos goto out; /* Shouldn't happen */
3795484a5efSchristos }
3805484a5efSchristos /* Consume terminating \0 */
3815484a5efSchristos if ((r = sshbuf_consume_end(buf, 1)) != 0)
3825484a5efSchristos goto out;
3835484a5efSchristos r = 0;
3845484a5efSchristos out:
3855484a5efSchristos va_end(ap2);
3865484a5efSchristos return r;
3875484a5efSchristos }
3885484a5efSchristos
3895484a5efSchristos int
sshbuf_put_u64(struct sshbuf * buf,u_int64_t val)3905484a5efSchristos sshbuf_put_u64(struct sshbuf *buf, u_int64_t val)
3915484a5efSchristos {
3925484a5efSchristos u_char *p;
3935484a5efSchristos int r;
3945484a5efSchristos
3955484a5efSchristos if ((r = sshbuf_reserve(buf, 8, &p)) < 0)
3965484a5efSchristos return r;
3975484a5efSchristos POKE_U64(p, val);
3985484a5efSchristos return 0;
3995484a5efSchristos }
4005484a5efSchristos
4015484a5efSchristos int
sshbuf_put_u32(struct sshbuf * buf,u_int32_t val)4025484a5efSchristos sshbuf_put_u32(struct sshbuf *buf, u_int32_t val)
4035484a5efSchristos {
4045484a5efSchristos u_char *p;
4055484a5efSchristos int r;
4065484a5efSchristos
4075484a5efSchristos if ((r = sshbuf_reserve(buf, 4, &p)) < 0)
4085484a5efSchristos return r;
4095484a5efSchristos POKE_U32(p, val);
4105484a5efSchristos return 0;
4115484a5efSchristos }
4125484a5efSchristos
4135484a5efSchristos int
sshbuf_put_u16(struct sshbuf * buf,u_int16_t val)4145484a5efSchristos sshbuf_put_u16(struct sshbuf *buf, u_int16_t val)
4155484a5efSchristos {
4165484a5efSchristos u_char *p;
4175484a5efSchristos int r;
4185484a5efSchristos
4195484a5efSchristos if ((r = sshbuf_reserve(buf, 2, &p)) < 0)
4205484a5efSchristos return r;
4215484a5efSchristos POKE_U16(p, val);
4225484a5efSchristos return 0;
4235484a5efSchristos }
4245484a5efSchristos
4255484a5efSchristos int
sshbuf_put_u8(struct sshbuf * buf,u_char val)4265484a5efSchristos sshbuf_put_u8(struct sshbuf *buf, u_char val)
4275484a5efSchristos {
4285484a5efSchristos u_char *p;
4295484a5efSchristos int r;
4305484a5efSchristos
4315484a5efSchristos if ((r = sshbuf_reserve(buf, 1, &p)) < 0)
4325484a5efSchristos return r;
4335484a5efSchristos p[0] = val;
4345484a5efSchristos return 0;
4355484a5efSchristos }
4365484a5efSchristos
437cd4ada6aSchristos static int
check_woffset(struct sshbuf * buf,size_t offset,size_t len,u_char ** p)438cd4ada6aSchristos check_woffset(struct sshbuf *buf, size_t offset, size_t len, u_char **p)
439cd4ada6aSchristos {
440cd4ada6aSchristos int r;
441cd4ada6aSchristos
442cd4ada6aSchristos *p = NULL;
443cd4ada6aSchristos if ((r = check_offset(buf, 1, offset, len)) != 0)
444cd4ada6aSchristos return r;
445cd4ada6aSchristos if (sshbuf_mutable_ptr(buf) == NULL)
446cd4ada6aSchristos return SSH_ERR_BUFFER_READ_ONLY;
447cd4ada6aSchristos *p = sshbuf_mutable_ptr(buf) + offset;
448cd4ada6aSchristos return 0;
449cd4ada6aSchristos }
450cd4ada6aSchristos
451cd4ada6aSchristos int
sshbuf_poke_u64(struct sshbuf * buf,size_t offset,u_int64_t val)452cd4ada6aSchristos sshbuf_poke_u64(struct sshbuf *buf, size_t offset, u_int64_t val)
453cd4ada6aSchristos {
454cd4ada6aSchristos u_char *p = NULL;
455cd4ada6aSchristos int r;
456cd4ada6aSchristos
457cd4ada6aSchristos if ((r = check_woffset(buf, offset, 8, &p)) != 0)
458cd4ada6aSchristos return r;
459cd4ada6aSchristos POKE_U64(p, val);
460cd4ada6aSchristos return 0;
461cd4ada6aSchristos }
462cd4ada6aSchristos
463cd4ada6aSchristos int
sshbuf_poke_u32(struct sshbuf * buf,size_t offset,u_int32_t val)464cd4ada6aSchristos sshbuf_poke_u32(struct sshbuf *buf, size_t offset, u_int32_t val)
465cd4ada6aSchristos {
466cd4ada6aSchristos u_char *p = NULL;
467cd4ada6aSchristos int r;
468cd4ada6aSchristos
469cd4ada6aSchristos if ((r = check_woffset(buf, offset, 4, &p)) != 0)
470cd4ada6aSchristos return r;
471cd4ada6aSchristos POKE_U32(p, val);
472cd4ada6aSchristos return 0;
473cd4ada6aSchristos }
474cd4ada6aSchristos
475cd4ada6aSchristos int
sshbuf_poke_u16(struct sshbuf * buf,size_t offset,u_int16_t val)476cd4ada6aSchristos sshbuf_poke_u16(struct sshbuf *buf, size_t offset, u_int16_t val)
477cd4ada6aSchristos {
478cd4ada6aSchristos u_char *p = NULL;
479cd4ada6aSchristos int r;
480cd4ada6aSchristos
481cd4ada6aSchristos if ((r = check_woffset(buf, offset, 2, &p)) != 0)
482cd4ada6aSchristos return r;
483cd4ada6aSchristos POKE_U16(p, val);
484cd4ada6aSchristos return 0;
485cd4ada6aSchristos }
486cd4ada6aSchristos
487cd4ada6aSchristos int
sshbuf_poke_u8(struct sshbuf * buf,size_t offset,u_char val)488cd4ada6aSchristos sshbuf_poke_u8(struct sshbuf *buf, size_t offset, u_char val)
489cd4ada6aSchristos {
490cd4ada6aSchristos u_char *p = NULL;
491cd4ada6aSchristos int r;
492cd4ada6aSchristos
493cd4ada6aSchristos if ((r = check_woffset(buf, offset, 1, &p)) != 0)
494cd4ada6aSchristos return r;
495cd4ada6aSchristos *p = val;
496cd4ada6aSchristos return 0;
497cd4ada6aSchristos }
498cd4ada6aSchristos
499cd4ada6aSchristos int
sshbuf_poke(struct sshbuf * buf,size_t offset,void * v,size_t len)500cd4ada6aSchristos sshbuf_poke(struct sshbuf *buf, size_t offset, void *v, size_t len)
501cd4ada6aSchristos {
502cd4ada6aSchristos u_char *p = NULL;
503cd4ada6aSchristos int r;
504cd4ada6aSchristos
505cd4ada6aSchristos if ((r = check_woffset(buf, offset, len, &p)) != 0)
506cd4ada6aSchristos return r;
507cd4ada6aSchristos memcpy(p, v, len);
508cd4ada6aSchristos return 0;
509cd4ada6aSchristos }
510cd4ada6aSchristos
5115484a5efSchristos int
sshbuf_put_string(struct sshbuf * buf,const void * v,size_t len)5125484a5efSchristos sshbuf_put_string(struct sshbuf *buf, const void *v, size_t len)
5135484a5efSchristos {
5145484a5efSchristos u_char *d;
5155484a5efSchristos int r;
5165484a5efSchristos
5175484a5efSchristos if (len > SSHBUF_SIZE_MAX - 4) {
5185484a5efSchristos SSHBUF_DBG(("SSH_ERR_NO_BUFFER_SPACE"));
5195484a5efSchristos return SSH_ERR_NO_BUFFER_SPACE;
5205484a5efSchristos }
5215484a5efSchristos if ((r = sshbuf_reserve(buf, len + 4, &d)) < 0)
5225484a5efSchristos return r;
5235484a5efSchristos POKE_U32(d, len);
524e4d43b82Schristos if (len != 0)
5255484a5efSchristos memcpy(d + 4, v, len);
5265484a5efSchristos return 0;
5275484a5efSchristos }
5285484a5efSchristos
5295484a5efSchristos int
sshbuf_put_cstring(struct sshbuf * buf,const char * v)5305484a5efSchristos sshbuf_put_cstring(struct sshbuf *buf, const char *v)
5315484a5efSchristos {
532e4d43b82Schristos return sshbuf_put_string(buf, __UNCONST(v), v == NULL ? 0 : strlen(v));
5335484a5efSchristos }
5345484a5efSchristos
5355484a5efSchristos int
sshbuf_put_stringb(struct sshbuf * buf,const struct sshbuf * v)5365484a5efSchristos sshbuf_put_stringb(struct sshbuf *buf, const struct sshbuf *v)
5375484a5efSchristos {
538ed75d7a8Schristos if (v == NULL)
539ed75d7a8Schristos return sshbuf_put_string(buf, NULL, 0);
540ed75d7a8Schristos
5415484a5efSchristos return sshbuf_put_string(buf, sshbuf_ptr(v), sshbuf_len(v));
5425484a5efSchristos }
5435484a5efSchristos
5445484a5efSchristos int
sshbuf_froms(struct sshbuf * buf,struct sshbuf ** bufp)5455484a5efSchristos sshbuf_froms(struct sshbuf *buf, struct sshbuf **bufp)
5465484a5efSchristos {
5475484a5efSchristos const u_char *p;
5485484a5efSchristos size_t len;
5495484a5efSchristos struct sshbuf *ret;
5505484a5efSchristos int r;
5515484a5efSchristos
5525484a5efSchristos if (buf == NULL || bufp == NULL)
5535484a5efSchristos return SSH_ERR_INVALID_ARGUMENT;
5545484a5efSchristos *bufp = NULL;
5555484a5efSchristos if ((r = sshbuf_peek_string_direct(buf, &p, &len)) != 0)
5565484a5efSchristos return r;
5575484a5efSchristos if ((ret = sshbuf_from(p, len)) == NULL)
5585484a5efSchristos return SSH_ERR_ALLOC_FAIL;
5595484a5efSchristos if ((r = sshbuf_consume(buf, len + 4)) != 0 || /* Shouldn't happen */
5605484a5efSchristos (r = sshbuf_set_parent(ret, buf)) != 0) {
5615484a5efSchristos sshbuf_free(ret);
5625484a5efSchristos return r;
5635484a5efSchristos }
5645484a5efSchristos *bufp = ret;
5655484a5efSchristos return 0;
5665484a5efSchristos }
5675484a5efSchristos
5685484a5efSchristos int
sshbuf_put_bignum2_bytes(struct sshbuf * buf,const void * v,size_t len)5695484a5efSchristos sshbuf_put_bignum2_bytes(struct sshbuf *buf, const void *v, size_t len)
5705484a5efSchristos {
5715484a5efSchristos u_char *d;
5725484a5efSchristos const u_char *s = (const u_char *)v;
5735484a5efSchristos int r, prepend;
5745484a5efSchristos
5755484a5efSchristos if (len > SSHBUF_SIZE_MAX - 5) {
5765484a5efSchristos SSHBUF_DBG(("SSH_ERR_NO_BUFFER_SPACE"));
5775484a5efSchristos return SSH_ERR_NO_BUFFER_SPACE;
5785484a5efSchristos }
5795484a5efSchristos /* Skip leading zero bytes */
5805484a5efSchristos for (; len > 0 && *s == 0; len--, s++)
5815484a5efSchristos ;
5825484a5efSchristos /*
5835484a5efSchristos * If most significant bit is set then prepend a zero byte to
5845484a5efSchristos * avoid interpretation as a negative number.
5855484a5efSchristos */
5865484a5efSchristos prepend = len > 0 && (s[0] & 0x80) != 0;
5875484a5efSchristos if ((r = sshbuf_reserve(buf, len + 4 + prepend, &d)) < 0)
5885484a5efSchristos return r;
5895484a5efSchristos POKE_U32(d, len + prepend);
5905484a5efSchristos if (prepend)
5915484a5efSchristos d[4] = 0;
592e4d43b82Schristos if (len != 0)
5935484a5efSchristos memcpy(d + 4 + prepend, s, len);
5945484a5efSchristos return 0;
5955484a5efSchristos }
596e4d43b82Schristos
597e4d43b82Schristos int
sshbuf_get_bignum2_bytes_direct(struct sshbuf * buf,const u_char ** valp,size_t * lenp)598e4d43b82Schristos sshbuf_get_bignum2_bytes_direct(struct sshbuf *buf,
599e4d43b82Schristos const u_char **valp, size_t *lenp)
600e4d43b82Schristos {
601e4d43b82Schristos const u_char *d;
602e4d43b82Schristos size_t len, olen;
603e4d43b82Schristos int r;
604e4d43b82Schristos
605e4d43b82Schristos if ((r = sshbuf_peek_string_direct(buf, &d, &olen)) < 0)
606e4d43b82Schristos return r;
607e4d43b82Schristos len = olen;
608e4d43b82Schristos /* Refuse negative (MSB set) bignums */
609e4d43b82Schristos if ((len != 0 && (*d & 0x80) != 0))
610e4d43b82Schristos return SSH_ERR_BIGNUM_IS_NEGATIVE;
611e4d43b82Schristos /* Refuse overlong bignums, allow prepended \0 to avoid MSB set */
612e4d43b82Schristos if (len > SSHBUF_MAX_BIGNUM + 1 ||
613e4d43b82Schristos (len == SSHBUF_MAX_BIGNUM + 1 && *d != 0))
614e4d43b82Schristos return SSH_ERR_BIGNUM_TOO_LARGE;
615e4d43b82Schristos /* Trim leading zeros */
616e4d43b82Schristos while (len > 0 && *d == 0x00) {
617e4d43b82Schristos d++;
618e4d43b82Schristos len--;
619e4d43b82Schristos }
62079976551Schristos if (valp != NULL)
621e4d43b82Schristos *valp = d;
622e4d43b82Schristos if (lenp != NULL)
623e4d43b82Schristos *lenp = len;
624e4d43b82Schristos if (sshbuf_consume(buf, olen + 4) != 0) {
625e4d43b82Schristos /* Shouldn't happen */
626e4d43b82Schristos SSHBUF_DBG(("SSH_ERR_INTERNAL_ERROR"));
627e4d43b82Schristos SSHBUF_ABORT();
628e4d43b82Schristos return SSH_ERR_INTERNAL_ERROR;
629e4d43b82Schristos }
630e4d43b82Schristos return 0;
631e4d43b82Schristos }
632