1*19261079SEd Maste /* $OpenBSD: sshbuf-getput-basic.c,v 1.11 2020/06/05 03:25:35 djm Exp $ */ 2a0ee8cc6SDag-Erling Smørgrav /* 3a0ee8cc6SDag-Erling Smørgrav * Copyright (c) 2011 Damien Miller 4a0ee8cc6SDag-Erling Smørgrav * 5a0ee8cc6SDag-Erling Smørgrav * Permission to use, copy, modify, and distribute this software for any 6a0ee8cc6SDag-Erling Smørgrav * purpose with or without fee is hereby granted, provided that the above 7a0ee8cc6SDag-Erling Smørgrav * copyright notice and this permission notice appear in all copies. 8a0ee8cc6SDag-Erling Smørgrav * 9a0ee8cc6SDag-Erling Smørgrav * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10a0ee8cc6SDag-Erling Smørgrav * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11a0ee8cc6SDag-Erling Smørgrav * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12a0ee8cc6SDag-Erling Smørgrav * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13a0ee8cc6SDag-Erling Smørgrav * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14a0ee8cc6SDag-Erling Smørgrav * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15a0ee8cc6SDag-Erling Smørgrav * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16a0ee8cc6SDag-Erling Smørgrav */ 17a0ee8cc6SDag-Erling Smørgrav 18a0ee8cc6SDag-Erling Smørgrav #define SSHBUF_INTERNAL 19a0ee8cc6SDag-Erling Smørgrav #include "includes.h" 20a0ee8cc6SDag-Erling Smørgrav 21a0ee8cc6SDag-Erling Smørgrav #include <sys/types.h> 22076ad2f8SDag-Erling Smørgrav 23076ad2f8SDag-Erling Smørgrav #include <stdarg.h> 24a0ee8cc6SDag-Erling Smørgrav #include <stdlib.h> 25a0ee8cc6SDag-Erling Smørgrav #include <stdio.h> 26a0ee8cc6SDag-Erling Smørgrav #include <string.h> 27*19261079SEd Maste #ifdef HAVE_STDINT_H 28*19261079SEd Maste # include <stdint.h> 29*19261079SEd Maste #endif 30a0ee8cc6SDag-Erling Smørgrav 31a0ee8cc6SDag-Erling Smørgrav #include "ssherr.h" 32a0ee8cc6SDag-Erling Smørgrav #include "sshbuf.h" 33a0ee8cc6SDag-Erling Smørgrav 34a0ee8cc6SDag-Erling Smørgrav int 35a0ee8cc6SDag-Erling Smørgrav sshbuf_get(struct sshbuf *buf, void *v, size_t len) 36a0ee8cc6SDag-Erling Smørgrav { 37a0ee8cc6SDag-Erling Smørgrav const u_char *p = sshbuf_ptr(buf); 38a0ee8cc6SDag-Erling Smørgrav int r; 39a0ee8cc6SDag-Erling Smørgrav 40a0ee8cc6SDag-Erling Smørgrav if ((r = sshbuf_consume(buf, len)) < 0) 41a0ee8cc6SDag-Erling Smørgrav return r; 42bc5531deSDag-Erling Smørgrav if (v != NULL && len != 0) 43a0ee8cc6SDag-Erling Smørgrav memcpy(v, p, len); 44a0ee8cc6SDag-Erling Smørgrav return 0; 45a0ee8cc6SDag-Erling Smørgrav } 46a0ee8cc6SDag-Erling Smørgrav 47a0ee8cc6SDag-Erling Smørgrav int 48a0ee8cc6SDag-Erling Smørgrav sshbuf_get_u64(struct sshbuf *buf, u_int64_t *valp) 49a0ee8cc6SDag-Erling Smørgrav { 50a0ee8cc6SDag-Erling Smørgrav const u_char *p = sshbuf_ptr(buf); 51a0ee8cc6SDag-Erling Smørgrav int r; 52a0ee8cc6SDag-Erling Smørgrav 53a0ee8cc6SDag-Erling Smørgrav if ((r = sshbuf_consume(buf, 8)) < 0) 54a0ee8cc6SDag-Erling Smørgrav return r; 55a0ee8cc6SDag-Erling Smørgrav if (valp != NULL) 56a0ee8cc6SDag-Erling Smørgrav *valp = PEEK_U64(p); 57a0ee8cc6SDag-Erling Smørgrav return 0; 58a0ee8cc6SDag-Erling Smørgrav } 59a0ee8cc6SDag-Erling Smørgrav 60a0ee8cc6SDag-Erling Smørgrav int 61a0ee8cc6SDag-Erling Smørgrav sshbuf_get_u32(struct sshbuf *buf, u_int32_t *valp) 62a0ee8cc6SDag-Erling Smørgrav { 63a0ee8cc6SDag-Erling Smørgrav const u_char *p = sshbuf_ptr(buf); 64a0ee8cc6SDag-Erling Smørgrav int r; 65a0ee8cc6SDag-Erling Smørgrav 66a0ee8cc6SDag-Erling Smørgrav if ((r = sshbuf_consume(buf, 4)) < 0) 67a0ee8cc6SDag-Erling Smørgrav return r; 68a0ee8cc6SDag-Erling Smørgrav if (valp != NULL) 69a0ee8cc6SDag-Erling Smørgrav *valp = PEEK_U32(p); 70a0ee8cc6SDag-Erling Smørgrav return 0; 71a0ee8cc6SDag-Erling Smørgrav } 72a0ee8cc6SDag-Erling Smørgrav 73a0ee8cc6SDag-Erling Smørgrav int 74a0ee8cc6SDag-Erling Smørgrav sshbuf_get_u16(struct sshbuf *buf, u_int16_t *valp) 75a0ee8cc6SDag-Erling Smørgrav { 76a0ee8cc6SDag-Erling Smørgrav const u_char *p = sshbuf_ptr(buf); 77a0ee8cc6SDag-Erling Smørgrav int r; 78a0ee8cc6SDag-Erling Smørgrav 79a0ee8cc6SDag-Erling Smørgrav if ((r = sshbuf_consume(buf, 2)) < 0) 80a0ee8cc6SDag-Erling Smørgrav return r; 81a0ee8cc6SDag-Erling Smørgrav if (valp != NULL) 82a0ee8cc6SDag-Erling Smørgrav *valp = PEEK_U16(p); 83a0ee8cc6SDag-Erling Smørgrav return 0; 84a0ee8cc6SDag-Erling Smørgrav } 85a0ee8cc6SDag-Erling Smørgrav 86a0ee8cc6SDag-Erling Smørgrav int 87a0ee8cc6SDag-Erling Smørgrav sshbuf_get_u8(struct sshbuf *buf, u_char *valp) 88a0ee8cc6SDag-Erling Smørgrav { 89a0ee8cc6SDag-Erling Smørgrav const u_char *p = sshbuf_ptr(buf); 90a0ee8cc6SDag-Erling Smørgrav int r; 91a0ee8cc6SDag-Erling Smørgrav 92a0ee8cc6SDag-Erling Smørgrav if ((r = sshbuf_consume(buf, 1)) < 0) 93a0ee8cc6SDag-Erling Smørgrav return r; 94a0ee8cc6SDag-Erling Smørgrav if (valp != NULL) 95a0ee8cc6SDag-Erling Smørgrav *valp = (u_int8_t)*p; 96a0ee8cc6SDag-Erling Smørgrav return 0; 97a0ee8cc6SDag-Erling Smørgrav } 98a0ee8cc6SDag-Erling Smørgrav 99*19261079SEd Maste static int 100*19261079SEd Maste check_offset(const struct sshbuf *buf, int wr, size_t offset, size_t len) 101*19261079SEd Maste { 102*19261079SEd Maste if (sshbuf_ptr(buf) == NULL) /* calls sshbuf_check_sanity() */ 103*19261079SEd Maste return SSH_ERR_INTERNAL_ERROR; 104*19261079SEd Maste if (offset >= SIZE_MAX - len) 105*19261079SEd Maste return SSH_ERR_INVALID_ARGUMENT; 106*19261079SEd Maste if (offset + len > sshbuf_len(buf)) { 107*19261079SEd Maste return wr ? 108*19261079SEd Maste SSH_ERR_NO_BUFFER_SPACE : SSH_ERR_MESSAGE_INCOMPLETE; 109*19261079SEd Maste } 110*19261079SEd Maste return 0; 111*19261079SEd Maste } 112*19261079SEd Maste 113*19261079SEd Maste static int 114*19261079SEd Maste check_roffset(const struct sshbuf *buf, size_t offset, size_t len, 115*19261079SEd Maste const u_char **p) 116*19261079SEd Maste { 117*19261079SEd Maste int r; 118*19261079SEd Maste 119*19261079SEd Maste *p = NULL; 120*19261079SEd Maste if ((r = check_offset(buf, 0, offset, len)) != 0) 121*19261079SEd Maste return r; 122*19261079SEd Maste *p = sshbuf_ptr(buf) + offset; 123*19261079SEd Maste return 0; 124*19261079SEd Maste } 125*19261079SEd Maste 126*19261079SEd Maste int 127*19261079SEd Maste sshbuf_peek_u64(const struct sshbuf *buf, size_t offset, u_int64_t *valp) 128*19261079SEd Maste { 129*19261079SEd Maste const u_char *p = NULL; 130*19261079SEd Maste int r; 131*19261079SEd Maste 132*19261079SEd Maste if (valp != NULL) 133*19261079SEd Maste *valp = 0; 134*19261079SEd Maste if ((r = check_roffset(buf, offset, 8, &p)) != 0) 135*19261079SEd Maste return r; 136*19261079SEd Maste if (valp != NULL) 137*19261079SEd Maste *valp = PEEK_U64(p); 138*19261079SEd Maste return 0; 139*19261079SEd Maste } 140*19261079SEd Maste 141*19261079SEd Maste int 142*19261079SEd Maste sshbuf_peek_u32(const struct sshbuf *buf, size_t offset, u_int32_t *valp) 143*19261079SEd Maste { 144*19261079SEd Maste const u_char *p = NULL; 145*19261079SEd Maste int r; 146*19261079SEd Maste 147*19261079SEd Maste if (valp != NULL) 148*19261079SEd Maste *valp = 0; 149*19261079SEd Maste if ((r = check_roffset(buf, offset, 4, &p)) != 0) 150*19261079SEd Maste return r; 151*19261079SEd Maste if (valp != NULL) 152*19261079SEd Maste *valp = PEEK_U32(p); 153*19261079SEd Maste return 0; 154*19261079SEd Maste } 155*19261079SEd Maste 156*19261079SEd Maste int 157*19261079SEd Maste sshbuf_peek_u16(const struct sshbuf *buf, size_t offset, u_int16_t *valp) 158*19261079SEd Maste { 159*19261079SEd Maste const u_char *p = NULL; 160*19261079SEd Maste int r; 161*19261079SEd Maste 162*19261079SEd Maste if (valp != NULL) 163*19261079SEd Maste *valp = 0; 164*19261079SEd Maste if ((r = check_roffset(buf, offset, 2, &p)) != 0) 165*19261079SEd Maste return r; 166*19261079SEd Maste if (valp != NULL) 167*19261079SEd Maste *valp = PEEK_U16(p); 168*19261079SEd Maste return 0; 169*19261079SEd Maste } 170*19261079SEd Maste 171*19261079SEd Maste int 172*19261079SEd Maste sshbuf_peek_u8(const struct sshbuf *buf, size_t offset, u_char *valp) 173*19261079SEd Maste { 174*19261079SEd Maste const u_char *p = NULL; 175*19261079SEd Maste int r; 176*19261079SEd Maste 177*19261079SEd Maste if (valp != NULL) 178*19261079SEd Maste *valp = 0; 179*19261079SEd Maste if ((r = check_roffset(buf, offset, 1, &p)) != 0) 180*19261079SEd Maste return r; 181*19261079SEd Maste if (valp != NULL) 182*19261079SEd Maste *valp = *p; 183*19261079SEd Maste return 0; 184*19261079SEd Maste } 185*19261079SEd Maste 186a0ee8cc6SDag-Erling Smørgrav int 187a0ee8cc6SDag-Erling Smørgrav sshbuf_get_string(struct sshbuf *buf, u_char **valp, size_t *lenp) 188a0ee8cc6SDag-Erling Smørgrav { 189a0ee8cc6SDag-Erling Smørgrav const u_char *val; 190a0ee8cc6SDag-Erling Smørgrav size_t len; 191a0ee8cc6SDag-Erling Smørgrav int r; 192a0ee8cc6SDag-Erling Smørgrav 193a0ee8cc6SDag-Erling Smørgrav if (valp != NULL) 194a0ee8cc6SDag-Erling Smørgrav *valp = NULL; 195a0ee8cc6SDag-Erling Smørgrav if (lenp != NULL) 196a0ee8cc6SDag-Erling Smørgrav *lenp = 0; 197a0ee8cc6SDag-Erling Smørgrav if ((r = sshbuf_get_string_direct(buf, &val, &len)) < 0) 198a0ee8cc6SDag-Erling Smørgrav return r; 199a0ee8cc6SDag-Erling Smørgrav if (valp != NULL) { 200a0ee8cc6SDag-Erling Smørgrav if ((*valp = malloc(len + 1)) == NULL) { 201a0ee8cc6SDag-Erling Smørgrav SSHBUF_DBG(("SSH_ERR_ALLOC_FAIL")); 202a0ee8cc6SDag-Erling Smørgrav return SSH_ERR_ALLOC_FAIL; 203a0ee8cc6SDag-Erling Smørgrav } 204bc5531deSDag-Erling Smørgrav if (len != 0) 205a0ee8cc6SDag-Erling Smørgrav memcpy(*valp, val, len); 206a0ee8cc6SDag-Erling Smørgrav (*valp)[len] = '\0'; 207a0ee8cc6SDag-Erling Smørgrav } 208a0ee8cc6SDag-Erling Smørgrav if (lenp != NULL) 209a0ee8cc6SDag-Erling Smørgrav *lenp = len; 210a0ee8cc6SDag-Erling Smørgrav return 0; 211a0ee8cc6SDag-Erling Smørgrav } 212a0ee8cc6SDag-Erling Smørgrav 213a0ee8cc6SDag-Erling Smørgrav int 214a0ee8cc6SDag-Erling Smørgrav sshbuf_get_string_direct(struct sshbuf *buf, const u_char **valp, size_t *lenp) 215a0ee8cc6SDag-Erling Smørgrav { 216a0ee8cc6SDag-Erling Smørgrav size_t len; 217a0ee8cc6SDag-Erling Smørgrav const u_char *p; 218a0ee8cc6SDag-Erling Smørgrav int r; 219a0ee8cc6SDag-Erling Smørgrav 220a0ee8cc6SDag-Erling Smørgrav if (valp != NULL) 221a0ee8cc6SDag-Erling Smørgrav *valp = NULL; 222a0ee8cc6SDag-Erling Smørgrav if (lenp != NULL) 223a0ee8cc6SDag-Erling Smørgrav *lenp = 0; 224a0ee8cc6SDag-Erling Smørgrav if ((r = sshbuf_peek_string_direct(buf, &p, &len)) < 0) 225a0ee8cc6SDag-Erling Smørgrav return r; 226acc1a9efSDag-Erling Smørgrav if (valp != NULL) 227a0ee8cc6SDag-Erling Smørgrav *valp = p; 228a0ee8cc6SDag-Erling Smørgrav if (lenp != NULL) 229a0ee8cc6SDag-Erling Smørgrav *lenp = len; 230a0ee8cc6SDag-Erling Smørgrav if (sshbuf_consume(buf, len + 4) != 0) { 231a0ee8cc6SDag-Erling Smørgrav /* Shouldn't happen */ 232a0ee8cc6SDag-Erling Smørgrav SSHBUF_DBG(("SSH_ERR_INTERNAL_ERROR")); 233a0ee8cc6SDag-Erling Smørgrav SSHBUF_ABORT(); 234a0ee8cc6SDag-Erling Smørgrav return SSH_ERR_INTERNAL_ERROR; 235a0ee8cc6SDag-Erling Smørgrav } 236a0ee8cc6SDag-Erling Smørgrav return 0; 237a0ee8cc6SDag-Erling Smørgrav } 238a0ee8cc6SDag-Erling Smørgrav 239a0ee8cc6SDag-Erling Smørgrav int 240a0ee8cc6SDag-Erling Smørgrav sshbuf_peek_string_direct(const struct sshbuf *buf, const u_char **valp, 241a0ee8cc6SDag-Erling Smørgrav size_t *lenp) 242a0ee8cc6SDag-Erling Smørgrav { 243a0ee8cc6SDag-Erling Smørgrav u_int32_t len; 244a0ee8cc6SDag-Erling Smørgrav const u_char *p = sshbuf_ptr(buf); 245a0ee8cc6SDag-Erling Smørgrav 246a0ee8cc6SDag-Erling Smørgrav if (valp != NULL) 247a0ee8cc6SDag-Erling Smørgrav *valp = NULL; 248a0ee8cc6SDag-Erling Smørgrav if (lenp != NULL) 249a0ee8cc6SDag-Erling Smørgrav *lenp = 0; 250a0ee8cc6SDag-Erling Smørgrav if (sshbuf_len(buf) < 4) { 251a0ee8cc6SDag-Erling Smørgrav SSHBUF_DBG(("SSH_ERR_MESSAGE_INCOMPLETE")); 252a0ee8cc6SDag-Erling Smørgrav return SSH_ERR_MESSAGE_INCOMPLETE; 253a0ee8cc6SDag-Erling Smørgrav } 254a0ee8cc6SDag-Erling Smørgrav len = PEEK_U32(p); 255a0ee8cc6SDag-Erling Smørgrav if (len > SSHBUF_SIZE_MAX - 4) { 256a0ee8cc6SDag-Erling Smørgrav SSHBUF_DBG(("SSH_ERR_STRING_TOO_LARGE")); 257a0ee8cc6SDag-Erling Smørgrav return SSH_ERR_STRING_TOO_LARGE; 258a0ee8cc6SDag-Erling Smørgrav } 259a0ee8cc6SDag-Erling Smørgrav if (sshbuf_len(buf) - 4 < len) { 260a0ee8cc6SDag-Erling Smørgrav SSHBUF_DBG(("SSH_ERR_MESSAGE_INCOMPLETE")); 261a0ee8cc6SDag-Erling Smørgrav return SSH_ERR_MESSAGE_INCOMPLETE; 262a0ee8cc6SDag-Erling Smørgrav } 263acc1a9efSDag-Erling Smørgrav if (valp != NULL) 264a0ee8cc6SDag-Erling Smørgrav *valp = p + 4; 265a0ee8cc6SDag-Erling Smørgrav if (lenp != NULL) 266a0ee8cc6SDag-Erling Smørgrav *lenp = len; 267a0ee8cc6SDag-Erling Smørgrav return 0; 268a0ee8cc6SDag-Erling Smørgrav } 269a0ee8cc6SDag-Erling Smørgrav 270a0ee8cc6SDag-Erling Smørgrav int 271a0ee8cc6SDag-Erling Smørgrav sshbuf_get_cstring(struct sshbuf *buf, char **valp, size_t *lenp) 272a0ee8cc6SDag-Erling Smørgrav { 273a0ee8cc6SDag-Erling Smørgrav size_t len; 274a0ee8cc6SDag-Erling Smørgrav const u_char *p, *z; 275a0ee8cc6SDag-Erling Smørgrav int r; 276a0ee8cc6SDag-Erling Smørgrav 277a0ee8cc6SDag-Erling Smørgrav if (valp != NULL) 278a0ee8cc6SDag-Erling Smørgrav *valp = NULL; 279a0ee8cc6SDag-Erling Smørgrav if (lenp != NULL) 280a0ee8cc6SDag-Erling Smørgrav *lenp = 0; 281a0ee8cc6SDag-Erling Smørgrav if ((r = sshbuf_peek_string_direct(buf, &p, &len)) != 0) 282a0ee8cc6SDag-Erling Smørgrav return r; 283a0ee8cc6SDag-Erling Smørgrav /* Allow a \0 only at the end of the string */ 284a0ee8cc6SDag-Erling Smørgrav if (len > 0 && 285a0ee8cc6SDag-Erling Smørgrav (z = memchr(p , '\0', len)) != NULL && z < p + len - 1) { 286a0ee8cc6SDag-Erling Smørgrav SSHBUF_DBG(("SSH_ERR_INVALID_FORMAT")); 287a0ee8cc6SDag-Erling Smørgrav return SSH_ERR_INVALID_FORMAT; 288a0ee8cc6SDag-Erling Smørgrav } 289a0ee8cc6SDag-Erling Smørgrav if ((r = sshbuf_skip_string(buf)) != 0) 290a0ee8cc6SDag-Erling Smørgrav return -1; 291a0ee8cc6SDag-Erling Smørgrav if (valp != NULL) { 292a0ee8cc6SDag-Erling Smørgrav if ((*valp = malloc(len + 1)) == NULL) { 293a0ee8cc6SDag-Erling Smørgrav SSHBUF_DBG(("SSH_ERR_ALLOC_FAIL")); 294a0ee8cc6SDag-Erling Smørgrav return SSH_ERR_ALLOC_FAIL; 295a0ee8cc6SDag-Erling Smørgrav } 296bc5531deSDag-Erling Smørgrav if (len != 0) 297a0ee8cc6SDag-Erling Smørgrav memcpy(*valp, p, len); 298a0ee8cc6SDag-Erling Smørgrav (*valp)[len] = '\0'; 299a0ee8cc6SDag-Erling Smørgrav } 300a0ee8cc6SDag-Erling Smørgrav if (lenp != NULL) 301a0ee8cc6SDag-Erling Smørgrav *lenp = (size_t)len; 302a0ee8cc6SDag-Erling Smørgrav return 0; 303a0ee8cc6SDag-Erling Smørgrav } 304a0ee8cc6SDag-Erling Smørgrav 305a0ee8cc6SDag-Erling Smørgrav int 306a0ee8cc6SDag-Erling Smørgrav sshbuf_get_stringb(struct sshbuf *buf, struct sshbuf *v) 307a0ee8cc6SDag-Erling Smørgrav { 308a0ee8cc6SDag-Erling Smørgrav u_int32_t len; 309a0ee8cc6SDag-Erling Smørgrav u_char *p; 310a0ee8cc6SDag-Erling Smørgrav int r; 311a0ee8cc6SDag-Erling Smørgrav 312a0ee8cc6SDag-Erling Smørgrav /* 313a0ee8cc6SDag-Erling Smørgrav * Use sshbuf_peek_string_direct() to figure out if there is 314a0ee8cc6SDag-Erling Smørgrav * a complete string in 'buf' and copy the string directly 315a0ee8cc6SDag-Erling Smørgrav * into 'v'. 316a0ee8cc6SDag-Erling Smørgrav */ 317a0ee8cc6SDag-Erling Smørgrav if ((r = sshbuf_peek_string_direct(buf, NULL, NULL)) != 0 || 318a0ee8cc6SDag-Erling Smørgrav (r = sshbuf_get_u32(buf, &len)) != 0 || 319a0ee8cc6SDag-Erling Smørgrav (r = sshbuf_reserve(v, len, &p)) != 0 || 320a0ee8cc6SDag-Erling Smørgrav (r = sshbuf_get(buf, p, len)) != 0) 321a0ee8cc6SDag-Erling Smørgrav return r; 322a0ee8cc6SDag-Erling Smørgrav return 0; 323a0ee8cc6SDag-Erling Smørgrav } 324a0ee8cc6SDag-Erling Smørgrav 325a0ee8cc6SDag-Erling Smørgrav int 326a0ee8cc6SDag-Erling Smørgrav sshbuf_put(struct sshbuf *buf, const void *v, size_t len) 327a0ee8cc6SDag-Erling Smørgrav { 328a0ee8cc6SDag-Erling Smørgrav u_char *p; 329a0ee8cc6SDag-Erling Smørgrav int r; 330a0ee8cc6SDag-Erling Smørgrav 331a0ee8cc6SDag-Erling Smørgrav if ((r = sshbuf_reserve(buf, len, &p)) < 0) 332a0ee8cc6SDag-Erling Smørgrav return r; 333bc5531deSDag-Erling Smørgrav if (len != 0) 334a0ee8cc6SDag-Erling Smørgrav memcpy(p, v, len); 335a0ee8cc6SDag-Erling Smørgrav return 0; 336a0ee8cc6SDag-Erling Smørgrav } 337a0ee8cc6SDag-Erling Smørgrav 338a0ee8cc6SDag-Erling Smørgrav int 339a0ee8cc6SDag-Erling Smørgrav sshbuf_putb(struct sshbuf *buf, const struct sshbuf *v) 340a0ee8cc6SDag-Erling Smørgrav { 341*19261079SEd Maste if (v == NULL) 342*19261079SEd Maste return 0; 343a0ee8cc6SDag-Erling Smørgrav return sshbuf_put(buf, sshbuf_ptr(v), sshbuf_len(v)); 344a0ee8cc6SDag-Erling Smørgrav } 345a0ee8cc6SDag-Erling Smørgrav 346a0ee8cc6SDag-Erling Smørgrav int 347a0ee8cc6SDag-Erling Smørgrav sshbuf_putf(struct sshbuf *buf, const char *fmt, ...) 348a0ee8cc6SDag-Erling Smørgrav { 349a0ee8cc6SDag-Erling Smørgrav va_list ap; 350a0ee8cc6SDag-Erling Smørgrav int r; 351a0ee8cc6SDag-Erling Smørgrav 352a0ee8cc6SDag-Erling Smørgrav va_start(ap, fmt); 353a0ee8cc6SDag-Erling Smørgrav r = sshbuf_putfv(buf, fmt, ap); 354a0ee8cc6SDag-Erling Smørgrav va_end(ap); 355a0ee8cc6SDag-Erling Smørgrav return r; 356a0ee8cc6SDag-Erling Smørgrav } 357a0ee8cc6SDag-Erling Smørgrav 358a0ee8cc6SDag-Erling Smørgrav int 359a0ee8cc6SDag-Erling Smørgrav sshbuf_putfv(struct sshbuf *buf, const char *fmt, va_list ap) 360a0ee8cc6SDag-Erling Smørgrav { 361a0ee8cc6SDag-Erling Smørgrav va_list ap2; 362a0ee8cc6SDag-Erling Smørgrav int r, len; 363a0ee8cc6SDag-Erling Smørgrav u_char *p; 364a0ee8cc6SDag-Erling Smørgrav 365076ad2f8SDag-Erling Smørgrav VA_COPY(ap2, ap); 366a0ee8cc6SDag-Erling Smørgrav if ((len = vsnprintf(NULL, 0, fmt, ap2)) < 0) { 367a0ee8cc6SDag-Erling Smørgrav r = SSH_ERR_INVALID_ARGUMENT; 368a0ee8cc6SDag-Erling Smørgrav goto out; 369a0ee8cc6SDag-Erling Smørgrav } 370a0ee8cc6SDag-Erling Smørgrav if (len == 0) { 371a0ee8cc6SDag-Erling Smørgrav r = 0; 372a0ee8cc6SDag-Erling Smørgrav goto out; /* Nothing to do */ 373a0ee8cc6SDag-Erling Smørgrav } 374a0ee8cc6SDag-Erling Smørgrav va_end(ap2); 375076ad2f8SDag-Erling Smørgrav VA_COPY(ap2, ap); 376a0ee8cc6SDag-Erling Smørgrav if ((r = sshbuf_reserve(buf, (size_t)len + 1, &p)) < 0) 377a0ee8cc6SDag-Erling Smørgrav goto out; 378a0ee8cc6SDag-Erling Smørgrav if ((r = vsnprintf((char *)p, len + 1, fmt, ap2)) != len) { 379a0ee8cc6SDag-Erling Smørgrav r = SSH_ERR_INTERNAL_ERROR; 380a0ee8cc6SDag-Erling Smørgrav goto out; /* Shouldn't happen */ 381a0ee8cc6SDag-Erling Smørgrav } 382a0ee8cc6SDag-Erling Smørgrav /* Consume terminating \0 */ 383a0ee8cc6SDag-Erling Smørgrav if ((r = sshbuf_consume_end(buf, 1)) != 0) 384a0ee8cc6SDag-Erling Smørgrav goto out; 385a0ee8cc6SDag-Erling Smørgrav r = 0; 386a0ee8cc6SDag-Erling Smørgrav out: 387a0ee8cc6SDag-Erling Smørgrav va_end(ap2); 388a0ee8cc6SDag-Erling Smørgrav return r; 389a0ee8cc6SDag-Erling Smørgrav } 390a0ee8cc6SDag-Erling Smørgrav 391a0ee8cc6SDag-Erling Smørgrav int 392a0ee8cc6SDag-Erling Smørgrav sshbuf_put_u64(struct sshbuf *buf, u_int64_t val) 393a0ee8cc6SDag-Erling Smørgrav { 394a0ee8cc6SDag-Erling Smørgrav u_char *p; 395a0ee8cc6SDag-Erling Smørgrav int r; 396a0ee8cc6SDag-Erling Smørgrav 397a0ee8cc6SDag-Erling Smørgrav if ((r = sshbuf_reserve(buf, 8, &p)) < 0) 398a0ee8cc6SDag-Erling Smørgrav return r; 399a0ee8cc6SDag-Erling Smørgrav POKE_U64(p, val); 400a0ee8cc6SDag-Erling Smørgrav return 0; 401a0ee8cc6SDag-Erling Smørgrav } 402a0ee8cc6SDag-Erling Smørgrav 403a0ee8cc6SDag-Erling Smørgrav int 404a0ee8cc6SDag-Erling Smørgrav sshbuf_put_u32(struct sshbuf *buf, u_int32_t val) 405a0ee8cc6SDag-Erling Smørgrav { 406a0ee8cc6SDag-Erling Smørgrav u_char *p; 407a0ee8cc6SDag-Erling Smørgrav int r; 408a0ee8cc6SDag-Erling Smørgrav 409a0ee8cc6SDag-Erling Smørgrav if ((r = sshbuf_reserve(buf, 4, &p)) < 0) 410a0ee8cc6SDag-Erling Smørgrav return r; 411a0ee8cc6SDag-Erling Smørgrav POKE_U32(p, val); 412a0ee8cc6SDag-Erling Smørgrav return 0; 413a0ee8cc6SDag-Erling Smørgrav } 414a0ee8cc6SDag-Erling Smørgrav 415a0ee8cc6SDag-Erling Smørgrav int 416a0ee8cc6SDag-Erling Smørgrav sshbuf_put_u16(struct sshbuf *buf, u_int16_t val) 417a0ee8cc6SDag-Erling Smørgrav { 418a0ee8cc6SDag-Erling Smørgrav u_char *p; 419a0ee8cc6SDag-Erling Smørgrav int r; 420a0ee8cc6SDag-Erling Smørgrav 421a0ee8cc6SDag-Erling Smørgrav if ((r = sshbuf_reserve(buf, 2, &p)) < 0) 422a0ee8cc6SDag-Erling Smørgrav return r; 423a0ee8cc6SDag-Erling Smørgrav POKE_U16(p, val); 424a0ee8cc6SDag-Erling Smørgrav return 0; 425a0ee8cc6SDag-Erling Smørgrav } 426a0ee8cc6SDag-Erling Smørgrav 427a0ee8cc6SDag-Erling Smørgrav int 428a0ee8cc6SDag-Erling Smørgrav sshbuf_put_u8(struct sshbuf *buf, u_char val) 429a0ee8cc6SDag-Erling Smørgrav { 430a0ee8cc6SDag-Erling Smørgrav u_char *p; 431a0ee8cc6SDag-Erling Smørgrav int r; 432a0ee8cc6SDag-Erling Smørgrav 433a0ee8cc6SDag-Erling Smørgrav if ((r = sshbuf_reserve(buf, 1, &p)) < 0) 434a0ee8cc6SDag-Erling Smørgrav return r; 435a0ee8cc6SDag-Erling Smørgrav p[0] = val; 436a0ee8cc6SDag-Erling Smørgrav return 0; 437a0ee8cc6SDag-Erling Smørgrav } 438a0ee8cc6SDag-Erling Smørgrav 439*19261079SEd Maste static int 440*19261079SEd Maste check_woffset(struct sshbuf *buf, size_t offset, size_t len, u_char **p) 441*19261079SEd Maste { 442*19261079SEd Maste int r; 443*19261079SEd Maste 444*19261079SEd Maste *p = NULL; 445*19261079SEd Maste if ((r = check_offset(buf, 1, offset, len)) != 0) 446*19261079SEd Maste return r; 447*19261079SEd Maste if (sshbuf_mutable_ptr(buf) == NULL) 448*19261079SEd Maste return SSH_ERR_BUFFER_READ_ONLY; 449*19261079SEd Maste *p = sshbuf_mutable_ptr(buf) + offset; 450*19261079SEd Maste return 0; 451*19261079SEd Maste } 452*19261079SEd Maste 453*19261079SEd Maste int 454*19261079SEd Maste sshbuf_poke_u64(struct sshbuf *buf, size_t offset, u_int64_t val) 455*19261079SEd Maste { 456*19261079SEd Maste u_char *p = NULL; 457*19261079SEd Maste int r; 458*19261079SEd Maste 459*19261079SEd Maste if ((r = check_woffset(buf, offset, 8, &p)) != 0) 460*19261079SEd Maste return r; 461*19261079SEd Maste POKE_U64(p, val); 462*19261079SEd Maste return 0; 463*19261079SEd Maste } 464*19261079SEd Maste 465*19261079SEd Maste int 466*19261079SEd Maste sshbuf_poke_u32(struct sshbuf *buf, size_t offset, u_int32_t val) 467*19261079SEd Maste { 468*19261079SEd Maste u_char *p = NULL; 469*19261079SEd Maste int r; 470*19261079SEd Maste 471*19261079SEd Maste if ((r = check_woffset(buf, offset, 4, &p)) != 0) 472*19261079SEd Maste return r; 473*19261079SEd Maste POKE_U32(p, val); 474*19261079SEd Maste return 0; 475*19261079SEd Maste } 476*19261079SEd Maste 477*19261079SEd Maste int 478*19261079SEd Maste sshbuf_poke_u16(struct sshbuf *buf, size_t offset, u_int16_t val) 479*19261079SEd Maste { 480*19261079SEd Maste u_char *p = NULL; 481*19261079SEd Maste int r; 482*19261079SEd Maste 483*19261079SEd Maste if ((r = check_woffset(buf, offset, 2, &p)) != 0) 484*19261079SEd Maste return r; 485*19261079SEd Maste POKE_U16(p, val); 486*19261079SEd Maste return 0; 487*19261079SEd Maste } 488*19261079SEd Maste 489*19261079SEd Maste int 490*19261079SEd Maste sshbuf_poke_u8(struct sshbuf *buf, size_t offset, u_char val) 491*19261079SEd Maste { 492*19261079SEd Maste u_char *p = NULL; 493*19261079SEd Maste int r; 494*19261079SEd Maste 495*19261079SEd Maste if ((r = check_woffset(buf, offset, 1, &p)) != 0) 496*19261079SEd Maste return r; 497*19261079SEd Maste *p = val; 498*19261079SEd Maste return 0; 499*19261079SEd Maste } 500*19261079SEd Maste 501*19261079SEd Maste int 502*19261079SEd Maste sshbuf_poke(struct sshbuf *buf, size_t offset, void *v, size_t len) 503*19261079SEd Maste { 504*19261079SEd Maste u_char *p = NULL; 505*19261079SEd Maste int r; 506*19261079SEd Maste 507*19261079SEd Maste if ((r = check_woffset(buf, offset, len, &p)) != 0) 508*19261079SEd Maste return r; 509*19261079SEd Maste memcpy(p, v, len); 510*19261079SEd Maste return 0; 511*19261079SEd Maste } 512*19261079SEd Maste 513a0ee8cc6SDag-Erling Smørgrav int 514a0ee8cc6SDag-Erling Smørgrav sshbuf_put_string(struct sshbuf *buf, const void *v, size_t len) 515a0ee8cc6SDag-Erling Smørgrav { 516a0ee8cc6SDag-Erling Smørgrav u_char *d; 517a0ee8cc6SDag-Erling Smørgrav int r; 518a0ee8cc6SDag-Erling Smørgrav 519a0ee8cc6SDag-Erling Smørgrav if (len > SSHBUF_SIZE_MAX - 4) { 520a0ee8cc6SDag-Erling Smørgrav SSHBUF_DBG(("SSH_ERR_NO_BUFFER_SPACE")); 521a0ee8cc6SDag-Erling Smørgrav return SSH_ERR_NO_BUFFER_SPACE; 522a0ee8cc6SDag-Erling Smørgrav } 523a0ee8cc6SDag-Erling Smørgrav if ((r = sshbuf_reserve(buf, len + 4, &d)) < 0) 524a0ee8cc6SDag-Erling Smørgrav return r; 525a0ee8cc6SDag-Erling Smørgrav POKE_U32(d, len); 526bc5531deSDag-Erling Smørgrav if (len != 0) 527a0ee8cc6SDag-Erling Smørgrav memcpy(d + 4, v, len); 528a0ee8cc6SDag-Erling Smørgrav return 0; 529a0ee8cc6SDag-Erling Smørgrav } 530a0ee8cc6SDag-Erling Smørgrav 531a0ee8cc6SDag-Erling Smørgrav int 532a0ee8cc6SDag-Erling Smørgrav sshbuf_put_cstring(struct sshbuf *buf, const char *v) 533a0ee8cc6SDag-Erling Smørgrav { 5344f52dfbbSDag-Erling Smørgrav return sshbuf_put_string(buf, v, v == NULL ? 0 : strlen(v)); 535a0ee8cc6SDag-Erling Smørgrav } 536a0ee8cc6SDag-Erling Smørgrav 537a0ee8cc6SDag-Erling Smørgrav int 538a0ee8cc6SDag-Erling Smørgrav sshbuf_put_stringb(struct sshbuf *buf, const struct sshbuf *v) 539a0ee8cc6SDag-Erling Smørgrav { 540*19261079SEd Maste if (v == NULL) 541*19261079SEd Maste return sshbuf_put_string(buf, NULL, 0); 542*19261079SEd Maste 543a0ee8cc6SDag-Erling Smørgrav return sshbuf_put_string(buf, sshbuf_ptr(v), sshbuf_len(v)); 544a0ee8cc6SDag-Erling Smørgrav } 545a0ee8cc6SDag-Erling Smørgrav 546a0ee8cc6SDag-Erling Smørgrav int 547a0ee8cc6SDag-Erling Smørgrav sshbuf_froms(struct sshbuf *buf, struct sshbuf **bufp) 548a0ee8cc6SDag-Erling Smørgrav { 549a0ee8cc6SDag-Erling Smørgrav const u_char *p; 550a0ee8cc6SDag-Erling Smørgrav size_t len; 551a0ee8cc6SDag-Erling Smørgrav struct sshbuf *ret; 552a0ee8cc6SDag-Erling Smørgrav int r; 553a0ee8cc6SDag-Erling Smørgrav 554a0ee8cc6SDag-Erling Smørgrav if (buf == NULL || bufp == NULL) 555a0ee8cc6SDag-Erling Smørgrav return SSH_ERR_INVALID_ARGUMENT; 556a0ee8cc6SDag-Erling Smørgrav *bufp = NULL; 557a0ee8cc6SDag-Erling Smørgrav if ((r = sshbuf_peek_string_direct(buf, &p, &len)) != 0) 558a0ee8cc6SDag-Erling Smørgrav return r; 559a0ee8cc6SDag-Erling Smørgrav if ((ret = sshbuf_from(p, len)) == NULL) 560a0ee8cc6SDag-Erling Smørgrav return SSH_ERR_ALLOC_FAIL; 561a0ee8cc6SDag-Erling Smørgrav if ((r = sshbuf_consume(buf, len + 4)) != 0 || /* Shouldn't happen */ 562a0ee8cc6SDag-Erling Smørgrav (r = sshbuf_set_parent(ret, buf)) != 0) { 563a0ee8cc6SDag-Erling Smørgrav sshbuf_free(ret); 564a0ee8cc6SDag-Erling Smørgrav return r; 565a0ee8cc6SDag-Erling Smørgrav } 566a0ee8cc6SDag-Erling Smørgrav *bufp = ret; 567a0ee8cc6SDag-Erling Smørgrav return 0; 568a0ee8cc6SDag-Erling Smørgrav } 569a0ee8cc6SDag-Erling Smørgrav 570a0ee8cc6SDag-Erling Smørgrav int 571a0ee8cc6SDag-Erling Smørgrav sshbuf_put_bignum2_bytes(struct sshbuf *buf, const void *v, size_t len) 572a0ee8cc6SDag-Erling Smørgrav { 573a0ee8cc6SDag-Erling Smørgrav u_char *d; 574a0ee8cc6SDag-Erling Smørgrav const u_char *s = (const u_char *)v; 575a0ee8cc6SDag-Erling Smørgrav int r, prepend; 576a0ee8cc6SDag-Erling Smørgrav 577a0ee8cc6SDag-Erling Smørgrav if (len > SSHBUF_SIZE_MAX - 5) { 578a0ee8cc6SDag-Erling Smørgrav SSHBUF_DBG(("SSH_ERR_NO_BUFFER_SPACE")); 579a0ee8cc6SDag-Erling Smørgrav return SSH_ERR_NO_BUFFER_SPACE; 580a0ee8cc6SDag-Erling Smørgrav } 581a0ee8cc6SDag-Erling Smørgrav /* Skip leading zero bytes */ 582a0ee8cc6SDag-Erling Smørgrav for (; len > 0 && *s == 0; len--, s++) 583a0ee8cc6SDag-Erling Smørgrav ; 584a0ee8cc6SDag-Erling Smørgrav /* 585a0ee8cc6SDag-Erling Smørgrav * If most significant bit is set then prepend a zero byte to 586a0ee8cc6SDag-Erling Smørgrav * avoid interpretation as a negative number. 587a0ee8cc6SDag-Erling Smørgrav */ 588a0ee8cc6SDag-Erling Smørgrav prepend = len > 0 && (s[0] & 0x80) != 0; 589a0ee8cc6SDag-Erling Smørgrav if ((r = sshbuf_reserve(buf, len + 4 + prepend, &d)) < 0) 590a0ee8cc6SDag-Erling Smørgrav return r; 591a0ee8cc6SDag-Erling Smørgrav POKE_U32(d, len + prepend); 592a0ee8cc6SDag-Erling Smørgrav if (prepend) 593a0ee8cc6SDag-Erling Smørgrav d[4] = 0; 594bc5531deSDag-Erling Smørgrav if (len != 0) 595a0ee8cc6SDag-Erling Smørgrav memcpy(d + 4 + prepend, s, len); 596a0ee8cc6SDag-Erling Smørgrav return 0; 597a0ee8cc6SDag-Erling Smørgrav } 598bc5531deSDag-Erling Smørgrav 599bc5531deSDag-Erling Smørgrav int 600bc5531deSDag-Erling Smørgrav sshbuf_get_bignum2_bytes_direct(struct sshbuf *buf, 601bc5531deSDag-Erling Smørgrav const u_char **valp, size_t *lenp) 602bc5531deSDag-Erling Smørgrav { 603bc5531deSDag-Erling Smørgrav const u_char *d; 604bc5531deSDag-Erling Smørgrav size_t len, olen; 605bc5531deSDag-Erling Smørgrav int r; 606bc5531deSDag-Erling Smørgrav 607bc5531deSDag-Erling Smørgrav if ((r = sshbuf_peek_string_direct(buf, &d, &olen)) < 0) 608bc5531deSDag-Erling Smørgrav return r; 609bc5531deSDag-Erling Smørgrav len = olen; 610bc5531deSDag-Erling Smørgrav /* Refuse negative (MSB set) bignums */ 611bc5531deSDag-Erling Smørgrav if ((len != 0 && (*d & 0x80) != 0)) 612bc5531deSDag-Erling Smørgrav return SSH_ERR_BIGNUM_IS_NEGATIVE; 613bc5531deSDag-Erling Smørgrav /* Refuse overlong bignums, allow prepended \0 to avoid MSB set */ 614bc5531deSDag-Erling Smørgrav if (len > SSHBUF_MAX_BIGNUM + 1 || 615bc5531deSDag-Erling Smørgrav (len == SSHBUF_MAX_BIGNUM + 1 && *d != 0)) 616bc5531deSDag-Erling Smørgrav return SSH_ERR_BIGNUM_TOO_LARGE; 617bc5531deSDag-Erling Smørgrav /* Trim leading zeros */ 618bc5531deSDag-Erling Smørgrav while (len > 0 && *d == 0x00) { 619bc5531deSDag-Erling Smørgrav d++; 620bc5531deSDag-Erling Smørgrav len--; 621bc5531deSDag-Erling Smørgrav } 622acc1a9efSDag-Erling Smørgrav if (valp != NULL) 623bc5531deSDag-Erling Smørgrav *valp = d; 624bc5531deSDag-Erling Smørgrav if (lenp != NULL) 625bc5531deSDag-Erling Smørgrav *lenp = len; 626bc5531deSDag-Erling Smørgrav if (sshbuf_consume(buf, olen + 4) != 0) { 627bc5531deSDag-Erling Smørgrav /* Shouldn't happen */ 628bc5531deSDag-Erling Smørgrav SSHBUF_DBG(("SSH_ERR_INTERNAL_ERROR")); 629bc5531deSDag-Erling Smørgrav SSHBUF_ABORT(); 630bc5531deSDag-Erling Smørgrav return SSH_ERR_INTERNAL_ERROR; 631bc5531deSDag-Erling Smørgrav } 632bc5531deSDag-Erling Smørgrav return 0; 633bc5531deSDag-Erling Smørgrav } 634