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