Commit c748834f authored by Matt Caswell's avatar Matt Caswell
Browse files

Add a bi-directional shutdown test

parent 93f528f3
Loading
Loading
Loading
Loading
+123 −0
Original line number Diff line number Diff line
@@ -4972,6 +4972,128 @@ static int test_ticket_callbacks(int tst)
    return testresult;
}

/*
 * Test bi-directional shutdown.
 * Test 0: TLSv1.2
 * Test 1: TLSv1.2, server continues to read/write after client shutdown
 * Test 2: TLSv1.3, no pending NewSessionTicket messages
 * Test 3: TLSv1.3, pending NewSessionTicket messages
 * Test 4: TLSv1.3, server continues to read/write after client shutdown, client
 *                  reads it
 * Test 5: TLSv1.3, server continues to read/write after client shutdown, client
 *                  doesn't read it
 */
static int test_shutdown(int tst)
{
    SSL_CTX *cctx = NULL, *sctx = NULL;
    SSL *clientssl = NULL, *serverssl = NULL;
    int testresult = 0;
    char msg[] = "A test message";
    char buf[80];
    size_t written, readbytes;

#ifdef OPENSSL_NO_TLS1_2
    if (tst == 0)
        return 1;
#endif
#ifdef OPENSSL_NO_TLS1_3
    if (tst != 0)
        return 1;
#endif

    if (!TEST_true(create_ssl_ctx_pair(TLS_server_method(),
                                       TLS_client_method(),
                                       TLS1_VERSION,
                                       (tst <= 1) ? TLS1_2_VERSION
                                                  : TLS1_3_VERSION,
                                       &sctx, &cctx, cert, privkey))
            || !TEST_true(create_ssl_objects(sctx, cctx, &serverssl, &clientssl,
                                             NULL, NULL)))
        goto end;

    if (tst == 3) {
        if (!TEST_true(create_bare_ssl_connection(serverssl, clientssl,
                                                  SSL_ERROR_NONE)))
            goto end;
    } else if (!TEST_true(create_ssl_connection(serverssl, clientssl,
                                              SSL_ERROR_NONE))) {
        goto end;
    }

    if (!TEST_int_eq(SSL_shutdown(clientssl), 0))
        goto end;

    if (tst >= 4) {
        /*
         * Reading on the server after the client has sent close_notify should
         * fail and provide SSL_ERROR_ZERO_RETURN
         */
        if (!TEST_false(SSL_read_ex(serverssl, buf, sizeof(buf), &readbytes))
                || !TEST_int_eq(SSL_get_error(serverssl, 0),
                                SSL_ERROR_ZERO_RETURN)
                || !TEST_int_eq(SSL_get_shutdown(serverssl),
                                SSL_RECEIVED_SHUTDOWN)
                   /*
                    * Even though we're shutdown on receive we should still be
                    * able to write.
                    */
                || !TEST_true(SSL_write(serverssl, msg, sizeof(msg)))
                || !TEST_int_eq(SSL_shutdown(serverssl), 1))
            goto end;
        if (tst == 4) {
                   /* Should still be able to read data from server */
            if (!TEST_true(SSL_read_ex(clientssl, buf, sizeof(buf),
                                          &readbytes))
                    || !TEST_size_t_eq(readbytes, sizeof(msg))
                    || !TEST_int_eq(memcmp(msg, buf, readbytes), 0))
                goto end;
        }
    }

    /* Writing on the client after sending close_notify shouldn't be possible */
    if (!TEST_false(SSL_write_ex(clientssl, msg, sizeof(msg), &written))
               /*
                * Writing on the server after sending close_notify shouldn't be
                * possible.
                */
            || !TEST_false(SSL_write_ex(clientssl, msg, sizeof(msg), &written)))
        goto end;

    if (tst < 4) {
        /*
         * For these tests the client has sent close_notify but it has not yet
         * been received by the server. The server has not sent close_notify
         * yet.
         */
        if (!TEST_int_eq(SSL_shutdown(serverssl), 0)
                || !TEST_int_eq(SSL_shutdown(clientssl), 1)
                || !TEST_int_eq(SSL_shutdown(serverssl), 1))
            goto end;
    } else {
        /*
         * In this test the client has sent close_notify and it has been
         * received by the server which has responded with a close_notify. The
         * client needs to read the close_notify sent by the server. When
         * tst == 5, there is application data to be read first but this is
         * discarded with a -1 return value.
         */
        if (tst == 5 && !TEST_int_eq(SSL_shutdown(clientssl), -1))
            goto end;
        if (!TEST_int_eq(SSL_shutdown(clientssl), 1))
            goto end;
    }

    testresult = 1;

 end:
    SSL_free(serverssl);
    SSL_free(clientssl);
    SSL_CTX_free(sctx);
    SSL_CTX_free(cctx);

    return testresult;
}

int setup_tests(void)
{
    if (!TEST_ptr(cert = test_get_argument(0))
@@ -5069,6 +5191,7 @@ int setup_tests(void)
    ADD_ALL_TESTS(test_ssl_pending, 2);
    ADD_ALL_TESTS(test_ssl_get_shared_ciphers, OSSL_NELEM(shared_ciphers_data));
    ADD_ALL_TESTS(test_ticket_callbacks, 12);
    ADD_ALL_TESTS(test_shutdown, 6);
    return 1;
}

+22 −4
Original line number Diff line number Diff line
@@ -680,12 +680,14 @@ int create_ssl_objects(SSL_CTX *serverctx, SSL_CTX *clientctx, SSL **sssl,
    return 0;
}

int create_ssl_connection(SSL *serverssl, SSL *clientssl, int want)
/*
 * Create an SSL connection, but does not ready any post-handshake
 * NewSessionTicket messages.
 */
int create_bare_ssl_connection(SSL *serverssl, SSL *clientssl, int want)
{
    int retc = -1, rets = -1, err, abortctr = 0, i;
    int retc = -1, rets = -1, err, abortctr = 0;
    int clienterr = 0, servererr = 0;
    unsigned char buf;
    size_t readbytes;
    int isdtls = SSL_is_dtls(serverssl);

    do {
@@ -738,6 +740,22 @@ int create_ssl_connection(SSL *serverssl, SSL *clientssl, int want)
        }
    } while (retc <=0 || rets <= 0);

    return 1;
}

/*
 * Create an SSL connection including any post handshake NewSessionTicket
 * messages.
 */
int create_ssl_connection(SSL *serverssl, SSL *clientssl, int want)
{
    int i;
    unsigned char buf;
    size_t readbytes;

    if (!create_bare_ssl_connection(serverssl, clientssl, want))
        return 0;

    /*
     * We attempt to read some data on the client side which we expect to fail.
     * This will ensure we have received the NewSessionTicket in TLSv1.3 where
+1 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ int create_ssl_ctx_pair(const SSL_METHOD *sm, const SSL_METHOD *cm,
                        char *privkeyfile);
int create_ssl_objects(SSL_CTX *serverctx, SSL_CTX *clientctx, SSL **sssl,
                       SSL **cssl, BIO *s_to_c_fbio, BIO *c_to_s_fbio);
int create_bare_ssl_connection(SSL *serverssl, SSL *clientssl, int want);
int create_ssl_connection(SSL *serverssl, SSL *clientssl, int want);
void shutdown_ssl_connection(SSL *serverssl, SSL *clientssl);