[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.5

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