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

/*
13
 * Allocate bytes in the WPACKET for the output. This reserves the bytes
14 15
 * and count them as "written", but doesn't actually do the writing.
 */
16
int WPACKET_allocate_bytes(WPACKET *pkt, size_t len, unsigned char **allocbytes)
17
{
18 19
    if (pkt->subs == NULL || len == 0)
        return 0;
20

21
    if (SIZE_MAX - pkt->written < len)
22 23
        return 0;

24
    if (pkt->maxsize > 0 && pkt->written + len > pkt->maxsize)
25 26
        return 0;

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

30
        if (pkt->buf->length > SIZE_MAX / 2)
31 32
            newlen = SIZE_MAX;
        else
33 34 35
            newlen = pkt->buf->length * 2;
        if (BUF_MEM_grow(pkt->buf, newlen) == 0)
            return 0;
36
    }
37 38 39
    pkt->written += len;
    *allocbytes = pkt->curr;
    pkt->curr += len;
40

41
    return 1;
42 43 44
}

/*
M
Matt Caswell 已提交
45 46
 * Initialise a WPACKET with the buffer in |buf|. The buffer must exist
 * for the whole time that the WPACKET is being used. Additionally |lenbytes| of
47
 * data is preallocated at the start of the buffer to store the length of the
M
Matt Caswell 已提交
48
 * WPACKET once we know it.
49
 */
M
Matt Caswell 已提交
50
int WPACKET_init_len(WPACKET *pkt, BUF_MEM *buf, size_t lenbytes)
51 52 53 54 55
{
    /* Sanity check */
    if (buf == NULL)
        return 0;

56 57 58 59
    pkt->buf = buf;
    pkt->curr = (unsigned char *)buf->data;
    pkt->written = 0;
    pkt->maxsize = 0;
60

61 62 63
    pkt->subs = OPENSSL_zalloc(sizeof(*pkt->subs));
    if (pkt->subs == NULL)
        return 0;
64

65
    if (lenbytes == 0)
66 67
        return 1;

68 69 70 71 72 73
    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;
74 75 76 77 78 79 80
        return 0;
    }

    return 1;
}

/*
M
Matt Caswell 已提交
81
 * Same as WPACKET_init_len except there is no preallocation of the WPACKET
82 83
 * length.
 */
M
Matt Caswell 已提交
84
int WPACKET_init(WPACKET *pkt, BUF_MEM *buf)
85
{
M
Matt Caswell 已提交
86
    return WPACKET_init_len(pkt, buf, 0);
87 88 89
}

/*
M
Matt Caswell 已提交
90 91 92
 * Set the WPACKET length, and the location for where we should write that
 * length. Normally this will be at the start of the WPACKET, and therefore
 * the WPACKET would have been initialised via WPACKET_init_len(). However there
93
 * is the possibility that the length needs to be written to some other location
M
Matt Caswell 已提交
94
 * other than the start of the WPACKET. In that case init via WPACKET_init() and
95 96
 * then set the location for the length using this function.
 */
M
Matt Caswell 已提交
97
int WPACKET_set_packet_len(WPACKET *pkt, unsigned char *packet_len,
98 99 100
                           size_t lenbytes)
{
    /* We only allow this to be set once */
101
    if (pkt->subs == NULL)
102 103
        return 0;

104 105
    pkt->subs->lenbytes = lenbytes;
    pkt->subs->packet_len = packet_len;
106 107 108 109

    return 1;
}

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

    pkt->subs->flags = flags;
116 117 118 119

    return 1;
}

120

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

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

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

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

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

151
        lenbytes = sub->lenbytes;
152 153

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

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

    return 1;
}

/*
173 174 175 176
 * Closes the most recent sub-packet. It also writes out the length of the
 * packet to the required location (normally the start of the WPACKET) if
 * appropriate. The top level WPACKET should be closed using WPACKET_finish()
 * instead of this function.
177
 */
178
int WPACKET_close(WPACKET *pkt)
179
{
180
    if (pkt->subs == NULL || pkt->subs->parent == NULL)
181 182
        return 0;

183
    return wpacket_intern_close(pkt);
184 185 186
}

/*
187 188
 * The same as WPACKET_close() but only for the top most WPACKET. Additionally
 * frees memory resources for this WPACKET.
189
 */
190
int WPACKET_finish(WPACKET *pkt)
191
{
192 193 194 195 196 197 198 199 200 201 202
    int ret;

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

    ret = wpacket_intern_close(pkt);

    /* We free up memory no matter whether |ret| is zero or not */
    OPENSSL_free(pkt->subs);
    pkt->subs = NULL;
    return ret;
203 204 205
}

/*
206 207
 * Initialise a new sub-packet. Additionally |lenbytes| of data is preallocated
 * at the start of the sub-packet to store its length once we know it.
208
 */
209
int WPACKET_start_sub_packet_len(WPACKET *pkt, size_t lenbytes)
210
{
211
    WPACKET_SUB *sub;
212

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

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

220 221 222 223 224 225 226 227 228 229 230 231 232
    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;
    }
233 234 235 236

    return 1;
}

237 238 239 240 241 242 243 244 245
/*
 * Same as WPACKET_get_sub_packet_len() except no bytes are pre-allocated for
 * the sub-packet length.
 */
int WPACKET_start_sub_packet(WPACKET *pkt)
{
    return WPACKET_start_sub_packet_len(pkt, 0);
}

246
/*
M
Matt Caswell 已提交
247
 * Write the value stored in |val| into the WPACKET. The value will consome
248 249 250 251
 * |bytes| amount of storage. An error will occur if |val| cannot be accommdated
 * in |bytes| storage, e.g. attempting to write the value 256 into 1 byte will
 * fail.
 */
M
Matt Caswell 已提交
252
int WPACKET_put_bytes(WPACKET *pkt, unsigned int val, size_t bytes)
253 254 255 256
{
    unsigned char *data;

    if (bytes > sizeof(unsigned int)
M
Matt Caswell 已提交
257
            || !WPACKET_allocate_bytes(pkt, bytes, &data))
258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274
        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 已提交
275
 * Set a maximum size that we will not allow the WPACKET to grow beyond. If not
276 277
 * set then there is no maximum.
 */
M
Matt Caswell 已提交
278
int WPACKET_set_max_size(WPACKET *pkt, size_t maxsize)
279
{
280
    pkt->maxsize = maxsize;
281 282 283 284 285

    return 1;
}

/*
M
Matt Caswell 已提交
286
 * Copy |len| bytes of data from |*src| into the WPACKET.
287
 */
M
Matt Caswell 已提交
288
int WPACKET_memcpy(WPACKET *pkt, const void *src, size_t len)
289 290 291 292 293 294
{
    unsigned char *dest;

    if (len == 0)
        return 1;

M
Matt Caswell 已提交
295
    if (!WPACKET_allocate_bytes(pkt, len, &dest))
296 297 298 299 300 301 302 303 304
        return 0;

    memcpy(dest, src, len);

    return 1;
}

/*
 * Return the total number of bytes written so far to the underlying buffer.
M
Matt Caswell 已提交
305
 * This might includes bytes written by a parent WPACKET.
306
 */
M
Matt Caswell 已提交
307
int WPACKET_get_total_written(WPACKET *pkt, size_t *written)
308
{
309
    if (pkt->subs == NULL || written == NULL)
310 311
        return 0;

312
    *written = pkt->written;
313 314 315 316 317

    return 1;
}

/*
318
 * Returns the length of the last sub-packet. This excludes any bytes allocated
319 320
 * for the length itself.
 */
M
Matt Caswell 已提交
321
int WPACKET_get_length(WPACKET *pkt, size_t *len)
322
{
323
    if (pkt->subs == NULL || len == NULL)
324 325
        return 0;

326
    *len = pkt->written - pkt->subs->pwritten;
327 328 329

    return 1;
}