BIO_s_dgram_pair

Reviewed-by: Matt Caswell <matt@openssl.org>
Reviewed-by: Paul Dale <pauli@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/18442)
This commit is contained in:
Hugo Landau 2022-05-31 20:22:40 +01:00 committed by Pauli
parent a29ad912b8
commit b88ce46ee8
14 changed files with 1809 additions and 12 deletions

View File

@ -78,6 +78,8 @@ static const ERR_STRING_DATA BIO_str_reasons[] = {
{ERR_PACK(ERR_LIB_BIO, 0, BIO_R_WSASTARTUP), "WSAStartup"},
{ERR_PACK(ERR_LIB_BIO, 0, BIO_R_LOCAL_ADDR_NOT_AVAILABLE),
"local address not available"},
{ERR_PACK(ERR_LIB_BIO, 0, BIO_R_PEER_ADDR_NOT_AVAILABLE),
"peer address not available"},
{ERR_PACK(ERR_LIB_BIO, 0, BIO_R_NON_FATAL),
"non-fatal or transient error"},
{ERR_PACK(ERR_LIB_BIO, 0, BIO_R_PORT_MISMATCH),

1136
crypto/bio/bss_dgram_pair.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -11,7 +11,7 @@ SOURCE[../../libcrypto]=\
SOURCE[../../libcrypto]=\
bss_null.c bss_mem.c bss_bio.c bss_fd.c bss_file.c \
bss_sock.c bss_conn.c bss_acpt.c bss_dgram.c \
bss_log.c bss_core.c
bss_log.c bss_core.c bss_dgram_pair.c
# Filters
SOURCE[../../libcrypto]=\

View File

@ -146,12 +146,14 @@ BIO_R_LOCAL_ADDR_NOT_AVAILABLE:111:local addr not available
BIO_R_LOOKUP_RETURNED_NOTHING:142:lookup returned nothing
BIO_R_MALFORMED_HOST_OR_SERVICE:130:malformed host or service
BIO_R_NBIO_CONNECT_ERROR:110:nbio connect error
BIO_R_NON_FATAL:112:non fatal
BIO_R_NO_ACCEPT_ADDR_OR_SERVICE_SPECIFIED:143:\
no accept addr or service specified
BIO_R_NO_HOSTNAME_OR_SERVICE_SPECIFIED:144:no hostname or service specified
BIO_R_NO_PORT_DEFINED:113:no port defined
BIO_R_NO_SUCH_FILE:128:no such file
BIO_R_PORT_MISMATCH:150:port mismatch
BIO_R_PEER_ADDR_NOT_AVAILABLE:114:peer addr not available
BIO_R_TFO_DISABLED:106:tfo disabled
BIO_R_TFO_NO_KERNEL_SUPPORT:108:tfo no kernel support
BIO_R_TRANSFER_ERROR:104:transfer error

View File

@ -651,6 +651,10 @@ DEPEND[html/man3/BIO_s_core.html]=man3/BIO_s_core.pod
GENERATE[html/man3/BIO_s_core.html]=man3/BIO_s_core.pod
DEPEND[man/man3/BIO_s_core.3]=man3/BIO_s_core.pod
GENERATE[man/man3/BIO_s_core.3]=man3/BIO_s_core.pod
DEPEND[html/man3/BIO_s_dgram_pair.html]=man3/BIO_s_dgram_pair.pod
GENERATE[html/man3/BIO_s_dgram_pair.html]=man3/BIO_s_dgram_pair.pod
DEPEND[man/man3/BIO_s_dgram_pair.3]=man3/BIO_s_dgram_pair.pod
GENERATE[man/man3/BIO_s_dgram_pair.3]=man3/BIO_s_dgram_pair.pod
DEPEND[html/man3/BIO_s_fd.html]=man3/BIO_s_fd.pod
GENERATE[html/man3/BIO_s_fd.html]=man3/BIO_s_fd.pod
DEPEND[man/man3/BIO_s_fd.3]=man3/BIO_s_fd.pod
@ -2914,6 +2918,7 @@ html/man3/BIO_s_accept.html \
html/man3/BIO_s_bio.html \
html/man3/BIO_s_connect.html \
html/man3/BIO_s_core.html \
html/man3/BIO_s_dgram_pair.html \
html/man3/BIO_s_fd.html \
html/man3/BIO_s_file.html \
html/man3/BIO_s_mem.html \
@ -3514,6 +3519,7 @@ man/man3/BIO_s_accept.3 \
man/man3/BIO_s_bio.3 \
man/man3/BIO_s_connect.3 \
man/man3/BIO_s_core.3 \
man/man3/BIO_s_dgram_pair.3 \
man/man3/BIO_s_fd.3 \
man/man3/BIO_s_file.3 \
man/man3/BIO_s_mem.3 \

View File

@ -0,0 +1,222 @@
=pod
=head1 NAME
BIO_s_dgram_pair, BIO_new_bio_dgram_pair, BIO_dgram_set_no_trunc,
BIO_dgram_get_no_trunc, BIO_dgram_get_effective_caps, BIO_dgram_get_caps,
BIO_dgram_set_caps, BIO_dgram_set_mtu, BIO_dgram_get_mtu - datagram pair BIO
=head1 SYNOPSIS
#include <openssl/bio.h>
const BIO_METHOD *BIO_s_dgram_pair(void);
int BIO_new_bio_dgram_pair(BIO **bio1, size_t writebuf1,
BIO **bio2, size_t writebuf2);
int BIO_dgram_set_no_trunc(BIO *bio, int enable);
int BIO_dgram_get_no_trunc(BIO *bio);
uint32_t BIO_dgram_get_effective_caps(BIO *bio);
uint32_t BIO_dgram_get_caps(BIO *bio);
int BIO_dgram_set_caps(BIO *bio, uint32_t caps);
int BIO_dgram_set_mtu(BIO *bio, unsigned int mtu);
unsigned int BIO_dgram_get_mtu(BIO *bio);
=head1 DESCRIPTION
BIO_s_dgram_pair() returns the method for a BIO datagram pair. A BIO datagram
pair is similar to a BIO pair (see L<BIO_s_bio(3)>) but has datagram semantics.
Broadly, this means that the length of the buffer passed to a write call will
match that retrieved by a read call. If the buffer passed to a read call is too
short, the datagram is truncated or the read fails, depending on how the BIO is
configured.
The BIO datagram pair attaches certain metadata to each write, such as source
and destination addresses. This information may be retrieved on read.
A typical application of a BIO datagram pair is to allow an application to keep
all datagram network I/O requested by libssl under application control.
The BIO datagram pair is designed to support multithreaded use where certain
restrictions are observed; see THREADING.
The BIO datagram pair allows each half of a pair to signal to the other half
whether they support certain capabilities; see CAPABILITY INDICATION.
BIO_new_bio_dgram_pair() combines the calls to L<BIO_new(3)>,
L<BIO_make_bio_pair(3)> and L<BIO_set_write_buf_size(3)> to create a connected
pair of BIOs B<bio1>, B<bio2> with write buffer sizes B<writebuf1> and
B<writebuf2>. If either size is zero then the default size is used.
L<BIO_make_bio_pair(3)> may be used to join two datagram pair BIOs into a pair.
The two BIOs must both use the method returned by BIO_s_dgram_pair() and neither
of the BIOs may currently be associated in a pair.
L<BIO_destroy_bio_pair(3)> destroys the association between two connected BIOs.
Freeing either half of the pair will automatically destroy the association.
L<BIO_reset(3)> clears any data in the write buffer of the given BIO. This means
that the opposite BIO in the pair will no longer have any data waiting to be
read.
The BIO maintains a fixed size internal write buffer. When the buffer is full,
further writes will fail until the buffer is drained via calls to
L<BIO_read(3)>. The size of the buffer can be changed using
L<BIO_set_write_buf_size(3)> and queried using L<BIO_get_write_buf_size(3)>.
Note that the write buffer is partially consumed by metadata stored internally
which is attached to each datagram, such as source and destination addresses.
The size of this overhead is undefined and may change between releases.
The standard L<BIO_ctrl_pending(3)> call has modified behaviour and returns the
size of the next datagram waiting to be read in bytes. An application can use
this function to ensure it provides an adequate buffer to a subsequent read
call. If no datagram is waiting to be read, zero is returned.
This BIO does not support sending or receiving zero-length datagrams. Passing a
zero-length buffer to BIO_write is treated as a no-op.
L<BIO_eof(3)> returns 1 only if the given BIO datagram pair BIO is not currently
connected to a peer BIO.
L<BIO_get_write_guarantee(3)> and L<BIO_ctrl_get_write_guarantee(3)> return how
large a datagram the next call to L<BIO_write(3)> can accept. If there is not
enough space in the write buffer to accept another datagram equal in size to the
configured MTU, zero is returned (see below). This is intended to avoid a
situation where an application attempts to read a datagram from a network
intending to write it to a BIO datagram pair, but where the received datagram
ends up being too large to write to the BIO datagram pair.
BIO_dgram_set_no_trunc() and BIO_ctrl_get_no_trunc() set and retrieve the
truncation mode for the given half of a BIO datagram pair. When no-truncate mode
is enabled, BIO_read() will fail if the buffer provided is inadequate to hold
the next datagram to be read. If no-truncate mode is disabled (the default), the
datagram will be silently truncated. This default behaviour maintains
compatibility with the semantics of the Berkeley sockets API.
BIO_dgram_set_mtu() and BIO_dgram_get_mtu() may be used to set an informational
MTU value on the BIO datagram pair. If BIO_dgram_set_mtu() is used on a BIO
which is currently part of a BIO datagram pair, the MTU value is set on both
halves of the pair. The value does not affect the operation of the BIO datagram
pair (except for BIO_get_write_guarantee(); see above) but may be used by other
code to determine a requested MTU. When a BIO datagram pair BIO is created, the
MTU is set to an unspecified but valid value.
L<BIO_flush(3)> is a no-op.
=head1 NOTES
The halves of a BIO datagram pair have independent lifetimes and must be
separately freed.
=head1 THREADING
L<BIO_recvmmsg(3)>, L<BIO_sendmmsg(3)>, L<BIO_read(3)>, L<BIO_write(3)>,
L<BIO_pending(3)>, L<BIO_get_write_guarantee(3)> and L<BIO_flush(3)> may be used
by multiple threads simultaneously on the same BIO datagram pair. Specific
L<BIO_ctrl(3)> operations (namely BIO_CTRL_PENDING, BIO_CTRL_FLUSH and
BIO_C_GET_WRITE_GUARANTEE) may also be used. Invoking any other BIO call, or any
other L<BIO_ctrl(3)> operation, on either half of a BIO datagram pair while any
other BIO call is also in progress to either half of the same BIO datagram pair
results in undefined behaviour.
=head1 CAPABILITY INDICATION
The BIO datagram pair can be used to enqueue datagrams which have source and
destination addresses attached. It is important that the component consuming one
side of a BIO datagram pair understand whether the other side of the pair will
honour any source and destination addresses it attaches to each datagram. For
example, if datagrams are queued with destination addresses set but simply read
by simple calls to L<BIO_read(3)>, the destination addresses will be discarded.
Each half of a BIO datagram pair can have capability flags set on it which
indicate whether source and destination addresses will be honoured by the reader
and whether they will be provided by the writer. These capability flags should
be set via a call to BIO_dgram_set_caps(), and these capabilities will be
reflected in the value returned by BIO_dgram_get_effective_caps() on the
opposite BIO. If necessary, the capability value previously set can be retrieved
using BIO_dgram_get_caps(). Note that BIO_dgram_set_caps() on a given BIO
controls the capabilities advertised to the peer, and
BIO_dgram_get_effective_caps() on a given BIO determines the capabilities
advertised by the peer of that BIO.
The following capabilities are available:
=over 4
=item B<BIO_DGRAM_CAP_HANDLES_SRC_ADDR>
The user of the datagram pair BIO promises to honour source addresses provided
with datagrams written to the BIO pair.
=item B<BIO_DGRAM_CAP_HANDLES_DST_ADDR>
The user of the datagram pair BIO promises to honour destination addresses provided
with datagrams written to the BIO pair.
=item B<BIO_DGRAM_CAP_PROVIDES_SRC_ADDR>
The user of the datagram pair BIO advertises the fact that it will provide source
addressing information with future writes to the BIO pair, where available.
=item B<BIO_DGRAM_CAP_PROVIDES_DST_ADDR>
The user of the datagram pair BIO advertises the fact that it will provide
destination addressing information with future writes to the BIO pair, where
available.
=back
If a caller attempts to specify a destination address (for example, using
L<BIO_sendmmsg(3)>) and the peer has not advertised the
B<BIO_DGRAM_CAP_HANDLES_DST_ADDR> capability, the operation fails. Thus,
capability negotiation is mandatory.
If a caller attempts to specify a source address when writing, or requests a
destination address when receiving, and local address support has not been
enabled, the operation fails; see L<BIO_dgram_set_local_addr_enable(3)>.
If a caller attempts to enable local address support using
L<BIO_dgram_set_local_addr_enable(3)> and L<BIO_dgram_get_local_addr_cap(3)>
does not return 1 (meaning that the peer has not advertised both the
B<BIO_DGRAM_CAP_HANDLES_SRC_ADDR> and the B<BIO_DGRAM_CAP_PROVIDES_DST_ADDR>
capability), the operation fails.
B<BIO_DGRAM_CAP_PROVIDES_SRC_ADDR> and B<BIO_DGRAM_CAP_PROVIDES_DST_ADDR>
indicate that the application using that half of a BIO datagram pair promises to
provide source and destination addresses respectively when writing datagrams to
that half of the BIO datagram pair. However, these capability flags do not
affect the behaviour of the BIO datagram pair.
=head1 RETURN VALUES
BIO_new_bio_dgram_pair() returns 1 on success, with the new BIOs available in
B<bio1> and B<bio2>, or 0 on failure, with NULL pointers stored into the
locations for B<bio1> and B<bio2>. Check the error stack for more information.
BIO_dgram_set_no_trunc(), BIO_dgram_set_caps() and BIO_dgram_set_mtu() return 1
on success and 0 on failure.
BIO_dgram_get_no_trunc() returns 1 if no-truncate mode is enabled on a BIO, or 0
if no-truncate mode is not enabled or not supported on a given BIO.
BIO_dgram_get_effective_caps() and BIO_dgram_get_caps() return zero if no
capabilities are supported.
BIO_dgram_get_mtu() returns the MTU value configured on the BIO, or zero if the
operation is not supported.
=head1 SEE ALSO
L<BIO_s_bio(3)>, L<bio(7)>
=head1 COPYRIGHT
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
L<https://www.openssl.org/source/license.html>.
=cut

View File

@ -158,6 +158,11 @@ particular may be noted:
The I<local> field was set to a non-NULL value, but local address support is not
available or not enabled on the BIO.
=item B<BIO_R_PEER_ADDR_NOT_AVAILABLE>
The I<peer> field was set to a non-NULL value, but peer address support is not
available on the BIO.
=item B<BIO_R_UNSUPPORTED_METHOD>
The BIO_sendmmsg() or BIO_recvmmsg() method is not supported on the BIO.

View File

@ -68,6 +68,7 @@ extern "C" {
# define BIO_TYPE_DGRAM_SCTP (24|BIO_TYPE_SOURCE_SINK|BIO_TYPE_DESCRIPTOR)
# endif
# define BIO_TYPE_CORE_TO_PROV (25|BIO_TYPE_SOURCE_SINK)
# define BIO_TYPE_DGRAM_PAIR (26|BIO_TYPE_SOURCE_SINK)
#define BIO_TYPE_START 128
@ -175,6 +176,17 @@ extern "C" {
# define BIO_CTRL_DGRAM_GET_LOCAL_ADDR_CAP 82
# define BIO_CTRL_DGRAM_GET_LOCAL_ADDR_ENABLE 83
# define BIO_CTRL_DGRAM_SET_LOCAL_ADDR_ENABLE 84
# define BIO_CTRL_DGRAM_GET_EFFECTIVE_CAPS 85
# define BIO_CTRL_DGRAM_GET_CAPS 86
# define BIO_CTRL_DGRAM_SET_CAPS 87
# define BIO_CTRL_DGRAM_GET_NO_TRUNC 88
# define BIO_CTRL_DGRAM_SET_NO_TRUNC 89
# define BIO_DGRAM_CAP_NONE 0U
# define BIO_DGRAM_CAP_HANDLES_SRC_ADDR (1U << 0)
# define BIO_DGRAM_CAP_HANDLES_DST_ADDR (1U << 1)
# define BIO_DGRAM_CAP_PROVIDES_SRC_ADDR (1U << 2)
# define BIO_DGRAM_CAP_PROVIDES_DST_ADDR (1U << 3)
# ifndef OPENSSL_NO_KTLS
# define BIO_get_ktls_send(b) \
@ -607,6 +619,20 @@ int BIO_ctrl_reset_read_request(BIO *b);
(int)BIO_ctrl((b), BIO_CTRL_DGRAM_GET_LOCAL_ADDR_ENABLE, 0, (char *)(penable))
# define BIO_dgram_set_local_addr_enable(b, enable) \
(int)BIO_ctrl((b), BIO_CTRL_DGRAM_SET_LOCAL_ADDR_ENABLE, (enable), NULL)
# define BIO_dgram_get_effective_caps(b) \
(uint32_t)BIO_ctrl((b), BIO_CTRL_DGRAM_GET_EFFECTIVE_CAPS, 0, NULL)
# define BIO_dgram_get_caps(b) \
(uint32_t)BIO_ctrl((b), BIO_CTRL_DGRAM_GET_CAPS, 0, NULL)
# define BIO_dgram_set_caps(b, caps) \
(int)BIO_ctrl((b), BIO_CTRL_DGRAM_SET_CAPS, (long)(caps), NULL)
# define BIO_dgram_get_no_trunc(b) \
(unsigned int)BIO_ctrl((b), BIO_CTRL_DGRAM_GET_NO_TRUNC, 0, NULL)
# define BIO_dgram_set_no_trunc(b, enable) \
(int)BIO_ctrl((b), BIO_CTRL_DGRAM_SET_NO_TRUNC, (enable), NULL)
# define BIO_dgram_get_mtu(b) \
(unsigned int)BIO_ctrl((b), BIO_CTRL_DGRAM_GET_MTU, 0, NULL)
# define BIO_dgram_set_mtu(b, mtu) \
(int)BIO_ctrl((b), BIO_CTRL_DGRAM_SET_MTU, (mtu), NULL)
/* ctrl macros for BIO_f_prefix */
# define BIO_set_prefix(b,p) BIO_ctrl((b), BIO_CTRL_SET_PREFIX, 0, (void *)(p))
@ -702,6 +728,7 @@ const BIO_METHOD *BIO_f_nbio_test(void);
const BIO_METHOD *BIO_f_prefix(void);
const BIO_METHOD *BIO_s_core(void);
# ifndef OPENSSL_NO_DGRAM
const BIO_METHOD *BIO_s_dgram_pair(void);
const BIO_METHOD *BIO_s_datagram(void);
int BIO_dgram_non_fatal_error(int error);
BIO *BIO_new_dgram(int fd, int close_flag);
@ -824,6 +851,11 @@ BIO *BIO_new_fd(int fd, int close_flag);
int BIO_new_bio_pair(BIO **bio1, size_t writebuf1,
BIO **bio2, size_t writebuf2);
# ifndef OPENSSL_NO_DGRAM
int BIO_new_bio_dgram_pair(BIO **bio1, size_t writebuf1,
BIO **bio2, size_t writebuf2);
# endif
/*
* If successful, returns 1 and in *bio1, *bio2 two BIO pair endpoints.
* Otherwise returns 0 and sets *bio1 and *bio2 to NULL. Size 0 uses default

View File

@ -41,10 +41,12 @@
# define BIO_R_LOOKUP_RETURNED_NOTHING 142
# define BIO_R_MALFORMED_HOST_OR_SERVICE 130
# define BIO_R_NBIO_CONNECT_ERROR 110
# define BIO_R_NON_FATAL 112
# define BIO_R_NO_ACCEPT_ADDR_OR_SERVICE_SPECIFIED 143
# define BIO_R_NO_HOSTNAME_OR_SERVICE_SPECIFIED 144
# define BIO_R_NO_PORT_DEFINED 113
# define BIO_R_NO_SUCH_FILE 128
# define BIO_R_NULL_PARAMETER 115 /* unused */
# define BIO_R_TFO_DISABLED 106
# define BIO_R_TFO_NO_KERNEL_SUPPORT 108
# define BIO_R_TRANSFER_ERROR 104
@ -64,7 +66,7 @@
# define BIO_R_UNSUPPORTED_PROTOCOL_FAMILY 131
# define BIO_R_WRITE_TO_READ_ONLY_BIO 126
# define BIO_R_WSASTARTUP 122
# define BIO_R_NON_FATAL 149
# define BIO_R_PORT_MISMATCH 150
# define BIO_R_PEER_ADDR_NOT_AVAILABLE 151
#endif

View File

@ -1,5 +1,5 @@
/*
* Copyright 2021 The OpenSSL Project Authors. All Rights Reserved.
* 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
@ -9,6 +9,7 @@
#include <string.h>
#include <openssl/bio.h>
#include <openssl/rand.h>
#include "testutil.h"
#include "internal/sockets.h"
@ -450,6 +451,299 @@ static int test_bio_dgram(int idx)
bio_dgram_cases[idx].local);
}
static int random_data(const uint32_t *key, uint8_t *data, size_t data_len, size_t offset)
{
int ret = 0, outl;
EVP_CIPHER_CTX *ctx = NULL;
EVP_CIPHER *cipher = NULL;
static const uint8_t zeroes[2048];
uint32_t counter[4] = {0};
counter[0] = (uint32_t)offset;
ctx = EVP_CIPHER_CTX_new();
if (ctx == NULL)
goto err;
cipher = EVP_CIPHER_fetch(NULL, "ChaCha20", NULL);
if (cipher == NULL)
goto err;
if (EVP_EncryptInit_ex2(ctx, cipher, (uint8_t *)key, (uint8_t *)counter, NULL) == 0)
goto err;
while (data_len > 0) {
outl = data_len > sizeof(zeroes) ? (int)sizeof(zeroes) : (int)data_len;
if (EVP_EncryptUpdate(ctx, data, &outl, zeroes, outl) != 1)
goto err;
data += outl;
data_len -= outl;
}
ret = 1;
err:
EVP_CIPHER_CTX_free(ctx);
EVP_CIPHER_free(cipher);
return ret;
}
static int test_bio_dgram_pair(void)
{
int testresult = 0, blen, mtu1, mtu2, r;
BIO *bio1 = NULL, *bio2 = NULL;
uint8_t scratch[2048 + 4], scratch2[2048];
uint32_t key[8];
size_t i, num_dgram, num_processed = 0;
BIO_MSG msgs[2] = {0}, rmsgs[2] = {0};
BIO_ADDR *addr1 = NULL, *addr2 = NULL, *addr3 = NULL, *addr4 = NULL;
struct in_addr in_local;
size_t total = 0;
const uint32_t ref_caps = BIO_DGRAM_CAP_HANDLES_SRC_ADDR
| BIO_DGRAM_CAP_HANDLES_DST_ADDR
| BIO_DGRAM_CAP_PROVIDES_SRC_ADDR
| BIO_DGRAM_CAP_PROVIDES_DST_ADDR;
in_local.s_addr = ntohl(0x7f000001);
for (i = 0; i < OSSL_NELEM(key); ++i)
key[i] = test_random();
if (!TEST_int_eq(BIO_new_bio_dgram_pair(&bio1, 0, &bio2, 0), 1))
goto err;
mtu1 = BIO_dgram_get_mtu(bio1);
if (!TEST_int_ge(mtu1, 1280))
goto err;
mtu2 = BIO_dgram_get_mtu(bio2);
if (!TEST_int_ge(mtu2, 1280))
goto err;
if (!TEST_int_eq(mtu1, mtu2))
goto err;
if (!TEST_int_le(mtu1, sizeof(scratch) - 4))
goto err;
for (i = 0;; ++i) {
if (!TEST_int_eq(random_data(key, scratch, sizeof(scratch), i), 1))
goto err;
blen = (*(uint32_t*)scratch) % mtu1;
r = BIO_write(bio1, scratch + 4, blen);
if (r == -1)
break;
if (!TEST_int_eq(r, blen))
goto err;
total += blen;
if (!TEST_size_t_lt(total, 1 * 1024 * 1024))
goto err;
}
/*
* Should be able to fit at least 9 datagrams in default write buffer size
* in worst case
*/
if (!TEST_int_ge(i, 9))
goto err;
/* Check we read back the same data */
num_dgram = i;
for (i = 0; i < num_dgram; ++i) {
if (!TEST_int_eq(random_data(key, scratch, sizeof(scratch), i), 1))
goto err;
blen = (*(uint32_t*)scratch) % mtu1;
r = BIO_read(bio2, scratch2, sizeof(scratch2));
if (!TEST_int_eq(r, blen))
goto err;
if (!TEST_mem_eq(scratch + 4, blen, scratch2, blen))
goto err;
}
/* Should now be out of data */
if (!TEST_int_eq(BIO_read(bio2, scratch2, sizeof(scratch2)), -1))
goto err;
/* sendmmsg/recvmmsg */
if (!TEST_int_eq(random_data(key, scratch, sizeof(scratch), 0), 1))
goto err;
msgs[0].data = scratch;
msgs[0].data_len = 19;
msgs[1].data = scratch + 19;
msgs[1].data_len = 46;
if (!TEST_true(BIO_sendmmsg(bio1, msgs, sizeof(BIO_MSG), OSSL_NELEM(msgs), 0,
&num_processed))
|| !TEST_size_t_eq(num_processed, 2))
goto err;
rmsgs[0].data = scratch2;
rmsgs[0].data_len = 64;
rmsgs[1].data = scratch2 + 64;
rmsgs[1].data_len = 64;
if (!TEST_true(BIO_recvmmsg(bio2, rmsgs, sizeof(BIO_MSG), OSSL_NELEM(rmsgs), 0,
&num_processed))
|| !TEST_size_t_eq(num_processed, 2))
goto err;
if (!TEST_mem_eq(rmsgs[0].data, rmsgs[0].data_len, scratch, 19))
goto err;
if (!TEST_mem_eq(rmsgs[1].data, rmsgs[1].data_len, scratch + 19, 46))
goto err;
/* sendmmsg/recvmmsg with peer */
addr1 = BIO_ADDR_new();
if (!TEST_ptr(addr1))
goto err;
if (!TEST_int_eq(BIO_ADDR_rawmake(addr1, AF_INET, &in_local,
sizeof(in_local), 1234), 1))
goto err;
addr2 = BIO_ADDR_new();
if (!TEST_ptr(addr2))
goto err;
if (!TEST_int_eq(BIO_ADDR_rawmake(addr2, AF_INET, &in_local,
sizeof(in_local), 2345), 1))
goto err;
addr3 = BIO_ADDR_new();
if (!TEST_ptr(addr3))
goto err;
addr4 = BIO_ADDR_new();
if (!TEST_ptr(addr4))
goto err;
msgs[0].peer = addr1;
/* fails due to lack of caps on peer */
if (!TEST_false(BIO_sendmmsg(bio1, msgs, sizeof(BIO_MSG), OSSL_NELEM(msgs),
0, &num_processed))
|| !TEST_size_t_eq(num_processed, 0))
goto err;
if (!TEST_int_eq(BIO_dgram_set_caps(bio2, ref_caps), 1))
goto err;
if (!TEST_int_eq(BIO_dgram_get_caps(bio2), ref_caps))
goto err;
if (!TEST_int_eq(BIO_dgram_get_effective_caps(bio1), ref_caps))
goto err;
if (!TEST_int_eq(BIO_dgram_get_effective_caps(bio2), 0))
goto err;
if (!TEST_int_eq(BIO_dgram_set_caps(bio1, ref_caps), 1))
goto err;
/* succeeds with cap now available */
if (!TEST_true(BIO_sendmmsg(bio1, msgs, sizeof(BIO_MSG), 1, 0, &num_processed))
|| !TEST_size_t_eq(num_processed, 1))
goto err;
/* enable local addr support */
if (!TEST_int_eq(BIO_dgram_set_local_addr_enable(bio2, 1), 1))
goto err;
rmsgs[0].data = scratch2;
rmsgs[0].data_len = 64;
rmsgs[0].peer = addr3;
rmsgs[0].local = addr4;
if (!TEST_true(BIO_recvmmsg(bio2, rmsgs, sizeof(BIO_MSG), OSSL_NELEM(rmsgs), 0,
&num_processed))
|| !TEST_size_t_eq(num_processed, 1))
goto err;
if (!TEST_mem_eq(rmsgs[0].data, rmsgs[0].data_len, msgs[0].data, 19))
goto err;
/* We didn't set the source address so this should be zero */
if (!TEST_int_eq(BIO_ADDR_family(addr3), 0))
goto err;
if (!TEST_int_eq(BIO_ADDR_family(addr4), AF_INET))
goto err;
if (!TEST_int_eq(BIO_ADDR_rawport(addr4), 1234))
goto err;
/* test source address */
msgs[0].local = addr2;
if (!TEST_int_eq(BIO_dgram_set_local_addr_enable(bio1, 1), 1))
goto err;
if (!TEST_true(BIO_sendmmsg(bio1, msgs, sizeof(BIO_MSG), 1, 0, &num_processed))
|| !TEST_size_t_eq(num_processed, 1))
goto err;
rmsgs[0].data = scratch2;
rmsgs[0].data_len = 64;
if (!TEST_true(BIO_recvmmsg(bio2, rmsgs, sizeof(BIO_MSG), OSSL_NELEM(rmsgs), 0, &num_processed))
|| !TEST_size_t_eq(num_processed, 1))
goto err;
if (!TEST_mem_eq(rmsgs[0].data, rmsgs[0].data_len,
msgs[0].data, msgs[0].data_len))
goto err;
if (!TEST_int_eq(BIO_ADDR_family(addr3), AF_INET))
goto err;
if (!TEST_int_eq(BIO_ADDR_rawport(addr3), 2345))
goto err;
if (!TEST_int_eq(BIO_ADDR_family(addr4), AF_INET))
goto err;
if (!TEST_int_eq(BIO_ADDR_rawport(addr4), 1234))
goto err;
/* test truncation, pending */
r = BIO_write(bio1, scratch, 64);
if (!TEST_int_eq(r, 64))
goto err;
memset(scratch2, 0, 64);
if (!TEST_int_eq(BIO_dgram_set_no_trunc(bio2, 1), 1))
goto err;
if (!TEST_int_eq(BIO_read(bio2, scratch2, 32), -1))
goto err;
if (!TEST_int_eq(BIO_pending(bio2), 64))
goto err;
if (!TEST_int_eq(BIO_dgram_set_no_trunc(bio2, 0), 1))
goto err;
if (!TEST_int_eq(BIO_read(bio2, scratch2, 32), 32))
goto err;
if (!TEST_mem_eq(scratch, 32, scratch2, 32))
goto err;
testresult = 1;
err:
BIO_free(bio1);
BIO_free(bio2);
BIO_ADDR_free(addr1);
BIO_ADDR_free(addr2);
BIO_ADDR_free(addr3);
BIO_ADDR_free(addr4);
return testresult;
}
#endif /* !defined(OPENSSL_NO_DGRAM) && !defined(OPENSSL_NO_SOCK) */
int setup_tests(void)
@ -461,6 +755,8 @@ int setup_tests(void)
#if !defined(OPENSSL_NO_DGRAM) && !defined(OPENSSL_NO_SOCK)
ADD_ALL_TESTS(test_bio_dgram, OSSL_NELEM(bio_dgram_cases));
ADD_TEST(test_bio_dgram_pair);
#endif
return 1;
}

View File

@ -63,7 +63,7 @@ IF[{- !$disabled{tests} -}]
keymgmt_internal_test hexstr_test provider_status_test defltfips_test \
bio_readbuffer_test user_property_test pkcs7_test upcallstest \
provfetchtest prov_config_test rand_test ca_internals_test \
bio_tfo_test membio_test list_test fips_version_test
bio_tfo_test membio_test bio_dgram_test list_test fips_version_test
IF[{- !$disabled{'deprecated-3.0'} -}]
PROGRAMS{noinst}=enginetest
@ -404,6 +404,10 @@ IF[{- !$disabled{tests} -}]
INCLUDE[membio_test]=../include ../apps/include ..
DEPEND[membio_test]=../libcrypto libtestutil.a
SOURCE[bio_dgram_test]=bio_dgram_test.c
INCLUDE[bio_dgram_test]=../include ../apps/include ..
DEPEND[bio_dgram_test]=../libcrypto libtestutil.a
SOURCE[params_api_test]=params_api_test.c
INCLUDE[params_api_test]=../include ../apps/include
DEPEND[params_api_test]=../libcrypto libtestutil.a

View File

@ -24,6 +24,7 @@
#include <openssl/rsa.h>
#include <openssl/aes.h>
#include <openssl/err.h>
#include <openssl/rand.h>
#include "internal/tsan_assist.h"
#include "internal/nelem.h"
#include "testutil.h"
@ -44,6 +45,8 @@ static const char *default_provider[] = { "default", NULL };
static const char *fips_provider[] = { "fips", NULL };
static const char *fips_and_default_providers[] = { "default", "fips", NULL };
static CRYPTO_RWLOCK *global_lock;
#ifdef TSAN_REQUIRES_LOCKING
static CRYPTO_RWLOCK *tsan_lock;
#endif
@ -266,6 +269,19 @@ static void multi_intialise(void)
memset(multi_provider, 0, sizeof(multi_provider));
}
static void multi_set_success(int ok)
{
if (CRYPTO_THREAD_write_lock(global_lock) == 0) {
/* not synchronized, but better than not reporting failure */
multi_success = ok;
return;
}
multi_success = ok;
CRYPTO_THREAD_unlock(global_lock);
}
static void thead_teardown_libctx(void)
{
OSSL_PROVIDER **p;
@ -407,7 +423,7 @@ static void thread_general_worker(void)
EVP_CIPHER_free(ciph);
EVP_PKEY_free(pkey);
if (!testresult)
multi_success = 0;
multi_set_success(0);
}
static void thread_multi_simple_fetch(void)
@ -417,7 +433,7 @@ static void thread_multi_simple_fetch(void)
if (md != NULL)
EVP_MD_free(md);
else
multi_success = 0;
multi_set_success(0);
}
static EVP_PKEY *shared_evp_pkey = NULL;
@ -466,7 +482,7 @@ static void thread_shared_evp_pkey(void)
err:
EVP_PKEY_CTX_free(ctx);
if (!success)
multi_success = 0;
multi_set_success(0);
}
static void thread_provider_load_unload(void)
@ -475,7 +491,7 @@ static void thread_provider_load_unload(void)
if (!TEST_ptr(deflt)
|| !TEST_true(OSSL_PROVIDER_available(multi_libctx, "default")))
multi_success = 0;
multi_set_success(0);
OSSL_PROVIDER_unload(deflt);
}
@ -532,7 +548,7 @@ static void thread_downgrade_shared_evp_pkey(void)
* downgrading
*/
if (EVP_PKEY_get0_RSA(shared_evp_pkey) == NULL)
multi_success = 0;
multi_set_success(0);
}
static int test_multi_downgrade_shared_pkey(void)
@ -588,7 +604,7 @@ static void test_multi_load_worker(void)
if (!TEST_ptr(prov = OSSL_PROVIDER_load(multi_libctx, multi_load_provider))
|| !TEST_true(OSSL_PROVIDER_unload(prov)))
multi_success = 0;
multi_set_success(0);
}
static int test_multi_default(void)
@ -644,7 +660,7 @@ static void test_obj_create_one(void)
if (!TEST_int_ne(id, 0)
|| !TEST_true(id = OBJ_create(oid, sn, ln))
|| !TEST_true(OBJ_add_sigid(id, NID_sha3_256, NID_rsa)))
multi_success = 0;
multi_set_success(0);
}
static int test_obj_add(void)
@ -657,7 +673,7 @@ static int test_obj_add(void)
static void test_lib_ctx_load_config_worker(void)
{
if (!TEST_int_eq(OSSL_LIB_CTX_load_config(multi_libctx, config_file), 1))
multi_success = 0;
multi_set_success(0);
}
static int test_lib_ctx_load_config(void)
@ -667,6 +683,64 @@ static int test_lib_ctx_load_config(void)
1, default_provider);
}
#if !defined(OPENSSL_NO_DGRAM) && !defined(OPENSSL_NO_SOCK)
static BIO *multi_bio1, *multi_bio2;
static void test_bio_dgram_pair_worker(void)
{
ossl_unused int r;
int ok = 0;
uint8_t ch = 0;
uint8_t scratch[64];
BIO_MSG msg = {0};
size_t num_processed = 0;
if (!TEST_int_eq(RAND_bytes_ex(multi_libctx, &ch, 1, 64), 1))
goto err;
msg.data = scratch;
msg.data_len = sizeof(scratch);
/*
* We do not test for failure here as recvmmsg may fail if no sendmmsg
* has been called yet. The purpose of this code is to exercise tsan.
*/
if (ch & 2)
r = BIO_sendmmsg(ch & 1 ? multi_bio2 : multi_bio1, &msg,
sizeof(BIO_MSG), 1, 0, &num_processed);
else
r = BIO_recvmmsg(ch & 1 ? multi_bio2 : multi_bio1, &msg,
sizeof(BIO_MSG), 1, 0, &num_processed);
ok = 1;
err:
if (ok == 0)
multi_set_success(0);
}
static int test_bio_dgram_pair(void)
{
int r;
BIO *bio1 = NULL, *bio2 = NULL;
r = BIO_new_bio_dgram_pair(&bio1, 0, &bio2, 0);
if (!TEST_int_eq(r, 1))
goto err;
multi_bio1 = bio1;
multi_bio2 = bio2;
r = thread_run_test(&test_bio_dgram_pair_worker,
MAXIMUM_THREADS, &test_bio_dgram_pair_worker,
1, default_provider);
err:
BIO_free(bio1);
BIO_free(bio2);
return r;
}
#endif
typedef enum OPTION_choice {
OPT_ERR = -1,
OPT_EOF = 0,
@ -713,6 +787,9 @@ int setup_tests(void)
if (!TEST_ptr(privkey))
return 0;
if (!TEST_ptr(global_lock = CRYPTO_THREAD_lock_new()))
return 0;
#ifdef TSAN_REQUIRES_LOCKING
if (!TEST_ptr(tsan_lock = CRYPTO_THREAD_lock_new()))
return 0;
@ -736,6 +813,9 @@ int setup_tests(void)
ADD_TEST(test_multi_load_unload_provider);
ADD_TEST(test_obj_add);
ADD_TEST(test_lib_ctx_load_config);
#if !defined(OPENSSL_NO_DGRAM) && !defined(OPENSSL_NO_SOCK)
ADD_TEST(test_bio_dgram_pair);
#endif
return 1;
}
@ -745,4 +825,5 @@ void cleanup_tests(void)
#ifdef TSAN_REQUIRES_LOCKING
CRYPTO_THREAD_lock_free(tsan_lock);
#endif
CRYPTO_THREAD_lock_free(global_lock);
}

View File

@ -5459,3 +5459,5 @@ BIO_err_is_non_fatal ? 3_1_0 EXIST::FUNCTION:SOCK
X509_get_default_cert_uri ? 3_1_0 EXIST::FUNCTION:
X509_get_default_cert_uri_env ? 3_1_0 EXIST::FUNCTION:
X509_get_default_cert_path_env ? 3_1_0 EXIST::FUNCTION:
BIO_s_dgram_pair ? 3_1_0 EXIST::FUNCTION:DGRAM
BIO_new_bio_dgram_pair ? 3_1_0 EXIST::FUNCTION:DGRAM

View File

@ -148,6 +148,13 @@ BIO_destroy_bio_pair define
BIO_dgram_get_local_addr_cap define
BIO_dgram_get_local_addr_enable define
BIO_dgram_set_local_addr_enable define
BIO_dgram_set_no_trunc define
BIO_dgram_get_no_trunc define
BIO_dgram_get_caps define
BIO_dgram_set_caps define
BIO_dgram_get_effective_caps define
BIO_dgram_get_mtu define
BIO_dgram_set_mtu define
BIO_do_accept define
BIO_do_connect define
BIO_do_handshake define