packet.c 7.5 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 27
        size_t newlen;

28
        if (pkt->buf->length > SIZE_MAX / 2) {
29
            newlen = SIZE_MAX;
30
        } else {
M
Matt Caswell 已提交
31 32
            newlen = (pkt->buf->length == 0) ? DEFAULT_BUF_SIZE
                                             : pkt->buf->length * 2;
33
        }
34 35
        if (BUF_MEM_grow(pkt->buf, newlen) == 0)
            return 0;
36
    }
37
    pkt->written += len;
M
Matt Caswell 已提交
38
    *allocbytes = (unsigned char *)pkt->buf->data + pkt->curr;
39
    pkt->curr += len;
40

41
    return 1;
42 43
}

44 45 46 47 48 49 50 51
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 已提交
52
int WPACKET_init_len(WPACKET *pkt, BUF_MEM *buf, size_t lenbytes)
53
{
M
Matt Caswell 已提交
54 55
    unsigned char *lenchars;

56 57
    /* Internal API, so should not fail */
    assert(buf != NULL);
58 59 60
    if (buf == NULL)
        return 0;

61
    pkt->buf = buf;
M
Matt Caswell 已提交
62
    pkt->curr = 0;
63
    pkt->written = 0;
64
    pkt->maxsize = maxmaxsize(lenbytes);
65

66 67 68
    pkt->subs = OPENSSL_zalloc(sizeof(*pkt->subs));
    if (pkt->subs == NULL)
        return 0;
69

70
    if (lenbytes == 0)
71 72
        return 1;

73 74 75
    pkt->subs->pwritten = lenbytes;
    pkt->subs->lenbytes = lenbytes;

M
Matt Caswell 已提交
76
    if (!WPACKET_allocate_bytes(pkt, lenbytes, &lenchars)) {
77 78
        OPENSSL_free(pkt->subs);
        pkt->subs = NULL;
79 80
        return 0;
    }
M
Matt Caswell 已提交
81
    pkt->subs->packet_len = lenchars - (unsigned char *)pkt->buf->data;
82 83 84 85

    return 1;
}

M
Matt Caswell 已提交
86
int WPACKET_init(WPACKET *pkt, BUF_MEM *buf)
87
{
M
Matt Caswell 已提交
88
    return WPACKET_init_len(pkt, buf, 0);
89 90
}

M
Matt Caswell 已提交
91
int WPACKET_set_flags(WPACKET *pkt, unsigned int flags)
92
{
93 94
    /* Internal API, so should not fail */
    assert(pkt->subs != NULL);
95 96 97 98
    if (pkt->subs == NULL)
        return 0;

    pkt->subs->flags = flags;
99 100 101 102

    return 1;
}

103

104
/*
105 106
 * Internal helper function used by WPACKET_close() and WPACKET_finish() to
 * close a sub-packet and write out its length if necessary.
107
 */
108
static int wpacket_intern_close(WPACKET *pkt)
109
{
110
    WPACKET_SUB *sub = pkt->subs;
M
Matt Caswell 已提交
111
    size_t packlen = pkt->written - sub->pwritten;
112

113
    if (packlen == 0
M
Matt Caswell 已提交
114
            && sub->flags & WPACKET_FLAGS_NON_ZERO_LENGTH)
115 116 117
        return 0;

    if (packlen == 0
M
Matt Caswell 已提交
118
            && sub->flags & WPACKET_FLAGS_ABANDON_ON_ZERO_LENGTH) {
M
Matt Caswell 已提交
119
        /* Deallocate any bytes allocated for the length of the WPACKET */
120 121 122
        if ((pkt->curr - sub->lenbytes) == sub->packet_len) {
            pkt->written -= sub->lenbytes;
            pkt->curr -= sub->lenbytes;
123 124 125
        }

        /* Don't write out the packet length */
M
Matt Caswell 已提交
126 127
        sub->packet_len = 0;
        sub->lenbytes = 0;
128 129
    }

M
Matt Caswell 已提交
130
    /* Write out the WPACKET length if needed */
M
Matt Caswell 已提交
131
    if (sub->lenbytes > 0) {
132 133
        size_t lenbytes;

M
Matt Caswell 已提交
134 135
        for (lenbytes = sub->lenbytes; lenbytes > 0; lenbytes--) {
            pkt->buf->data[sub->packet_len + lenbytes - 1]
136
                = (unsigned char)(packlen & 0xff);
137 138 139 140 141 142 143 144 145 146
            packlen >>= 8;
        }
        if (packlen > 0) {
            /*
             * We've extended beyond the max allowed for the number of len bytes
             */
            return 0;
        }
    }

147 148
    pkt->subs = sub->parent;
    OPENSSL_free(sub);
149 150 151 152

    return 1;
}

153
int WPACKET_close(WPACKET *pkt)
154
{
155 156 157 158
    /*
     * Internal API, so should not fail - but we do negative testing of this
     * so no assert (otherwise the tests fail)
     */
159
    if (pkt->subs == NULL || pkt->subs->parent == NULL)
160 161
        return 0;

162
    return wpacket_intern_close(pkt);
163 164
}

165
int WPACKET_finish(WPACKET *pkt)
166
{
167 168
    int ret;

169 170 171 172
    /*
     * Internal API, so should not fail - but we do negative testing of this
     * so no assert (otherwise the tests fail)
     */
173 174 175 176
    if (pkt->subs == NULL || pkt->subs->parent != NULL)
        return 0;

    ret = wpacket_intern_close(pkt);
177 178 179 180
    if (ret) {
        OPENSSL_free(pkt->subs);
        pkt->subs = NULL;
    }
M
Matt Caswell 已提交
181

182
    return ret;
183 184
}

185
int WPACKET_start_sub_packet_len(WPACKET *pkt, size_t lenbytes)
186
{
187
    WPACKET_SUB *sub;
M
Matt Caswell 已提交
188
    unsigned char *lenchars;
189

190 191
    /* Internal API, so should not fail */
    assert(pkt->subs != NULL);
192
    if (pkt->subs == NULL)
193 194
        return 0;

195 196
    sub = OPENSSL_zalloc(sizeof(*sub));
    if (sub == NULL)
197 198
        return 0;

199 200 201 202 203 204
    sub->parent = pkt->subs;
    pkt->subs = sub;
    sub->pwritten = pkt->written + lenbytes;
    sub->lenbytes = lenbytes;

    if (lenbytes == 0) {
M
Matt Caswell 已提交
205
        sub->packet_len = 0;
206 207 208
        return 1;
    }

M
Matt Caswell 已提交
209
    if (!WPACKET_allocate_bytes(pkt, lenbytes, &lenchars))
210
        return 0;
M
Matt Caswell 已提交
211
    sub->packet_len = lenchars - (unsigned char *)pkt->buf->data;
212 213 214 215

    return 1;
}

216 217 218 219 220
int WPACKET_start_sub_packet(WPACKET *pkt)
{
    return WPACKET_start_sub_packet_len(pkt, 0);
}

M
Matt Caswell 已提交
221
int WPACKET_put_bytes(WPACKET *pkt, unsigned int val, size_t size)
222 223 224
{
    unsigned char *data;

225 226
    /* Internal API, so should not fail */
    assert(size <= sizeof(unsigned int));
M
Matt Caswell 已提交
227 228
    if (size > sizeof(unsigned int)
            || !WPACKET_allocate_bytes(pkt, size, &data))
229 230
        return 0;

M
Matt Caswell 已提交
231
    for (data += size - 1; size > 0; size--) {
232 233 234 235 236 237 238 239 240 241 242 243
        *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 已提交
244
int WPACKET_set_max_size(WPACKET *pkt, size_t maxsize)
245
{
246 247 248
    WPACKET_SUB *sub;
    size_t lenbytes;

249 250
    /* Internal API, so should not fail */
    assert(pkt->subs != NULL);
251 252 253 254
    if (pkt->subs == NULL)
        return 0;

    /* Find the WPACKET_SUB for the top level */
M
Matt Caswell 已提交
255 256
    for (sub = pkt->subs; sub->parent != NULL; sub = sub->parent)
        continue;
257 258 259 260 261 262 263 264

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

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

265
    pkt->maxsize = maxsize;
266 267 268 269

    return 1;
}

M
Matt Caswell 已提交
270
int WPACKET_memcpy(WPACKET *pkt, const void *src, size_t len)
271 272 273 274 275 276
{
    unsigned char *dest;

    if (len == 0)
        return 1;

M
Matt Caswell 已提交
277
    if (!WPACKET_allocate_bytes(pkt, len, &dest))
278 279 280 281 282 283 284
        return 0;

    memcpy(dest, src, len);

    return 1;
}

M
Matt Caswell 已提交
285 286 287 288 289 290 291 292 293 294
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 已提交
295
int WPACKET_get_total_written(WPACKET *pkt, size_t *written)
296
{
297 298
    /* Internal API, so should not fail */
    assert(written != NULL);
299
    if (written == NULL)
300 301
        return 0;

302
    *written = pkt->written;
303 304 305 306

    return 1;
}

M
Matt Caswell 已提交
307
int WPACKET_get_length(WPACKET *pkt, size_t *len)
308
{
309 310
    /* Internal API, so should not fail */
    assert(pkt->subs != NULL && len != NULL);
311
    if (pkt->subs == NULL || len == NULL)
312 313
        return 0;

314
    *len = pkt->written - pkt->subs->pwritten;
315 316 317

    return 1;
}
318 319 320 321 322 323 324 325 326 327 328

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