packet.c 7.9 KB
Newer Older
1 2 3 4 5 6 7 8 9
/*
 * 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
 */

10
#include <assert.h>
11 12
#include "packet_locl.h"

13 14
#define DEFAULT_BUF_SIZE    256

15
int WPACKET_allocate_bytes(WPACKET *pkt, size_t len, unsigned char **allocbytes)
16
{
17 18
    /* Internal API, so should not fail */
    assert(pkt->subs != NULL && len != 0);
19 20
    if (pkt->subs == NULL || len == 0)
        return 0;
21

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

25
    if (pkt->buf->length - pkt->written < len) {
26
        size_t newlen;
M
Matt Caswell 已提交
27
        size_t reflen;
28

M
Matt Caswell 已提交
29 30 31
        reflen = (len > pkt->buf->length) ? len : pkt->buf->length;

        if (reflen > SIZE_MAX / 2) {
32
            newlen = SIZE_MAX;
33
        } else {
M
Matt Caswell 已提交
34 35 36
            newlen = reflen * 2;
            if (newlen < DEFAULT_BUF_SIZE)
                newlen = DEFAULT_BUF_SIZE;
37
        }
38 39
        if (BUF_MEM_grow(pkt->buf, newlen) == 0)
            return 0;
40
    }
M
Matt Caswell 已提交
41
    *allocbytes = (unsigned char *)pkt->buf->data + pkt->curr;
42
    pkt->written += len;
43
    pkt->curr += len;
44

45
    return 1;
46 47
}

48 49
int WPACKET_sub_allocate_bytes__(WPACKET *pkt, size_t len,
                                 unsigned char **allocbytes, size_t lenbytes)
50
{
51
    if (!WPACKET_start_sub_packet_len__(pkt, lenbytes)
52 53 54 55 56 57 58
            || !WPACKET_allocate_bytes(pkt, len, allocbytes)
            || !WPACKET_close(pkt))
        return 0;

    return 1;
}

59 60 61 62
static size_t maxmaxsize(size_t lenbytes)
{
    if (lenbytes >= sizeof(size_t) || lenbytes == 0)
        return SIZE_MAX;
63 64

    return ((size_t)1 << (lenbytes * 8)) - 1 + lenbytes;
65 66
}

M
Matt Caswell 已提交
67
int WPACKET_init_len(WPACKET *pkt, BUF_MEM *buf, size_t lenbytes)
68
{
M
Matt Caswell 已提交
69 70
    unsigned char *lenchars;

71 72
    /* Internal API, so should not fail */
    assert(buf != NULL);
73 74 75
    if (buf == NULL)
        return 0;

76
    pkt->buf = buf;
M
Matt Caswell 已提交
77
    pkt->curr = 0;
78
    pkt->written = 0;
79
    pkt->maxsize = maxmaxsize(lenbytes);
80

81 82 83
    pkt->subs = OPENSSL_zalloc(sizeof(*pkt->subs));
    if (pkt->subs == NULL)
        return 0;
84

85
    if (lenbytes == 0)
86 87
        return 1;

88 89 90
    pkt->subs->pwritten = lenbytes;
    pkt->subs->lenbytes = lenbytes;

M
Matt Caswell 已提交
91
    if (!WPACKET_allocate_bytes(pkt, lenbytes, &lenchars)) {
92 93
        OPENSSL_free(pkt->subs);
        pkt->subs = NULL;
94 95
        return 0;
    }
M
Matt Caswell 已提交
96
    pkt->subs->packet_len = lenchars - (unsigned char *)pkt->buf->data;
97 98 99 100

    return 1;
}

M
Matt Caswell 已提交
101
int WPACKET_init(WPACKET *pkt, BUF_MEM *buf)
102
{
M
Matt Caswell 已提交
103
    return WPACKET_init_len(pkt, buf, 0);
104 105
}

M
Matt Caswell 已提交
106
int WPACKET_set_flags(WPACKET *pkt, unsigned int flags)
107
{
108 109
    /* Internal API, so should not fail */
    assert(pkt->subs != NULL);
110 111 112 113
    if (pkt->subs == NULL)
        return 0;

    pkt->subs->flags = flags;
114 115 116 117

    return 1;
}

118 119
/* Store the |value| of length |len| at location |data| */
static int put_value(unsigned char *data, size_t value, size_t len)
120
{
121
    for (data += len - 1; len > 0; len--) {
122 123 124 125 126 127 128 129 130 131 132 133
        *data = (unsigned char)(value & 0xff);
        data--;
        value >>= 8;
    }

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

    return 1;
}

134

135
/*
136 137
 * Internal helper function used by WPACKET_close() and WPACKET_finish() to
 * close a sub-packet and write out its length if necessary.
138
 */
139
static int wpacket_intern_close(WPACKET *pkt)
140
{
141
    WPACKET_SUB *sub = pkt->subs;
M
Matt Caswell 已提交
142
    size_t packlen = pkt->written - sub->pwritten;
143

144
    if (packlen == 0
145
            && (sub->flags & WPACKET_FLAGS_NON_ZERO_LENGTH) != 0)
146 147 148
        return 0;

    if (packlen == 0
M
Matt Caswell 已提交
149
            && sub->flags & WPACKET_FLAGS_ABANDON_ON_ZERO_LENGTH) {
M
Matt Caswell 已提交
150
        /* Deallocate any bytes allocated for the length of the WPACKET */
151 152 153
        if ((pkt->curr - sub->lenbytes) == sub->packet_len) {
            pkt->written -= sub->lenbytes;
            pkt->curr -= sub->lenbytes;
154 155 156
        }

        /* Don't write out the packet length */
M
Matt Caswell 已提交
157 158
        sub->packet_len = 0;
        sub->lenbytes = 0;
159 160
    }

M
Matt Caswell 已提交
161
    /* Write out the WPACKET length if needed */
162 163 164
    if (sub->lenbytes > 0 
                && !put_value((unsigned char *)&pkt->buf->data[sub->packet_len],
                              packlen, sub->lenbytes))
165 166
            return 0;

167 168
    pkt->subs = sub->parent;
    OPENSSL_free(sub);
169 170 171 172

    return 1;
}

173
int WPACKET_close(WPACKET *pkt)
174
{
175 176 177 178
    /*
     * Internal API, so should not fail - but we do negative testing of this
     * so no assert (otherwise the tests fail)
     */
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
    int ret;

189 190 191 192
    /*
     * Internal API, so should not fail - but we do negative testing of this
     * so no assert (otherwise the tests fail)
     */
193 194 195 196
    if (pkt->subs == NULL || pkt->subs->parent != NULL)
        return 0;

    ret = wpacket_intern_close(pkt);
197 198 199 200
    if (ret) {
        OPENSSL_free(pkt->subs);
        pkt->subs = NULL;
    }
M
Matt Caswell 已提交
201

202
    return ret;
203 204
}

205
int WPACKET_start_sub_packet_len__(WPACKET *pkt, size_t lenbytes)
206
{
207
    WPACKET_SUB *sub;
M
Matt Caswell 已提交
208
    unsigned char *lenchars;
209

210 211
    /* Internal API, so should not fail */
    assert(pkt->subs != NULL);
212
    if (pkt->subs == NULL)
213 214
        return 0;

215 216
    sub = OPENSSL_zalloc(sizeof(*sub));
    if (sub == NULL)
217 218
        return 0;

219 220 221 222 223 224
    sub->parent = pkt->subs;
    pkt->subs = sub;
    sub->pwritten = pkt->written + lenbytes;
    sub->lenbytes = lenbytes;

    if (lenbytes == 0) {
M
Matt Caswell 已提交
225
        sub->packet_len = 0;
226 227 228
        return 1;
    }

M
Matt Caswell 已提交
229
    if (!WPACKET_allocate_bytes(pkt, lenbytes, &lenchars))
230
        return 0;
231
    /* Convert to an offset in case the underlying BUF_MEM gets realloc'd */
M
Matt Caswell 已提交
232
    sub->packet_len = lenchars - (unsigned char *)pkt->buf->data;
233 234 235 236

    return 1;
}

237 238
int WPACKET_start_sub_packet(WPACKET *pkt)
{
239
    return WPACKET_start_sub_packet_len__(pkt, 0);
240 241
}

242
int WPACKET_put_bytes__(WPACKET *pkt, unsigned int val, size_t size)
243 244 245
{
    unsigned char *data;

246 247
    /* Internal API, so should not fail */
    assert(size <= sizeof(unsigned int));
248

M
Matt Caswell 已提交
249
    if (size > sizeof(unsigned int)
250 251
            || !WPACKET_allocate_bytes(pkt, size, &data)
            || !put_value(data, val, size))
252 253 254 255 256
        return 0;

    return 1;
}

M
Matt Caswell 已提交
257
int WPACKET_set_max_size(WPACKET *pkt, size_t maxsize)
258
{
259 260 261
    WPACKET_SUB *sub;
    size_t lenbytes;

262 263
    /* Internal API, so should not fail */
    assert(pkt->subs != NULL);
264 265 266 267
    if (pkt->subs == NULL)
        return 0;

    /* Find the WPACKET_SUB for the top level */
M
Matt Caswell 已提交
268 269
    for (sub = pkt->subs; sub->parent != NULL; sub = sub->parent)
        continue;
270 271 272 273 274 275 276 277

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

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

278
    pkt->maxsize = maxsize;
279 280 281 282

    return 1;
}

M
Matt Caswell 已提交
283
int WPACKET_memcpy(WPACKET *pkt, const void *src, size_t len)
284 285 286 287 288 289
{
    unsigned char *dest;

    if (len == 0)
        return 1;

M
Matt Caswell 已提交
290
    if (!WPACKET_allocate_bytes(pkt, len, &dest))
291 292 293 294 295 296 297
        return 0;

    memcpy(dest, src, len);

    return 1;
}

298 299
int WPACKET_sub_memcpy__(WPACKET *pkt, const void *src, size_t len,
                         size_t lenbytes)
M
Matt Caswell 已提交
300
{
301
    if (!WPACKET_start_sub_packet_len__(pkt, lenbytes)
M
Matt Caswell 已提交
302 303 304 305 306 307 308
            || !WPACKET_memcpy(pkt, src, len)
            || !WPACKET_close(pkt))
        return 0;

    return 1;
}

M
Matt Caswell 已提交
309
int WPACKET_get_total_written(WPACKET *pkt, size_t *written)
310
{
311 312
    /* Internal API, so should not fail */
    assert(written != NULL);
313
    if (written == NULL)
314 315
        return 0;

316
    *written = pkt->written;
317 318 319 320

    return 1;
}

M
Matt Caswell 已提交
321
int WPACKET_get_length(WPACKET *pkt, size_t *len)
322
{
323 324
    /* Internal API, so should not fail */
    assert(pkt->subs != NULL && len != NULL);
325
    if (pkt->subs == NULL || len == NULL)
326 327
        return 0;

328
    *len = pkt->written - pkt->subs->pwritten;
329 330 331

    return 1;
}
332 333 334 335 336 337 338 339 340 341 342

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;
}