1d059297112922cabb0c674840589be8db821fd9aAdam Langley/*	$OpenBSD: sshbuf-getput-basic.c,v 1.4 2015/01/14 15:02:39 djm Exp $	*/
2d059297112922cabb0c674840589be8db821fd9aAdam Langley/*
3d059297112922cabb0c674840589be8db821fd9aAdam Langley * Copyright (c) 2011 Damien Miller
4d059297112922cabb0c674840589be8db821fd9aAdam Langley *
5d059297112922cabb0c674840589be8db821fd9aAdam Langley * Permission to use, copy, modify, and distribute this software for any
6d059297112922cabb0c674840589be8db821fd9aAdam Langley * purpose with or without fee is hereby granted, provided that the above
7d059297112922cabb0c674840589be8db821fd9aAdam Langley * copyright notice and this permission notice appear in all copies.
8d059297112922cabb0c674840589be8db821fd9aAdam Langley *
9d059297112922cabb0c674840589be8db821fd9aAdam Langley * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10d059297112922cabb0c674840589be8db821fd9aAdam Langley * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11d059297112922cabb0c674840589be8db821fd9aAdam Langley * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12d059297112922cabb0c674840589be8db821fd9aAdam Langley * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13d059297112922cabb0c674840589be8db821fd9aAdam Langley * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14d059297112922cabb0c674840589be8db821fd9aAdam Langley * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15d059297112922cabb0c674840589be8db821fd9aAdam Langley * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16d059297112922cabb0c674840589be8db821fd9aAdam Langley */
17d059297112922cabb0c674840589be8db821fd9aAdam Langley
18d059297112922cabb0c674840589be8db821fd9aAdam Langley#define SSHBUF_INTERNAL
19d059297112922cabb0c674840589be8db821fd9aAdam Langley#include "includes.h"
20d059297112922cabb0c674840589be8db821fd9aAdam Langley
21d059297112922cabb0c674840589be8db821fd9aAdam Langley#include <sys/types.h>
22d059297112922cabb0c674840589be8db821fd9aAdam Langley#include <stdlib.h>
23d059297112922cabb0c674840589be8db821fd9aAdam Langley#include <stdio.h>
24d059297112922cabb0c674840589be8db821fd9aAdam Langley#include <string.h>
25d059297112922cabb0c674840589be8db821fd9aAdam Langley
26d059297112922cabb0c674840589be8db821fd9aAdam Langley#include "ssherr.h"
27d059297112922cabb0c674840589be8db821fd9aAdam Langley#include "sshbuf.h"
28d059297112922cabb0c674840589be8db821fd9aAdam Langley
29d059297112922cabb0c674840589be8db821fd9aAdam Langleyint
30d059297112922cabb0c674840589be8db821fd9aAdam Langleysshbuf_get(struct sshbuf *buf, void *v, size_t len)
31d059297112922cabb0c674840589be8db821fd9aAdam Langley{
32d059297112922cabb0c674840589be8db821fd9aAdam Langley	const u_char *p = sshbuf_ptr(buf);
33d059297112922cabb0c674840589be8db821fd9aAdam Langley	int r;
34d059297112922cabb0c674840589be8db821fd9aAdam Langley
35d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((r = sshbuf_consume(buf, len)) < 0)
36d059297112922cabb0c674840589be8db821fd9aAdam Langley		return r;
37d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (v != NULL && len != 0)
38d059297112922cabb0c674840589be8db821fd9aAdam Langley		memcpy(v, p, len);
39d059297112922cabb0c674840589be8db821fd9aAdam Langley	return 0;
40d059297112922cabb0c674840589be8db821fd9aAdam Langley}
41d059297112922cabb0c674840589be8db821fd9aAdam Langley
42d059297112922cabb0c674840589be8db821fd9aAdam Langleyint
43d059297112922cabb0c674840589be8db821fd9aAdam Langleysshbuf_get_u64(struct sshbuf *buf, u_int64_t *valp)
44d059297112922cabb0c674840589be8db821fd9aAdam Langley{
45d059297112922cabb0c674840589be8db821fd9aAdam Langley	const u_char *p = sshbuf_ptr(buf);
46d059297112922cabb0c674840589be8db821fd9aAdam Langley	int r;
47d059297112922cabb0c674840589be8db821fd9aAdam Langley
48d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((r = sshbuf_consume(buf, 8)) < 0)
49d059297112922cabb0c674840589be8db821fd9aAdam Langley		return r;
50d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (valp != NULL)
51d059297112922cabb0c674840589be8db821fd9aAdam Langley		*valp = PEEK_U64(p);
52d059297112922cabb0c674840589be8db821fd9aAdam Langley	return 0;
53d059297112922cabb0c674840589be8db821fd9aAdam Langley}
54d059297112922cabb0c674840589be8db821fd9aAdam Langley
55d059297112922cabb0c674840589be8db821fd9aAdam Langleyint
56d059297112922cabb0c674840589be8db821fd9aAdam Langleysshbuf_get_u32(struct sshbuf *buf, u_int32_t *valp)
57d059297112922cabb0c674840589be8db821fd9aAdam Langley{
58d059297112922cabb0c674840589be8db821fd9aAdam Langley	const u_char *p = sshbuf_ptr(buf);
59d059297112922cabb0c674840589be8db821fd9aAdam Langley	int r;
60d059297112922cabb0c674840589be8db821fd9aAdam Langley
61d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((r = sshbuf_consume(buf, 4)) < 0)
62d059297112922cabb0c674840589be8db821fd9aAdam Langley		return r;
63d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (valp != NULL)
64d059297112922cabb0c674840589be8db821fd9aAdam Langley		*valp = PEEK_U32(p);
65d059297112922cabb0c674840589be8db821fd9aAdam Langley	return 0;
66d059297112922cabb0c674840589be8db821fd9aAdam Langley}
67d059297112922cabb0c674840589be8db821fd9aAdam Langley
68d059297112922cabb0c674840589be8db821fd9aAdam Langleyint
69d059297112922cabb0c674840589be8db821fd9aAdam Langleysshbuf_get_u16(struct sshbuf *buf, u_int16_t *valp)
70d059297112922cabb0c674840589be8db821fd9aAdam Langley{
71d059297112922cabb0c674840589be8db821fd9aAdam Langley	const u_char *p = sshbuf_ptr(buf);
72d059297112922cabb0c674840589be8db821fd9aAdam Langley	int r;
73d059297112922cabb0c674840589be8db821fd9aAdam Langley
74d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((r = sshbuf_consume(buf, 2)) < 0)
75d059297112922cabb0c674840589be8db821fd9aAdam Langley		return r;
76d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (valp != NULL)
77d059297112922cabb0c674840589be8db821fd9aAdam Langley		*valp = PEEK_U16(p);
78d059297112922cabb0c674840589be8db821fd9aAdam Langley	return 0;
79d059297112922cabb0c674840589be8db821fd9aAdam Langley}
80d059297112922cabb0c674840589be8db821fd9aAdam Langley
81d059297112922cabb0c674840589be8db821fd9aAdam Langleyint
82d059297112922cabb0c674840589be8db821fd9aAdam Langleysshbuf_get_u8(struct sshbuf *buf, u_char *valp)
83d059297112922cabb0c674840589be8db821fd9aAdam Langley{
84d059297112922cabb0c674840589be8db821fd9aAdam Langley	const u_char *p = sshbuf_ptr(buf);
85d059297112922cabb0c674840589be8db821fd9aAdam Langley	int r;
86d059297112922cabb0c674840589be8db821fd9aAdam Langley
87d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((r = sshbuf_consume(buf, 1)) < 0)
88d059297112922cabb0c674840589be8db821fd9aAdam Langley		return r;
89d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (valp != NULL)
90d059297112922cabb0c674840589be8db821fd9aAdam Langley		*valp = (u_int8_t)*p;
91d059297112922cabb0c674840589be8db821fd9aAdam Langley	return 0;
92d059297112922cabb0c674840589be8db821fd9aAdam Langley}
93d059297112922cabb0c674840589be8db821fd9aAdam Langley
94d059297112922cabb0c674840589be8db821fd9aAdam Langleyint
95d059297112922cabb0c674840589be8db821fd9aAdam Langleysshbuf_get_string(struct sshbuf *buf, u_char **valp, size_t *lenp)
96d059297112922cabb0c674840589be8db821fd9aAdam Langley{
97d059297112922cabb0c674840589be8db821fd9aAdam Langley	const u_char *val;
98d059297112922cabb0c674840589be8db821fd9aAdam Langley	size_t len;
99d059297112922cabb0c674840589be8db821fd9aAdam Langley	int r;
100d059297112922cabb0c674840589be8db821fd9aAdam Langley
101d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (valp != NULL)
102d059297112922cabb0c674840589be8db821fd9aAdam Langley		*valp = NULL;
103d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (lenp != NULL)
104d059297112922cabb0c674840589be8db821fd9aAdam Langley		*lenp = 0;
105d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((r = sshbuf_get_string_direct(buf, &val, &len)) < 0)
106d059297112922cabb0c674840589be8db821fd9aAdam Langley		return r;
107d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (valp != NULL) {
108d059297112922cabb0c674840589be8db821fd9aAdam Langley		if ((*valp = malloc(len + 1)) == NULL) {
109d059297112922cabb0c674840589be8db821fd9aAdam Langley			SSHBUF_DBG(("SSH_ERR_ALLOC_FAIL"));
110d059297112922cabb0c674840589be8db821fd9aAdam Langley			return SSH_ERR_ALLOC_FAIL;
111d059297112922cabb0c674840589be8db821fd9aAdam Langley		}
112d059297112922cabb0c674840589be8db821fd9aAdam Langley		if (len != 0)
113d059297112922cabb0c674840589be8db821fd9aAdam Langley			memcpy(*valp, val, len);
114d059297112922cabb0c674840589be8db821fd9aAdam Langley		(*valp)[len] = '\0';
115d059297112922cabb0c674840589be8db821fd9aAdam Langley	}
116d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (lenp != NULL)
117d059297112922cabb0c674840589be8db821fd9aAdam Langley		*lenp = len;
118d059297112922cabb0c674840589be8db821fd9aAdam Langley	return 0;
119d059297112922cabb0c674840589be8db821fd9aAdam Langley}
120d059297112922cabb0c674840589be8db821fd9aAdam Langley
121d059297112922cabb0c674840589be8db821fd9aAdam Langleyint
122d059297112922cabb0c674840589be8db821fd9aAdam Langleysshbuf_get_string_direct(struct sshbuf *buf, const u_char **valp, size_t *lenp)
123d059297112922cabb0c674840589be8db821fd9aAdam Langley{
124d059297112922cabb0c674840589be8db821fd9aAdam Langley	size_t len;
125d059297112922cabb0c674840589be8db821fd9aAdam Langley	const u_char *p;
126d059297112922cabb0c674840589be8db821fd9aAdam Langley	int r;
127d059297112922cabb0c674840589be8db821fd9aAdam Langley
128d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (valp != NULL)
129d059297112922cabb0c674840589be8db821fd9aAdam Langley		*valp = NULL;
130d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (lenp != NULL)
131d059297112922cabb0c674840589be8db821fd9aAdam Langley		*lenp = 0;
132d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((r = sshbuf_peek_string_direct(buf, &p, &len)) < 0)
133d059297112922cabb0c674840589be8db821fd9aAdam Langley		return r;
134d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (valp != 0)
135d059297112922cabb0c674840589be8db821fd9aAdam Langley		*valp = p;
136d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (lenp != NULL)
137d059297112922cabb0c674840589be8db821fd9aAdam Langley		*lenp = len;
138d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (sshbuf_consume(buf, len + 4) != 0) {
139d059297112922cabb0c674840589be8db821fd9aAdam Langley		/* Shouldn't happen */
140d059297112922cabb0c674840589be8db821fd9aAdam Langley		SSHBUF_DBG(("SSH_ERR_INTERNAL_ERROR"));
141d059297112922cabb0c674840589be8db821fd9aAdam Langley		SSHBUF_ABORT();
142d059297112922cabb0c674840589be8db821fd9aAdam Langley		return SSH_ERR_INTERNAL_ERROR;
143d059297112922cabb0c674840589be8db821fd9aAdam Langley	}
144d059297112922cabb0c674840589be8db821fd9aAdam Langley	return 0;
145d059297112922cabb0c674840589be8db821fd9aAdam Langley}
146d059297112922cabb0c674840589be8db821fd9aAdam Langley
147d059297112922cabb0c674840589be8db821fd9aAdam Langleyint
148d059297112922cabb0c674840589be8db821fd9aAdam Langleysshbuf_peek_string_direct(const struct sshbuf *buf, const u_char **valp,
149d059297112922cabb0c674840589be8db821fd9aAdam Langley    size_t *lenp)
150d059297112922cabb0c674840589be8db821fd9aAdam Langley{
151d059297112922cabb0c674840589be8db821fd9aAdam Langley	u_int32_t len;
152d059297112922cabb0c674840589be8db821fd9aAdam Langley	const u_char *p = sshbuf_ptr(buf);
153d059297112922cabb0c674840589be8db821fd9aAdam Langley
154d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (valp != NULL)
155d059297112922cabb0c674840589be8db821fd9aAdam Langley		*valp = NULL;
156d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (lenp != NULL)
157d059297112922cabb0c674840589be8db821fd9aAdam Langley		*lenp = 0;
158d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (sshbuf_len(buf) < 4) {
159d059297112922cabb0c674840589be8db821fd9aAdam Langley		SSHBUF_DBG(("SSH_ERR_MESSAGE_INCOMPLETE"));
160d059297112922cabb0c674840589be8db821fd9aAdam Langley		return SSH_ERR_MESSAGE_INCOMPLETE;
161d059297112922cabb0c674840589be8db821fd9aAdam Langley	}
162d059297112922cabb0c674840589be8db821fd9aAdam Langley	len = PEEK_U32(p);
163d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (len > SSHBUF_SIZE_MAX - 4) {
164d059297112922cabb0c674840589be8db821fd9aAdam Langley		SSHBUF_DBG(("SSH_ERR_STRING_TOO_LARGE"));
165d059297112922cabb0c674840589be8db821fd9aAdam Langley		return SSH_ERR_STRING_TOO_LARGE;
166d059297112922cabb0c674840589be8db821fd9aAdam Langley	}
167d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (sshbuf_len(buf) - 4 < len) {
168d059297112922cabb0c674840589be8db821fd9aAdam Langley		SSHBUF_DBG(("SSH_ERR_MESSAGE_INCOMPLETE"));
169d059297112922cabb0c674840589be8db821fd9aAdam Langley		return SSH_ERR_MESSAGE_INCOMPLETE;
170d059297112922cabb0c674840589be8db821fd9aAdam Langley	}
171d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (valp != 0)
172d059297112922cabb0c674840589be8db821fd9aAdam Langley		*valp = p + 4;
173d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (lenp != NULL)
174d059297112922cabb0c674840589be8db821fd9aAdam Langley		*lenp = len;
175d059297112922cabb0c674840589be8db821fd9aAdam Langley	return 0;
176d059297112922cabb0c674840589be8db821fd9aAdam Langley}
177d059297112922cabb0c674840589be8db821fd9aAdam Langley
178d059297112922cabb0c674840589be8db821fd9aAdam Langleyint
179d059297112922cabb0c674840589be8db821fd9aAdam Langleysshbuf_get_cstring(struct sshbuf *buf, char **valp, size_t *lenp)
180d059297112922cabb0c674840589be8db821fd9aAdam Langley{
181d059297112922cabb0c674840589be8db821fd9aAdam Langley	size_t len;
182d059297112922cabb0c674840589be8db821fd9aAdam Langley	const u_char *p, *z;
183d059297112922cabb0c674840589be8db821fd9aAdam Langley	int r;
184d059297112922cabb0c674840589be8db821fd9aAdam Langley
185d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (valp != NULL)
186d059297112922cabb0c674840589be8db821fd9aAdam Langley		*valp = NULL;
187d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (lenp != NULL)
188d059297112922cabb0c674840589be8db821fd9aAdam Langley		*lenp = 0;
189d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((r = sshbuf_peek_string_direct(buf, &p, &len)) != 0)
190d059297112922cabb0c674840589be8db821fd9aAdam Langley		return r;
191d059297112922cabb0c674840589be8db821fd9aAdam Langley	/* Allow a \0 only at the end of the string */
192d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (len > 0 &&
193d059297112922cabb0c674840589be8db821fd9aAdam Langley	    (z = memchr(p , '\0', len)) != NULL && z < p + len - 1) {
194d059297112922cabb0c674840589be8db821fd9aAdam Langley		SSHBUF_DBG(("SSH_ERR_INVALID_FORMAT"));
195d059297112922cabb0c674840589be8db821fd9aAdam Langley		return SSH_ERR_INVALID_FORMAT;
196d059297112922cabb0c674840589be8db821fd9aAdam Langley	}
197d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((r = sshbuf_skip_string(buf)) != 0)
198d059297112922cabb0c674840589be8db821fd9aAdam Langley		return -1;
199d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (valp != NULL) {
200d059297112922cabb0c674840589be8db821fd9aAdam Langley		if ((*valp = malloc(len + 1)) == NULL) {
201d059297112922cabb0c674840589be8db821fd9aAdam Langley			SSHBUF_DBG(("SSH_ERR_ALLOC_FAIL"));
202d059297112922cabb0c674840589be8db821fd9aAdam Langley			return SSH_ERR_ALLOC_FAIL;
203d059297112922cabb0c674840589be8db821fd9aAdam Langley		}
204d059297112922cabb0c674840589be8db821fd9aAdam Langley		if (len != 0)
205d059297112922cabb0c674840589be8db821fd9aAdam Langley			memcpy(*valp, p, len);
206d059297112922cabb0c674840589be8db821fd9aAdam Langley		(*valp)[len] = '\0';
207d059297112922cabb0c674840589be8db821fd9aAdam Langley	}
208d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (lenp != NULL)
209d059297112922cabb0c674840589be8db821fd9aAdam Langley		*lenp = (size_t)len;
210d059297112922cabb0c674840589be8db821fd9aAdam Langley	return 0;
211d059297112922cabb0c674840589be8db821fd9aAdam Langley}
212d059297112922cabb0c674840589be8db821fd9aAdam Langley
213d059297112922cabb0c674840589be8db821fd9aAdam Langleyint
214d059297112922cabb0c674840589be8db821fd9aAdam Langleysshbuf_get_stringb(struct sshbuf *buf, struct sshbuf *v)
215d059297112922cabb0c674840589be8db821fd9aAdam Langley{
216d059297112922cabb0c674840589be8db821fd9aAdam Langley	u_int32_t len;
217d059297112922cabb0c674840589be8db821fd9aAdam Langley	u_char *p;
218d059297112922cabb0c674840589be8db821fd9aAdam Langley	int r;
219d059297112922cabb0c674840589be8db821fd9aAdam Langley
220d059297112922cabb0c674840589be8db821fd9aAdam Langley	/*
221d059297112922cabb0c674840589be8db821fd9aAdam Langley	 * Use sshbuf_peek_string_direct() to figure out if there is
222d059297112922cabb0c674840589be8db821fd9aAdam Langley	 * a complete string in 'buf' and copy the string directly
223d059297112922cabb0c674840589be8db821fd9aAdam Langley	 * into 'v'.
224d059297112922cabb0c674840589be8db821fd9aAdam Langley	 */
225d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((r = sshbuf_peek_string_direct(buf, NULL, NULL)) != 0 ||
226d059297112922cabb0c674840589be8db821fd9aAdam Langley	    (r = sshbuf_get_u32(buf, &len)) != 0 ||
227d059297112922cabb0c674840589be8db821fd9aAdam Langley	    (r = sshbuf_reserve(v, len, &p)) != 0 ||
228d059297112922cabb0c674840589be8db821fd9aAdam Langley	    (r = sshbuf_get(buf, p, len)) != 0)
229d059297112922cabb0c674840589be8db821fd9aAdam Langley		return r;
230d059297112922cabb0c674840589be8db821fd9aAdam Langley	return 0;
231d059297112922cabb0c674840589be8db821fd9aAdam Langley}
232d059297112922cabb0c674840589be8db821fd9aAdam Langley
233d059297112922cabb0c674840589be8db821fd9aAdam Langleyint
234d059297112922cabb0c674840589be8db821fd9aAdam Langleysshbuf_put(struct sshbuf *buf, const void *v, size_t len)
235d059297112922cabb0c674840589be8db821fd9aAdam Langley{
236d059297112922cabb0c674840589be8db821fd9aAdam Langley	u_char *p;
237d059297112922cabb0c674840589be8db821fd9aAdam Langley	int r;
238d059297112922cabb0c674840589be8db821fd9aAdam Langley
239d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((r = sshbuf_reserve(buf, len, &p)) < 0)
240d059297112922cabb0c674840589be8db821fd9aAdam Langley		return r;
241d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (len != 0)
242d059297112922cabb0c674840589be8db821fd9aAdam Langley		memcpy(p, v, len);
243d059297112922cabb0c674840589be8db821fd9aAdam Langley	return 0;
244d059297112922cabb0c674840589be8db821fd9aAdam Langley}
245d059297112922cabb0c674840589be8db821fd9aAdam Langley
246d059297112922cabb0c674840589be8db821fd9aAdam Langleyint
247d059297112922cabb0c674840589be8db821fd9aAdam Langleysshbuf_putb(struct sshbuf *buf, const struct sshbuf *v)
248d059297112922cabb0c674840589be8db821fd9aAdam Langley{
249d059297112922cabb0c674840589be8db821fd9aAdam Langley	return sshbuf_put(buf, sshbuf_ptr(v), sshbuf_len(v));
250d059297112922cabb0c674840589be8db821fd9aAdam Langley}
251d059297112922cabb0c674840589be8db821fd9aAdam Langley
252d059297112922cabb0c674840589be8db821fd9aAdam Langleyint
253d059297112922cabb0c674840589be8db821fd9aAdam Langleysshbuf_putf(struct sshbuf *buf, const char *fmt, ...)
254d059297112922cabb0c674840589be8db821fd9aAdam Langley{
255d059297112922cabb0c674840589be8db821fd9aAdam Langley	va_list ap;
256d059297112922cabb0c674840589be8db821fd9aAdam Langley	int r;
257d059297112922cabb0c674840589be8db821fd9aAdam Langley
258d059297112922cabb0c674840589be8db821fd9aAdam Langley	va_start(ap, fmt);
259d059297112922cabb0c674840589be8db821fd9aAdam Langley	r = sshbuf_putfv(buf, fmt, ap);
260d059297112922cabb0c674840589be8db821fd9aAdam Langley	va_end(ap);
261d059297112922cabb0c674840589be8db821fd9aAdam Langley	return r;
262d059297112922cabb0c674840589be8db821fd9aAdam Langley}
263d059297112922cabb0c674840589be8db821fd9aAdam Langley
264d059297112922cabb0c674840589be8db821fd9aAdam Langleyint
265d059297112922cabb0c674840589be8db821fd9aAdam Langleysshbuf_putfv(struct sshbuf *buf, const char *fmt, va_list ap)
266d059297112922cabb0c674840589be8db821fd9aAdam Langley{
267d059297112922cabb0c674840589be8db821fd9aAdam Langley	va_list ap2;
268d059297112922cabb0c674840589be8db821fd9aAdam Langley	int r, len;
269d059297112922cabb0c674840589be8db821fd9aAdam Langley	u_char *p;
270d059297112922cabb0c674840589be8db821fd9aAdam Langley
271d059297112922cabb0c674840589be8db821fd9aAdam Langley	va_copy(ap2, ap);
272d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((len = vsnprintf(NULL, 0, fmt, ap2)) < 0) {
273d059297112922cabb0c674840589be8db821fd9aAdam Langley		r = SSH_ERR_INVALID_ARGUMENT;
274d059297112922cabb0c674840589be8db821fd9aAdam Langley		goto out;
275d059297112922cabb0c674840589be8db821fd9aAdam Langley	}
276d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (len == 0) {
277d059297112922cabb0c674840589be8db821fd9aAdam Langley		r = 0;
278d059297112922cabb0c674840589be8db821fd9aAdam Langley		goto out; /* Nothing to do */
279d059297112922cabb0c674840589be8db821fd9aAdam Langley	}
280d059297112922cabb0c674840589be8db821fd9aAdam Langley	va_end(ap2);
281d059297112922cabb0c674840589be8db821fd9aAdam Langley	va_copy(ap2, ap);
282d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((r = sshbuf_reserve(buf, (size_t)len + 1, &p)) < 0)
283d059297112922cabb0c674840589be8db821fd9aAdam Langley		goto out;
284d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((r = vsnprintf((char *)p, len + 1, fmt, ap2)) != len) {
285d059297112922cabb0c674840589be8db821fd9aAdam Langley		r = SSH_ERR_INTERNAL_ERROR;
286d059297112922cabb0c674840589be8db821fd9aAdam Langley		goto out; /* Shouldn't happen */
287d059297112922cabb0c674840589be8db821fd9aAdam Langley	}
288d059297112922cabb0c674840589be8db821fd9aAdam Langley	/* Consume terminating \0 */
289d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((r = sshbuf_consume_end(buf, 1)) != 0)
290d059297112922cabb0c674840589be8db821fd9aAdam Langley		goto out;
291d059297112922cabb0c674840589be8db821fd9aAdam Langley	r = 0;
292d059297112922cabb0c674840589be8db821fd9aAdam Langley out:
293d059297112922cabb0c674840589be8db821fd9aAdam Langley	va_end(ap2);
294d059297112922cabb0c674840589be8db821fd9aAdam Langley	return r;
295d059297112922cabb0c674840589be8db821fd9aAdam Langley}
296d059297112922cabb0c674840589be8db821fd9aAdam Langley
297d059297112922cabb0c674840589be8db821fd9aAdam Langleyint
298d059297112922cabb0c674840589be8db821fd9aAdam Langleysshbuf_put_u64(struct sshbuf *buf, u_int64_t val)
299d059297112922cabb0c674840589be8db821fd9aAdam Langley{
300d059297112922cabb0c674840589be8db821fd9aAdam Langley	u_char *p;
301d059297112922cabb0c674840589be8db821fd9aAdam Langley	int r;
302d059297112922cabb0c674840589be8db821fd9aAdam Langley
303d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((r = sshbuf_reserve(buf, 8, &p)) < 0)
304d059297112922cabb0c674840589be8db821fd9aAdam Langley		return r;
305d059297112922cabb0c674840589be8db821fd9aAdam Langley	POKE_U64(p, val);
306d059297112922cabb0c674840589be8db821fd9aAdam Langley	return 0;
307d059297112922cabb0c674840589be8db821fd9aAdam Langley}
308d059297112922cabb0c674840589be8db821fd9aAdam Langley
309d059297112922cabb0c674840589be8db821fd9aAdam Langleyint
310d059297112922cabb0c674840589be8db821fd9aAdam Langleysshbuf_put_u32(struct sshbuf *buf, u_int32_t val)
311d059297112922cabb0c674840589be8db821fd9aAdam Langley{
312d059297112922cabb0c674840589be8db821fd9aAdam Langley	u_char *p;
313d059297112922cabb0c674840589be8db821fd9aAdam Langley	int r;
314d059297112922cabb0c674840589be8db821fd9aAdam Langley
315d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((r = sshbuf_reserve(buf, 4, &p)) < 0)
316d059297112922cabb0c674840589be8db821fd9aAdam Langley		return r;
317d059297112922cabb0c674840589be8db821fd9aAdam Langley	POKE_U32(p, val);
318d059297112922cabb0c674840589be8db821fd9aAdam Langley	return 0;
319d059297112922cabb0c674840589be8db821fd9aAdam Langley}
320d059297112922cabb0c674840589be8db821fd9aAdam Langley
321d059297112922cabb0c674840589be8db821fd9aAdam Langleyint
322d059297112922cabb0c674840589be8db821fd9aAdam Langleysshbuf_put_u16(struct sshbuf *buf, u_int16_t val)
323d059297112922cabb0c674840589be8db821fd9aAdam Langley{
324d059297112922cabb0c674840589be8db821fd9aAdam Langley	u_char *p;
325d059297112922cabb0c674840589be8db821fd9aAdam Langley	int r;
326d059297112922cabb0c674840589be8db821fd9aAdam Langley
327d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((r = sshbuf_reserve(buf, 2, &p)) < 0)
328d059297112922cabb0c674840589be8db821fd9aAdam Langley		return r;
329d059297112922cabb0c674840589be8db821fd9aAdam Langley	POKE_U16(p, val);
330d059297112922cabb0c674840589be8db821fd9aAdam Langley	return 0;
331d059297112922cabb0c674840589be8db821fd9aAdam Langley}
332d059297112922cabb0c674840589be8db821fd9aAdam Langley
333d059297112922cabb0c674840589be8db821fd9aAdam Langleyint
334d059297112922cabb0c674840589be8db821fd9aAdam Langleysshbuf_put_u8(struct sshbuf *buf, u_char val)
335d059297112922cabb0c674840589be8db821fd9aAdam Langley{
336d059297112922cabb0c674840589be8db821fd9aAdam Langley	u_char *p;
337d059297112922cabb0c674840589be8db821fd9aAdam Langley	int r;
338d059297112922cabb0c674840589be8db821fd9aAdam Langley
339d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((r = sshbuf_reserve(buf, 1, &p)) < 0)
340d059297112922cabb0c674840589be8db821fd9aAdam Langley		return r;
341d059297112922cabb0c674840589be8db821fd9aAdam Langley	p[0] = val;
342d059297112922cabb0c674840589be8db821fd9aAdam Langley	return 0;
343d059297112922cabb0c674840589be8db821fd9aAdam Langley}
344d059297112922cabb0c674840589be8db821fd9aAdam Langley
345d059297112922cabb0c674840589be8db821fd9aAdam Langleyint
346d059297112922cabb0c674840589be8db821fd9aAdam Langleysshbuf_put_string(struct sshbuf *buf, const void *v, size_t len)
347d059297112922cabb0c674840589be8db821fd9aAdam Langley{
348d059297112922cabb0c674840589be8db821fd9aAdam Langley	u_char *d;
349d059297112922cabb0c674840589be8db821fd9aAdam Langley	int r;
350d059297112922cabb0c674840589be8db821fd9aAdam Langley
351d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (len > SSHBUF_SIZE_MAX - 4) {
352d059297112922cabb0c674840589be8db821fd9aAdam Langley		SSHBUF_DBG(("SSH_ERR_NO_BUFFER_SPACE"));
353d059297112922cabb0c674840589be8db821fd9aAdam Langley		return SSH_ERR_NO_BUFFER_SPACE;
354d059297112922cabb0c674840589be8db821fd9aAdam Langley	}
355d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((r = sshbuf_reserve(buf, len + 4, &d)) < 0)
356d059297112922cabb0c674840589be8db821fd9aAdam Langley		return r;
357d059297112922cabb0c674840589be8db821fd9aAdam Langley	POKE_U32(d, len);
358d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (len != 0)
359d059297112922cabb0c674840589be8db821fd9aAdam Langley		memcpy(d + 4, v, len);
360d059297112922cabb0c674840589be8db821fd9aAdam Langley	return 0;
361d059297112922cabb0c674840589be8db821fd9aAdam Langley}
362d059297112922cabb0c674840589be8db821fd9aAdam Langley
363d059297112922cabb0c674840589be8db821fd9aAdam Langleyint
364d059297112922cabb0c674840589be8db821fd9aAdam Langleysshbuf_put_cstring(struct sshbuf *buf, const char *v)
365d059297112922cabb0c674840589be8db821fd9aAdam Langley{
366d059297112922cabb0c674840589be8db821fd9aAdam Langley	return sshbuf_put_string(buf, (u_char *)v, v == NULL ? 0 : strlen(v));
367d059297112922cabb0c674840589be8db821fd9aAdam Langley}
368d059297112922cabb0c674840589be8db821fd9aAdam Langley
369d059297112922cabb0c674840589be8db821fd9aAdam Langleyint
370d059297112922cabb0c674840589be8db821fd9aAdam Langleysshbuf_put_stringb(struct sshbuf *buf, const struct sshbuf *v)
371d059297112922cabb0c674840589be8db821fd9aAdam Langley{
372d059297112922cabb0c674840589be8db821fd9aAdam Langley	return sshbuf_put_string(buf, sshbuf_ptr(v), sshbuf_len(v));
373d059297112922cabb0c674840589be8db821fd9aAdam Langley}
374d059297112922cabb0c674840589be8db821fd9aAdam Langley
375d059297112922cabb0c674840589be8db821fd9aAdam Langleyint
376d059297112922cabb0c674840589be8db821fd9aAdam Langleysshbuf_froms(struct sshbuf *buf, struct sshbuf **bufp)
377d059297112922cabb0c674840589be8db821fd9aAdam Langley{
378d059297112922cabb0c674840589be8db821fd9aAdam Langley	const u_char *p;
379d059297112922cabb0c674840589be8db821fd9aAdam Langley	size_t len;
380d059297112922cabb0c674840589be8db821fd9aAdam Langley	struct sshbuf *ret;
381d059297112922cabb0c674840589be8db821fd9aAdam Langley	int r;
382d059297112922cabb0c674840589be8db821fd9aAdam Langley
383d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (buf == NULL || bufp == NULL)
384d059297112922cabb0c674840589be8db821fd9aAdam Langley		return SSH_ERR_INVALID_ARGUMENT;
385d059297112922cabb0c674840589be8db821fd9aAdam Langley	*bufp = NULL;
386d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((r = sshbuf_peek_string_direct(buf, &p, &len)) != 0)
387d059297112922cabb0c674840589be8db821fd9aAdam Langley		return r;
388d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((ret = sshbuf_from(p, len)) == NULL)
389d059297112922cabb0c674840589be8db821fd9aAdam Langley		return SSH_ERR_ALLOC_FAIL;
390d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((r = sshbuf_consume(buf, len + 4)) != 0 ||  /* Shouldn't happen */
391d059297112922cabb0c674840589be8db821fd9aAdam Langley	    (r = sshbuf_set_parent(ret, buf)) != 0) {
392d059297112922cabb0c674840589be8db821fd9aAdam Langley		sshbuf_free(ret);
393d059297112922cabb0c674840589be8db821fd9aAdam Langley		return r;
394d059297112922cabb0c674840589be8db821fd9aAdam Langley	}
395d059297112922cabb0c674840589be8db821fd9aAdam Langley	*bufp = ret;
396d059297112922cabb0c674840589be8db821fd9aAdam Langley	return 0;
397d059297112922cabb0c674840589be8db821fd9aAdam Langley}
398d059297112922cabb0c674840589be8db821fd9aAdam Langley
399d059297112922cabb0c674840589be8db821fd9aAdam Langleyint
400d059297112922cabb0c674840589be8db821fd9aAdam Langleysshbuf_put_bignum2_bytes(struct sshbuf *buf, const void *v, size_t len)
401d059297112922cabb0c674840589be8db821fd9aAdam Langley{
402d059297112922cabb0c674840589be8db821fd9aAdam Langley	u_char *d;
403d059297112922cabb0c674840589be8db821fd9aAdam Langley	const u_char *s = (const u_char *)v;
404d059297112922cabb0c674840589be8db821fd9aAdam Langley	int r, prepend;
405d059297112922cabb0c674840589be8db821fd9aAdam Langley
406d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (len > SSHBUF_SIZE_MAX - 5) {
407d059297112922cabb0c674840589be8db821fd9aAdam Langley		SSHBUF_DBG(("SSH_ERR_NO_BUFFER_SPACE"));
408d059297112922cabb0c674840589be8db821fd9aAdam Langley		return SSH_ERR_NO_BUFFER_SPACE;
409d059297112922cabb0c674840589be8db821fd9aAdam Langley	}
410d059297112922cabb0c674840589be8db821fd9aAdam Langley	/* Skip leading zero bytes */
411d059297112922cabb0c674840589be8db821fd9aAdam Langley	for (; len > 0 && *s == 0; len--, s++)
412d059297112922cabb0c674840589be8db821fd9aAdam Langley		;
413d059297112922cabb0c674840589be8db821fd9aAdam Langley	/*
414d059297112922cabb0c674840589be8db821fd9aAdam Langley	 * If most significant bit is set then prepend a zero byte to
415d059297112922cabb0c674840589be8db821fd9aAdam Langley	 * avoid interpretation as a negative number.
416d059297112922cabb0c674840589be8db821fd9aAdam Langley	 */
417d059297112922cabb0c674840589be8db821fd9aAdam Langley	prepend = len > 0 && (s[0] & 0x80) != 0;
418d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((r = sshbuf_reserve(buf, len + 4 + prepend, &d)) < 0)
419d059297112922cabb0c674840589be8db821fd9aAdam Langley		return r;
420d059297112922cabb0c674840589be8db821fd9aAdam Langley	POKE_U32(d, len + prepend);
421d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (prepend)
422d059297112922cabb0c674840589be8db821fd9aAdam Langley		d[4] = 0;
423d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (len != 0)
424d059297112922cabb0c674840589be8db821fd9aAdam Langley		memcpy(d + 4 + prepend, s, len);
425d059297112922cabb0c674840589be8db821fd9aAdam Langley	return 0;
426d059297112922cabb0c674840589be8db821fd9aAdam Langley}
427d059297112922cabb0c674840589be8db821fd9aAdam Langley
428d059297112922cabb0c674840589be8db821fd9aAdam Langleyint
429d059297112922cabb0c674840589be8db821fd9aAdam Langleysshbuf_get_bignum2_bytes_direct(struct sshbuf *buf,
430d059297112922cabb0c674840589be8db821fd9aAdam Langley    const u_char **valp, size_t *lenp)
431d059297112922cabb0c674840589be8db821fd9aAdam Langley{
432d059297112922cabb0c674840589be8db821fd9aAdam Langley	const u_char *d;
433d059297112922cabb0c674840589be8db821fd9aAdam Langley	size_t len, olen;
434d059297112922cabb0c674840589be8db821fd9aAdam Langley	int r;
435d059297112922cabb0c674840589be8db821fd9aAdam Langley
436d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((r = sshbuf_peek_string_direct(buf, &d, &olen)) < 0)
437d059297112922cabb0c674840589be8db821fd9aAdam Langley		return r;
438d059297112922cabb0c674840589be8db821fd9aAdam Langley	len = olen;
439d059297112922cabb0c674840589be8db821fd9aAdam Langley	/* Refuse negative (MSB set) bignums */
440d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((len != 0 && (*d & 0x80) != 0))
441d059297112922cabb0c674840589be8db821fd9aAdam Langley		return SSH_ERR_BIGNUM_IS_NEGATIVE;
442d059297112922cabb0c674840589be8db821fd9aAdam Langley	/* Refuse overlong bignums, allow prepended \0 to avoid MSB set */
443d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (len > SSHBUF_MAX_BIGNUM + 1 ||
444d059297112922cabb0c674840589be8db821fd9aAdam Langley	    (len == SSHBUF_MAX_BIGNUM + 1 && *d != 0))
445d059297112922cabb0c674840589be8db821fd9aAdam Langley		return SSH_ERR_BIGNUM_TOO_LARGE;
446d059297112922cabb0c674840589be8db821fd9aAdam Langley	/* Trim leading zeros */
447d059297112922cabb0c674840589be8db821fd9aAdam Langley	while (len > 0 && *d == 0x00) {
448d059297112922cabb0c674840589be8db821fd9aAdam Langley		d++;
449d059297112922cabb0c674840589be8db821fd9aAdam Langley		len--;
450d059297112922cabb0c674840589be8db821fd9aAdam Langley	}
451d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (valp != 0)
452d059297112922cabb0c674840589be8db821fd9aAdam Langley		*valp = d;
453d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (lenp != NULL)
454d059297112922cabb0c674840589be8db821fd9aAdam Langley		*lenp = len;
455d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (sshbuf_consume(buf, olen + 4) != 0) {
456d059297112922cabb0c674840589be8db821fd9aAdam Langley		/* Shouldn't happen */
457d059297112922cabb0c674840589be8db821fd9aAdam Langley		SSHBUF_DBG(("SSH_ERR_INTERNAL_ERROR"));
458d059297112922cabb0c674840589be8db821fd9aAdam Langley		SSHBUF_ABORT();
459d059297112922cabb0c674840589be8db821fd9aAdam Langley		return SSH_ERR_INTERNAL_ERROR;
460d059297112922cabb0c674840589be8db821fd9aAdam Langley	}
461d059297112922cabb0c674840589be8db821fd9aAdam Langley	return 0;
462d059297112922cabb0c674840589be8db821fd9aAdam Langley}
463