Annotation of src/usr.bin/ssh/sshbuf-getput-basic.c, Revision 1.1
1.1 ! djm 1: /* $OpenBSD$ */
! 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:
! 27: int
! 28: sshbuf_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:
! 40: int
! 41: sshbuf_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:
! 53: int
! 54: sshbuf_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:
! 66: int
! 67: sshbuf_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:
! 79: int
! 80: sshbuf_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:
! 92: int
! 93: sshbuf_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:
! 118: int
! 119: sshbuf_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:
! 144: int
! 145: sshbuf_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:
! 175: int
! 176: sshbuf_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:
! 209: int
! 210: sshbuf_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:
! 229: int
! 230: sshbuf_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:
! 241: int
! 242: sshbuf_putb(struct sshbuf *buf, const struct sshbuf *v)
! 243: {
! 244: return sshbuf_put(buf, sshbuf_ptr(v), sshbuf_len(v));
! 245: }
! 246:
! 247: int
! 248: sshbuf_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:
! 259: int
! 260: sshbuf_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:
! 292: int
! 293: sshbuf_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:
! 304: int
! 305: sshbuf_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:
! 316: int
! 317: sshbuf_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:
! 328: int
! 329: sshbuf_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:
! 340: int
! 341: sshbuf_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:
! 357: int
! 358: sshbuf_put_cstring(struct sshbuf *buf, const char *v)
! 359: {
! 360: return sshbuf_put_string(buf, (u_char *)v, strlen(v));
! 361: }
! 362:
! 363: int
! 364: sshbuf_put_stringb(struct sshbuf *buf, const struct sshbuf *v)
! 365: {
! 366: return sshbuf_put_string(buf, sshbuf_ptr(v), sshbuf_len(v));
! 367: }
! 368:
! 369: int
! 370: sshbuf_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:
! 393: int
! 394: sshbuf_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: }