mirror of
https://github.com/openssl/openssl.git
synced 2024-11-27 05:21:51 +08:00
QUIC Frame Encoding and Decoding Functions
This adds functions for encoding and decoding QUIC frames. Reviewed-by: Tomas Mraz <tomas@openssl.org> Reviewed-by: Paul Dale <pauli@openssl.org> (Merged from https://github.com/openssl/openssl/pull/18795)
This commit is contained in:
parent
205957405d
commit
dffafaf481
@ -207,7 +207,7 @@ int WPACKET_set_flags(WPACKET *pkt, unsigned int flags)
|
||||
}
|
||||
|
||||
/* Store the |value| of length |len| at location |data| */
|
||||
static int put_value(unsigned char *data, size_t value, size_t len)
|
||||
static int put_value(unsigned char *data, uint64_t value, size_t len)
|
||||
{
|
||||
if (data == NULL)
|
||||
return 1;
|
||||
@ -396,12 +396,12 @@ int WPACKET_start_sub_packet(WPACKET *pkt)
|
||||
return WPACKET_start_sub_packet_len__(pkt, 0);
|
||||
}
|
||||
|
||||
int WPACKET_put_bytes__(WPACKET *pkt, unsigned int val, size_t size)
|
||||
int WPACKET_put_bytes__(WPACKET *pkt, uint64_t val, size_t size)
|
||||
{
|
||||
unsigned char *data;
|
||||
|
||||
/* Internal API, so should not fail */
|
||||
if (!ossl_assert(size <= sizeof(unsigned int))
|
||||
if (!ossl_assert(size <= sizeof(uint64_t))
|
||||
|| !WPACKET_allocate_bytes(pkt, size, &data)
|
||||
|| !put_value(data, val, size))
|
||||
return 0;
|
||||
|
@ -229,6 +229,28 @@ __owur static ossl_inline int PACKET_peek_net_4(const PACKET *pkt,
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Peek ahead at 8 bytes in network order from |pkt| and store the value in
|
||||
* |*data|
|
||||
*/
|
||||
__owur static ossl_inline int PACKET_peek_net_8(const PACKET *pkt,
|
||||
uint64_t *data)
|
||||
{
|
||||
if (PACKET_remaining(pkt) < 8)
|
||||
return 0;
|
||||
|
||||
*data = ((uint64_t)(*pkt->curr)) << 56;
|
||||
*data |= ((uint64_t)(*(pkt->curr + 1))) << 48;
|
||||
*data |= ((uint64_t)(*(pkt->curr + 2))) << 40;
|
||||
*data |= ((uint64_t)(*(pkt->curr + 3))) << 32;
|
||||
*data |= ((uint64_t)(*(pkt->curr + 4))) << 24;
|
||||
*data |= ((uint64_t)(*(pkt->curr + 5))) << 16;
|
||||
*data |= ((uint64_t)(*(pkt->curr + 6))) << 8;
|
||||
*data |= *(pkt->curr + 7);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Decodes a QUIC variable-length integer in |pkt| and stores the result in
|
||||
* |data|.
|
||||
@ -251,6 +273,47 @@ __owur static ossl_inline int PACKET_get_quic_vlint(PACKET *pkt,
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Decodes a QUIC variable-length integer in |pkt| and stores the result in
|
||||
* |data|. Unlike PACKET_get_quic_vlint, this does not advance the current
|
||||
* position.
|
||||
*/
|
||||
__owur static ossl_inline int PACKET_peek_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);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Skips over a QUIC variable-length integer in |pkt| without decoding it.
|
||||
*/
|
||||
__owur static ossl_inline int PACKET_skip_quic_vlint(PACKET *pkt)
|
||||
{
|
||||
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;
|
||||
|
||||
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)
|
||||
@ -275,6 +338,17 @@ __owur static ossl_inline int PACKET_get_net_4_len(PACKET *pkt, size_t *data)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Get 8 bytes in network order from |pkt| and store the value in |*data| */
|
||||
__owur static ossl_inline int PACKET_get_net_8(PACKET *pkt, uint64_t *data)
|
||||
{
|
||||
if (!PACKET_peek_net_8(pkt, data))
|
||||
return 0;
|
||||
|
||||
packet_forward(pkt, 8);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Peek ahead at 1 byte from |pkt| and store the value in |*data| */
|
||||
__owur static ossl_inline int PACKET_peek_1(const PACKET *pkt,
|
||||
unsigned int *data)
|
||||
@ -885,7 +959,7 @@ int WPACKET_sub_reserve_bytes__(WPACKET *pkt, size_t len,
|
||||
* 1 byte will fail. Don't call this directly. Use the convenience macros below
|
||||
* instead.
|
||||
*/
|
||||
int WPACKET_put_bytes__(WPACKET *pkt, unsigned int val, size_t bytes);
|
||||
int WPACKET_put_bytes__(WPACKET *pkt, uint64_t val, size_t bytes);
|
||||
|
||||
/*
|
||||
* Convenience macros for calling WPACKET_put_bytes with different
|
||||
@ -899,6 +973,8 @@ int WPACKET_put_bytes__(WPACKET *pkt, unsigned int val, size_t bytes);
|
||||
WPACKET_put_bytes__((pkt), (val), 3)
|
||||
#define WPACKET_put_bytes_u32(pkt, val) \
|
||||
WPACKET_put_bytes__((pkt), (val), 4)
|
||||
#define WPACKET_put_bytes_u64(pkt, val) \
|
||||
WPACKET_put_bytes__((pkt), (val), 8)
|
||||
|
||||
/* Set a maximum size that we will not allow the WPACKET to grow beyond */
|
||||
int WPACKET_set_max_size(WPACKET *pkt, size_t maxsize);
|
||||
|
29
include/internal/quic_types.h
Normal file
29
include/internal/quic_types.h
Normal file
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* 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_QUIC_TYPES_H
|
||||
# define OSSL_QUIC_TYPES_H
|
||||
|
||||
# include <openssl/ssl.h>
|
||||
|
||||
/* QUIC packet number representation. */
|
||||
typedef uint64_t QUIC_PN;
|
||||
# define QUIC_PN_INVALID UINT64_MAX
|
||||
|
||||
static ossl_unused ossl_inline QUIC_PN ossl_quic_pn_max(QUIC_PN a, QUIC_PN b)
|
||||
{
|
||||
return a > b ? a : b;
|
||||
}
|
||||
|
||||
static ossl_unused ossl_inline QUIC_PN ossl_quic_pn_min(QUIC_PN a, QUIC_PN b)
|
||||
{
|
||||
return a < b ? a : b;
|
||||
}
|
||||
|
||||
#endif
|
695
include/internal/quic_wire.h
Normal file
695
include/internal/quic_wire.h
Normal file
@ -0,0 +1,695 @@
|
||||
/*
|
||||
* 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_WIRE_H
|
||||
# define OSSL_INTERNAL_QUIC_WIRE_H
|
||||
# pragma once
|
||||
|
||||
#include "internal/e_os.h"
|
||||
#include "internal/time.h"
|
||||
#include "internal/quic_types.h"
|
||||
#include "internal/packet.h"
|
||||
|
||||
#define OSSL_QUIC_FRAME_TYPE_PADDING 0x00
|
||||
#define OSSL_QUIC_FRAME_TYPE_PING 0x01
|
||||
#define OSSL_QUIC_FRAME_TYPE_ACK_WITHOUT_ECN 0x02
|
||||
#define OSSL_QUIC_FRAME_TYPE_ACK_WITH_ECN 0x03
|
||||
#define OSSL_QUIC_FRAME_TYPE_RESET_STREAM 0x04
|
||||
#define OSSL_QUIC_FRAME_TYPE_STOP_SENDING 0x05
|
||||
#define OSSL_QUIC_FRAME_TYPE_CRYPTO 0x06
|
||||
#define OSSL_QUIC_FRAME_TYPE_NEW_TOKEN 0x07
|
||||
#define OSSL_QUIC_FRAME_TYPE_MAX_DATA 0x10
|
||||
#define OSSL_QUIC_FRAME_TYPE_MAX_STREAM_DATA 0x11
|
||||
#define OSSL_QUIC_FRAME_TYPE_MAX_STREAMS_BIDI 0x12
|
||||
#define OSSL_QUIC_FRAME_TYPE_MAX_STREAMS_UNI 0x13
|
||||
#define OSSL_QUIC_FRAME_TYPE_DATA_BLOCKED 0x14
|
||||
#define OSSL_QUIC_FRAME_TYPE_STREAM_DATA_BLOCKED 0x15
|
||||
#define OSSL_QUIC_FRAME_TYPE_STREAMS_BLOCKED_BIDI 0x16
|
||||
#define OSSL_QUIC_FRAME_TYPE_STREAMS_BLOCKED_UNI 0x17
|
||||
#define OSSL_QUIC_FRAME_TYPE_NEW_CONN_ID 0x18
|
||||
#define OSSL_QUIC_FRAME_TYPE_RETIRE_CONN_ID 0x19
|
||||
#define OSSL_QUIC_FRAME_TYPE_PATH_CHALLENGE 0x1A
|
||||
#define OSSL_QUIC_FRAME_TYPE_PATH_RESPONSE 0x1B
|
||||
#define OSSL_QUIC_FRAME_TYPE_CONN_CLOSE_TRANSPORT 0x1C
|
||||
#define OSSL_QUIC_FRAME_TYPE_CONN_CLOSE_APP 0x1D
|
||||
#define OSSL_QUIC_FRAME_TYPE_HANDSHAKE_DONE 0x1E
|
||||
|
||||
#define OSSL_QUIC_FRAME_FLAG_STREAM_FIN 0x01
|
||||
#define OSSL_QUIC_FRAME_FLAG_STREAM_LEN 0x02
|
||||
#define OSSL_QUIC_FRAME_FLAG_STREAM_OFF 0x04
|
||||
#define OSSL_QUIC_FRAME_FLAG_STREAM_MASK ((uint64_t)0x07)
|
||||
|
||||
/* Low 3 bits of the type contain flags */
|
||||
#define OSSL_QUIC_FRAME_TYPE_STREAM 0x08 /* base ID */
|
||||
#define OSSL_QUIC_FRAME_TYPE_STREAM_FIN \
|
||||
(OSSL_QUIC_FRAME_TYPE_STREAM | \
|
||||
OSSL_QUIC_FRAME_FLAG_STREAM_FIN)
|
||||
#define OSSL_QUIC_FRAME_TYPE_STREAM_LEN \
|
||||
(OSSL_QUIC_FRAME_TYPE_STREAM | \
|
||||
OSSL_QUIC_FRAME_FLAG_STREAM_LEN)
|
||||
#define OSSL_QUIC_FRAME_TYPE_STREAM_LEN_FIN \
|
||||
(OSSL_QUIC_FRAME_TYPE_STREAM | \
|
||||
OSSL_QUIC_FRAME_FLAG_STREAM_LEN | \
|
||||
OSSL_QUIC_FRAME_FLAG_STREAM_FIN)
|
||||
#define OSSL_QUIC_FRAME_TYPE_STREAM_OFF \
|
||||
(OSSL_QUIC_FRAME_TYPE_STREAM | \
|
||||
OSSL_QUIC_FRAME_FLAG_STREAM_OFF)
|
||||
#define OSSL_QUIC_FRAME_TYPE_STREAM_OFF_FIN \
|
||||
(OSSL_QUIC_FRAME_TYPE_STREAM | \
|
||||
OSSL_QUIC_FRAME_FLAG_STREAM_OFF | \
|
||||
OSSL_QUIC_FRAME_FLAG_STREAM_FIN)
|
||||
#define OSSL_QUIC_FRAME_TYPE_STREAM_OFF_LEN \
|
||||
(OSSL_QUIC_FRAME_TYPE_STREAM | \
|
||||
OSSL_QUIC_FRAME_FLAG_STREAM_OFF | \
|
||||
OSSL_QUIC_FRAME_FLAG_STREAM_LEN)
|
||||
#define OSSL_QUIC_FRAME_TYPE_STREAM_OFF_LEN_FIN \
|
||||
(OSSL_QUIC_FRAME_TYPE_STREAM | \
|
||||
OSSL_QUIC_FRAME_FLAG_STREAM_OFF | \
|
||||
OSSL_QUIC_FRAME_FLAG_STREAM_LEN | \
|
||||
OSSL_QUIC_FRAME_FLAG_STREAM_FIN)
|
||||
|
||||
#define OSSL_QUIC_FRAME_TYPE_IS_STREAM(x) \
|
||||
(((x) & ~OSSL_QUIC_FRAME_FLAG_STREAM_MASK) == OSSL_QUIC_FRAME_TYPE_STREAM)
|
||||
#define OSSL_QUIC_FRAME_TYPE_IS_ACK(x) \
|
||||
(((x) & ~(uint64_t)1) == OSSL_QUIC_FRAME_TYPE_ACK_WITHOUT_ECN)
|
||||
#define OSSL_QUIC_FRAME_TYPE_IS_MAX_STREAMS(x) \
|
||||
(((x) & ~(uint64_t)1) == OSSL_QUIC_FRAME_TYPE_MAX_STREAMS_BIDI)
|
||||
#define OSSL_QUIC_FRAME_TYPE_IS_STREAMS_BLOCKED(x) \
|
||||
(((x) & ~(uint64_t)1) == OSSL_QUIC_FRAME_TYPE_STREAMS_BLOCKED_BIDI)
|
||||
#define OSSL_QUIC_FRAME_TYPE_IS_CONN_CLOSE(x) \
|
||||
(((x) & ~(uint64_t)1) == OSSL_QUIC_FRAME_TYPE_CONN_CLOSE_TRANSPORT)
|
||||
|
||||
/*
|
||||
* QUIC Frame Logical Representations
|
||||
* ==================================
|
||||
*/
|
||||
|
||||
/* QUIC Frame: ACK */
|
||||
typedef struct ossl_quic_ack_range_st {
|
||||
/*
|
||||
* Represents an inclusive range of packet numbers [start, end].
|
||||
* start must be <= end.
|
||||
*/
|
||||
QUIC_PN start, end;
|
||||
} OSSL_QUIC_ACK_RANGE;
|
||||
|
||||
typedef struct ossl_quic_frame_ack_st {
|
||||
/*
|
||||
* A sequence of packet number ranges [[start, end]...].
|
||||
*
|
||||
* The ranges must be sorted in descending order, for example:
|
||||
* [ 95, 100]
|
||||
* [ 90, 92]
|
||||
* etc.
|
||||
*
|
||||
* As such, ack_ranges[0].end is always the highest packet number
|
||||
* being acknowledged and ack_ranges[num_ack_ranges-1].start is
|
||||
* always the lowest packet number being acknowledged.
|
||||
*
|
||||
* num_ack_ranges must be greater than zero, as an ACK frame must
|
||||
* acknowledge at least one packet number.
|
||||
*/
|
||||
OSSL_QUIC_ACK_RANGE *ack_ranges;
|
||||
size_t num_ack_ranges;
|
||||
|
||||
OSSL_TIME delay_time;
|
||||
uint64_t ect0, ect1, ecnce;
|
||||
unsigned int ecn_present : 1;
|
||||
} OSSL_QUIC_FRAME_ACK;
|
||||
|
||||
/* QUIC Frame: STREAM */
|
||||
typedef struct ossl_quic_frame_stream_st {
|
||||
uint64_t stream_id; /* Stream ID */
|
||||
uint64_t offset; /* Logical offset in stream */
|
||||
uint64_t len; /* Length of data in bytes */
|
||||
const unsigned char *data;
|
||||
|
||||
/*
|
||||
* On encode, this determines whether the len field should be encoded or
|
||||
* not. If zero, the len field is not encoded and it is assumed the frame
|
||||
* runs to the end of the packet.
|
||||
*
|
||||
* On decode, this determines whether the frame had an explicitly encoded
|
||||
* length. If not set, the frame runs to the end of the packet and len has
|
||||
* been set accordingly.
|
||||
*/
|
||||
unsigned int has_explicit_len : 1;
|
||||
|
||||
/* 1 if this is the end of the stream */
|
||||
unsigned int is_fin : 1;
|
||||
} OSSL_QUIC_FRAME_STREAM;
|
||||
|
||||
/* QUIC Frame: CRYPTO */
|
||||
typedef struct ossl_quic_frame_crypto_st {
|
||||
uint64_t offset; /* Logical offset in stream */
|
||||
uint64_t len; /* Length of the data in bytes */
|
||||
const unsigned char *data;
|
||||
} OSSL_QUIC_FRAME_CRYPTO;
|
||||
|
||||
/* QUIC Frame: RESET_STREAM */
|
||||
typedef struct ossl_quic_frame_reset_stream_st {
|
||||
uint64_t stream_id;
|
||||
uint64_t app_error_code;
|
||||
uint64_t final_size;
|
||||
} OSSL_QUIC_FRAME_RESET_STREAM;
|
||||
|
||||
/* QUIC Frame: STOP_SENDING */
|
||||
typedef struct ossl_quic_frame_stop_sending_st {
|
||||
uint64_t stream_id;
|
||||
uint64_t app_error_code;
|
||||
} OSSL_QUIC_FRAME_STOP_SENDING;
|
||||
|
||||
/* QUIC Frame: NEW_CONNECTION_ID */
|
||||
#define OSSL_QUIC_MAX_CONN_ID_LEN 20
|
||||
typedef struct ossl_quic_conn_id_st {
|
||||
unsigned char id_len; /* length of id in bytes */
|
||||
unsigned char id[OSSL_QUIC_MAX_CONN_ID_LEN];
|
||||
} OSSL_QUIC_CONN_ID;
|
||||
|
||||
typedef struct ossl_quic_frame_new_conn_id_st {
|
||||
uint64_t seq_num;
|
||||
uint64_t retire_prior_to;
|
||||
OSSL_QUIC_CONN_ID conn_id;
|
||||
unsigned char stateless_reset_token[16];
|
||||
} OSSL_QUIC_FRAME_NEW_CONN_ID;
|
||||
|
||||
/* QUIC Frame: CONNECTION_CLOSE */
|
||||
typedef struct ossl_quic_frame_conn_close_st {
|
||||
unsigned int is_app : 1; /* 0: transport error, 1: app error */
|
||||
uint64_t error_code; /* 62-bit transport or app error code */
|
||||
uint64_t frame_type; /* transport errors only */
|
||||
const char *reason; /* UTF-8 string, not necessarily zero-terminated */
|
||||
size_t reason_len; /* Length of reason in bytes */
|
||||
} OSSL_QUIC_FRAME_CONN_CLOSE;
|
||||
|
||||
/*
|
||||
* QUIC Wire Format Encoding
|
||||
* =========================
|
||||
*
|
||||
* These functions return 1 on success and 0 on failure.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Encodes zero or more QUIC PADDING frames to the packet writer. Each PADDING
|
||||
* frame consumes one byte; num_bytes specifies the number of bytes of padding
|
||||
* to write.
|
||||
*/
|
||||
int ossl_quic_wire_encode_padding(WPACKET *pkt, size_t num_bytes);
|
||||
|
||||
/*
|
||||
* Encodes a QUIC PING frame to the packet writer. This frame type takes
|
||||
* no arguments.
|
||||
*/
|
||||
int ossl_quic_wire_encode_frame_ping(WPACKET *pkt);
|
||||
|
||||
/*
|
||||
* Encodes a QUIC ACK frame to the packet writer, given a logical representation
|
||||
* of the ACK frame.
|
||||
*
|
||||
* The ACK ranges passed must be sorted in descending order.
|
||||
*
|
||||
* The logical representation stores a list of packet number ranges. The wire
|
||||
* encoding is slightly different and stores the first range in the list
|
||||
* in a different manner.
|
||||
*
|
||||
* The ack_delay_exponent argument specifies the index of a power of two by
|
||||
* which the ack->ack_delay field is be divided. This exponent value must match
|
||||
* the value used when decoding.
|
||||
*/
|
||||
int ossl_quic_wire_encode_frame_ack(WPACKET *pkt,
|
||||
uint32_t ack_delay_exponent,
|
||||
const OSSL_QUIC_FRAME_ACK *ack);
|
||||
|
||||
/*
|
||||
* Encodes a QUIC RESET_STREAM frame to the packet writer, given a logical
|
||||
* representation of the RESET_STREAM frame.
|
||||
*/
|
||||
int ossl_quic_wire_encode_frame_reset_stream(WPACKET *pkt,
|
||||
const OSSL_QUIC_FRAME_RESET_STREAM *f);
|
||||
|
||||
/*
|
||||
* Encodes a QUIC STOP_SENDING frame to the packet writer, given a logical
|
||||
* representation of the STOP_SENDING frame.
|
||||
*/
|
||||
int ossl_quic_wire_encode_frame_stop_sending(WPACKET *pkt,
|
||||
const OSSL_QUIC_FRAME_STOP_SENDING *f);
|
||||
|
||||
/*
|
||||
* Encodes a QUIC CRYPTO frame header to the packet writer.
|
||||
*
|
||||
* To create a well-formed frame, the data written using this function must be
|
||||
* immediately followed by f->len bytes of data.
|
||||
*/
|
||||
int ossl_quic_wire_encode_frame_crypto_hdr(WPACKET *hdr,
|
||||
const OSSL_QUIC_FRAME_CRYPTO *f);
|
||||
|
||||
/*
|
||||
* Encodes a QUIC CRYPTO frame to the packet writer.
|
||||
*
|
||||
* This function returns a pointer to a buffer of f->len bytes which the caller
|
||||
* should fill however it wishes. If f->data is non-NULL, it is automatically
|
||||
* copied to the target buffer, otherwise the caller must fill the returned
|
||||
* buffer. Returns NULL on failure.
|
||||
*/
|
||||
void *ossl_quic_wire_encode_frame_crypto(WPACKET *pkt,
|
||||
const OSSL_QUIC_FRAME_CRYPTO *f);
|
||||
|
||||
/*
|
||||
* Encodes a QUIC NEW_TOKEN frame to the packet writer.
|
||||
*/
|
||||
int ossl_quic_wire_encode_frame_new_token(WPACKET *pkt,
|
||||
const unsigned char *token,
|
||||
size_t token_len);
|
||||
|
||||
/*
|
||||
* Encodes a QUIC STREAM frame's header to the packet writer. The f->stream_id,
|
||||
* f->offset and f->len fields are the values for the respective Stream ID,
|
||||
* Offset and Length fields.
|
||||
*
|
||||
* If f->is_fin is non-zero, the frame is marked as the final frame in the
|
||||
* stream.
|
||||
*
|
||||
* If f->has_explicit_len is zerro, the frame is assumed to be the final frame
|
||||
* in the packet, which the caller is responsible for ensuring; the Length
|
||||
* field is then omitted.
|
||||
*
|
||||
* To create a well-formed frame, the data written using this function must be
|
||||
* immediately followed by f->len bytes of stream data.
|
||||
*/
|
||||
int ossl_quic_wire_encode_frame_stream_hdr(WPACKET *pkt,
|
||||
const OSSL_QUIC_FRAME_STREAM *f);
|
||||
|
||||
/*
|
||||
* Functions similarly to ossl_quic_wire_encode_frame_stream_hdr, but it also
|
||||
* allocates space for f->len bytes of data after the header, creating a
|
||||
* well-formed QUIC STREAM frame in one call.
|
||||
*
|
||||
* A pointer to the bytes allocated for the framme payload is returned,
|
||||
* which the caller can fill however it wishes. If f->data is non-NULL,
|
||||
* it is automatically copied to the target buffer, otherwise the caller
|
||||
* must fill the returned buffer. Returns NULL on failure.
|
||||
*/
|
||||
void *ossl_quic_wire_encode_frame_stream(WPACKET *pkt,
|
||||
const OSSL_QUIC_FRAME_STREAM *f);
|
||||
|
||||
/*
|
||||
* Encodes a QUIC MAX_DATA frame to the packet writer.
|
||||
*/
|
||||
int ossl_quic_wire_encode_frame_max_data(WPACKET *pkt,
|
||||
uint64_t max_data);
|
||||
|
||||
/*
|
||||
* Encodes a QUIC MAX_STREAM_DATA frame to the packet writer.
|
||||
*/
|
||||
int ossl_quic_wire_encode_frame_max_stream_data(WPACKET *pkt,
|
||||
uint64_t stream_id,
|
||||
uint64_t max_data);
|
||||
|
||||
/*
|
||||
* Encodes a QUIC MAX_STREAMS frame to the packet writer.
|
||||
*
|
||||
* If is_uni is 0, the count specifies the maximum number of
|
||||
* bidirectional streams; else it specifies the maximum number of unidirectional
|
||||
* streams.
|
||||
*/
|
||||
int ossl_quic_wire_encode_frame_max_streams(WPACKET *pkt,
|
||||
char is_uni,
|
||||
uint64_t max_streams);
|
||||
|
||||
/*
|
||||
* Encodes a QUIC DATA_BLOCKED frame to the packet writer.
|
||||
*/
|
||||
int ossl_quic_wire_encode_frame_data_blocked(WPACKET *pkt,
|
||||
uint64_t max_data);
|
||||
|
||||
/*
|
||||
* Encodes a QUIC STREAM_DATA_BLOCKED frame to the packet writer.
|
||||
*/
|
||||
int ossl_quic_wire_encode_frame_stream_data_blocked(WPACKET *pkt,
|
||||
uint64_t stream_id,
|
||||
uint64_t max_stream_data);
|
||||
/*
|
||||
* Encodes a QUIC STREAMS_BLOCKED frame to the packet writer.
|
||||
*
|
||||
* If is_uni is 0, the count specifies the maximum number of
|
||||
* bidirectional streams; else it specifies the maximum number of unidirectional
|
||||
* streams.
|
||||
*/
|
||||
int ossl_quic_wire_encode_frame_streams_blocked(WPACKET *pkt,
|
||||
char is_uni,
|
||||
uint64_t max_streams);
|
||||
|
||||
/*
|
||||
* Encodes a QUIC NEW_CONNECTION_ID frame to the packet writer, given a logical
|
||||
* representation of the NEW_CONNECTION_ID frame.
|
||||
*
|
||||
* The buffer pointed to by the conn_id field must be valid for the duration of
|
||||
* the call.
|
||||
*/
|
||||
int ossl_quic_wire_encode_frame_new_conn_id(WPACKET *pkt,
|
||||
const OSSL_QUIC_FRAME_NEW_CONN_ID *f);
|
||||
|
||||
/*
|
||||
* Encodes a QUIC RETIRE_CONNECTION_ID frame to the packet writer.
|
||||
*/
|
||||
int ossl_quic_wire_encode_frame_retire_conn_id(WPACKET *pkt,
|
||||
uint64_t seq_num);
|
||||
|
||||
/*
|
||||
* Encodes a QUIC PATH_CHALLENGE frame to the packet writer.
|
||||
*/
|
||||
int ossl_quic_wire_encode_frame_path_challenge(WPACKET *pkt,
|
||||
uint64_t data);
|
||||
|
||||
/*
|
||||
* Encodes a QUIC PATH_RESPONSE frame to the packet writer.
|
||||
*/
|
||||
int ossl_quic_wire_encode_frame_path_response(WPACKET *pkt,
|
||||
uint64_t data);
|
||||
|
||||
/*
|
||||
* Encodes a QUIC CONNECTION_CLOSE frame to the packet writer, given a logical
|
||||
* representation of the CONNECTION_CLOSE frame.
|
||||
*
|
||||
* The reason field may be NULL, in which case no reason is encoded. If the
|
||||
* reason field is non-NULL, it must point to a valid UTF-8 string and
|
||||
* reason_len must be set to the length of the reason string in bytes. The
|
||||
* reason string need not be zero terminated.
|
||||
*/
|
||||
int ossl_quic_wire_encode_frame_conn_close(WPACKET *pkt,
|
||||
const OSSL_QUIC_FRAME_CONN_CLOSE *f);
|
||||
|
||||
/*
|
||||
* Encodes a QUIC HANDSHAKE_DONE frame to the packet writer. This frame type
|
||||
* takes no arguiments.
|
||||
*/
|
||||
int ossl_quic_wire_encode_frame_handshake_done(WPACKET *pkt);
|
||||
|
||||
/*
|
||||
* Encodes a QUIC transport parameter TLV with the given ID into the WPACKET.
|
||||
* The payload is an arbitrary buffer.
|
||||
*
|
||||
* If value is non-NULL, the value is copied into the packet.
|
||||
* If it is NULL, value_len bytes are allocated for the payload and the caller
|
||||
* should fill the buffer using the returned pointer.
|
||||
*
|
||||
* Returns a pointer to the start of the payload on success, or NULL on failure.
|
||||
*/
|
||||
unsigned char *ossl_quic_wire_encode_transport_param_bytes(WPACKET *pkt,
|
||||
uint64_t id,
|
||||
const unsigned char *value,
|
||||
size_t value_len);
|
||||
|
||||
/*
|
||||
* Encodes a QUIC transport parameter TLV with the given ID into the WPACKET.
|
||||
* The payload is a QUIC variable-length integer with the given value.
|
||||
*/
|
||||
int ossl_quic_wire_encode_transport_param_int(WPACKET *pkt,
|
||||
uint64_t id,
|
||||
uint64_t value);
|
||||
|
||||
/*
|
||||
* QUIC Wire Format Decoding
|
||||
* =========================
|
||||
*
|
||||
* These functions return 1 on success or 0 for failure. Typical reasons
|
||||
* why these functions may fail include:
|
||||
*
|
||||
* - A frame decode function is called but the frame in the PACKET's buffer
|
||||
* is not of the correct type.
|
||||
*
|
||||
* - A variable-length field in the encoded frame appears to exceed the bounds
|
||||
* of the PACKET's buffer.
|
||||
*
|
||||
* These functions should be called with the PACKET pointing to the start of the
|
||||
* frame (including the initial type field), and consume an entire frame
|
||||
* including its type field. The expectation is that the caller will have
|
||||
* already discerned the frame type using ossl_quic_wire_peek_frame_header().
|
||||
*/
|
||||
|
||||
/*
|
||||
* Decodes the type field header of a QUIC frame (without advancing the current
|
||||
* position). This can be used to determine the frame type and determine which
|
||||
* frame decoding function to call.
|
||||
*/
|
||||
int ossl_quic_wire_peek_frame_header(PACKET *pkt, uint64_t *type);
|
||||
|
||||
/*
|
||||
* Like ossl_quic_wire_peek_frame_header, but advances the current position
|
||||
* so that the type field is consumed. For advanced use only.
|
||||
*/
|
||||
int ossl_quic_wire_skip_frame_header(PACKET *pkt, uint64_t *type);
|
||||
|
||||
/*
|
||||
* Determines how many ranges are needed to decode a QUIC ACK frame.
|
||||
*
|
||||
* The number of ranges which must be allocated before the call to
|
||||
* ossl_quic_wire_decode_frame_ack is written to *total_ranges.
|
||||
*
|
||||
* The PACKET is not advanced.
|
||||
*/
|
||||
int ossl_quic_wire_peek_frame_ack_num_ranges(const PACKET *pkt,
|
||||
uint64_t *total_ranges);
|
||||
|
||||
/*
|
||||
* Decodes a QUIC ACK frame. The ack_ranges field of the passed structure should
|
||||
* point to a preallocated array of ACK ranges and the num_ack_ranges field
|
||||
* should specify the length of allocation.
|
||||
*
|
||||
* *total_ranges is written with the number of ranges in the decoded frame,
|
||||
* which may be greater than the number of ranges which were decoded (i.e. if
|
||||
* num_ack_ranges was too small to decode all ranges).
|
||||
*
|
||||
* On success, this function modifies the num_ack_ranges field to indicate the
|
||||
* number of ranges in the decoded frame. This is the number of entries in the
|
||||
* ACK ranges array written by this function; any additional entries are not
|
||||
* modified.
|
||||
*
|
||||
* If the number of ACK ranges in the decoded frame exceeds that in
|
||||
* num_ack_ranges, as many ACK ranges as possible are decoded into the range
|
||||
* array. The caller can use the value written to *total_ranges to detect this
|
||||
* condition, as *total_ranges will exceed num_ack_ranges.
|
||||
*
|
||||
* If ack is NULL, the frame is still decoded, but only *total_ranges is
|
||||
* written. This can be used to determine the number of ranges which must be
|
||||
* allocated.
|
||||
*
|
||||
* The ack_delay_exponent argument specifies the index of a power of two used to
|
||||
* decode the ack_delay field. This must match the ack_delay_exponent value used
|
||||
* to encode the frame.
|
||||
*/
|
||||
int ossl_quic_wire_decode_frame_ack(PACKET *pkt,
|
||||
uint32_t ack_delay_exponent,
|
||||
OSSL_QUIC_FRAME_ACK *ack,
|
||||
uint64_t *total_ranges);
|
||||
|
||||
/*
|
||||
* Decodes a QUIC RESET_STREAM frame.
|
||||
*/
|
||||
int ossl_quic_wire_decode_frame_reset_stream(PACKET *pkt,
|
||||
OSSL_QUIC_FRAME_RESET_STREAM *f);
|
||||
|
||||
/*
|
||||
* Decodes a QUIC STOP_SENDING frame.
|
||||
*/
|
||||
int ossl_quic_wire_decode_frame_stop_sending(PACKET *pkt,
|
||||
OSSL_QUIC_FRAME_STOP_SENDING *f);
|
||||
|
||||
/*
|
||||
* Decodes a QUIC CRYPTO frame.
|
||||
*
|
||||
* f->data is set to point inside the packet buffer inside the PACKET, therefore
|
||||
* it is safe to access for as long as the packet buffer exists.
|
||||
*/
|
||||
int ossl_quic_wire_decode_frame_crypto(PACKET *pkt,
|
||||
OSSL_QUIC_FRAME_CRYPTO *f);
|
||||
|
||||
/*
|
||||
* Decodes a QUIC NEW_TOKEN frame. *token is written with a pointer to the token
|
||||
* bytes and *token_len is written with the length of the token in bytes.
|
||||
*/
|
||||
int ossl_quic_wire_decode_frame_new_token(PACKET *pkt,
|
||||
const unsigned char **token,
|
||||
size_t *token_len);
|
||||
|
||||
/*
|
||||
* Decodes a QUIC STREAM frame.
|
||||
*
|
||||
* If the frame did not contain an offset field, f->offset is set to 0, as the
|
||||
* absence of an offset field is equivalent to an offset of 0.
|
||||
*
|
||||
* If the frame contained a length field, f->has_explicit_len is set to 1 and
|
||||
* the length of the data is placed in f->len. This function ensures that the
|
||||
* length does not exceed the packet buffer, thus it is safe to access f->data.
|
||||
*
|
||||
* If the frame did not contain a length field, this means that the frame runs
|
||||
* until the end of the packet. This function sets f->has_explicit_len to zero,
|
||||
* and f->len to the amount of data remaining in the input buffer. Therefore,
|
||||
* this function should be used with a PACKET representing a single packet (and
|
||||
* not e.g. multiple packets).
|
||||
*
|
||||
* Note also that this means f->len is always valid after this function returns
|
||||
* successfully, regardless of the value of f->has_explicit_len.
|
||||
*
|
||||
* f->data points inside the packet buffer inside the PACKET, therefore it is
|
||||
* safe to access for as long as the packet buffer exists.
|
||||
*
|
||||
* f->is_fin is set according to whether the frame was marked as ending the
|
||||
* stream.
|
||||
*/
|
||||
int ossl_quic_wire_decode_frame_stream(PACKET *pkt,
|
||||
OSSL_QUIC_FRAME_STREAM *f);
|
||||
|
||||
/*
|
||||
* Decodes a QUIC MAX_DATA frame. The Maximum Data field is written to
|
||||
* *max_data.
|
||||
*/
|
||||
int ossl_quic_wire_decode_frame_max_data(PACKET *pkt,
|
||||
uint64_t *max_data);
|
||||
|
||||
/*
|
||||
* Decodes a QUIC MAX_STREAM_DATA frame. The Stream ID is written to *stream_id
|
||||
* and Maximum Stream Data field is written to *max_stream_data.
|
||||
*/
|
||||
int ossl_quic_wire_decode_frame_max_stream_data(PACKET *pkt,
|
||||
uint64_t *stream_id,
|
||||
uint64_t *max_stream_data);
|
||||
/*
|
||||
* Decodes a QUIC MAX_STREAMS frame. The Maximum Streams field is written to
|
||||
* *max_streams.
|
||||
*
|
||||
* Whether the limit concerns bidirectional streams or unidirectional streams is
|
||||
* denoted by the frame type; the caller should examine the frame type to
|
||||
* determine this.
|
||||
*/
|
||||
int ossl_quic_wire_decode_frame_max_streams(PACKET *pkt,
|
||||
uint64_t *max_streams);
|
||||
|
||||
/*
|
||||
* Decodes a QUIC DATA_BLOCKED frame. The Maximum Data field is written to
|
||||
* *max_data.
|
||||
*/
|
||||
int ossl_quic_wire_decode_frame_data_blocked(PACKET *pkt,
|
||||
uint64_t *max_data);
|
||||
|
||||
/*
|
||||
* Decodes a QUIC STREAM_DATA_BLOCKED frame. The Stream ID and Maximum Stream
|
||||
* Data fields are written to *stream_id and *max_stream_data respectively.
|
||||
*/
|
||||
int ossl_quic_wire_decode_frame_stream_data_blocked(PACKET *pkt,
|
||||
uint64_t *stream_id,
|
||||
uint64_t *max_stream_data);
|
||||
|
||||
/*
|
||||
* Decodes a QUIC STREAMS_BLOCKED frame. The Maximum Streams field is written to
|
||||
* *max_streams.
|
||||
*
|
||||
* Whether the limit concerns bidirectional streams or unidirectional streams is
|
||||
* denoted by the frame type; the caller should examine the frame type to
|
||||
* determine this.
|
||||
*/
|
||||
int ossl_quic_wire_decode_frame_streams_blocked(PACKET *pkt,
|
||||
uint64_t *max_streams);
|
||||
|
||||
|
||||
/*
|
||||
* Decodes a QUIC NEW_CONNECTION_ID frame. The logical representation of the
|
||||
* frame is written to *f.
|
||||
*
|
||||
* The conn_id field is set to point to the connection ID string inside the
|
||||
* packet buffer; it is therefore valid for as long as the PACKET's buffer is
|
||||
* valid. The conn_id_len field is set to the length of the connection ID string
|
||||
* in bytes.
|
||||
*/
|
||||
int ossl_quic_wire_decode_frame_new_conn_id(PACKET *pkt,
|
||||
OSSL_QUIC_FRAME_NEW_CONN_ID *f);
|
||||
|
||||
/*
|
||||
* Decodes a QUIC RETIRE_CONNECTION_ID frame. The Sequence Number field
|
||||
* is written to *seq_num.
|
||||
*/
|
||||
int ossl_quic_wire_decode_frame_retire_conn_id(PACKET *pkt,
|
||||
uint64_t *seq_num);
|
||||
|
||||
/*
|
||||
* Decodes a QUIC PATH_CHALLENGE frame. The Data field is written to *data.
|
||||
*/
|
||||
int ossl_quic_wire_decode_frame_path_challenge(PACKET *pkt,
|
||||
uint64_t *data);
|
||||
|
||||
/*
|
||||
* Decodes a QUIC PATH_CHALLENGE frame. The Data field is written to *data.
|
||||
*/
|
||||
int ossl_quic_wire_decode_frame_path_response(PACKET *pkt,
|
||||
uint64_t *data);
|
||||
|
||||
/*
|
||||
* Decodes a QUIC CONNECTION_CLOSE frame. The logical representation
|
||||
* of the frame is written to *f.
|
||||
*
|
||||
* The reason field is set to point to the UTF-8 reason string inside
|
||||
* the packet buffer; it is therefore valid for as long as the PACKET's
|
||||
* buffer is valid. The reason_len field is set to the length of the
|
||||
* reason string in bytes.
|
||||
*
|
||||
* IMPORTANT: The reason string is not zero-terminated.
|
||||
*
|
||||
* Returns 1 on success or 0 on failure.
|
||||
*/
|
||||
int ossl_quic_wire_decode_frame_conn_close(PACKET *pkt,
|
||||
OSSL_QUIC_FRAME_CONN_CLOSE *f);
|
||||
|
||||
/*
|
||||
* Decodes one or more PADDING frames. PADDING frames have no arguments.
|
||||
*
|
||||
* Returns the number of PADDING frames decoded or 0 on error.
|
||||
*/
|
||||
size_t ossl_quic_wire_decode_padding(PACKET *pkt);
|
||||
|
||||
/*
|
||||
* Decodes a PING frame. The frame has no arguments.
|
||||
*/
|
||||
int ossl_quic_wire_decode_frame_ping(PACKET *pkt);
|
||||
|
||||
/*
|
||||
* Decodes a HANDSHAKE_DONE frame. The frame has no arguments.
|
||||
*/
|
||||
int ossl_quic_wire_decode_frame_handshake_done(PACKET *pkt);
|
||||
|
||||
/*
|
||||
* Peeks at the ID of the next QUIC transport parameter TLV in the stream.
|
||||
* The ID is written to *id.
|
||||
*/
|
||||
int ossl_quic_wire_peek_transport_param(PACKET *pkt, uint64_t *id);
|
||||
|
||||
/*
|
||||
* Decodes a QUIC transport parameter TLV. A pointer to the value buffer is
|
||||
* returned on success. This points inside the PACKET's buffer and is therefore
|
||||
* valid as long as the PACKET's buffer is valid.
|
||||
*
|
||||
* The transport parameter ID is written to *id and the length of the payload
|
||||
* in bytes is written to *len.
|
||||
*
|
||||
* Returns NULL on failure.
|
||||
*/
|
||||
const unsigned char *ossl_quic_wire_decode_transport_param_bytes(PACKET *pkt,
|
||||
uint64_t *id,
|
||||
size_t *len);
|
||||
|
||||
/*
|
||||
* Decodes a QUIC transport parameter TLV containing a variable-length integer.
|
||||
*
|
||||
* The transport parameter ID is written to *id and the value is written to
|
||||
* *value.
|
||||
*/
|
||||
int ossl_quic_wire_decode_transport_param_int(PACKET *pkt,
|
||||
uint64_t *id,
|
||||
uint64_t *value);
|
||||
|
||||
#endif
|
@ -16,7 +16,13 @@
|
||||
# include "internal/safe_math.h"
|
||||
|
||||
/* The precision of times allows this many values per second */
|
||||
# define OSSL_TIME_SECOND 1000000000
|
||||
# define OSSL_TIME_SECOND ((uint64_t)1000000000)
|
||||
|
||||
/* One millisecond. */
|
||||
# define OSSL_TIME_MS (OSSL_TIME_SECOND / 1000)
|
||||
|
||||
/* One microsecond. */
|
||||
# define OSSL_TIME_US (OSSL_TIME_MS / 1000)
|
||||
|
||||
/* Macro representing the most distant future time */
|
||||
# define OSSL_TIME_INFINITY (~(OSSL_TIME)0)
|
||||
@ -24,6 +30,9 @@
|
||||
/* Macro that's guaranteed to be now or before */
|
||||
# define OSSL_TIME_IMMEDIATE 0
|
||||
|
||||
/* Macro representing the zero value */
|
||||
# define OSSL_TIME_ZERO 0
|
||||
|
||||
/*
|
||||
* Internal type defining a time.
|
||||
* The time datum is Unix's 1970 and at nanosecond precision, this gives
|
||||
@ -84,4 +93,45 @@ OSSL_TIME ossl_time_subtract(OSSL_TIME a, OSSL_TIME b)
|
||||
return err ? 0 : r;
|
||||
}
|
||||
|
||||
/* Returns |a - b|. */
|
||||
static ossl_unused ossl_inline
|
||||
OSSL_TIME ossl_time_abs_difference(OSSL_TIME a, OSSL_TIME b)
|
||||
{
|
||||
return a > b ? ossl_time_subtract(a, b) : ossl_time_subtract(b, a);
|
||||
}
|
||||
|
||||
static ossl_unused ossl_inline
|
||||
OSSL_TIME ossl_time_multiply(OSSL_TIME a, uint64_t b)
|
||||
{
|
||||
OSSL_TIME r;
|
||||
int err = 0;
|
||||
|
||||
r = safe_mul_time(a, b, &err);
|
||||
return err ? OSSL_TIME_INFINITY : r;
|
||||
}
|
||||
|
||||
static ossl_unused ossl_inline
|
||||
OSSL_TIME ossl_time_divide(OSSL_TIME a, uint64_t b)
|
||||
{
|
||||
OSSL_TIME r;
|
||||
int err = 0;
|
||||
|
||||
r = safe_div_time(a, b, &err);
|
||||
return err ? 0 : r;
|
||||
}
|
||||
|
||||
/* Return higher of the two given time values. */
|
||||
static ossl_unused ossl_inline
|
||||
OSSL_TIME ossl_time_max(OSSL_TIME a, OSSL_TIME b)
|
||||
{
|
||||
return a > b ? a : b;
|
||||
}
|
||||
|
||||
/* Return the lower of the two given time values. */
|
||||
static ossl_unused ossl_inline
|
||||
OSSL_TIME ossl_time_min(OSSL_TIME a, OSSL_TIME b)
|
||||
{
|
||||
return a < b ? a : b;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -1,3 +1,3 @@
|
||||
$LIBSSL=../../libssl
|
||||
|
||||
SOURCE[$LIBSSL]=quic_method.c quic_impl.c
|
||||
SOURCE[$LIBSSL]=quic_method.c quic_impl.c quic_wire.c
|
||||
|
823
ssl/quic/quic_wire.c
Normal file
823
ssl/quic/quic_wire.c
Normal file
@ -0,0 +1,823 @@
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#include <openssl/macros.h>
|
||||
#include <openssl/objects.h>
|
||||
#include "quic_local.h"
|
||||
#include "internal/quic_vlint.h"
|
||||
#include "internal/quic_wire.h"
|
||||
|
||||
OSSL_SAFE_MATH_UNSIGNED(uint64_t, uint64_t)
|
||||
|
||||
/*
|
||||
* QUIC Wire Format Encoding
|
||||
* =========================
|
||||
*/
|
||||
|
||||
int ossl_quic_wire_encode_padding(WPACKET *pkt, size_t num_bytes)
|
||||
{
|
||||
/*
|
||||
* PADDING is frame type zero, which as a variable-length integer is
|
||||
* represented as a single zero byte. As an optimisation, just use memset.
|
||||
*/
|
||||
return WPACKET_memset(pkt, 0, num_bytes);
|
||||
}
|
||||
|
||||
static int encode_frame_hdr(WPACKET *pkt, uint64_t frame_type)
|
||||
{
|
||||
return WPACKET_quic_write_vlint(pkt, frame_type);
|
||||
}
|
||||
|
||||
int ossl_quic_wire_encode_frame_ping(WPACKET *pkt)
|
||||
{
|
||||
return encode_frame_hdr(pkt, OSSL_QUIC_FRAME_TYPE_PING);
|
||||
}
|
||||
|
||||
int ossl_quic_wire_encode_frame_ack(WPACKET *pkt,
|
||||
uint32_t ack_delay_exponent,
|
||||
const OSSL_QUIC_FRAME_ACK *ack)
|
||||
{
|
||||
uint64_t frame_type = ack->ecn_present ? OSSL_QUIC_FRAME_TYPE_ACK_WITH_ECN
|
||||
: OSSL_QUIC_FRAME_TYPE_ACK_WITHOUT_ECN;
|
||||
|
||||
uint64_t largest_ackd, first_ack_range, ack_delay_enc;
|
||||
size_t i, num_ack_ranges = ack->num_ack_ranges;
|
||||
|
||||
if (num_ack_ranges == 0)
|
||||
return 0;
|
||||
|
||||
ack_delay_enc = ossl_time_divide(ossl_time_divide(ack->delay_time,
|
||||
OSSL_TIME_US),
|
||||
1UL << ack_delay_exponent);
|
||||
largest_ackd = ack->ack_ranges[0].end;
|
||||
first_ack_range = ack->ack_ranges[0].end - ack->ack_ranges[0].start;
|
||||
|
||||
if (!encode_frame_hdr(pkt, frame_type)
|
||||
|| !WPACKET_quic_write_vlint(pkt, largest_ackd)
|
||||
|| !WPACKET_quic_write_vlint(pkt, ack_delay_enc)
|
||||
|| !WPACKET_quic_write_vlint(pkt, num_ack_ranges - 1)
|
||||
|| !WPACKET_quic_write_vlint(pkt, first_ack_range))
|
||||
return 0;
|
||||
|
||||
for (i = 1; i < num_ack_ranges; ++i) {
|
||||
uint64_t gap, range_len;
|
||||
|
||||
gap = ack->ack_ranges[i - 1].start - ack->ack_ranges[i].end - 2;
|
||||
range_len = ack->ack_ranges[i].end - ack->ack_ranges[i].start;
|
||||
|
||||
if (!WPACKET_quic_write_vlint(pkt, gap)
|
||||
|| !WPACKET_quic_write_vlint(pkt, range_len))
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ack->ecn_present)
|
||||
if (!WPACKET_quic_write_vlint(pkt, ack->ect0)
|
||||
|| !WPACKET_quic_write_vlint(pkt, ack->ect1)
|
||||
|| !WPACKET_quic_write_vlint(pkt, ack->ecnce))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ossl_quic_wire_encode_frame_reset_stream(WPACKET *pkt,
|
||||
const OSSL_QUIC_FRAME_RESET_STREAM *f)
|
||||
{
|
||||
if (!encode_frame_hdr(pkt, OSSL_QUIC_FRAME_TYPE_RESET_STREAM)
|
||||
|| !WPACKET_quic_write_vlint(pkt, f->stream_id)
|
||||
|| !WPACKET_quic_write_vlint(pkt, f->app_error_code)
|
||||
|| !WPACKET_quic_write_vlint(pkt, f->final_size))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ossl_quic_wire_encode_frame_stop_sending(WPACKET *pkt,
|
||||
const OSSL_QUIC_FRAME_STOP_SENDING *f)
|
||||
{
|
||||
if (!encode_frame_hdr(pkt, OSSL_QUIC_FRAME_TYPE_STOP_SENDING)
|
||||
|| !WPACKET_quic_write_vlint(pkt, f->stream_id)
|
||||
|| !WPACKET_quic_write_vlint(pkt, f->app_error_code))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ossl_quic_wire_encode_frame_crypto_hdr(WPACKET *pkt,
|
||||
const OSSL_QUIC_FRAME_CRYPTO *f)
|
||||
{
|
||||
if (!encode_frame_hdr(pkt, OSSL_QUIC_FRAME_TYPE_CRYPTO)
|
||||
|| !WPACKET_quic_write_vlint(pkt, f->offset)
|
||||
|| !WPACKET_quic_write_vlint(pkt, f->len))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void *ossl_quic_wire_encode_frame_crypto(WPACKET *pkt,
|
||||
const OSSL_QUIC_FRAME_CRYPTO *f)
|
||||
{
|
||||
unsigned char *p = NULL;
|
||||
|
||||
if (!ossl_quic_wire_encode_frame_crypto_hdr(pkt, f)
|
||||
|| !WPACKET_allocate_bytes(pkt, f->len, &p))
|
||||
return NULL;
|
||||
|
||||
if (f->data != NULL)
|
||||
memcpy(p, f->data, f->len);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
int ossl_quic_wire_encode_frame_new_token(WPACKET *pkt,
|
||||
const unsigned char *token,
|
||||
size_t token_len)
|
||||
{
|
||||
if (!encode_frame_hdr(pkt, OSSL_QUIC_FRAME_TYPE_NEW_TOKEN)
|
||||
|| !WPACKET_quic_write_vlint(pkt, token_len)
|
||||
|| !WPACKET_memcpy(pkt, token, token_len))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ossl_quic_wire_encode_frame_stream_hdr(WPACKET *pkt,
|
||||
const OSSL_QUIC_FRAME_STREAM *f)
|
||||
{
|
||||
uint64_t frame_type = OSSL_QUIC_FRAME_TYPE_STREAM;
|
||||
|
||||
if (f->offset != 0)
|
||||
frame_type |= OSSL_QUIC_FRAME_FLAG_STREAM_OFF;
|
||||
if (f->has_explicit_len)
|
||||
frame_type |= OSSL_QUIC_FRAME_FLAG_STREAM_LEN;
|
||||
if (f->is_fin)
|
||||
frame_type |= OSSL_QUIC_FRAME_FLAG_STREAM_FIN;
|
||||
|
||||
if (!encode_frame_hdr(pkt, frame_type)
|
||||
|| !WPACKET_quic_write_vlint(pkt, f->stream_id))
|
||||
return 0;
|
||||
|
||||
if (f->offset != 0 && !WPACKET_quic_write_vlint(pkt, f->offset))
|
||||
return 0;
|
||||
|
||||
if (f->has_explicit_len && !WPACKET_quic_write_vlint(pkt, f->len))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void *ossl_quic_wire_encode_frame_stream(WPACKET *pkt,
|
||||
const OSSL_QUIC_FRAME_STREAM *f)
|
||||
{
|
||||
|
||||
unsigned char *p = NULL;
|
||||
|
||||
if (!ossl_quic_wire_encode_frame_stream_hdr(pkt, f))
|
||||
return NULL;
|
||||
|
||||
if (!WPACKET_allocate_bytes(pkt, f->len, &p))
|
||||
return NULL;
|
||||
|
||||
if (f->data != NULL)
|
||||
memcpy(p, f->data, f->len);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
int ossl_quic_wire_encode_frame_max_data(WPACKET *pkt,
|
||||
uint64_t max_data)
|
||||
{
|
||||
if (!encode_frame_hdr(pkt, OSSL_QUIC_FRAME_TYPE_MAX_DATA)
|
||||
|| !WPACKET_quic_write_vlint(pkt, max_data))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ossl_quic_wire_encode_frame_max_stream_data(WPACKET *pkt,
|
||||
uint64_t stream_id,
|
||||
uint64_t max_data)
|
||||
{
|
||||
if (!encode_frame_hdr(pkt, OSSL_QUIC_FRAME_TYPE_MAX_STREAM_DATA)
|
||||
|| !WPACKET_quic_write_vlint(pkt, stream_id)
|
||||
|| !WPACKET_quic_write_vlint(pkt, max_data))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ossl_quic_wire_encode_frame_max_streams(WPACKET *pkt,
|
||||
char is_uni,
|
||||
uint64_t max_streams)
|
||||
{
|
||||
if (!encode_frame_hdr(pkt, is_uni ? OSSL_QUIC_FRAME_TYPE_MAX_STREAMS_UNI
|
||||
: OSSL_QUIC_FRAME_TYPE_MAX_STREAMS_BIDI)
|
||||
|| !WPACKET_quic_write_vlint(pkt, max_streams))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ossl_quic_wire_encode_frame_data_blocked(WPACKET *pkt,
|
||||
uint64_t max_data)
|
||||
{
|
||||
if (!encode_frame_hdr(pkt, OSSL_QUIC_FRAME_TYPE_DATA_BLOCKED)
|
||||
|| !WPACKET_quic_write_vlint(pkt, max_data))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int ossl_quic_wire_encode_frame_stream_data_blocked(WPACKET *pkt,
|
||||
uint64_t stream_id,
|
||||
uint64_t max_stream_data)
|
||||
{
|
||||
if (!encode_frame_hdr(pkt, OSSL_QUIC_FRAME_TYPE_STREAM_DATA_BLOCKED)
|
||||
|| !WPACKET_quic_write_vlint(pkt, stream_id)
|
||||
|| !WPACKET_quic_write_vlint(pkt, max_stream_data))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ossl_quic_wire_encode_frame_streams_blocked(WPACKET *pkt,
|
||||
char is_uni,
|
||||
uint64_t max_streams)
|
||||
{
|
||||
if (!encode_frame_hdr(pkt, is_uni ? OSSL_QUIC_FRAME_TYPE_STREAMS_BLOCKED_UNI
|
||||
: OSSL_QUIC_FRAME_TYPE_STREAMS_BLOCKED_BIDI)
|
||||
|| !WPACKET_quic_write_vlint(pkt, max_streams))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ossl_quic_wire_encode_frame_new_conn_id(WPACKET *pkt,
|
||||
const OSSL_QUIC_FRAME_NEW_CONN_ID *f)
|
||||
{
|
||||
if (f->conn_id.id_len > OSSL_QUIC_MAX_CONN_ID_LEN)
|
||||
return 0;
|
||||
|
||||
if (!encode_frame_hdr(pkt, OSSL_QUIC_FRAME_TYPE_NEW_CONN_ID)
|
||||
|| !WPACKET_quic_write_vlint(pkt, f->seq_num)
|
||||
|| !WPACKET_quic_write_vlint(pkt, f->retire_prior_to)
|
||||
|| !WPACKET_put_bytes_u8(pkt, f->conn_id.id_len)
|
||||
|| !WPACKET_memcpy(pkt, f->conn_id.id, f->conn_id.id_len)
|
||||
|| !WPACKET_memcpy(pkt, f->stateless_reset_token,
|
||||
sizeof(f->stateless_reset_token)))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ossl_quic_wire_encode_frame_retire_conn_id(WPACKET *pkt,
|
||||
uint64_t seq_num)
|
||||
{
|
||||
if (!encode_frame_hdr(pkt, OSSL_QUIC_FRAME_TYPE_RETIRE_CONN_ID)
|
||||
|| !WPACKET_quic_write_vlint(pkt, seq_num))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ossl_quic_wire_encode_frame_path_challenge(WPACKET *pkt,
|
||||
uint64_t data)
|
||||
{
|
||||
if (!encode_frame_hdr(pkt, OSSL_QUIC_FRAME_TYPE_PATH_CHALLENGE)
|
||||
|| !WPACKET_put_bytes_u64(pkt, data))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ossl_quic_wire_encode_frame_path_response(WPACKET *pkt,
|
||||
uint64_t data)
|
||||
{
|
||||
if (!encode_frame_hdr(pkt, OSSL_QUIC_FRAME_TYPE_PATH_RESPONSE)
|
||||
|| !WPACKET_put_bytes_u64(pkt, data))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ossl_quic_wire_encode_frame_conn_close(WPACKET *pkt,
|
||||
const OSSL_QUIC_FRAME_CONN_CLOSE *f)
|
||||
{
|
||||
if (!encode_frame_hdr(pkt, f->is_app ? OSSL_QUIC_FRAME_TYPE_CONN_CLOSE_APP
|
||||
: OSSL_QUIC_FRAME_TYPE_CONN_CLOSE_TRANSPORT)
|
||||
|| !WPACKET_quic_write_vlint(pkt, f->error_code))
|
||||
return 0;
|
||||
|
||||
if (!f->is_app && !WPACKET_quic_write_vlint(pkt, f->frame_type))
|
||||
return 0;
|
||||
|
||||
if (!WPACKET_quic_write_vlint(pkt, f->reason_len)
|
||||
|| !WPACKET_memcpy(pkt, f->reason, f->reason_len))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ossl_quic_wire_encode_frame_handshake_done(WPACKET *pkt)
|
||||
{
|
||||
return encode_frame_hdr(pkt, OSSL_QUIC_FRAME_TYPE_HANDSHAKE_DONE);
|
||||
}
|
||||
|
||||
unsigned char *ossl_quic_wire_encode_transport_param_bytes(WPACKET *pkt,
|
||||
uint64_t id,
|
||||
const unsigned char *value,
|
||||
size_t value_len)
|
||||
{
|
||||
unsigned char *b = NULL;
|
||||
|
||||
if (!WPACKET_quic_write_vlint(pkt, id)
|
||||
|| !WPACKET_quic_write_vlint(pkt, value_len)
|
||||
|| !WPACKET_allocate_bytes(pkt, value_len, (unsigned char **)&b))
|
||||
return NULL;
|
||||
|
||||
if (value != NULL)
|
||||
memcpy(b, value, value_len);
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
int ossl_quic_wire_encode_transport_param_int(WPACKET *pkt,
|
||||
uint64_t id,
|
||||
uint64_t value)
|
||||
{
|
||||
if (!WPACKET_quic_write_vlint(pkt, id)
|
||||
|| !WPACKET_quic_write_vlint(pkt, ossl_quic_vlint_encode_len(value))
|
||||
|| !WPACKET_quic_write_vlint(pkt, value))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* QUIC Wire Format Decoding
|
||||
* =========================
|
||||
*/
|
||||
int ossl_quic_wire_peek_frame_header(PACKET *pkt, uint64_t *type)
|
||||
{
|
||||
return PACKET_peek_quic_vlint(pkt, type);
|
||||
}
|
||||
|
||||
int ossl_quic_wire_skip_frame_header(PACKET *pkt, uint64_t *type)
|
||||
{
|
||||
return PACKET_get_quic_vlint(pkt, type);
|
||||
}
|
||||
|
||||
static int expect_frame_header_mask(PACKET *pkt,
|
||||
uint64_t expected_frame_type,
|
||||
uint64_t mask_bits,
|
||||
uint64_t *actual_frame_type)
|
||||
{
|
||||
uint64_t actual_frame_type_;
|
||||
|
||||
if (!ossl_quic_wire_skip_frame_header(pkt, &actual_frame_type_)
|
||||
|| (actual_frame_type_ & ~mask_bits) != expected_frame_type)
|
||||
return 0;
|
||||
|
||||
if (actual_frame_type != NULL)
|
||||
*actual_frame_type = actual_frame_type_;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int expect_frame_header(PACKET *pkt, uint64_t expected_frame_type)
|
||||
{
|
||||
uint64_t actual_frame_type;
|
||||
|
||||
if (!ossl_quic_wire_skip_frame_header(pkt, &actual_frame_type)
|
||||
|| actual_frame_type != expected_frame_type)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ossl_quic_wire_peek_frame_ack_num_ranges(const PACKET *orig_pkt,
|
||||
uint64_t *total_ranges)
|
||||
{
|
||||
PACKET pkt = *orig_pkt;
|
||||
uint64_t ack_range_count;
|
||||
|
||||
if (!expect_frame_header_mask(&pkt, OSSL_QUIC_FRAME_TYPE_ACK_WITHOUT_ECN,
|
||||
1, NULL)
|
||||
|| !PACKET_skip_quic_vlint(&pkt)
|
||||
|| !PACKET_skip_quic_vlint(&pkt)
|
||||
|| !PACKET_get_quic_vlint(&pkt, &ack_range_count))
|
||||
return 0;
|
||||
|
||||
/* (cannot overflow because QUIC vlints can only encode up to 2**62-1) */
|
||||
*total_ranges = ack_range_count + 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ossl_quic_wire_decode_frame_ack(PACKET *pkt,
|
||||
uint32_t ack_delay_exponent,
|
||||
OSSL_QUIC_FRAME_ACK *ack,
|
||||
uint64_t *total_ranges) {
|
||||
uint64_t frame_type, largest_ackd, ack_delay_raw;
|
||||
uint64_t ack_range_count, first_ack_range, start, end, i;
|
||||
|
||||
/* This call matches both ACK_WITHOUT_ECN and ACK_WITH_ECN. */
|
||||
if (!expect_frame_header_mask(pkt, OSSL_QUIC_FRAME_TYPE_ACK_WITHOUT_ECN,
|
||||
1, &frame_type)
|
||||
|| !PACKET_get_quic_vlint(pkt, &largest_ackd)
|
||||
|| !PACKET_get_quic_vlint(pkt, &ack_delay_raw)
|
||||
|| !PACKET_get_quic_vlint(pkt, &ack_range_count)
|
||||
|| !PACKET_get_quic_vlint(pkt, &first_ack_range))
|
||||
return 0;
|
||||
|
||||
if (first_ack_range > largest_ackd)
|
||||
return 0;
|
||||
|
||||
start = largest_ackd - first_ack_range;
|
||||
|
||||
if (ack != NULL) {
|
||||
int err = 0;
|
||||
ack->delay_time
|
||||
= ossl_time_multiply(OSSL_TIME_US,
|
||||
safe_mul_uint64_t(ack_delay_raw,
|
||||
1UL << ack_delay_exponent,
|
||||
&err));
|
||||
if (err)
|
||||
ack->delay_time = OSSL_TIME_INFINITY;
|
||||
|
||||
if (ack->num_ack_ranges > 0) {
|
||||
ack->ack_ranges[0].end = largest_ackd;
|
||||
ack->ack_ranges[0].start = start;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < ack_range_count; ++i) {
|
||||
uint64_t gap, len;
|
||||
|
||||
if (!PACKET_get_quic_vlint(pkt, &gap)
|
||||
|| !PACKET_get_quic_vlint(pkt, &len))
|
||||
return 0;
|
||||
|
||||
end = start - gap - 2;
|
||||
if (start < gap + 2 || len > end)
|
||||
return 0;
|
||||
|
||||
if (ack != NULL && i + 1 < ack->num_ack_ranges) {
|
||||
ack->ack_ranges[i + 1].start = start = end - len;
|
||||
ack->ack_ranges[i + 1].end = end;
|
||||
}
|
||||
}
|
||||
|
||||
if (ack != NULL && ack_range_count + 1 < ack->num_ack_ranges)
|
||||
ack->num_ack_ranges = ack_range_count + 1;
|
||||
|
||||
if (total_ranges != NULL)
|
||||
*total_ranges = ack_range_count + 1;
|
||||
|
||||
if (frame_type == OSSL_QUIC_FRAME_TYPE_ACK_WITH_ECN) {
|
||||
uint64_t ect0, ect1, ecnce;
|
||||
|
||||
if (!PACKET_get_quic_vlint(pkt, &ect0)
|
||||
|| !PACKET_get_quic_vlint(pkt, &ect1)
|
||||
|| !PACKET_get_quic_vlint(pkt, &ecnce))
|
||||
return 0;
|
||||
|
||||
if (ack != NULL) {
|
||||
ack->ect0 = ect0;
|
||||
ack->ect1 = ect1;
|
||||
ack->ecnce = ecnce;
|
||||
ack->ecn_present = 1;
|
||||
}
|
||||
} else if (ack != NULL) {
|
||||
ack->ecn_present = 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ossl_quic_wire_decode_frame_reset_stream(PACKET *pkt,
|
||||
OSSL_QUIC_FRAME_RESET_STREAM *f)
|
||||
{
|
||||
if (!expect_frame_header(pkt, OSSL_QUIC_FRAME_TYPE_RESET_STREAM)
|
||||
|| !PACKET_get_quic_vlint(pkt, &f->stream_id)
|
||||
|| !PACKET_get_quic_vlint(pkt, &f->app_error_code)
|
||||
|| !PACKET_get_quic_vlint(pkt, &f->final_size))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ossl_quic_wire_decode_frame_stop_sending(PACKET *pkt,
|
||||
OSSL_QUIC_FRAME_STOP_SENDING *f)
|
||||
{
|
||||
if (!expect_frame_header(pkt, OSSL_QUIC_FRAME_TYPE_STOP_SENDING)
|
||||
|| !PACKET_get_quic_vlint(pkt, &f->stream_id)
|
||||
|| !PACKET_get_quic_vlint(pkt, &f->app_error_code))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ossl_quic_wire_decode_frame_crypto(PACKET *pkt,
|
||||
OSSL_QUIC_FRAME_CRYPTO *f)
|
||||
{
|
||||
if (!expect_frame_header(pkt, OSSL_QUIC_FRAME_TYPE_CRYPTO)
|
||||
|| !PACKET_get_quic_vlint(pkt, &f->offset)
|
||||
|| !PACKET_get_quic_vlint(pkt, &f->len))
|
||||
return 0;
|
||||
|
||||
if (PACKET_remaining(pkt) < f->len)
|
||||
return 0;
|
||||
|
||||
f->data = PACKET_data(pkt);
|
||||
|
||||
if (!PACKET_forward(pkt, f->len))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ossl_quic_wire_decode_frame_new_token(PACKET *pkt,
|
||||
const unsigned char **token,
|
||||
size_t *token_len)
|
||||
{
|
||||
uint64_t token_len_;
|
||||
|
||||
if (!expect_frame_header(pkt, OSSL_QUIC_FRAME_TYPE_NEW_TOKEN)
|
||||
|| !PACKET_get_quic_vlint(pkt, &token_len_))
|
||||
return 0;
|
||||
|
||||
if (token_len_ > SIZE_MAX)
|
||||
return 0;
|
||||
|
||||
*token = PACKET_data(pkt);
|
||||
*token_len = token_len_;
|
||||
|
||||
if (!PACKET_forward(pkt, token_len_))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ossl_quic_wire_decode_frame_stream(PACKET *pkt,
|
||||
OSSL_QUIC_FRAME_STREAM *f)
|
||||
{
|
||||
uint64_t frame_type;
|
||||
|
||||
/* This call matches all STREAM values (low 3 bits are masked). */
|
||||
if (!expect_frame_header_mask(pkt, OSSL_QUIC_FRAME_TYPE_STREAM,
|
||||
OSSL_QUIC_FRAME_FLAG_STREAM_MASK,
|
||||
&frame_type)
|
||||
|| !PACKET_get_quic_vlint(pkt, &f->stream_id))
|
||||
return 0;
|
||||
|
||||
if ((frame_type & OSSL_QUIC_FRAME_FLAG_STREAM_OFF) != 0) {
|
||||
if (!PACKET_get_quic_vlint(pkt, &f->offset))
|
||||
return 0;
|
||||
} else {
|
||||
f->offset = 0;
|
||||
}
|
||||
|
||||
f->has_explicit_len = ((frame_type & OSSL_QUIC_FRAME_FLAG_STREAM_LEN) != 0);
|
||||
f->is_fin = ((frame_type & OSSL_QUIC_FRAME_FLAG_STREAM_FIN) != 0);
|
||||
|
||||
if (f->has_explicit_len) {
|
||||
if (!PACKET_get_quic_vlint(pkt, &f->len))
|
||||
return 0;
|
||||
} else {
|
||||
f->len = PACKET_remaining(pkt);
|
||||
}
|
||||
|
||||
f->data = PACKET_data(pkt);
|
||||
|
||||
if (!PACKET_forward(pkt, f->len))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ossl_quic_wire_decode_frame_max_data(PACKET *pkt,
|
||||
uint64_t *max_data)
|
||||
{
|
||||
if (!expect_frame_header(pkt, OSSL_QUIC_FRAME_TYPE_MAX_DATA)
|
||||
|| !PACKET_get_quic_vlint(pkt, max_data))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ossl_quic_wire_decode_frame_max_stream_data(PACKET *pkt,
|
||||
uint64_t *stream_id,
|
||||
uint64_t *max_stream_data)
|
||||
{
|
||||
if (!expect_frame_header(pkt, OSSL_QUIC_FRAME_TYPE_MAX_STREAM_DATA)
|
||||
|| !PACKET_get_quic_vlint(pkt, stream_id)
|
||||
|| !PACKET_get_quic_vlint(pkt, max_stream_data))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ossl_quic_wire_decode_frame_max_streams(PACKET *pkt,
|
||||
uint64_t *max_streams)
|
||||
{
|
||||
/* This call matches both MAX_STREAMS_BIDI and MAX_STREAMS_UNI. */
|
||||
if (!expect_frame_header_mask(pkt, OSSL_QUIC_FRAME_TYPE_MAX_STREAMS_BIDI,
|
||||
1, NULL)
|
||||
|| !PACKET_get_quic_vlint(pkt, max_streams))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ossl_quic_wire_decode_frame_data_blocked(PACKET *pkt,
|
||||
uint64_t *max_data)
|
||||
{
|
||||
if (!expect_frame_header(pkt, OSSL_QUIC_FRAME_TYPE_DATA_BLOCKED)
|
||||
|| !PACKET_get_quic_vlint(pkt, max_data))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ossl_quic_wire_decode_frame_stream_data_blocked(PACKET *pkt,
|
||||
uint64_t *stream_id,
|
||||
uint64_t *max_stream_data)
|
||||
{
|
||||
if (!expect_frame_header(pkt, OSSL_QUIC_FRAME_TYPE_STREAM_DATA_BLOCKED)
|
||||
|| !PACKET_get_quic_vlint(pkt, stream_id)
|
||||
|| !PACKET_get_quic_vlint(pkt, max_stream_data))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ossl_quic_wire_decode_frame_streams_blocked(PACKET *pkt,
|
||||
uint64_t *max_streams)
|
||||
{
|
||||
/* This call matches both STREAMS_BLOCKED_BIDI and STREAMS_BLOCKED_UNI. */
|
||||
if (!expect_frame_header_mask(pkt, OSSL_QUIC_FRAME_TYPE_STREAMS_BLOCKED_BIDI,
|
||||
1, NULL)
|
||||
|| !PACKET_get_quic_vlint(pkt, max_streams))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ossl_quic_wire_decode_frame_new_conn_id(PACKET *pkt,
|
||||
OSSL_QUIC_FRAME_NEW_CONN_ID *f)
|
||||
{
|
||||
unsigned int len;
|
||||
|
||||
if (!expect_frame_header(pkt, OSSL_QUIC_FRAME_TYPE_NEW_CONN_ID)
|
||||
|| !PACKET_get_quic_vlint(pkt, &f->seq_num)
|
||||
|| !PACKET_get_quic_vlint(pkt, &f->retire_prior_to)
|
||||
|| !PACKET_get_1(pkt, &len)
|
||||
|| len > OSSL_QUIC_MAX_CONN_ID_LEN)
|
||||
return 0;
|
||||
|
||||
f->conn_id.id_len = (unsigned char)len;
|
||||
if (!PACKET_copy_bytes(pkt, f->conn_id.id, len))
|
||||
return 0;
|
||||
|
||||
/* Clear unused bytes to allow consistent memcmp. */
|
||||
if (len < OSSL_QUIC_MAX_CONN_ID_LEN)
|
||||
memset(f->conn_id.id + len, 0, OSSL_QUIC_MAX_CONN_ID_LEN - len);
|
||||
|
||||
if (!PACKET_copy_bytes(pkt, f->stateless_reset_token,
|
||||
sizeof(f->stateless_reset_token)))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ossl_quic_wire_decode_frame_retire_conn_id(PACKET *pkt,
|
||||
uint64_t *seq_num)
|
||||
{
|
||||
if (!expect_frame_header(pkt, OSSL_QUIC_FRAME_TYPE_RETIRE_CONN_ID)
|
||||
|| !PACKET_get_quic_vlint(pkt, seq_num))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ossl_quic_wire_decode_frame_path_challenge(PACKET *pkt,
|
||||
uint64_t *data)
|
||||
{
|
||||
if (!expect_frame_header(pkt, OSSL_QUIC_FRAME_TYPE_PATH_CHALLENGE)
|
||||
|| !PACKET_get_net_8(pkt, data))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ossl_quic_wire_decode_frame_path_response(PACKET *pkt,
|
||||
uint64_t *data)
|
||||
{
|
||||
if (!expect_frame_header(pkt, OSSL_QUIC_FRAME_TYPE_PATH_RESPONSE)
|
||||
|| !PACKET_get_net_8(pkt, data))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ossl_quic_wire_decode_frame_conn_close(PACKET *pkt,
|
||||
OSSL_QUIC_FRAME_CONN_CLOSE *f)
|
||||
{
|
||||
uint64_t frame_type, reason_len;
|
||||
|
||||
/* This call matches both CONN_CLOSE_TRANSPORT and CONN_CLOSE_APP. */
|
||||
if (!expect_frame_header_mask(pkt, OSSL_QUIC_FRAME_TYPE_CONN_CLOSE_TRANSPORT,
|
||||
1, &frame_type)
|
||||
|| !PACKET_get_quic_vlint(pkt, &f->error_code))
|
||||
return 0;
|
||||
|
||||
f->is_app = ((frame_type & 1) != 0);
|
||||
|
||||
if (!f->is_app) {
|
||||
if (!PACKET_get_quic_vlint(pkt, &f->frame_type))
|
||||
return 0;
|
||||
} else {
|
||||
f->frame_type = 0;
|
||||
}
|
||||
|
||||
if (!PACKET_get_quic_vlint(pkt, &reason_len)
|
||||
|| reason_len > SIZE_MAX)
|
||||
return 0;
|
||||
|
||||
if (!PACKET_get_bytes(pkt, (const unsigned char **)&f->reason, reason_len))
|
||||
return 0;
|
||||
|
||||
f->reason_len = reason_len;
|
||||
return 1;
|
||||
}
|
||||
|
||||
size_t ossl_quic_wire_decode_padding(PACKET *pkt)
|
||||
{
|
||||
const unsigned char *start = PACKET_data(pkt), *end = PACKET_end(pkt),
|
||||
*p = start;
|
||||
|
||||
while (p < end && *p == 0)
|
||||
++p;
|
||||
|
||||
if (!PACKET_forward(pkt, p - start))
|
||||
return 0;
|
||||
|
||||
return p - start;
|
||||
}
|
||||
|
||||
int ossl_quic_wire_decode_frame_ping(PACKET *pkt)
|
||||
{
|
||||
return expect_frame_header(pkt, OSSL_QUIC_FRAME_TYPE_PING);
|
||||
}
|
||||
|
||||
int ossl_quic_wire_decode_frame_handshake_done(PACKET *pkt)
|
||||
{
|
||||
return expect_frame_header(pkt, OSSL_QUIC_FRAME_TYPE_HANDSHAKE_DONE);
|
||||
}
|
||||
|
||||
int ossl_quic_wire_peek_transport_param(PACKET *pkt, uint64_t *id)
|
||||
{
|
||||
return PACKET_peek_quic_vlint(pkt, id);
|
||||
}
|
||||
|
||||
const unsigned char *ossl_quic_wire_decode_transport_param_bytes(PACKET *pkt,
|
||||
uint64_t *id,
|
||||
size_t *len)
|
||||
{
|
||||
uint64_t len_;
|
||||
const unsigned char *b = NULL;
|
||||
|
||||
if (!PACKET_get_quic_vlint(pkt, id)
|
||||
|| !PACKET_get_quic_vlint(pkt, &len_))
|
||||
return NULL;
|
||||
|
||||
if (len_ > SIZE_MAX
|
||||
|| !PACKET_get_bytes(pkt, (const unsigned char **)&b, (size_t)len_))
|
||||
return NULL;
|
||||
|
||||
*len = (size_t)len_;
|
||||
return b;
|
||||
}
|
||||
|
||||
int ossl_quic_wire_decode_transport_param_int(PACKET *pkt,
|
||||
uint64_t *id,
|
||||
uint64_t *value)
|
||||
{
|
||||
PACKET sub;
|
||||
|
||||
sub.curr = ossl_quic_wire_decode_transport_param_bytes(pkt,
|
||||
id, &sub.remaining);
|
||||
if (sub.curr == NULL)
|
||||
return 0;
|
||||
|
||||
if (!PACKET_get_quic_vlint(&sub, value))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
@ -278,6 +278,10 @@ IF[{- !$disabled{tests} -}]
|
||||
INCLUDE[packettest]=../include ../apps/include
|
||||
DEPEND[packettest]=../libcrypto libtestutil.a
|
||||
|
||||
SOURCE[quic_wire_test]=quic_wire_test.c
|
||||
INCLUDE[quic_wire_test]=../include ../apps/include
|
||||
DEPEND[quic_wire_test]=../libcrypto.a ../libssl.a libtestutil.a
|
||||
|
||||
SOURCE[asynctest]=asynctest.c
|
||||
INCLUDE[asynctest]=../include ../apps/include
|
||||
DEPEND[asynctest]=../libcrypto
|
||||
@ -953,7 +957,7 @@ ENDIF
|
||||
DEPEND[build_wincrypt_test]=../libssl ../libcrypto
|
||||
|
||||
IF[{- !$disabled{'quic'} -}]
|
||||
PROGRAMS{noinst}=quicapitest
|
||||
PROGRAMS{noinst}=quicapitest quic_wire_test
|
||||
ENDIF
|
||||
|
||||
SOURCE[quicapitest]=quicapitest.c helpers/ssltestlib.c
|
||||
|
1364
test/quic_wire_test.c
Normal file
1364
test/quic_wire_test.c
Normal file
File diff suppressed because it is too large
Load Diff
19
test/recipes/70-test_quic_wire.t
Normal file
19
test/recipes/70-test_quic_wire.t
Normal file
@ -0,0 +1,19 @@
|
||||
#! /usr/bin/env perl
|
||||
# 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
|
||||
|
||||
use OpenSSL::Test;
|
||||
use OpenSSL::Test::Utils;
|
||||
|
||||
setup("test_quic_wire");
|
||||
|
||||
plan skip_all => "QUIC protocol is not supported by this OpenSSL build"
|
||||
if disabled('quic');
|
||||
|
||||
plan tests => 1;
|
||||
|
||||
ok(run(test(["quic_wire_test"])));
|
Loading…
Reference in New Issue
Block a user