packet.c 6.6 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
        } else {
M
Matt Caswell 已提交
28 29
            newlen = (pkt->buf->length == 0) ? DEFAULT_BUF_SIZE
                                             : pkt->buf->length * 2;
30
        }
31 32
        if (BUF_MEM_grow(pkt->buf, newlen) == 0)
            return 0;
33
    }
34
    pkt->written += len;
M
Matt Caswell 已提交
35
    *allocbytes = (unsigned char *)pkt->buf->data + pkt->curr;
36
    pkt->curr += len;
37

38
    return 1;
39 40
}

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

53 54 55 56
    /* Sanity check */
    if (buf == NULL)
        return 0;

57
    pkt->buf = buf;
M
Matt Caswell 已提交
58
    pkt->curr = 0;
59
    pkt->written = 0;
60
    pkt->maxsize = maxmaxsize(lenbytes);
61

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

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

69 70 71
    pkt->subs->pwritten = lenbytes;
    pkt->subs->lenbytes = lenbytes;

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

    return 1;
}

M
Matt Caswell 已提交
82
int WPACKET_init(WPACKET *pkt, BUF_MEM *buf)
83
{
M
Matt Caswell 已提交
84
    return WPACKET_init_len(pkt, buf, 0);
85 86
}

M
Matt Caswell 已提交
87
int WPACKET_set_flags(WPACKET *pkt, unsigned int flags)
88
{
89 90 91 92
    if (pkt->subs == NULL)
        return 0;

    pkt->subs->flags = flags;
93 94 95 96

    return 1;
}

97

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

107
    if (packlen == 0
M
Matt Caswell 已提交
108
            && sub->flags & WPACKET_FLAGS_NON_ZERO_LENGTH)
109 110 111
        return 0;

    if (packlen == 0
M
Matt Caswell 已提交
112
            && sub->flags & WPACKET_FLAGS_ABANDON_ON_ZERO_LENGTH) {
M
Matt Caswell 已提交
113
        /* Deallocate any bytes allocated for the length of the WPACKET */
114 115 116
        if ((pkt->curr - sub->lenbytes) == sub->packet_len) {
            pkt->written -= sub->lenbytes;
            pkt->curr -= sub->lenbytes;
117 118 119
        }

        /* Don't write out the packet length */
M
Matt Caswell 已提交
120 121
        sub->packet_len = 0;
        sub->lenbytes = 0;
122 123
    }

M
Matt Caswell 已提交
124
    /* Write out the WPACKET length if needed */
M
Matt Caswell 已提交
125
    if (sub->lenbytes > 0) {
126 127
        size_t lenbytes;

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

141 142
    pkt->subs = sub->parent;
    OPENSSL_free(sub);
143 144 145 146

    return 1;
}

147
int WPACKET_close(WPACKET *pkt)
148
{
149
    if (pkt->subs == NULL || pkt->subs->parent == NULL)
150 151
        return 0;

152
    return wpacket_intern_close(pkt);
153 154
}

155
int WPACKET_finish(WPACKET *pkt)
156
{
157 158 159 160 161 162
    int ret;

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

    ret = wpacket_intern_close(pkt);
163 164 165 166
    if (ret) {
        OPENSSL_free(pkt->subs);
        pkt->subs = NULL;
    }
M
Matt Caswell 已提交
167

168
    return ret;
169 170
}

171
int WPACKET_start_sub_packet_len(WPACKET *pkt, size_t lenbytes)
172
{
173
    WPACKET_SUB *sub;
M
Matt Caswell 已提交
174
    unsigned char *lenchars;
175

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

179 180
    sub = OPENSSL_zalloc(sizeof(*sub));
    if (sub == NULL)
181 182
        return 0;

183 184 185 186 187 188
    sub->parent = pkt->subs;
    pkt->subs = sub;
    sub->pwritten = pkt->written + lenbytes;
    sub->lenbytes = lenbytes;

    if (lenbytes == 0) {
M
Matt Caswell 已提交
189
        sub->packet_len = 0;
190 191 192
        return 1;
    }

M
Matt Caswell 已提交
193
    if (!WPACKET_allocate_bytes(pkt, lenbytes, &lenchars))
194
        return 0;
M
Matt Caswell 已提交
195
    sub->packet_len = lenchars - (unsigned char *)pkt->buf->data;
196 197 198 199

    return 1;
}

200 201 202 203 204
int WPACKET_start_sub_packet(WPACKET *pkt)
{
    return WPACKET_start_sub_packet_len(pkt, 0);
}

M
Matt Caswell 已提交
205
int WPACKET_put_bytes(WPACKET *pkt, unsigned int val, size_t size)
206 207 208
{
    unsigned char *data;

M
Matt Caswell 已提交
209 210
    if (size > sizeof(unsigned int)
            || !WPACKET_allocate_bytes(pkt, size, &data))
211 212
        return 0;

M
Matt Caswell 已提交
213
    for (data += size - 1; size > 0; size--) {
214 215 216 217 218 219 220 221 222 223 224 225
        *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 已提交
226
int WPACKET_set_max_size(WPACKET *pkt, size_t maxsize)
227
{
228 229 230 231 232 233 234
    WPACKET_SUB *sub;
    size_t lenbytes;

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

    /* Find the WPACKET_SUB for the top level */
M
Matt Caswell 已提交
235 236
    for (sub = pkt->subs; sub->parent != NULL; sub = sub->parent)
        continue;
237 238 239 240 241 242 243 244

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

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

245
    pkt->maxsize = maxsize;
246 247 248 249

    return 1;
}

M
Matt Caswell 已提交
250
int WPACKET_memcpy(WPACKET *pkt, const void *src, size_t len)
251 252 253 254 255 256
{
    unsigned char *dest;

    if (len == 0)
        return 1;

M
Matt Caswell 已提交
257
    if (!WPACKET_allocate_bytes(pkt, len, &dest))
258 259 260 261 262 263 264
        return 0;

    memcpy(dest, src, len);

    return 1;
}

M
Matt Caswell 已提交
265 266 267 268 269 270 271 272 273 274
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 已提交
275
int WPACKET_get_total_written(WPACKET *pkt, size_t *written)
276
{
277
    if (written == NULL)
278 279
        return 0;

280
    *written = pkt->written;
281 282 283 284

    return 1;
}

M
Matt Caswell 已提交
285
int WPACKET_get_length(WPACKET *pkt, size_t *len)
286
{
287
    if (pkt->subs == NULL || len == NULL)
288 289
        return 0;

290
    *len = pkt->written - pkt->subs->pwritten;
291 292 293

    return 1;
}
294 295 296 297 298 299 300 301 302 303 304

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