[BACK]Return to sshbuf-getput-basic.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / ssh

Annotation of src/usr.bin/ssh/sshbuf-getput-basic.c, Revision 1.6

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