packet.c 7.1 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 (pkt->maxsize - pkt->written < len)
20 21
        return 0;

22
    if (pkt->buf->length - pkt->written < len) {
23 24
        size_t newlen;

25
        if (pkt->buf->length > SIZE_MAX / 2) {
26
            newlen = SIZE_MAX;
27 28 29 30 31 32
        } else {
            if (pkt->buf->length == 0)
                newlen = DEFAULT_BUF_SIZE;
            else
                newlen = pkt->buf->length * 2;
        }
33 34
        if (BUF_MEM_grow(pkt->buf, newlen) == 0)
            return 0;
35 36 37 38 39 40 41
        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;
        }
42
    }
43 44 45
    pkt->written += len;
    *allocbytes = pkt->curr;
    pkt->curr += len;
46

47
    return 1;
48 49
}

50 51 52 53 54 55 56 57
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 已提交
58
int WPACKET_init_len(WPACKET *pkt, BUF_MEM *buf, size_t lenbytes)
59 60 61 62 63
{
    /* Sanity check */
    if (buf == NULL)
        return 0;

64 65 66
    pkt->buf = buf;
    pkt->curr = (unsigned char *)buf->data;
    pkt->written = 0;
67
    pkt->maxsize = maxmaxsize(lenbytes);
68

69 70 71
    pkt->subs = OPENSSL_zalloc(sizeof(*pkt->subs));
    if (pkt->subs == NULL)
        return 0;
72

73
    if (lenbytes == 0)
74 75
        return 1;

76 77 78 79 80 81
    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;
82 83 84 85 86 87
        return 0;
    }

    return 1;
}

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

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

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

102 103
    pkt->subs->lenbytes = lenbytes;
    pkt->subs->packet_len = packet_len;
104

105 106 107 108
    maxmax = maxmaxsize(lenbytes);
    if (pkt->maxsize > maxmax)
        pkt->maxsize = maxmax;

109 110 111
    return 1;
}

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

    pkt->subs->flags = flags;
118 119 120 121

    return 1;
}

122

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

132 133 134
    packlen = pkt->written - sub->pwritten;
    if (packlen == 0
            && sub->flags & OPENSSL_WPACKET_FLAGS_NON_ZERO_LENGTH)
135 136 137
        return 0;

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

        /* Don't write out the packet length */
146
        sub->packet_len = NULL;
147 148
    }

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

153
        lenbytes = sub->lenbytes;
154 155

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

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

    return 1;
}

174
int WPACKET_close(WPACKET *pkt)
175
{
176
    if (pkt->subs == NULL || pkt->subs->parent == NULL)
177 178
        return 0;

179
    return wpacket_intern_close(pkt);
180 181
}

182
int WPACKET_finish(WPACKET *pkt)
183
{
184 185 186 187 188 189 190
    int ret;

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

    ret = wpacket_intern_close(pkt);

191 192 193 194
    if (ret) {
        OPENSSL_free(pkt->subs);
        pkt->subs = NULL;
    }
195
    return ret;
196 197
}

198
int WPACKET_start_sub_packet_len(WPACKET *pkt, size_t lenbytes)
199
{
200
    WPACKET_SUB *sub;
201

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

205 206
    sub = OPENSSL_zalloc(sizeof(*sub));
    if (sub == NULL)
207 208
        return 0;

209 210 211 212 213 214 215 216 217 218 219 220 221
    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;
    }
222 223 224 225

    return 1;
}

226 227 228 229 230
int WPACKET_start_sub_packet(WPACKET *pkt)
{
    return WPACKET_start_sub_packet_len(pkt, 0);
}

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

    if (bytes > sizeof(unsigned int)
M
Matt Caswell 已提交
236
            || !WPACKET_allocate_bytes(pkt, bytes, &data))
237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252
        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 已提交
253
int WPACKET_set_max_size(WPACKET *pkt, size_t maxsize)
254
{
255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270
    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;

271
    pkt->maxsize = maxsize;
272 273 274 275

    return 1;
}

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

    if (len == 0)
        return 1;

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

    memcpy(dest, src, len);

    return 1;
}

M
Matt Caswell 已提交
291 292 293 294 295 296 297 298 299 300
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 已提交
301
int WPACKET_get_total_written(WPACKET *pkt, size_t *written)
302
{
303
    if (written == NULL)
304 305
        return 0;

306
    *written = pkt->written;
307 308 309 310

    return 1;
}

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

316
    *len = pkt->written - pkt->subs->pwritten;
317 318 319

    return 1;
}
320 321 322 323 324 325 326 327 328 329 330

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