mirror of
https://github.com/openssl/openssl.git
synced 2025-01-18 13:44:20 +08:00
Add a test for retries when sending app data
Reviewed-by: Hugo Landau <hlandau@openssl.org> Reviewed-by: Tomas Mraz <tomas@openssl.org> (Merged from https://github.com/openssl/openssl/pull/22473)
This commit is contained in:
parent
b9b9f4886f
commit
dbbdb940d4
@ -29,13 +29,15 @@ static int tls_dump_gets(BIO *bp, char *buf, int size);
|
||||
static int tls_dump_puts(BIO *bp, const char *str);
|
||||
|
||||
/* Choose a sufficiently large type likely to be unused for this custom BIO */
|
||||
#define BIO_TYPE_TLS_DUMP_FILTER (0x80 | BIO_TYPE_FILTER)
|
||||
#define BIO_TYPE_TLS_DUMP_FILTER (0x80 | BIO_TYPE_FILTER)
|
||||
#define BIO_TYPE_MEMPACKET_TEST 0x81
|
||||
#define BIO_TYPE_ALWAYS_RETRY 0x82
|
||||
#define BIO_TYPE_MAYBE_RETRY (0x83 | BIO_TYPE_FILTER)
|
||||
|
||||
static BIO_METHOD *method_tls_dump = NULL;
|
||||
static BIO_METHOD *meth_mem = NULL;
|
||||
static BIO_METHOD *meth_always_retry = NULL;
|
||||
static BIO_METHOD *meth_maybe_retry = NULL;
|
||||
static int retry_err = -1;
|
||||
|
||||
/* Note: Not thread safe! */
|
||||
@ -804,6 +806,100 @@ static int always_retry_puts(BIO *bio, const char *str)
|
||||
return retry_err;
|
||||
}
|
||||
|
||||
struct maybe_retry_data_st {
|
||||
unsigned int retrycnt;
|
||||
};
|
||||
|
||||
static int maybe_retry_new(BIO *bi);
|
||||
static int maybe_retry_free(BIO *a);
|
||||
static int maybe_retry_write(BIO *b, const char *in, int inl);
|
||||
static long maybe_retry_ctrl(BIO *b, int cmd, long num, void *ptr);
|
||||
|
||||
const BIO_METHOD *bio_s_maybe_retry(void)
|
||||
{
|
||||
if (meth_maybe_retry == NULL) {
|
||||
if (!TEST_ptr(meth_maybe_retry = BIO_meth_new(BIO_TYPE_MAYBE_RETRY,
|
||||
"Maybe Retry"))
|
||||
|| !TEST_true(BIO_meth_set_write(meth_maybe_retry,
|
||||
maybe_retry_write))
|
||||
|| !TEST_true(BIO_meth_set_ctrl(meth_maybe_retry,
|
||||
maybe_retry_ctrl))
|
||||
|| !TEST_true(BIO_meth_set_create(meth_maybe_retry,
|
||||
maybe_retry_new))
|
||||
|| !TEST_true(BIO_meth_set_destroy(meth_maybe_retry,
|
||||
maybe_retry_free)))
|
||||
return NULL;
|
||||
}
|
||||
return meth_maybe_retry;
|
||||
}
|
||||
|
||||
void bio_s_maybe_retry_free(void)
|
||||
{
|
||||
BIO_meth_free(meth_maybe_retry);
|
||||
}
|
||||
|
||||
static int maybe_retry_new(BIO *bio)
|
||||
{
|
||||
struct maybe_retry_data_st *data = OPENSSL_zalloc(sizeof(*data));
|
||||
|
||||
if (data == NULL)
|
||||
return 0;
|
||||
|
||||
BIO_set_data(bio, data);
|
||||
BIO_set_init(bio, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int maybe_retry_free(BIO *bio)
|
||||
{
|
||||
struct maybe_retry_data_st *data = BIO_get_data(bio);
|
||||
|
||||
OPENSSL_free(data);
|
||||
BIO_set_data(bio, NULL);
|
||||
BIO_set_init(bio, 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int maybe_retry_write(BIO *bio, const char *in, int inl)
|
||||
{
|
||||
struct maybe_retry_data_st *data = BIO_get_data(bio);
|
||||
|
||||
if (data == NULL)
|
||||
return -1;
|
||||
|
||||
if (data->retrycnt == 0) {
|
||||
BIO_set_retry_write(bio);
|
||||
return -1;
|
||||
}
|
||||
data->retrycnt--;
|
||||
|
||||
return BIO_write(BIO_next(bio), in, inl);
|
||||
}
|
||||
|
||||
static long maybe_retry_ctrl(BIO *bio, int cmd, long num, void *ptr)
|
||||
{
|
||||
struct maybe_retry_data_st *data = BIO_get_data(bio);
|
||||
|
||||
if (data == NULL)
|
||||
return 0;
|
||||
|
||||
switch (cmd) {
|
||||
case MAYBE_RETRY_CTRL_SET_RETRY_AFTER_CNT:
|
||||
data->retrycnt = num;
|
||||
return 1;
|
||||
|
||||
case BIO_CTRL_FLUSH:
|
||||
if (data->retrycnt == 0) {
|
||||
BIO_set_retry_write(bio);
|
||||
return -1;
|
||||
}
|
||||
data->retrycnt--;
|
||||
/* fall through */
|
||||
default:
|
||||
return BIO_ctrl(BIO_next(bio), cmd, num, ptr);
|
||||
}
|
||||
}
|
||||
|
||||
int create_ssl_ctx_pair(OSSL_LIB_CTX *libctx, const SSL_METHOD *sm,
|
||||
const SSL_METHOD *cm, int min_proto_version,
|
||||
int max_proto_version, SSL_CTX **sctx, SSL_CTX **cctx,
|
||||
|
@ -44,6 +44,15 @@ const BIO_METHOD *bio_s_always_retry(void);
|
||||
void bio_s_always_retry_free(void);
|
||||
void set_always_retry_err_val(int err);
|
||||
|
||||
/*
|
||||
* Maybe retry BIO ctrls. We make them large enough to not clash with standard
|
||||
* BIO ctrl codes.
|
||||
*/
|
||||
#define MAYBE_RETRY_CTRL_SET_RETRY_AFTER_CNT (1 << 15)
|
||||
|
||||
const BIO_METHOD *bio_s_maybe_retry(void);
|
||||
void bio_s_maybe_retry_free(void);
|
||||
|
||||
/* Packet types - value 0 is reserved */
|
||||
#define INJECT_PACKET 1
|
||||
#define INJECT_PACKET_IGNORE_REC_SEQ 2
|
||||
|
@ -11138,6 +11138,102 @@ end:
|
||||
return testresult;
|
||||
}
|
||||
|
||||
/*
|
||||
* Test that receiving retries when writing application data works as expected
|
||||
*/
|
||||
static int test_data_retry(void)
|
||||
{
|
||||
SSL_CTX *cctx = NULL, *sctx = NULL;
|
||||
SSL *clientssl = NULL, *serverssl = NULL;
|
||||
int testresult = 0;
|
||||
unsigned char inbuf[1200], outbuf[1200];
|
||||
size_t i;
|
||||
BIO *tmp = NULL;
|
||||
BIO *bretry = BIO_new(bio_s_maybe_retry());
|
||||
size_t written, readbytes, totread = 0;
|
||||
|
||||
if (!TEST_ptr(bretry))
|
||||
goto end;
|
||||
|
||||
for (i = 0; i < sizeof(inbuf); i++)
|
||||
inbuf[i] = i;
|
||||
memset(outbuf, 0, sizeof(outbuf));
|
||||
|
||||
if (!TEST_true(create_ssl_ctx_pair(libctx, TLS_server_method(),
|
||||
TLS_client_method(), 0, 0, &sctx, &cctx,
|
||||
cert, privkey)))
|
||||
goto end;
|
||||
|
||||
if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl, &clientssl, NULL,
|
||||
NULL)))
|
||||
goto end;
|
||||
|
||||
if (!TEST_true(create_ssl_connection(serverssl, clientssl, SSL_ERROR_NONE)))
|
||||
goto end;
|
||||
|
||||
/* Smallest possible max send fragment is 512 */
|
||||
if (!TEST_true(SSL_set_max_send_fragment(clientssl, 512)))
|
||||
goto end;
|
||||
|
||||
tmp = SSL_get_wbio(clientssl);
|
||||
if (!TEST_ptr(tmp))
|
||||
goto end;
|
||||
if (!TEST_true(BIO_up_ref(tmp)))
|
||||
goto end;
|
||||
BIO_push(bretry, tmp);
|
||||
tmp = NULL;
|
||||
SSL_set0_wbio(clientssl, bretry);
|
||||
if (!BIO_up_ref(bretry)) {
|
||||
bretry = NULL;
|
||||
goto end;
|
||||
}
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
/* We expect this call to make no progress and indicate retry */
|
||||
if (!TEST_false(SSL_write_ex(clientssl, inbuf, sizeof(inbuf), &written)))
|
||||
goto end;
|
||||
if (!TEST_int_eq(SSL_get_error(clientssl, 0), SSL_ERROR_WANT_WRITE))
|
||||
goto end;
|
||||
|
||||
/* Allow one write to progess, but the next one to signal retry */
|
||||
if (!TEST_true(BIO_ctrl(bretry, MAYBE_RETRY_CTRL_SET_RETRY_AFTER_CNT, 1,
|
||||
NULL)))
|
||||
goto end;
|
||||
|
||||
if (i == 2)
|
||||
break;
|
||||
|
||||
/*
|
||||
* This call will hopefully make progress but will still indicate retry
|
||||
* because there is more data than will fit into a single record.
|
||||
*/
|
||||
if (!TEST_false(SSL_write_ex(clientssl, inbuf, sizeof(inbuf), &written)))
|
||||
goto end;
|
||||
if (!TEST_int_eq(SSL_get_error(clientssl, 0), SSL_ERROR_WANT_WRITE))
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* The final call should write the last chunk of data and succeed */
|
||||
if (!TEST_true(SSL_write_ex(clientssl, inbuf, sizeof(inbuf), &written)))
|
||||
goto end;
|
||||
/* Read all the data available */
|
||||
while (SSL_read_ex(serverssl, outbuf + totread, sizeof(outbuf) - totread,
|
||||
&readbytes))
|
||||
totread += readbytes;
|
||||
if (!TEST_mem_eq(inbuf, sizeof(inbuf), outbuf, totread))
|
||||
goto end;
|
||||
|
||||
testresult = 1;
|
||||
end:
|
||||
SSL_free(serverssl);
|
||||
SSL_free(clientssl);
|
||||
SSL_CTX_free(sctx);
|
||||
SSL_CTX_free(cctx);
|
||||
BIO_free_all(bretry);
|
||||
BIO_free(tmp);
|
||||
return testresult;
|
||||
}
|
||||
|
||||
OPT_TEST_DECLARE_USAGE("certfile privkeyfile srpvfile tmpfile provider config dhfile\n")
|
||||
|
||||
int setup_tests(void)
|
||||
@ -11444,6 +11540,7 @@ int setup_tests(void)
|
||||
ADD_ALL_TESTS(test_version, 6);
|
||||
ADD_TEST(test_rstate_string);
|
||||
ADD_ALL_TESTS(test_handshake_retry, 16);
|
||||
ADD_TEST(test_data_retry);
|
||||
return 1;
|
||||
|
||||
err:
|
||||
@ -11473,6 +11570,7 @@ void cleanup_tests(void)
|
||||
OPENSSL_free(privkey8192);
|
||||
bio_s_mempacket_test_free();
|
||||
bio_s_always_retry_free();
|
||||
bio_s_maybe_retry_free();
|
||||
OSSL_PROVIDER_unload(defctxnull);
|
||||
OSSL_LIB_CTX_free(libctx);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user