packet.c 7.2 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11
/*
 * Copyright 2015-2016 The OpenSSL Project Authors. All Rights Reserved.
 *
 * Licensed under the OpenSSL license (the "License").  You may not use
 * this file except in compliance with the License.  You can obtain a copy
 * in the file LICENSE in the source distribution or at
 * https://www.openssl.org/source/license.html
 */

#include "packet_locl.h"

12 13
#define DEFAULT_BUF_SIZE    256

14
int WPACKET_allocate_bytes(WPACKET *pkt, size_t len, unsigned char **allocbytes)
15
{
16 17
    if (pkt->subs == NULL || len == 0)
        return 0;
18

19
    if (SIZE_MAX - pkt->written < len)
20 21
        return 0;

22
    if (pkt->written + len > pkt->maxsize)
23 24
        return 0;

25
    if (pkt->buf->length - pkt->written < len) {
26 27
        size_t newlen;

28
        if (pkt->buf->length > SIZE_MAX / 2) {
29
            newlen = SIZE_MAX;
30 31 32 33 34 35
        } else {
            if (pkt->buf->length == 0)
                newlen = DEFAULT_BUF_SIZE;
            else
                newlen = pkt->buf->length * 2;
        }
36 37
        if (BUF_MEM_grow(pkt->buf, newlen) == 0)
            return 0;
38 39 40 41 42 43 44
        if (pkt->curr == NULL) {
            /*
             * Can happen if initialised with a BUF_MEM that hasn't been
             * pre-allocated.
             */
            pkt->curr = (unsigned char *)pkt->buf->data;
        }
45
    }
46 47 48
    pkt->written += len;
    *allocbytes = pkt->curr;
    pkt->curr += len;
49

50
    return 1;
51 52
}

53 54 55 56 57 58 59 60
static size_t maxmaxsize(size_t lenbytes)
{
    if (lenbytes >= sizeof(size_t) || lenbytes == 0)
        return SIZE_MAX;
    else
        return ((size_t)1 << (lenbytes * 8)) - 1 + lenbytes;
}

M
Matt Caswell 已提交
61
int WPACKET_init_len(WPACKET *pkt, BUF_MEM *buf, size_t lenbytes)
62 63 64 65 66
{
    /* Sanity check */
    if (buf == NULL)
        return 0;

67 68 69
    pkt->buf = buf;
    pkt->curr = (unsigned char *)buf->data;
    pkt->written = 0;
70
    pkt->maxsize = maxmaxsize(lenbytes);
71

72 73 74
    pkt->subs = OPENSSL_zalloc(sizeof(*pkt->subs));
    if (pkt->subs == NULL)
        return 0;
75

76
    if (lenbytes == 0)
77 78
        return 1;

79 80 81 82 83 84
    pkt->subs->pwritten = lenbytes;
    pkt->subs->lenbytes = lenbytes;

    if (!WPACKET_allocate_bytes(pkt, lenbytes, &(pkt->subs->packet_len))) {
        OPENSSL_free(pkt->subs);
        pkt->subs = NULL;
85 86 87 88 89 90
        return 0;
    }

    return 1;
}

M
Matt Caswell 已提交
91
int WPACKET_init(WPACKET *pkt, BUF_MEM *buf)
92
{
M
Matt Caswell 已提交
93
    return WPACKET_init_len(pkt, buf, 0);
94 95
}

M
Matt Caswell 已提交
96
int WPACKET_set_packet_len(WPACKET *pkt, unsigned char *packet_len,
97 98
                           size_t lenbytes)
{
99 100
    size_t maxmax;

101
    /* We only allow this to be set once */
102
    if (pkt->subs == NULL || pkt->subs->lenbytes != 0)
103 104
        return 0;

105 106
    pkt->subs->lenbytes = lenbytes;
    pkt->subs->packet_len = packet_len;
107

108 109 110 111
    maxmax = maxmaxsize(lenbytes);
    if (pkt->maxsize > maxmax)
        pkt->maxsize = maxmax;

112 113 114
    return 1;
}

M
Matt Caswell 已提交
115
int WPACKET_set_flags(WPACKET *pkt, unsigned int flags)
116
{
117 118 119 120
    if (pkt->subs == NULL)
        return 0;

    pkt->subs->flags = flags;
121 122 123 124

    return 1;
}

125

126
/*
127 128
 * Internal helper function used by WPACKET_close() and WPACKET_finish() to
 * close a sub-packet and write out its length if necessary.
129
 */
130
static int wpacket_intern_close(WPACKET *pkt)
131 132
{
    size_t packlen;
133
    WPACKET_SUB *sub = pkt->subs;
134

135 136 137
    packlen = pkt->written - sub->pwritten;
    if (packlen == 0
            && sub->flags & OPENSSL_WPACKET_FLAGS_NON_ZERO_LENGTH)
138 139 140
        return 0;

    if (packlen == 0
141
            && sub->flags & OPENSSL_WPACKET_FLAGS_ABANDON_ON_ZERO_LENGTH) {
M
Matt Caswell 已提交
142
        /* Deallocate any bytes allocated for the length of the WPACKET */
143 144 145
        if ((pkt->curr - sub->lenbytes) == sub->packet_len) {
            pkt->written -= sub->lenbytes;
            pkt->curr -= sub->lenbytes;
146 147 148
        }

        /* Don't write out the packet length */
149
        sub->packet_len = NULL;
150 151
    }

M
Matt Caswell 已提交
152
    /* Write out the WPACKET length if needed */
153
    if (sub->packet_len != NULL) {
154 155
        size_t lenbytes;

156
        lenbytes = sub->lenbytes;
157 158

        for (; lenbytes > 0; lenbytes--) {
159 160
            sub->packet_len[lenbytes - 1]
                = (unsigned char)(packlen & 0xff);
161 162 163 164 165 166 167 168 169 170
            packlen >>= 8;
        }
        if (packlen > 0) {
            /*
             * We've extended beyond the max allowed for the number of len bytes
             */
            return 0;
        }
    }

171 172
    pkt->subs = sub->parent;
    OPENSSL_free(sub);
173 174 175 176

    return 1;
}

177
int WPACKET_close(WPACKET *pkt)
178
{
179
    if (pkt->subs == NULL || pkt->subs->parent == NULL)
180 181
        return 0;

182
    return wpacket_intern_close(pkt);
183 184
}

185
int WPACKET_finish(WPACKET *pkt)
186
{
187 188 189 190 191 192 193
    int ret;

    if (pkt->subs == NULL || pkt->subs->parent != NULL)
        return 0;

    ret = wpacket_intern_close(pkt);

194 195 196 197
    if (ret) {
        OPENSSL_free(pkt->subs);
        pkt->subs = NULL;
    }
198
    return ret;
199 200
}

201
int WPACKET_start_sub_packet_len(WPACKET *pkt, size_t lenbytes)
202
{
203
    WPACKET_SUB *sub;
204

205
    if (pkt->subs == NULL)
206 207
        return 0;

208 209
    sub = OPENSSL_zalloc(sizeof(*sub));
    if (sub == NULL)
210 211
        return 0;

212 213 214 215 216 217 218 219 220 221 222 223 224
    sub->parent = pkt->subs;
    pkt->subs = sub;
    sub->pwritten = pkt->written + lenbytes;
    sub->lenbytes = lenbytes;

    if (lenbytes == 0) {
        sub->packet_len = NULL;
        return 1;
    }

    if (!WPACKET_allocate_bytes(pkt, lenbytes, &sub->packet_len)) {
        return 0;
    }
225 226 227 228

    return 1;
}

229 230 231 232 233
int WPACKET_start_sub_packet(WPACKET *pkt)
{
    return WPACKET_start_sub_packet_len(pkt, 0);
}

M
Matt Caswell 已提交
234
int WPACKET_put_bytes(WPACKET *pkt, unsigned int val, size_t bytes)
235 236 237 238
{
    unsigned char *data;

    if (bytes > sizeof(unsigned int)
M
Matt Caswell 已提交
239
            || !WPACKET_allocate_bytes(pkt, bytes, &data))
240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255
        return 0;

    data += bytes - 1;
    for (; bytes > 0; bytes--) {
        *data = (unsigned char)(val & 0xff);
        data--;
        val >>= 8;
    }

    /* Check whether we could fit the value in the assigned number of bytes */
    if (val > 0)
        return 0;

    return 1;
}

M
Matt Caswell 已提交
256
int WPACKET_set_max_size(WPACKET *pkt, size_t maxsize)
257
{
258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273
    WPACKET_SUB *sub;
    size_t lenbytes;

    if (pkt->subs == NULL)
        return 0;

    /* Find the WPACKET_SUB for the top level */
    for (sub = pkt->subs; sub->parent != NULL; sub = sub->parent);

    lenbytes = sub->lenbytes;
    if (lenbytes == 0)
        lenbytes = sizeof(pkt->maxsize);

    if (maxmaxsize(lenbytes) < maxsize || maxsize < pkt->written)
        return 0;

274
    pkt->maxsize = maxsize;
275 276 277 278

    return 1;
}

M
Matt Caswell 已提交
279
int WPACKET_memcpy(WPACKET *pkt, const void *src, size_t len)
280 281 282 283 284 285
{
    unsigned char *dest;

    if (len == 0)
        return 1;

M
Matt Caswell 已提交
286
    if (!WPACKET_allocate_bytes(pkt, len, &dest))
287 288 289 290 291 292 293
        return 0;

    memcpy(dest, src, len);

    return 1;
}

M
Matt Caswell 已提交
294 295 296 297 298 299 300 301 302 303
int WPACKET_sub_memcpy(WPACKET *pkt, const void *src, size_t len, size_t lenbytes)
{
    if (!WPACKET_start_sub_packet_len(pkt, lenbytes)
            || !WPACKET_memcpy(pkt, src, len)
            || !WPACKET_close(pkt))
        return 0;

    return 1;
}

M
Matt Caswell 已提交
304
int WPACKET_get_total_written(WPACKET *pkt, size_t *written)
305
{
306
    if (written == NULL)
307 308
        return 0;

309
    *written = pkt->written;
310 311 312 313

    return 1;
}

M
Matt Caswell 已提交
314
int WPACKET_get_length(WPACKET *pkt, size_t *len)
315
{
316
    if (pkt->subs == NULL || len == NULL)
317 318
        return 0;

319
    *len = pkt->written - pkt->subs->pwritten;
320 321 322

    return 1;
}
323 324 325 326 327 328 329 330 331 332 333

void WPACKET_cleanup(WPACKET *pkt)
{
    WPACKET_SUB *sub, *parent;

    for (sub = pkt->subs; sub != NULL; sub = parent) {
        parent = sub->parent;
        OPENSSL_free(sub);
    }
    pkt->subs = NULL;
}