Home | History | Annotate | Line # | Download | only in crypto
      1 /*
      2  * Copyright 2015-2023 The OpenSSL Project Authors. All Rights Reserved.
      3  *
      4  * Licensed under the Apache License 2.0 (the "License").  You may not use
      5  * this file except in compliance with the License.  You can obtain a copy
      6  * in the file LICENSE in the source distribution or at
      7  * https://www.openssl.org/source/license.html
      8  */
      9 
     10 #include "internal/cryptlib.h"
     11 #include "internal/packet.h"
     12 #if !defined OPENSSL_NO_QUIC && !defined FIPS_MODULE
     13 #include "internal/packet_quic.h"
     14 #endif
     15 #include <openssl/err.h>
     16 
     17 #define DEFAULT_BUF_SIZE 256
     18 
     19 int WPACKET_allocate_bytes(WPACKET *pkt, size_t len, unsigned char **allocbytes)
     20 {
     21     if (!WPACKET_reserve_bytes(pkt, len, allocbytes))
     22         return 0;
     23 
     24     pkt->written += len;
     25     pkt->curr += len;
     26     return 1;
     27 }
     28 
     29 int WPACKET_sub_allocate_bytes__(WPACKET *pkt, size_t len,
     30     unsigned char **allocbytes, size_t lenbytes)
     31 {
     32     if (!WPACKET_start_sub_packet_len__(pkt, lenbytes)
     33         || !WPACKET_allocate_bytes(pkt, len, allocbytes)
     34         || !WPACKET_close(pkt))
     35         return 0;
     36 
     37     return 1;
     38 }
     39 
     40 #define GETBUF(p) (((p)->staticbuf != NULL)         \
     41         ? (p)->staticbuf                            \
     42         : ((p)->buf != NULL                         \
     43                   ? (unsigned char *)(p)->buf->data \
     44                   : NULL))
     45 
     46 int WPACKET_reserve_bytes(WPACKET *pkt, size_t len, unsigned char **allocbytes)
     47 {
     48     /* Internal API, so should not fail */
     49     if (!ossl_assert(pkt->subs != NULL && len != 0))
     50         return 0;
     51 
     52     if (pkt->maxsize - pkt->written < len)
     53         return 0;
     54 
     55     if (pkt->buf != NULL && (pkt->buf->length - pkt->written < len)) {
     56         size_t newlen;
     57         size_t reflen;
     58 
     59         reflen = (len > pkt->buf->length) ? len : pkt->buf->length;
     60 
     61         if (reflen > SIZE_MAX / 2) {
     62             newlen = SIZE_MAX;
     63         } else {
     64             newlen = reflen * 2;
     65             if (newlen < DEFAULT_BUF_SIZE)
     66                 newlen = DEFAULT_BUF_SIZE;
     67         }
     68         if (BUF_MEM_grow(pkt->buf, newlen) == 0)
     69             return 0;
     70     }
     71     if (allocbytes != NULL) {
     72         *allocbytes = WPACKET_get_curr(pkt);
     73         if (pkt->endfirst && *allocbytes != NULL)
     74             *allocbytes -= len;
     75     }
     76 
     77     return 1;
     78 }
     79 
     80 int WPACKET_sub_reserve_bytes__(WPACKET *pkt, size_t len,
     81     unsigned char **allocbytes, size_t lenbytes)
     82 {
     83     if (pkt->endfirst && lenbytes > 0)
     84         return 0;
     85 
     86     if (!WPACKET_reserve_bytes(pkt, lenbytes + len, allocbytes))
     87         return 0;
     88 
     89     if (*allocbytes != NULL)
     90         *allocbytes += lenbytes;
     91 
     92     return 1;
     93 }
     94 
     95 static size_t maxmaxsize(size_t lenbytes)
     96 {
     97     if (lenbytes >= sizeof(size_t) || lenbytes == 0)
     98         return SIZE_MAX;
     99 
    100     return ((size_t)1 << (lenbytes * 8)) - 1 + lenbytes;
    101 }
    102 
    103 static int wpacket_intern_init_len(WPACKET *pkt, size_t lenbytes)
    104 {
    105     unsigned char *lenchars;
    106 
    107     pkt->curr = 0;
    108     pkt->written = 0;
    109 
    110     if ((pkt->subs = OPENSSL_zalloc(sizeof(*pkt->subs))) == NULL)
    111         return 0;
    112 
    113     if (lenbytes == 0)
    114         return 1;
    115 
    116     pkt->subs->pwritten = lenbytes;
    117     pkt->subs->lenbytes = lenbytes;
    118 
    119     if (!WPACKET_allocate_bytes(pkt, lenbytes, &lenchars)) {
    120         OPENSSL_free(pkt->subs);
    121         pkt->subs = NULL;
    122         return 0;
    123     }
    124     pkt->subs->packet_len = 0;
    125 
    126     return 1;
    127 }
    128 
    129 int WPACKET_init_static_len(WPACKET *pkt, unsigned char *buf, size_t len,
    130     size_t lenbytes)
    131 {
    132     size_t max = maxmaxsize(lenbytes);
    133 
    134     /* Internal API, so should not fail */
    135     if (!ossl_assert(buf != NULL && len > 0))
    136         return 0;
    137 
    138     pkt->staticbuf = buf;
    139     pkt->buf = NULL;
    140     pkt->maxsize = (max < len) ? max : len;
    141     pkt->endfirst = 0;
    142 
    143     return wpacket_intern_init_len(pkt, lenbytes);
    144 }
    145 
    146 int WPACKET_init_der(WPACKET *pkt, unsigned char *buf, size_t len)
    147 {
    148     /* Internal API, so should not fail */
    149     if (!ossl_assert(buf != NULL && len > 0))
    150         return 0;
    151 
    152     pkt->staticbuf = buf;
    153     pkt->buf = NULL;
    154     pkt->maxsize = len;
    155     pkt->endfirst = 1;
    156 
    157     return wpacket_intern_init_len(pkt, 0);
    158 }
    159 
    160 int WPACKET_init_len(WPACKET *pkt, BUF_MEM *buf, size_t lenbytes)
    161 {
    162     /* Internal API, so should not fail */
    163     if (!ossl_assert(buf != NULL))
    164         return 0;
    165 
    166     pkt->staticbuf = NULL;
    167     pkt->buf = buf;
    168     pkt->maxsize = maxmaxsize(lenbytes);
    169     pkt->endfirst = 0;
    170 
    171     return wpacket_intern_init_len(pkt, lenbytes);
    172 }
    173 
    174 int WPACKET_init(WPACKET *pkt, BUF_MEM *buf)
    175 {
    176     return WPACKET_init_len(pkt, buf, 0);
    177 }
    178 
    179 int WPACKET_init_null(WPACKET *pkt, size_t lenbytes)
    180 {
    181     pkt->staticbuf = NULL;
    182     pkt->buf = NULL;
    183     pkt->maxsize = maxmaxsize(lenbytes);
    184     pkt->endfirst = 0;
    185 
    186     return wpacket_intern_init_len(pkt, 0);
    187 }
    188 
    189 int WPACKET_init_null_der(WPACKET *pkt)
    190 {
    191     pkt->staticbuf = NULL;
    192     pkt->buf = NULL;
    193     pkt->maxsize = SIZE_MAX;
    194     pkt->endfirst = 1;
    195 
    196     return wpacket_intern_init_len(pkt, 0);
    197 }
    198 
    199 int WPACKET_set_flags(WPACKET *pkt, unsigned int flags)
    200 {
    201     /* Internal API, so should not fail */
    202     if (!ossl_assert(pkt->subs != NULL))
    203         return 0;
    204 
    205     pkt->subs->flags = flags;
    206 
    207     return 1;
    208 }
    209 
    210 /* Store the |value| of length |len| at location |data| */
    211 static int put_value(unsigned char *data, uint64_t value, size_t len)
    212 {
    213     if (data == NULL)
    214         return 1;
    215 
    216     for (data += len - 1; len > 0; len--) {
    217         *data = (unsigned char)(value & 0xff);
    218         data--;
    219         value >>= 8;
    220     }
    221 
    222     /* Check whether we could fit the value in the assigned number of bytes */
    223     if (value > 0)
    224         return 0;
    225 
    226     return 1;
    227 }
    228 
    229 #if !defined OPENSSL_NO_QUIC && !defined FIPS_MODULE
    230 static int put_quic_value(unsigned char *data, size_t value, size_t len)
    231 {
    232     if (data == NULL)
    233         return 1;
    234 
    235     /* Value too large for field. */
    236     if (ossl_quic_vlint_encode_len(value) > len)
    237         return 0;
    238 
    239     ossl_quic_vlint_encode_n(data, value, len);
    240     return 1;
    241 }
    242 #endif
    243 
    244 /*
    245  * Internal helper function used by WPACKET_close(), WPACKET_finish() and
    246  * WPACKET_fill_lengths() to close a sub-packet and write out its length if
    247  * necessary. If |doclose| is 0 then it goes through the motions of closing
    248  * (i.e. it fills in all the lengths), but doesn't actually close anything.
    249  */
    250 static int wpacket_intern_close(WPACKET *pkt, WPACKET_SUB *sub, int doclose)
    251 {
    252     size_t packlen = pkt->written - sub->pwritten;
    253 
    254     if (packlen == 0
    255         && (sub->flags & WPACKET_FLAGS_NON_ZERO_LENGTH) != 0)
    256         return 0;
    257 
    258     if (packlen == 0
    259         && sub->flags & WPACKET_FLAGS_ABANDON_ON_ZERO_LENGTH) {
    260         /* We can't handle this case. Return an error */
    261         if (!doclose)
    262             return 0;
    263 
    264         /* Deallocate any bytes allocated for the length of the WPACKET */
    265         if ((pkt->curr - sub->lenbytes) == sub->packet_len) {
    266             pkt->written -= sub->lenbytes;
    267             pkt->curr -= sub->lenbytes;
    268         }
    269 
    270         /* Don't write out the packet length */
    271         sub->packet_len = 0;
    272         sub->lenbytes = 0;
    273     }
    274 
    275     /* Write out the WPACKET length if needed */
    276     if (sub->lenbytes > 0) {
    277         unsigned char *buf = GETBUF(pkt);
    278 
    279         if (buf != NULL) {
    280 #if !defined OPENSSL_NO_QUIC && !defined FIPS_MODULE
    281             if ((sub->flags & WPACKET_FLAGS_QUIC_VLINT) == 0) {
    282                 if (!put_value(&buf[sub->packet_len], packlen, sub->lenbytes))
    283                     return 0;
    284             } else {
    285                 if (!put_quic_value(&buf[sub->packet_len], packlen, sub->lenbytes))
    286                     return 0;
    287             }
    288 #else
    289             if (!put_value(&buf[sub->packet_len], packlen, sub->lenbytes))
    290                 return 0;
    291 #endif
    292         }
    293     } else if (pkt->endfirst && sub->parent != NULL
    294         && (packlen != 0
    295             || (sub->flags
    296                    & WPACKET_FLAGS_ABANDON_ON_ZERO_LENGTH)
    297                 == 0)) {
    298         size_t tmplen = packlen;
    299         size_t numlenbytes = 1;
    300 
    301         while ((tmplen = tmplen >> 8) > 0)
    302             numlenbytes++;
    303         if (!WPACKET_put_bytes__(pkt, packlen, numlenbytes))
    304             return 0;
    305         if (packlen > 0x7f) {
    306             numlenbytes |= 0x80;
    307             if (!WPACKET_put_bytes_u8(pkt, numlenbytes))
    308                 return 0;
    309         }
    310     }
    311 
    312     if (doclose) {
    313         pkt->subs = sub->parent;
    314         OPENSSL_free(sub);
    315     }
    316 
    317     return 1;
    318 }
    319 
    320 int WPACKET_fill_lengths(WPACKET *pkt)
    321 {
    322     WPACKET_SUB *sub;
    323 
    324     if (!ossl_assert(pkt->subs != NULL))
    325         return 0;
    326 
    327     for (sub = pkt->subs; sub != NULL; sub = sub->parent) {
    328         if (!wpacket_intern_close(pkt, sub, 0))
    329             return 0;
    330     }
    331 
    332     return 1;
    333 }
    334 
    335 int WPACKET_close(WPACKET *pkt)
    336 {
    337     /*
    338      * Internal API, so should not fail - but we do negative testing of this
    339      * so no assert (otherwise the tests fail)
    340      */
    341     if (pkt->subs == NULL || pkt->subs->parent == NULL)
    342         return 0;
    343 
    344     return wpacket_intern_close(pkt, pkt->subs, 1);
    345 }
    346 
    347 int WPACKET_finish(WPACKET *pkt)
    348 {
    349     int ret;
    350 
    351     /*
    352      * Internal API, so should not fail - but we do negative testing of this
    353      * so no assert (otherwise the tests fail)
    354      */
    355     if (pkt->subs == NULL || pkt->subs->parent != NULL)
    356         return 0;
    357 
    358     ret = wpacket_intern_close(pkt, pkt->subs, 1);
    359     if (ret) {
    360         OPENSSL_free(pkt->subs);
    361         pkt->subs = NULL;
    362     }
    363 
    364     return ret;
    365 }
    366 
    367 int WPACKET_start_sub_packet_len__(WPACKET *pkt, size_t lenbytes)
    368 {
    369     WPACKET_SUB *sub;
    370     unsigned char *lenchars;
    371 
    372     /* Internal API, so should not fail */
    373     if (!ossl_assert(pkt->subs != NULL))
    374         return 0;
    375 
    376     /* We don't support lenbytes greater than 0 when doing endfirst writing */
    377     if (lenbytes > 0 && pkt->endfirst)
    378         return 0;
    379 
    380     if ((sub = OPENSSL_zalloc(sizeof(*sub))) == NULL)
    381         return 0;
    382 
    383     sub->parent = pkt->subs;
    384     pkt->subs = sub;
    385     sub->pwritten = pkt->written + lenbytes;
    386     sub->lenbytes = lenbytes;
    387 
    388     if (lenbytes == 0) {
    389         sub->packet_len = 0;
    390         return 1;
    391     }
    392 
    393     sub->packet_len = pkt->written;
    394 
    395     if (!WPACKET_allocate_bytes(pkt, lenbytes, &lenchars))
    396         return 0;
    397 
    398     return 1;
    399 }
    400 
    401 int WPACKET_start_sub_packet(WPACKET *pkt)
    402 {
    403     return WPACKET_start_sub_packet_len__(pkt, 0);
    404 }
    405 
    406 int WPACKET_put_bytes__(WPACKET *pkt, uint64_t val, size_t size)
    407 {
    408     unsigned char *data;
    409 
    410     /* Internal API, so should not fail */
    411     if (!ossl_assert(size <= sizeof(uint64_t))
    412         || !WPACKET_allocate_bytes(pkt, size, &data)
    413         || !put_value(data, val, size))
    414         return 0;
    415 
    416     return 1;
    417 }
    418 
    419 int WPACKET_set_max_size(WPACKET *pkt, size_t maxsize)
    420 {
    421     WPACKET_SUB *sub;
    422     size_t lenbytes;
    423 
    424     /* Internal API, so should not fail */
    425     if (!ossl_assert(pkt->subs != NULL))
    426         return 0;
    427 
    428     /* Find the WPACKET_SUB for the top level */
    429     for (sub = pkt->subs; sub->parent != NULL; sub = sub->parent)
    430         continue;
    431 
    432     lenbytes = sub->lenbytes;
    433     if (lenbytes == 0)
    434         lenbytes = sizeof(pkt->maxsize);
    435 
    436     if (maxmaxsize(lenbytes) < maxsize || maxsize < pkt->written)
    437         return 0;
    438 
    439     pkt->maxsize = maxsize;
    440 
    441     return 1;
    442 }
    443 
    444 int WPACKET_memset(WPACKET *pkt, int ch, size_t len)
    445 {
    446     unsigned char *dest;
    447 
    448     if (len == 0)
    449         return 1;
    450 
    451     if (!WPACKET_allocate_bytes(pkt, len, &dest))
    452         return 0;
    453 
    454     if (dest != NULL)
    455         memset(dest, ch, len);
    456 
    457     return 1;
    458 }
    459 
    460 int WPACKET_memcpy(WPACKET *pkt, const void *src, size_t len)
    461 {
    462     unsigned char *dest;
    463 
    464     if (len == 0)
    465         return 1;
    466 
    467     if (!WPACKET_allocate_bytes(pkt, len, &dest))
    468         return 0;
    469 
    470     if (dest != NULL)
    471         memcpy(dest, src, len);
    472 
    473     return 1;
    474 }
    475 
    476 int WPACKET_sub_memcpy__(WPACKET *pkt, const void *src, size_t len,
    477     size_t lenbytes)
    478 {
    479     if (!WPACKET_start_sub_packet_len__(pkt, lenbytes)
    480         || !WPACKET_memcpy(pkt, src, len)
    481         || !WPACKET_close(pkt))
    482         return 0;
    483 
    484     return 1;
    485 }
    486 
    487 int WPACKET_get_total_written(WPACKET *pkt, size_t *written)
    488 {
    489     /* Internal API, so should not fail */
    490     if (!ossl_assert(written != NULL))
    491         return 0;
    492 
    493     *written = pkt->written;
    494 
    495     return 1;
    496 }
    497 
    498 int WPACKET_get_length(WPACKET *pkt, size_t *len)
    499 {
    500     /* Internal API, so should not fail */
    501     if (!ossl_assert(pkt->subs != NULL && len != NULL))
    502         return 0;
    503 
    504     *len = pkt->written - pkt->subs->pwritten;
    505 
    506     return 1;
    507 }
    508 
    509 unsigned char *WPACKET_get_curr(WPACKET *pkt)
    510 {
    511     unsigned char *buf = GETBUF(pkt);
    512 
    513     if (buf == NULL)
    514         return NULL;
    515 
    516     if (pkt->endfirst)
    517         return buf + pkt->maxsize - pkt->curr;
    518 
    519     return buf + pkt->curr;
    520 }
    521 
    522 int WPACKET_is_null_buf(WPACKET *pkt)
    523 {
    524     return pkt->buf == NULL && pkt->staticbuf == NULL;
    525 }
    526 
    527 void WPACKET_cleanup(WPACKET *pkt)
    528 {
    529     WPACKET_SUB *sub, *parent;
    530 
    531     for (sub = pkt->subs; sub != NULL; sub = parent) {
    532         parent = sub->parent;
    533         OPENSSL_free(sub);
    534     }
    535     pkt->subs = NULL;
    536 }
    537 
    538 #if !defined OPENSSL_NO_QUIC && !defined FIPS_MODULE
    539 
    540 int WPACKET_start_quic_sub_packet_bound(WPACKET *pkt, size_t max_len)
    541 {
    542     size_t enclen = ossl_quic_vlint_encode_len(max_len);
    543 
    544     if (enclen == 0)
    545         return 0;
    546 
    547     if (WPACKET_start_sub_packet_len__(pkt, enclen) == 0)
    548         return 0;
    549 
    550     pkt->subs->flags |= WPACKET_FLAGS_QUIC_VLINT;
    551     return 1;
    552 }
    553 
    554 int WPACKET_start_quic_sub_packet(WPACKET *pkt)
    555 {
    556     /*
    557      * Assume no (sub)packet will exceed 4GiB, thus the 8-byte encoding need not
    558      * be used.
    559      */
    560     return WPACKET_start_quic_sub_packet_bound(pkt, OSSL_QUIC_VLINT_4B_MIN);
    561 }
    562 
    563 int WPACKET_quic_sub_allocate_bytes(WPACKET *pkt, size_t len, unsigned char **allocbytes)
    564 {
    565     if (!WPACKET_start_quic_sub_packet_bound(pkt, len)
    566         || !WPACKET_allocate_bytes(pkt, len, allocbytes)
    567         || !WPACKET_close(pkt))
    568         return 0;
    569 
    570     return 1;
    571 }
    572 
    573 /*
    574  * Write a QUIC variable-length integer to the packet.
    575  */
    576 int WPACKET_quic_write_vlint(WPACKET *pkt, uint64_t v)
    577 {
    578     unsigned char *b = NULL;
    579     size_t enclen = ossl_quic_vlint_encode_len(v);
    580 
    581     if (enclen == 0)
    582         return 0;
    583 
    584     if (WPACKET_allocate_bytes(pkt, enclen, &b) == 0)
    585         return 0;
    586 
    587     ossl_quic_vlint_encode(b, v);
    588     return 1;
    589 }
    590 
    591 #endif
    592