cryptlib.c params.c params_from_text.c bsearch.c ex_data.c o_str.c \
threads_pthread.c threads_win.c threads_none.c initthread.c \
context.c sparse_array.c asn1_dsa.c packet.c param_build.c \
- param_build_set.c der_writer.c threads_lib.c params_dup.c
+ param_build_set.c der_writer.c threads_lib.c params_dup.c \
+ quic_vlint.c
SOURCE[../libcrypto]=$UTIL_COMMON \
mem.c mem_sec.c \
return 1;
}
+static int put_quic_value(unsigned char *data, size_t value, size_t len)
+{
+ if (data == NULL)
+ return 1;
+
+ /* Value too large for field. */
+ if (ossl_quic_vlint_encode_len(value) > len)
+ return 0;
+
+ ossl_quic_vlint_encode_n(data, value, len);
+ return 1;
+}
/*
* Internal helper function used by WPACKET_close(), WPACKET_finish() and
if (sub->lenbytes > 0) {
unsigned char *buf = GETBUF(pkt);
- if (buf != NULL
- && !put_value(&buf[sub->packet_len], packlen,
- sub->lenbytes))
- return 0;
+ if (buf != NULL) {
+ if ((sub->flags & WPACKET_FLAGS_QUIC_VLINT) == 0) {
+ if (!put_value(&buf[sub->packet_len], packlen, sub->lenbytes))
+ return 0;
+ } else {
+ if (!put_quic_value(&buf[sub->packet_len], packlen, sub->lenbytes))
+ return 0;
+ }
+ }
} else if (pkt->endfirst && sub->parent != NULL
&& (packlen != 0
|| (sub->flags
}
pkt->subs = NULL;
}
+
+int WPACKET_start_quic_sub_packet_bound(WPACKET *pkt, size_t max_len)
+{
+ size_t enclen = ossl_quic_vlint_encode_len(max_len);
+
+ if (enclen == 0)
+ return 0;
+
+ if (WPACKET_start_sub_packet_len__(pkt, enclen) == 0)
+ return 0;
+
+ pkt->subs->flags |= WPACKET_FLAGS_QUIC_VLINT;
+ return 1;
+}
+
+int WPACKET_start_quic_sub_packet(WPACKET *pkt)
+{
+ /*
+ * Assume no (sub)packet will exceed 4GiB, thus the 8-byte encoding need not
+ * be used.
+ */
+ return WPACKET_start_quic_sub_packet_bound(pkt, OSSL_QUIC_VLINT_4B_MIN);
+}
+
+int WPACKET_quic_sub_allocate_bytes(WPACKET *pkt, size_t len, unsigned char **allocbytes)
+{
+ if (!WPACKET_start_quic_sub_packet_bound(pkt, len)
+ || !WPACKET_allocate_bytes(pkt, len, allocbytes)
+ || !WPACKET_close(pkt))
+ return 0;
+
+ return 1;
+}
+
+/*
+ * Write a QUIC variable-length integer to the packet.
+ */
+int WPACKET_quic_write_vlint(WPACKET *pkt, uint64_t v)
+{
+ unsigned char *b = NULL;
+ size_t enclen = ossl_quic_vlint_encode_len(v);
+
+ if (enclen == 0)
+ return 0;
+
+ if (WPACKET_allocate_bytes(pkt, enclen, &b) == 0)
+ return 0;
+
+ ossl_quic_vlint_encode(b, v);
+ return 1;
+}
--- /dev/null
+#include "internal/quic_vlint.h"
+#include "internal/e_os.h"
+
+void ossl_quic_vlint_encode_n(uint8_t *buf, uint64_t v, int n)
+{
+ if (n == 1) {
+ buf[0] = (uint8_t)v;
+ } else if (n == 2) {
+ buf[0] = (uint8_t)(0x40 | ((v >> 8) & 0x3F));
+ buf[1] = (uint8_t)v;
+ } else if (n == 4) {
+ buf[0] = (uint8_t)(0x80 | ((v >> 24) & 0x3F));
+ buf[1] = (uint8_t)(v >> 16);
+ buf[2] = (uint8_t)(v >> 8);
+ buf[3] = (uint8_t)v;
+ } else {
+ buf[0] = (uint8_t)(0xC0 | ((v >> 56) & 0x3F));
+ buf[1] = (uint8_t)(v >> 48);
+ buf[2] = (uint8_t)(v >> 40);
+ buf[3] = (uint8_t)(v >> 32);
+ buf[4] = (uint8_t)(v >> 24);
+ buf[5] = (uint8_t)(v >> 16);
+ buf[6] = (uint8_t)(v >> 8);
+ buf[7] = (uint8_t)v;
+ }
+}
+
+void ossl_quic_vlint_encode(uint8_t *buf, uint64_t v)
+{
+ ossl_quic_vlint_encode_n(buf, v, ossl_quic_vlint_encode_len(v));
+}
+
+uint64_t ossl_quic_vlint_decode_unchecked(const unsigned char *buf)
+{
+ uint8_t first_byte = buf[0];
+ size_t sz = ossl_quic_vlint_decode_len(first_byte);
+
+ if (sz == 1)
+ return first_byte & 0x3F;
+
+ if (sz == 2)
+ return ((uint64_t)(first_byte & 0x3F) << 8)
+ | buf[1];
+
+ if (sz == 4)
+ return ((uint64_t)(first_byte & 0x3F) << 24)
+ | ((uint64_t)buf[1] << 16)
+ | ((uint64_t)buf[2] << 8)
+ | buf[3];
+
+ return ((uint64_t)(first_byte & 0x3F) << 56)
+ | ((uint64_t)buf[1] << 48)
+ | ((uint64_t)buf[2] << 40)
+ | ((uint64_t)buf[3] << 32)
+ | ((uint64_t)buf[4] << 24)
+ | ((uint64_t)buf[5] << 16)
+ | ((uint64_t)buf[6] << 8)
+ | buf[7];
+}
+
+int ossl_quic_vlint_decode(const unsigned char *buf, size_t buf_len, uint64_t *v)
+{
+ size_t dec_len;
+ uint64_t x;
+
+ if (buf_len < 1)
+ return 0;
+
+ dec_len = ossl_quic_vlint_decode_len(buf[0]);
+ if (buf_len < dec_len)
+ return 0;
+
+ x = ossl_quic_vlint_decode_unchecked(buf);
+
+ *v = x;
+ return dec_len;
+}
# include <openssl/e_os2.h>
# include "internal/numbers.h"
+# include "internal/quic_vlint.h"
typedef struct {
/* Pointer to where we are currently reading from */
return 1;
}
+/*
+ * Decodes a QUIC variable-length integer in |pkt| and stores the result in
+ * |data|.
+ */
+__owur static ossl_inline int PACKET_get_quic_vlint(PACKET *pkt,
+ uint64_t *data)
+{
+ size_t enclen;
+
+ if (PACKET_remaining(pkt) < 1)
+ return 0;
+
+ enclen = ossl_quic_vlint_decode_len(*pkt->curr);
+
+ if (PACKET_remaining(pkt) < enclen)
+ return 0;
+
+ *data = ossl_quic_vlint_decode_unchecked(pkt->curr);
+ packet_forward(pkt, enclen);
+ return 1;
+}
+
/* Equivalent of n2l */
/* Get 4 bytes in network order from |pkt| and store the value in |*data| */
__owur static ossl_inline int PACKET_get_net_4(PACKET *pkt, unsigned long *data)
return 1;
}
+/*
+ * Reads a variable-length vector prefixed with a QUIC variable-length integer
+ * denoting the length, and stores the contents in |subpkt|. |pkt| can equal
+ * |subpkt|. Data is not copied: the |subpkt| packet will share its underlying
+ * buffer with the original |pkt|, so data wrapped by |pkt| must outlive the
+ * |subpkt|. Upon failure, the original |pkt| and |subpkt| are not modified.
+ */
+__owur static ossl_inline int PACKET_get_quic_length_prefixed(PACKET *pkt,
+ PACKET *subpkt)
+{
+ uint64_t length;
+ const unsigned char *data;
+ PACKET tmp = *pkt;
+
+ if (!PACKET_get_quic_vlint(&tmp, &length) ||
+ length > SIZE_MAX ||
+ !PACKET_get_bytes(&tmp, &data, (size_t)length)) {
+ return 0;
+ }
+
+ *pkt = tmp;
+ subpkt->curr = data;
+ subpkt->remaining = (size_t)length;
+
+ return 1;
+}
+
/* Writeable packets */
typedef struct wpacket_sub WPACKET_SUB;
*/
#define WPACKET_FLAGS_ABANDON_ON_ZERO_LENGTH 2
+/* QUIC variable-length integer length prefix */
+#define WPACKET_FLAGS_QUIC_VLINT 4
/*
* Initialise a WPACKET with the buffer in |buf|. The buffer must exist
/* Release resources in a WPACKET if a failure has occurred. */
void WPACKET_cleanup(WPACKET *pkt);
+/*
+ * Starts a QUIC sub-packet headed by a QUIC variable-length integer. A 4-byte
+ * representation is used.
+ */
+__owur int WPACKET_start_quic_sub_packet(WPACKET *pkt);
+
+/*
+ * Starts a QUIC sub-packet headed by a QUIC variable-length integer. max_len
+ * specifies the upper bound for the sub-packet size at the time the sub-packet
+ * is closed, which determines the encoding size for tthe variable-length
+ * integer header. max_len can be a precise figure or a worst-case bound
+ * if a precise figure is not available.
+ */
+__owur int WPACKET_start_quic_sub_packet_bound(WPACKET *pkt, size_t max_len);
+
+/*
+ * Allocates a QUIC sub-packet with exactly len bytes of payload, headed by a
+ * QUIC variable-length integer. The pointer to the payload buffer is output and
+ * must be filled by the caller. This function assures optimal selection of
+ * variable-length integer encoding length.
+ */
+__owur int WPACKET_quic_sub_allocate_bytes(WPACKET *pkt, size_t len,
+ unsigned char **bytes);
+
+/*
+ * Write a QUIC variable-length integer to the packet.
+ */
+__owur int WPACKET_quic_write_vlint(WPACKET *pkt, uint64_t v);
+
#endif /* OSSL_INTERNAL_PACKET_H */
--- /dev/null
+/*
+* Copyright 2022 The OpenSSL Project Authors. All Rights Reserved.
+*
+* Licensed under the Apache License 2.0 (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
+*/
+
+#ifndef OSSL_INTERNAL_QUIC_VLINT_H
+# define OSSL_INTERNAL_QUIC_VLINT_H
+# pragma once
+
+#include "internal/e_os.h"
+
+/* The smallest value requiring a 1, 2, 4, or 8-byte representation. */
+#define OSSL_QUIC_VLINT_1B_MIN 0
+#define OSSL_QUIC_VLINT_2B_MIN 64
+#define OSSL_QUIC_VLINT_4B_MIN 16384
+#define OSSL_QUIC_VLINT_8B_MIN 1073741824
+
+/* The largest value representable in a given number of bytes. */
+#define OSSL_QUIC_VLINT_1B_MAX (OSSL_QUIC_VLINT_2B_MIN - 1)
+#define OSSL_QUIC_VLINT_2B_MAX (OSSL_QUIC_VLINT_4B_MIN - 1)
+#define OSSL_QUIC_VLINT_4B_MAX (OSSL_QUIC_VLINT_8B_MIN - 1)
+#define OSSL_QUIC_VLINT_8B_MAX (((uint64_t)1 << 62) - 1)
+
+/* The largest value representable as a variable-length integer. */
+#define OSSL_QUIC_VLINT_MAX OSSL_QUIC_VLINT_8B_MAX
+
+/*
+ * Returns the number of bytes needed to encode v in the QUIC variable-length
+ * integer encoding.
+ *
+ * Returns 0 if v exceeds OSSL_QUIC_VLINT_MAX.
+ */
+static ossl_unused ossl_inline size_t ossl_quic_vlint_encode_len(uint64_t v)
+{
+ if (v < OSSL_QUIC_VLINT_2B_MIN)
+ return 1;
+
+ if (v < OSSL_QUIC_VLINT_4B_MIN)
+ return 2;
+
+ if (v < OSSL_QUIC_VLINT_8B_MIN)
+ return 4;
+
+ if (v <= OSSL_QUIC_VLINT_MAX)
+ return 8;
+
+ return 0;
+}
+
+/*
+ * This function writes a QUIC varable-length encoded integer to buf.
+ * The smallest usable representation is used.
+ *
+ * It is the caller's responsibility to ensure that the buffer is big enough by
+ * calling ossl_quic_vlint_encode_len(v) before calling this function.
+ *
+ * Precondition: buf is at least ossl_quic_vlint_enc_len(v) bytes in size
+ * (unchecked)
+ * Precondition: v does not exceed OSSL_QUIC_VLINT_MAX
+ * (unchecked)
+ */
+void ossl_quic_vlint_encode(unsigned char *buf, uint64_t v);
+
+/*
+ * This function writes a QUIC variable-length encoded integer to buf. The
+ * specified number of bytes n are used for the encoding, which means that the
+ * encoded value may take up more space than necessary.
+ *
+ * It is the caller's responsibility to ensure that the buffer is of at least n
+ * bytes, and that v is representable by a n-byte QUIC variable-length integer.
+ * The representable ranges are:
+ *
+ * 1-byte encoding: [0, 2** 6-1]
+ * 2-byte encoding: [0, 2**14-1]
+ * 4-byte encoding: [0, 2**30-1]
+ * 8-byte encoding: [0, 2**62-1]
+ *
+ * Precondition: buf is at least n bytes in size (unchecked)
+ * Precondition: v does not exceed the representable range
+ * (ossl_quic_vlint_encode_len(v) <= n) (unchecked)
+ * Precondition: v does not exceed OSSL_QUIC_VLINT_MAX
+ * (unchecked)
+ */
+void ossl_quic_vlint_encode_n(unsigned char *buf, uint64_t v, int n);
+
+/*
+ * Given the first byte of an encoded QUIC variable-length integer, returns
+ * the number of bytes comprising the encoded integer, including the first
+ * byte.
+ */
+static ossl_unused ossl_inline size_t ossl_quic_vlint_decode_len(uint8_t first_byte)
+{
+ return 1U << ((first_byte & 0xC0) >> 6);
+}
+
+/*
+ * Given a buffer containing an encoded QUIC variable-length integer, returns
+ * the decoded value. The buffer must be of at least
+ * ossl_quic_vlint_decode_len(buf[0]) bytes in size, and the caller is responsible
+ * for checking this.
+ *
+ * Precondition: buf is at least ossl_quic_vlint_decode_len(buf[0]) bytes in size
+ * (unchecked)
+ */
+uint64_t ossl_quic_vlint_decode_unchecked(const unsigned char *buf);
+
+/*
+ * Given a buffer buf of buf_len bytes in length, attempts to decode an encoded
+ * QUIC variable-length integer at the start of the buffer and writes the result
+ * to *v. If buf_len is inadequate, suggesting a truncated encoded integer, the
+ * function fails and 0 is returned. Otherwise, returns the number of bytes
+ * consumed.
+ *
+ * Precondition: buf is at least buf_len bytes in size
+ * Precondition: v (unchecked)
+ */
+int ossl_quic_vlint_decode(const unsigned char *buf, size_t buf_len, uint64_t *v);
+
+#endif
tls_depr.c $KTLSSRC
# For shared builds we need to include the libcrypto packet.c and sources
# needed in providers (s3_cbc.c and record/tls_pad.c) in libssl as well.
-SHARED_SOURCE[../libssl]=record/tls_pad.c ../crypto/packet.c
+SHARED_SOURCE[../libssl]=record/tls_pad.c ../crypto/packet.c ../crypto/quic_vlint.c
IF[{- !$disabled{'deprecated-3.0'} -}]
SHARED_SOURCE[../libssl]=s3_cbc.c
SOURCE[../libssl]=ssl_rsa_legacy.c
INCLUDE[bad_dtls_test]=../include ../apps/include
DEPEND[bad_dtls_test]=../libcrypto ../libssl libtestutil.a
- SOURCE[packettest]=packettest.c
+ SOURCE[packettest]=packettest.c ../crypto/quic_vlint.c
INCLUDE[packettest]=../include ../apps/include
DEPEND[packettest]=../libcrypto libtestutil.a
PROGRAMS{noinst}=tls13secretstest
SOURCE[tls13secretstest]=tls13secretstest.c
DEFINE[tls13secretstest]=OPENSSL_NO_KTLS
- SOURCE[tls13secretstest]= ../ssl/tls13_enc.c ../crypto/packet.c
+ SOURCE[tls13secretstest]= ../ssl/tls13_enc.c ../crypto/packet.c ../crypto/quic_vlint.c
INCLUDE[tls13secretstest]=.. ../include ../apps/include
DEPEND[tls13secretstest]=../libcrypto ../libssl libtestutil.a
ENDIF
return 1;
}
+static int test_PACKET_get_quic_vlint(void)
+{
+ struct quic_test_case {
+ unsigned char buf[16];
+ size_t expected_read_count;
+ uint64_t value;
+ };
+
+ static const struct quic_test_case cases[] = {
+ { {0x00}, 1, 0 },
+ { {0x01}, 1, 1 },
+ { {0x3e}, 1, 62 },
+ { {0x3f}, 1, 63 },
+ { {0x40,0x00}, 2, 0 },
+ { {0x40,0x01}, 2, 1 },
+ { {0x40,0x02}, 2, 2 },
+ { {0x40,0xff}, 2, 255 },
+ { {0x41,0x00}, 2, 256 },
+ { {0x7f,0xfe}, 2, 16382 },
+ { {0x7f,0xff}, 2, 16383 },
+ { {0x80,0x00,0x00,0x00}, 4, 0 },
+ { {0x80,0x00,0x00,0x01}, 4, 1 },
+ { {0x80,0x00,0x01,0x02}, 4, 258 },
+ { {0x80,0x18,0x49,0x65}, 4, 1591653 },
+ { {0xbe,0x18,0x49,0x65}, 4, 1041779045 },
+ { {0xbf,0xff,0xff,0xff}, 4, 1073741823 },
+ { {0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8, 0 },
+ { {0xc0,0x00,0x00,0x00,0x00,0x00,0x01,0x02}, 8, 258 },
+ { {0xfd,0x1f,0x59,0x8d,0xc9,0xf8,0x71,0x8a}, 8, 4404337426105397642 },
+ };
+
+ PACKET pkt;
+ size_t i;
+ uint64_t v;
+
+ for (i = 0; i < OSSL_NELEM(cases); ++i) {
+ memset(&pkt, 0, sizeof(pkt));
+ v = 55;
+
+ if (!TEST_true(PACKET_buf_init(&pkt, cases[i].buf, sizeof(cases[i].buf)))
+ || !TEST_true(PACKET_get_quic_vlint(&pkt, &v))
+ || !TEST_uint64_t_eq(v, cases[i].value)
+ || !TEST_size_t_eq(PACKET_remaining(&pkt),
+ sizeof(cases[i].buf) - cases[i].expected_read_count)
+ )
+ return 0;
+ }
+
+ return 1;
+}
+
+static int test_PACKET_get_quic_length_prefixed(void)
+{
+ struct quic_test_case {
+ unsigned char buf[16];
+ size_t enclen, len;
+ int fail;
+ };
+
+ static const struct quic_test_case cases[] = {
+ /* success cases */
+ { {0x00}, 1, 0, 0 },
+ { {0x01}, 1, 1, 0 },
+ { {0x02}, 1, 2, 0 },
+ { {0x03}, 1, 3, 0 },
+ { {0x04}, 1, 4, 0 },
+ { {0x05}, 1, 5, 0 },
+
+ /* failure cases */
+ { {0x10}, 1, 0, 1 },
+ { {0x3f}, 1, 0, 1 },
+ };
+
+ size_t i;
+ PACKET pkt, subpkt = {0};
+
+ for (i = 0; i < OSSL_NELEM(cases); ++i) {
+ memset(&pkt, 0, sizeof(pkt));
+
+ if (!TEST_true(PACKET_buf_init(&pkt, cases[i].buf,
+ cases[i].fail
+ ? sizeof(cases[i].buf)
+ : cases[i].enclen + cases[i].len)))
+ return 0;
+
+ if (!TEST_int_eq(PACKET_get_quic_length_prefixed(&pkt, &subpkt), !cases[i].fail))
+ return 0;
+
+ if (cases[i].fail) {
+ if (!TEST_ptr_eq(pkt.curr, cases[i].buf))
+ return 0;
+ continue;
+ }
+
+ if (!TEST_ptr_eq(subpkt.curr, cases[i].buf + cases[i].enclen))
+ return 0;
+
+ if (!TEST_size_t_eq(subpkt.remaining, cases[i].len))
+ return 0;
+ }
+
+ return 1;
+}
+
int setup_tests(void)
{
unsigned int i;
ADD_TEST(test_PACKET_get_length_prefixed_3);
ADD_TEST(test_PACKET_as_length_prefixed_1);
ADD_TEST(test_PACKET_as_length_prefixed_2);
+ ADD_TEST(test_PACKET_get_quic_vlint);
+ ADD_TEST(test_PACKET_get_quic_length_prefixed);
return 1;
}
DECLARE_COMPARISONS(unsigned char, uchar)
DECLARE_COMPARISONS(long, long)
DECLARE_COMPARISONS(unsigned long, ulong)
+DECLARE_COMPARISONS(int64_t, int64_t)
+DECLARE_COMPARISONS(uint64_t, uint64_t)
DECLARE_COMPARISONS(double, double)
DECLARE_COMPARISONS(time_t, time_t)
# define TEST_ulong_gt(a, b) test_ulong_gt(__FILE__, __LINE__, #a, #b, a, b)
# define TEST_ulong_ge(a, b) test_ulong_ge(__FILE__, __LINE__, #a, #b, a, b)
+# define TEST_uint64_t_eq(a, b) test_uint64_t_eq(__FILE__, __LINE__, #a, #b, a, b)
+# define TEST_uint64_t_ne(a, b) test_uint64_t_ne(__FILE__, __LINE__, #a, #b, a, b)
+# define TEST_uint64_t_lt(a, b) test_uint64_t_lt(__FILE__, __LINE__, #a, #b, a, b)
+# define TEST_uint64_t_le(a, b) test_uint64_t_le(__FILE__, __LINE__, #a, #b, a, b)
+# define TEST_uint64_t_gt(a, b) test_uint64_t_gt(__FILE__, __LINE__, #a, #b, a, b)
+# define TEST_uint64_t_ge(a, b) test_uint64_t_ge(__FILE__, __LINE__, #a, #b, a, b)
+
# define TEST_size_t_eq(a, b) test_size_t_eq(__FILE__, __LINE__, #a, #b, a, b)
# define TEST_size_t_ne(a, b) test_size_t_ne(__FILE__, __LINE__, #a, #b, a, b)
# define TEST_size_t_lt(a, b) test_size_t_lt(__FILE__, __LINE__, #a, #b, a, b)
* The desc argument is a printf format string followed by its arguments and
* this is included in the output if the condition being tested for is false.
*/
-#define DEFINE_COMPARISON(type, name, opname, op, fmt) \
+#define DEFINE_COMPARISON(type, name, opname, op, fmt, cast) \
int test_ ## name ## _ ## opname(const char *file, int line, \
const char *s1, const char *s2, \
const type t1, const type t2) \
return 1; \
test_fail_message(NULL, file, line, #type, s1, s2, #op, \
"[" fmt "] compared to [" fmt "]", \
- t1, t2); \
+ (cast)t1, (cast)t2); \
return 0; \
}
-#define DEFINE_COMPARISONS(type, name, fmt) \
- DEFINE_COMPARISON(type, name, eq, ==, fmt) \
- DEFINE_COMPARISON(type, name, ne, !=, fmt) \
- DEFINE_COMPARISON(type, name, lt, <, fmt) \
- DEFINE_COMPARISON(type, name, le, <=, fmt) \
- DEFINE_COMPARISON(type, name, gt, >, fmt) \
- DEFINE_COMPARISON(type, name, ge, >=, fmt)
-
-DEFINE_COMPARISONS(int, int, "%d")
-DEFINE_COMPARISONS(unsigned int, uint, "%u")
-DEFINE_COMPARISONS(char, char, "%c")
-DEFINE_COMPARISONS(unsigned char, uchar, "%u")
-DEFINE_COMPARISONS(long, long, "%ld")
-DEFINE_COMPARISONS(unsigned long, ulong, "%lu")
-DEFINE_COMPARISONS(size_t, size_t, "%zu")
-DEFINE_COMPARISONS(double, double, "%g")
-
-DEFINE_COMPARISON(void *, ptr, eq, ==, "%p")
-DEFINE_COMPARISON(void *, ptr, ne, !=, "%p")
+#define DEFINE_COMPARISONS(type, name, fmt, cast) \
+ DEFINE_COMPARISON(type, name, eq, ==, fmt, cast) \
+ DEFINE_COMPARISON(type, name, ne, !=, fmt, cast) \
+ DEFINE_COMPARISON(type, name, lt, <, fmt, cast) \
+ DEFINE_COMPARISON(type, name, le, <=, fmt, cast) \
+ DEFINE_COMPARISON(type, name, gt, >, fmt, cast) \
+ DEFINE_COMPARISON(type, name, ge, >=, fmt, cast)
+
+DEFINE_COMPARISONS(int, int, "%d", int)
+DEFINE_COMPARISONS(unsigned int, uint, "%u", unsigned int)
+DEFINE_COMPARISONS(char, char, "%c", char)
+DEFINE_COMPARISONS(unsigned char, uchar, "%u", unsigned char)
+DEFINE_COMPARISONS(long, long, "%ld", long)
+DEFINE_COMPARISONS(unsigned long, ulong, "%lu", unsigned long)
+DEFINE_COMPARISONS(int64_t, int64_t, "%lld", long long)
+DEFINE_COMPARISONS(uint64_t, uint64_t, "%llu", unsigned long long)
+DEFINE_COMPARISONS(size_t, size_t, "%zu", size_t)
+DEFINE_COMPARISONS(double, double, "%g", double)
+
+DEFINE_COMPARISON(void *, ptr, eq, ==, "%p", void *)
+DEFINE_COMPARISON(void *, ptr, ne, !=, "%p", void *)
int test_ptr_null(const char *file, int line, const char *s, const void *p)
{
0xfc, 0x04, 0x00, 0x01, 0x02, 0x03, 0xff, 0xfe, 0xfd
};
+/* QUIC sub-packet with 4-byte length prefix, containing a 1-byte vlint */
+static const unsigned char quic1[] = { 0x80, 0x00, 0x00, 0x01, 0x09 };
+/* QUIC sub-packet with 1-byte length prefix, containing a 1-byte vlint */
+static const unsigned char quic2[] = { 0x01, 0x09 };
+/* QUIC sub-packet with 2-byte length prefix, containing a 2-byte vlint */
+static const unsigned char quic3[] = { 0x40, 0x02, 0x40, 0x41 };
+/* QUIC sub-packet with 8-byte length prefix, containing a 4-byte vlint */
+static const unsigned char quic4[] = {
+ 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
+ 0x80, 0x01, 0x3c, 0x6a
+};
+/* QUIC sub-packet with 8-byte length prefix, containing a 8-byte vlint */
+static const unsigned char quic5[] = {
+ 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
+ 0xef, 0x77, 0x21, 0x3f, 0x3f, 0x50, 0x5b, 0xa5
+};
+/* QUIC sub-packet, length known up-front */
+static const unsigned char quic6[] = { 0x03, 0x55, 0x66, 0x77 };
+/* Nested and sequential sub-packets with length prefixes */
+static const unsigned char quic7[] = {
+ 0x07, 0x80, 0x00, 0x00, 0x08, 0x65, 0x14, 0x40, 0x01, 0x05,
+ 0x40, 0x01, 0x11, 0x40, 0x01, 0x12, 0x40, 0x01, 0x13
+};
+
static BUF_MEM *buf;
static int cleanup(WPACKET *pkt)
return 1;
}
+static int test_WPACKET_quic(void)
+{
+ WPACKET pkt;
+ size_t written, len;
+ unsigned char *bytes;
+
+ /* QUIC sub-packet with 4-byte length prefix, containing a 1-byte vlint */
+ if (!TEST_true(WPACKET_init(&pkt, buf))
+ || !TEST_true(WPACKET_start_quic_sub_packet(&pkt))
+ || !TEST_true(WPACKET_quic_write_vlint(&pkt, 0x09))
+ /* Can't finish because we have a sub packet */
+ || !TEST_false(WPACKET_finish(&pkt))
+ || !TEST_true(WPACKET_close(&pkt))
+ /* Sub packet is closed so can't close again */
+ || !TEST_false(WPACKET_close(&pkt))
+ /* Now a top level so finish should succeed */
+ || !TEST_true(WPACKET_finish(&pkt))
+ || !TEST_true(WPACKET_get_total_written(&pkt, &written))
+ || !TEST_mem_eq(buf->data, written, quic1, sizeof(quic1)))
+ return cleanup(&pkt);
+
+ /* QUIC sub-packet with 1-byte length prefix, containing a 1-byte vlint */
+ if (!TEST_true(WPACKET_init(&pkt, buf))
+ || !TEST_true(WPACKET_start_quic_sub_packet_bound(&pkt, OSSL_QUIC_VLINT_1B_MAX))
+ || !TEST_true(WPACKET_quic_write_vlint(&pkt, 0x09))
+ || !TEST_false(WPACKET_finish(&pkt))
+ || !TEST_true(WPACKET_close(&pkt))
+ || !TEST_false(WPACKET_close(&pkt))
+ || !TEST_true(WPACKET_finish(&pkt))
+ || !TEST_true(WPACKET_get_total_written(&pkt, &written))
+ || !TEST_mem_eq(buf->data, written, quic2, sizeof(quic2)))
+ return cleanup(&pkt);
+
+ /* QUIC sub-packet with 2-byte length prefix, containing a 2-byte vlint */
+ if (!TEST_true(WPACKET_init(&pkt, buf))
+ || !TEST_true(WPACKET_start_quic_sub_packet_bound(&pkt, OSSL_QUIC_VLINT_2B_MIN))
+ || !TEST_true(WPACKET_quic_write_vlint(&pkt, 0x41))
+ || !TEST_false(WPACKET_finish(&pkt))
+ || !TEST_true(WPACKET_close(&pkt))
+ || !TEST_false(WPACKET_close(&pkt))
+ || !TEST_true(WPACKET_finish(&pkt))
+ || !TEST_true(WPACKET_get_total_written(&pkt, &written))
+ || !TEST_mem_eq(buf->data, written, quic3, sizeof(quic3)))
+ return cleanup(&pkt);
+
+ /* QUIC sub-packet with 8-byte length prefix, containing a 4-byte vlint */
+ if (!TEST_true(WPACKET_init(&pkt, buf))
+ || !TEST_true(WPACKET_start_quic_sub_packet_bound(&pkt, OSSL_QUIC_VLINT_8B_MIN))
+ || !TEST_true(WPACKET_quic_write_vlint(&pkt, 0x13c6a))
+ || !TEST_false(WPACKET_finish(&pkt))
+ || !TEST_true(WPACKET_close(&pkt))
+ || !TEST_false(WPACKET_close(&pkt))
+ || !TEST_true(WPACKET_finish(&pkt))
+ || !TEST_true(WPACKET_get_total_written(&pkt, &written))
+ || !TEST_mem_eq(buf->data, written, quic4, sizeof(quic4)))
+ return cleanup(&pkt);
+
+ /* QUIC sub-packet with 8-byte length prefix, containing a 8-byte vlint */
+ if (!TEST_true(WPACKET_init(&pkt, buf))
+ || !TEST_true(WPACKET_start_quic_sub_packet_bound(&pkt, OSSL_QUIC_VLINT_8B_MIN))
+ || !TEST_true(WPACKET_quic_write_vlint(&pkt, 0x2f77213f3f505ba5ULL))
+ || !TEST_false(WPACKET_finish(&pkt))
+ || !TEST_true(WPACKET_close(&pkt))
+ || !TEST_false(WPACKET_close(&pkt))
+ || !TEST_true(WPACKET_finish(&pkt))
+ || !TEST_true(WPACKET_get_total_written(&pkt, &written))
+ || !TEST_mem_eq(buf->data, written, quic5, sizeof(quic5)))
+ return cleanup(&pkt);
+
+ /* QUIC sub-packet, length known up-front */
+ if (!TEST_true(WPACKET_init(&pkt, buf))
+ || !TEST_true(WPACKET_quic_sub_allocate_bytes(&pkt, 3, &bytes)))
+ return cleanup(&pkt);
+
+ bytes[0] = 0x55;
+ bytes[1] = 0x66;
+ bytes[2] = 0x77;
+
+ if (!TEST_true(WPACKET_finish(&pkt))
+ || !TEST_true(WPACKET_get_total_written(&pkt, &written))
+ || !TEST_mem_eq(buf->data, written, quic6, sizeof(quic6)))
+ return cleanup(&pkt);
+
+ /* Nested and sequential sub-packets with length prefixes */
+ if (!TEST_true(WPACKET_init(&pkt, buf))
+ || !TEST_true(WPACKET_quic_write_vlint(&pkt, 0x07))
+ || !TEST_true(WPACKET_get_length(&pkt, &len))
+ || !TEST_size_t_eq(len, 1)
+ || !TEST_true(WPACKET_start_quic_sub_packet_bound(&pkt, OSSL_QUIC_VLINT_4B_MIN))
+ || !TEST_true(WPACKET_quic_write_vlint(&pkt, 0x2514))
+ || !TEST_true(WPACKET_get_length(&pkt, &len))
+ || !TEST_size_t_eq(len, 2)
+ || !TEST_true(WPACKET_start_quic_sub_packet_bound(&pkt, OSSL_QUIC_VLINT_2B_MIN))
+ || !TEST_true(WPACKET_quic_write_vlint(&pkt, 0x05))
+ || !TEST_true(WPACKET_get_length(&pkt, &len))
+ || !TEST_size_t_eq(len, 1)
+ || !TEST_true(WPACKET_close(&pkt))
+ || !TEST_true(WPACKET_start_quic_sub_packet_bound(&pkt, OSSL_QUIC_VLINT_2B_MIN))
+ || !TEST_true(WPACKET_quic_write_vlint(&pkt, 0x11))
+ || !TEST_true(WPACKET_close(&pkt))
+ || !TEST_true(WPACKET_get_length(&pkt, &len))
+ || !TEST_size_t_eq(len, 8)
+ || !TEST_true(WPACKET_close(&pkt))
+ || !TEST_true(WPACKET_start_quic_sub_packet_bound(&pkt, OSSL_QUIC_VLINT_2B_MIN))
+ || !TEST_true(WPACKET_quic_write_vlint(&pkt, 0x12))
+ || !TEST_true(WPACKET_close(&pkt))
+ || !TEST_true(WPACKET_start_quic_sub_packet_bound(&pkt, OSSL_QUIC_VLINT_2B_MIN))
+ || !TEST_true(WPACKET_quic_write_vlint(&pkt, 0x13))
+ || !TEST_true(WPACKET_close(&pkt))
+ || !TEST_true(WPACKET_finish(&pkt))
+ || !TEST_true(WPACKET_get_total_written(&pkt, &written))
+ || !TEST_mem_eq(buf->data, written, quic7, sizeof(quic7)))
+ return cleanup(&pkt);
+
+ /* Trying to encode a value above OSSL_QUIC_VLINT_MAX should fail */
+ if (!TEST_true(WPACKET_init(&pkt, buf))
+ || !TEST_false(WPACKET_quic_write_vlint(&pkt, OSSL_QUIC_VLINT_MAX+1))
+ || !TEST_true(WPACKET_quic_write_vlint(&pkt, OSSL_QUIC_VLINT_MAX)))
+ return cleanup(&pkt);
+
+ WPACKET_cleanup(&pkt);
+ return 1;
+}
+
+static int test_WPACKET_quic_vlint_random(void)
+{
+ size_t i, written;
+ uint64_t expected, actual = 0;
+ unsigned char rand_data[9];
+ WPACKET pkt;
+ PACKET read_pkt = {0};
+
+ for (i = 0; i < 10000; ++i) {
+ if (!TEST_true(RAND_bytes(rand_data, sizeof(rand_data))))
+ return cleanup(&pkt);
+
+ expected = *(uint64_t*)rand_data;
+
+ /*
+ * Ensure that all size classes get tested with equal probability.
+ */
+ switch (rand_data[8] & 3) {
+ case 0:
+ expected &= OSSL_QUIC_VLINT_1B_MAX;
+ break;
+ case 1:
+ expected &= OSSL_QUIC_VLINT_2B_MAX;
+ break;
+ case 2:
+ expected &= OSSL_QUIC_VLINT_4B_MAX;
+ break;
+ case 3:
+ expected &= OSSL_QUIC_VLINT_8B_MAX;
+ break;
+ }
+
+ if (!TEST_true(WPACKET_init(&pkt, buf))
+ || !TEST_true(WPACKET_quic_write_vlint(&pkt, expected))
+ || !TEST_true(WPACKET_get_total_written(&pkt, &written)))
+ return cleanup(&pkt);
+
+ if (!TEST_true(PACKET_buf_init(&read_pkt, (unsigned char *)buf->data, written))
+ || !TEST_true(PACKET_get_quic_vlint(&read_pkt, &actual))
+ || !TEST_uint64_t_eq(expected, actual))
+ return cleanup(&pkt);
+
+ WPACKET_cleanup(&pkt);
+ }
+
+ WPACKET_cleanup(&pkt);
+ return 1;
+}
+
int setup_tests(void)
{
if (!TEST_ptr(buf = BUF_MEM_new()))
ADD_TEST(test_WPACKET_allocate_bytes);
ADD_TEST(test_WPACKET_memcpy);
ADD_TEST(test_WPACKET_init_der);
+ ADD_TEST(test_WPACKET_quic);
+ ADD_TEST(test_WPACKET_quic_vlint_random);
return 1;
}